void MonitorSettingDialog::onMonitorModeChanged() { const bool intersect = m_primary && m_model->monitorsIsIntersect(); if (intersect) updateModeList(m_model->monitorsSameModeList()); else updateModeList(m_monitor->modeList()); if (!intersect) { m_resolutionsModel->setSelectedIndex(m_resolutionsModel->index(m_monitor->modeList().indexOf(m_monitor->currentMode()))); } else { const ResolutionList list = m_model->monitorsSameModeList(); const Resolution mode = m_model->monitorList().first()->currentMode(); for (auto it = list.cbegin(); it != list.cend(); ++it) { if (it->id() == mode.id()) { m_resolutionsModel->setSelectedIndex(m_resolutionsModel->index(it - list.cbegin())); break; } } } }
void MonitorSettingDialog::onMonitorResolutionSelected(const int index) { const bool intersect = m_primary && m_model->monitorsIsIntersect(); if (intersect) { const ResolutionList modeList = m_model->monitorsSameModeList(); Q_ASSERT(modeList.size() > index); const Resolution mode = modeList[index]; for (Monitor* mon : m_model->monitorList()) { const ResolutionList& list = mon->modeList(); for (auto it = list.cbegin(); it != list.cend(); ++it) { if (it->width() == mode.width() && it->height() == mode.height()) { Q_EMIT requestSetMonitorResolution(mon, it->id()); break; } } } } else { const auto modeList = m_monitor->modeList(); Q_ASSERT(modeList.size() > index); Q_EMIT requestSetMonitorResolution(m_monitor, modeList[index].id()); } }
// Perform at most one value conversion from the following set: // // - integer conversions // - float conversions // - numeric conversions (int to float) // - boolean conversions (type to bool) // // Note that all such conversions take value expressions as operands: a // reference-to-value conversion must have been previously applied to // a reference expressions. // // TODO: Implement integer and floating point promotion. // // TODO: Support conversion of T[N] to T[]. // // TODO: Support pointer conversions. // // TODO: Support character conversions separately from integer // conversions? Expr& convert_value(Context& cxt, Expr& e, Type& t) { try { // Note that errors here are not fatal. If we can't find a conversion, // that doesn't mean the program is ill-formed. Suppress_diagnostics guard(cxt); debug(e); debug(t); // Search for a list of conversion operators for the given type. Name& id = cxt.get_conversion_id(t); Decl_list decls = unqualified_lookup(cxt, id); // FIXME: What do I do with ambiguous resolutions? Fail to convert? Resolution res = resolve_call(cxt, decls, e); Function_decl& decl = res.function(); Expr_list& args = res.arguments(); // Build a call to the selected conversion. Expr& fn = cxt.make_reference(decl.type(), decl); Call_expr& conv = cxt.make_call(decl.return_type(), fn, std::move(args)); conv.res_ = &decl; return conv; } catch (...) { return e; } return e; }
int ScreenOutput::setScreenResolution(Resolution newScreenResolution) { if(newScreenResolution.getWidth() > 0 && newScreenResolution.getHeight() > 0) { return resize(newScreenResolution, getAntiAliasingFactor()); } return 0; }
bool contains(const QList<Resolution> &container, const Resolution &item) { for (auto r : container) if (r.width() == item.width() && r.height() == item.height()) return true; return false; }
void SDLPlatform::getDesktopResolution( Resolution & _resolution ) const { SDL_DisplayMode dm; if (SDL_GetDesktopDisplayMode(0, &dm) == 0) { _resolution.setWidth(static_cast<uint32_t>(dm.w)); _resolution.setHeight(static_cast<uint32_t>(dm.h)); } }
int ScreenOutput::resize(Resolution newResolution, int newAntiAliasingFactor) { screenResolution = newResolution; antiAliasingFactor = newAntiAliasingFactor; renderResolution.setWidth(newResolution.getWidth() * newAntiAliasingFactor); renderResolution.setHeight(newResolution.getHeight() * newAntiAliasingFactor); renderBuffer.resize(renderResolution.getWidth(), renderResolution.getHeight()); screenBuffer.resize(screenResolution.getWidth(), screenResolution.getHeight()); screenBMP->SetSize(screenResolution.getWidth(), screenResolution.getHeight()); return 1; }
bool SDLPlatform::createWindow( uint32_t _icon, const Menge::WString & _projectTitle, const Resolution & _resolution, bool _fullscreen ) { PARAM_UNUSED(_icon); PARAM_UNUSED(_fullscreen); Menge::Char utf8Title[1024] = { 0 }; size_t utf8Size = 0; UNICODE_SERVICE( m_serviceProvider )->unicodeToUtf8(_projectTitle.c_str(), _projectTitle.size(), utf8Title, sizeof(utf8Title) - 1, &utf8Size); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1); Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; if( _fullscreen ) { windowFlags |= SDL_WINDOW_FULLSCREEN; } m_width = static_cast<int>(_resolution.getWidth()); m_height = static_cast<int>(_resolution.getHeight()); m_window = reinterpret_cast<WindowHandle>(SDL_CreateWindow(utf8Title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_width, m_height, windowFlags)); if( m_window == nullptr ) { return false; } m_glContext = SDL_GL_CreateContext(reinterpret_cast<SDL_Window*>(m_window)); if( m_glContext == nullptr ) { SDL_DestroyWindow(reinterpret_cast<SDL_Window*>(m_window)); return false; } m_sdlInput->updateSurfaceResolution(static_cast<float>(m_width), static_cast<float>(m_height)); return true; }
int ScreenOutput::initialize(Resolution initResolution, int initAntiAliasingFactor, TCanvas * initOutputCanvas) { // temp! screenResolution = initResolution; antiAliasingFactor = initAntiAliasingFactor; renderResolution.setWidth(initResolution.getWidth() * initAntiAliasingFactor); renderResolution.setHeight(initResolution.getHeight() * initAntiAliasingFactor); renderBuffer.initialize(renderResolution.getWidth(), renderResolution.getHeight()); currentForegroundRenderBuffer = &renderBuffer; screenBuffer.initialize(screenResolution.getWidth(), screenResolution.getHeight()); screenBMP = new Graphics::TBitmap; screenBMP->PixelFormat = pf32bit; screenBMP->SetSize(screenResolution.getWidth(), screenResolution.getHeight()); outputCanvas = initOutputCanvas; return 1; }
void Resolution::calcScale( const Resolution & _resolution, mt::vec2f & _scale ) const { mt::vec2f self_size; this->calcSize( self_size ); mt::vec2f other_size; _resolution.calcSize( other_size ); _scale = self_size / other_size; }
/* * this function tries to be a 1:1 C++ reimplementation of the Perl function * 'read_mcstas_res' of the McStas 'mcresplot' program */ Resolution calc_res(std::vector<vector<t_real>>&& Q_vec, const vector<t_real>& Q_avg, const std::vector<t_real>* pp_vec) { vector<t_real> Q_dir = tl::make_vec({Q_avg[0], Q_avg[1], Q_avg[2]}); Q_dir = Q_dir / norm_2(Q_dir); vector<t_real> Q_perp = tl::make_vec({-Q_dir[1], Q_dir[0], Q_dir[2]}); vector<t_real> vecUp = tl::cross_3(Q_dir, Q_perp); /* * transformation from the <Q_x, Q_y, Q_z, E> system * into the <Q_avg, Q_perp, Q_z, E> system, * i.e. rotate by the (ki,Q) angle */ matrix<t_real> trafo = identity_matrix<t_real>(4); tl::set_column(trafo, 0, Q_dir); tl::set_column(trafo, 1, Q_perp); tl::set_column(trafo, 2, vecUp); tl::log_info("Transformation: ", trafo); Resolution reso; reso.Q_avg_notrafo = Q_avg; reso.Q_avg = prod(trans(trafo), Q_avg); tl::log_info("Transformed average Q vector: ", reso.Q_avg); reso.res.resize(4,4,0); reso.cov.resize(4,4,0); reso.cov = tl::covariance(Q_vec, pp_vec); reso.cov = tl::transform<matrix<t_real>>(reso.cov, trafo, true); tl::log_info("Covariance matrix: ", reso.cov); if(!(reso.bHasRes = tl::inverse(reso.cov, reso.res))) tl::log_err("Covariance matrix could not be inverted!"); if(reso.bHasRes) { reso.dQ.resize(4, 0); for(int iQ=0; iQ<4; ++iQ) reso.dQ[iQ] = tl::get_SIGMA2HWHM<t_real>()/sqrt(reso.res(iQ,iQ)); tl::log_info("Resolution matrix: ", reso.res); std::ostringstream ostrVals; ostrVals << "Gaussian HWHM values: "; std::copy(reso.dQ.begin(), reso.dQ.end(), std::ostream_iterator<t_real>(ostrVals, ", ")); std::ostringstream ostrElli; ostrElli << "Ellipsoid offsets: "; std::copy(reso.Q_avg.begin(), reso.Q_avg.end(), std::ostream_iterator<t_real>(ostrElli, ", ")); reso.vecQ = std::move(Q_vec); tl::log_info(ostrVals.str()); tl::log_info(ostrElli.str()); } return reso; }
bool kanaelec::doKinematicFit(Int_t fflage, const TLorentzVector mup, const TLorentzVector nvp, const TLorentzVector ajp, const TLorentzVector bjp, TLorentzVector & fit_mup, TLorentzVector & fit_nvp, TLorentzVector & fit_ajp, TLorentzVector & fit_bjp, Float_t & fit_chi2, Int_t & fit_NDF, Int_t & fit_status) { bool OK = false; Resolution* resolution = new Resolution(); TMatrixD m1(3,3); TMatrixD m2(3,3); TMatrixD m3(3,3); TMatrixD m4(3,3); m1.Zero(); m2.Zero(); m3.Zero(); m4.Zero(); double etRes, etaRes, phiRes; // lepton resolution const std::string& leptonName = "electron"; const TLorentzVector lepton = mup; if(leptonName == "electron") { OK = resolution->electronResolution(lepton.Et(), lepton.Eta(), etRes, etaRes, phiRes); if(!OK) return OK; } else { OK = resolution->muonResolution( lepton.Et(), lepton.Eta(), etRes, etaRes, phiRes); if(!OK) return OK; } m1(0,0) = resolution->square(etRes); m1(1,1) = resolution->square(etaRes); m1(2,2) = resolution->square(phiRes); // MET resolution OK = resolution->PFMETResolution( nvp.Et(), etRes, etaRes, phiRes); if(!OK) return OK; m2(0,0) = resolution->square(etRes); m2(1,1) = 999.9; // resolution->square(etaRes) m2(2,2) = resolution->square(phiRes); // Leading Jet resolution OK = resolution->udscPFJetResolution( ajp.Et(), ajp.Eta(), etRes, etaRes, phiRes); if(!OK) return OK; m3(0,0) = resolution->square(etRes); m3(1,1) = resolution->square(etaRes); m3(2,2) = resolution->square(phiRes); // Leading Jet resolution OK = resolution->udscPFJetResolution( bjp.Et(), bjp.Eta(), etRes, etaRes, phiRes); if(!OK) return OK; m4(0,0) = resolution->square(etRes); m4(1,1) = resolution->square(etaRes); m4(2,2) = resolution->square(phiRes); TLorentzVector tmp_mup = mup; TLorentzVector tmp_nvp = nvp; TLorentzVector tmp_ajp = ajp; TLorentzVector tmp_bjp = bjp; // Fit Particle TFitParticleEtEtaPhi* particle1 = new TFitParticleEtEtaPhi( "Lepton", "Lepton", &tmp_mup, &m1 ); TFitParticleEtEtaPhi* particle2 = new TFitParticleEtEtaPhi( "Neutrino", "Neutrino", &tmp_nvp, &m2 ); TFitParticleEtEtaPhi* particle3 = new TFitParticleEtEtaPhi( "Jeta", "Jeta", &tmp_ajp, &m3 ); TFitParticleEtEtaPhi* particle4 = new TFitParticleEtEtaPhi( "Jetb", "Jetb", &tmp_bjp, &m4 ); // Constraint TFitConstraintM *mCons1 = new TFitConstraintM( "WMassConstrainta", "WMass-Constrainta", 0, 0 , 80.4); mCons1->addParticles1( particle1, particle2 ); TFitConstraintM *mCons2 = new TFitConstraintM( "WMassConstraintb", "WMass-Constraintb", 0, 0 , 80.4); mCons2->addParticles1( particle3, particle4 ); TFitConstraintEp *pxCons = new TFitConstraintEp( "PxConstraint", "Px-Constraint", 0, TFitConstraintEp::pX , (mup+nvp+ajp+bjp).Px() ); pxCons->addParticles( particle1, particle2, particle3, particle4 ); TFitConstraintEp *pyCons = new TFitConstraintEp( "PyConstraint", "Py-Constraint", 0, TFitConstraintEp::pY , (mup+nvp+ajp+bjp).Py() ); pyCons->addParticles( particle1, particle2, particle3, particle4 ); //Definition of the fitter TKinFitter* fitter = new TKinFitter("fitter", "fitter"); if (fflage == 1 ){ fitter->addMeasParticle( particle1 ); fitter->addMeasParticle( particle2 ); fitter->addMeasParticle( particle3 ); fitter->addMeasParticle( particle4 ); fitter->addConstraint( pxCons ); fitter->addConstraint( pyCons ); fitter->addConstraint( mCons1 ); fitter->addConstraint( mCons2 ); }else if(fflage == 2 ){ fitter->addMeasParticle( particle1 ); fitter->addMeasParticle( particle2 ); fitter->addConstraint( mCons1 ); }else {return false;} //Set convergence criteria fitter->setMaxNbIter( 30 ); fitter->setMaxDeltaS( 1e-2 ); fitter->setMaxF( 1e-1 ); fitter->setVerbosity(1); fitter->fit(); //Return the kinematic fit results fit_status = fitter->getStatus(); fit_chi2 = fitter->getS(); fit_NDF = fitter->getNDF(); fit_mup = *(particle1->getCurr4Vec()); fit_nvp = *(particle2->getCurr4Vec()); fit_ajp = *(particle3->getCurr4Vec()); fit_bjp = *(particle4->getCurr4Vec()); if(fitter->getStatus() == 0) { OK = true; } else { OK = false; } delete resolution; delete particle1; delete particle2; delete particle3; delete particle4; delete mCons1; delete mCons2; delete pxCons; delete pyCons; delete fitter; return OK; }
void draw_tof_singleparticle(const string ConfigDir="../..", const string InFileBase = "../../output/SingleParticle_rv02-00-01_sv02-00-01_mILD_l5_o1_v02/", const string OutFileBase = "../../output/SP") { string plot_config_path = ConfigDir + "/PlottingSettings.cnf"; string ptype_config_path = ConfigDir + "/ParticleTypes.cnf"; string res_config_path = ConfigDir + "/TimeResolutions.cnf"; float min_p = 0, max_p = 100; float min_beta = 0.5, max_beta = 1.05; ConfigReader plot_settings_reader(plot_config_path); auto beta_p_settings = plot_settings_reader["BetaPPlots"]; int bins_p = stoi(beta_p_settings["NbinsBeta"]); int bins_beta = stoi(beta_p_settings["NbinsP"]); int every_nth_bin = stoi(beta_p_settings["BinJumpsPerSlice"]); // Consider only every n-th bin (=slice) in the momentum distribution ConfigReader ptype_reader(ptype_config_path); ParticleVec particle_types {}; auto ptype_names = ptype_reader.get_keys(); for (auto & ptype_name: ptype_names) { auto ptype_sec = ptype_reader[ptype_name]; // Section particle_types.push_back( ParticleType(stoi(ptype_sec["pdgID"]), ptype_sec["name_s"], ptype_name, stod(ptype_sec["mass"]), stoi(ptype_sec["colour"])) ); } int N_ptypes = particle_types.size(); ConfigReader res_reader(res_config_path); ResVec resolutions {}; auto res_values = res_reader.get_keys(); for (auto & res_value: res_values) { auto res_sec = res_reader[res_value]; resolutions.push_back( Resolution(stof(res_value), stoi(res_sec["colour"])) ); } int N_ress = resolutions.size(); HistoMap beta_histos {}; for ( auto &ptype : particle_types ) { for ( auto &res : resolutions) { beta_histos.addHisto( ptype, res ); } } // TODO Also loop over different time estimators?? (Here: CH -> Closest Hit) unique_ptr<TCanvas> c_dummy {new TCanvas("dummy","",1000,800)}; // To write histos to that don't need to be written to current canvas unique_ptr<TCanvas> c_beta_p {new TCanvas("c_beta_p","#beta_{CH} vs momentum",400*N_ress,400*N_ptypes)}; unique_ptr<TCanvas> c_beta_p_average {new TCanvas("c_beta_p_average","#beta_{CH}^{average} vs momentum",400*N_ress,400*N_ptypes)}; c_beta_p->Clear(); c_beta_p_average->Clear(); c_beta_p->Divide(resolutions.size(), particle_types.size()); c_beta_p_average->Divide(resolutions.size(), particle_types.size()); int i_pad=0; vector<TFile*> closables {}; // Because ROOT... To collect files that I need to close later unique_ptr<TFile> file_beta_p {new TFile ( ( OutFileBase + "_beta_p.root" ).c_str() ,"recreate")}; // Get the beta vs p histograms and save for each particle type for ( auto & ptype : particle_types ) { TFile* file = new TFile ( ( InFileBase + to_string(ptype.pdg_id) + "_lctuple.root" ).c_str() ,"r"); TTree* tree = (TTree*) file->Get("MyLCTuple"); TF1* beta_func = new TF1( ("beta_func_" + ptype.name_s).c_str(), "x / sqrt(x^2 + [0]^2)", min_p, max_p); beta_func->SetParameter(0, ptype.mass); beta_func->SetLineWidth(1); beta_func->SetLineColorAlpha(6, 0.5); file_beta_p->WriteTObject(beta_func); for (auto &res : resolutions) { i_pad++; c_beta_p->cd(i_pad); string h_beta_name = "h_beta_" + ptype.name_s + "_" + res.str(); TH2F *h_beta = new TH2F( h_beta_name.c_str(), ("#beta_{CH} vs momentum, " + ptype.name_l + ", " + res.w_unit() + "; p [GeV/c] ; #beta ").c_str(), bins_p, min_p, max_p, bins_beta, min_beta, max_beta ); string tof_res = "tof" + res.str(); string draw_string = tof_res + "len/" + tof_res + "ch/299.8:sqrt(rcmox*rcmox+rcmoy*rcmoy+rcmoz*rcmoz)>>" + h_beta_name; string cut_string = tof_res + "len>1.&&" + tof_res + "ch>0.1&&(" + tof_res + "len/" + tof_res + "ch/299.8)<1.1 && sqrt(rcmox*rcmox+rcmoy*rcmoy+rcmoz*rcmoz)<100.&&abs(rccha)>0.005 && abs(rcmoz)/sqrt(rcmox*rcmox+rcmoy*rcmoy+rcmoz*rcmoz) < 0.792573 && sqrt(rcmox*rcmox+rcmoy*rcmoy) > 0.948543 && nrec==1"; tree->Draw( draw_string.c_str(), cut_string.c_str(), "colz" ); file_beta_p->WriteTObject(h_beta); beta_func->Draw("same"); c_dummy->cd(); beta_histos.getHisto(res, ptype)->histo = h_beta; beta_histos.getHisto(res, ptype)->slice_histo(every_nth_bin); c_beta_p_average->cd(i_pad); string h_beta_average_name = "h_beta_average_" + ptype.name_s + "_" + res.str(); TH1F* h_beta_average = new TH1F( h_beta_average_name.c_str(), ("#beta_{CH}^{average} vs momentum, " + ptype.name_l + ", " + res.w_unit() + ", error = #sigma_{gaus}; p [GeV/c] ; #beta ").c_str(), bins_p, min_p, max_p ); for ( auto & slice: beta_histos.getHisto(res, ptype)->slices ) { int bin = h_beta_average->FindBin(slice.p); if (slice.fit_successful) { h_beta_average->SetBinContent(bin, slice.mean); h_beta_average->SetBinError( bin, slice.sigma); } } h_beta_average->SetMarkerSize(0); h_beta_average->SetFillColor(2); h_beta_average->Draw("E5"); beta_func->Draw("same"); file_beta_p->WriteTObject(h_beta_average); file->cd(); } closables.push_back(file); } c_beta_p->Print( (OutFileBase + "_beta_p.pdf").c_str() ); c_beta_p_average->Print( (OutFileBase + "_beta_p_average.pdf").c_str() ); file_beta_p->Close(); // Save the sliced histograms for ( auto & res: resolutions ) { unique_ptr<TFile> file_slices { new TFile( (OutFileBase + "_slices_" + res.w_unit() + ".root").c_str(), "RECREATE" ) }; for ( auto & histo: beta_histos.getHistosToRes(res) ) { for ( auto & slice: histo->slices ) { slice.histo->Write(); } } file_slices->Close(); } unique_ptr<TFile> file_sep_pwr { new TFile( (OutFileBase + "_separation_powers.root").c_str(), "RECREATE" ) }; // Find separation power for all combinations for (int i=0; i<N_ptypes-1; i++) { if ( 1 == N_ptypes ) { cout << "Only one particle type given, not creating separation power plots." << endl; break; } for (int j=i+1; j<N_ptypes; j++) { // Loop avoids dublicats ParticleType ptype1 = particle_types[i]; ParticleType ptype2 = particle_types[j]; unique_ptr<TCanvas> c_sep_pwr {new TCanvas( ("c_sep_pwr_" + ptype1.name_s + "_" + ptype2.name_s).c_str() , "Separation power vs momentum", 800*resolutions.size(),800)}; c_sep_pwr->Divide(resolutions.size(), 1); int i_seppwr_pad = 1; vector<pair<Resolution,TH1D*>> sep_pwr_hists {}; for ( auto & res: resolutions ) { auto slices_p1 = beta_histos.getHisto(res, ptype1)->slices; auto slices_p2 = beta_histos.getHisto(res, ptype2)->slices; int N_slices = slices_p1.size(); TH1D* h_seppwr = new TH1D(("h_seppwr_" + ptype1.name_s + ptype2.name_s + res.str()).c_str(), (ptype1.name_l + " - " + ptype2.name_l + " TOF-separation, " + res.w_unit() + "; p [GeV/c] ; Separation Power [#sigma]").c_str(), N_slices, min_p, max_p); for (int i_slice=0; i_slice<N_slices; i_slice++) { auto slice_p1 = slices_p1[i_slice]; auto slice_p2 = slices_p2[i_slice]; double p = slice_p1.p; if ( ! (slice_p1.fit_successful && slice_p2.fit_successful) ) { cout << ptype1.name_l << " - " << ptype2.name_l << ", " << res.w_unit() << " : Fit in slice p=" << p << " not successful, point won't be drawn." << endl; continue; } double diff_mean = abs(slice_p1.mean - slice_p2.mean); double sigma_sqr_sum = pow(slice_p1.sigma, 2) + pow(slice_p2.sigma, 2); double ms_sigma = sigma_sqr_sum / 2.0; // ms = mean squared double rms_sigma = sqrt( ms_sigma ); // rms = root mean squared double sep_pwr = diff_mean / rms_sigma; double sep_pwr_err = sqrt( (pow(slice_p1.mean_err,2) + pow(slice_p2.mean_err,2))/ms_sigma + pow(diff_mean,2) * (pow(slice_p1.sigma,2)*pow(slice_p1.sigma_err,2) + pow(slice_p2.sigma,2)*pow(slice_p2.sigma_err,2)) / (4*pow(ms_sigma,3)) ); // Check that sep pwr is not NaN if ( sep_pwr != sep_pwr) { sep_pwr = sep_pwr_err = 0; } h_seppwr->SetBinContent(h_seppwr->FindBin(p), sep_pwr); h_seppwr->SetBinError( h_seppwr->FindBin(p), sep_pwr_err); } h_seppwr->Write(); c_sep_pwr->cd(i_seppwr_pad++); h_seppwr->Draw("pe"); // TODO Better drawing style: Set some better markers, REMOVE X ERROR h_seppwr->SetMinimum(0); h_seppwr->SetMaximum(40); sep_pwr_hists.push_back(make_pair(res,h_seppwr)); } c_sep_pwr->Write(); unique_ptr<TCanvas> c_sep_pwr_comb { new TCanvas( ("c_sep_pwr_comb_" + ptype1.name_s + "_" + ptype2.name_s).c_str() , "Separation power vs momentum", 800,800) }; unique_ptr<THStack> h_sep_pwr_comb { new THStack( ("h_seppwr_comb_" + ptype1.name_s + ptype2.name_s).c_str(), (ptype1.name_l + " - " + ptype2.name_l + " TOF-separation; p [GeV/c] ; Separation Power [#sigma]").c_str()) }; unique_ptr<TLegend> leg_sep_pwr_comb { new TLegend(0.48,0.7,0.8,0.9) }; for (auto &res_hist: sep_pwr_hists) { Resolution res = res_hist.first; TH1D* h_seppwr = res_hist.second; leg_sep_pwr_comb->AddEntry(h_seppwr, res.w_unit().c_str(), "lep"); h_sep_pwr_comb->Add(h_seppwr); h_seppwr->SetLineColor(res.colour_index); } h_sep_pwr_comb->Draw("nostack"); h_sep_pwr_comb->SetMinimum(0); if( h_sep_pwr_comb->GetMaximum() > 120 ) { h_sep_pwr_comb->SetMaximum(100); } gPad->Modified(); gPad->Update(); leg_sep_pwr_comb->Draw(); c_sep_pwr_comb->Write(); } } file_sep_pwr->Close(); for ( auto & closable : closables ) { closable->Close(); delete closable; } }