8 #include <ecl/modules/eclChargedPIDDataAnalysisExpert/ECLChargedPIDDataAnalysisValidationModule.h>
10 #include <ecl/dataobjects/ECLPidLikelihood.h>
11 #include <mdst/dataobjects/ECLCluster.h>
12 #include <mdst/dataobjects/MCParticle.h>
13 #include <mdst/dataobjects/Track.h>
15 #include <TEfficiency.h>
23 REG_MODULE(ECLChargedPIDDataAnalysisValidation);
32 setDescription(
"This module dumps a set of histograms with ECL charged PID-related info used for validation, starting from an input file w/ particle-gun-generated charged stable particles (and antiparticles).");
35 std::vector<int> defaultChargedPdgIds;
37 defaultChargedPdgIds.push_back(hypo.getPDGCode());
38 defaultChargedPdgIds.push_back(-hypo.getPDGCode());
42 "The list of (signed) pdgIds of the charged stable particles for which validation plots should be produced. Default is ALL charged stable particles.",
43 defaultChargedPdgIds);
45 "The list of (unsigned) pdgIds of the charged stable particles for which particle and antiparticle should be merged together in the plots. Default is no merging, meaning separate plots are generated for +/- charged particles for each input pdgId.",
46 std::vector<unsigned int>());
48 "The base name of the output file. The pdgId of the charged particle is appended to the name.",
49 std::string(
"ECLChargedPid"));
51 "If this flag is set to True, save also the validation TTree. Default is False.",
62 B2INFO(
"Initialising ROOT objects...");
73 B2WARNING(
"For (unsigned) hypothesis " << hypo.getPDGCode() <<
", validation plots will be merged for +/- charged particles.");
78 std::string chargedPdgIdStr;
85 B2FATAL(
"PDG: " << chargedPdgId <<
" in m_inputPdgIdSet is not that of a valid particle in Const::chargedStableSet! Aborting...");
95 auto chargedIdx = chargedHypo.
getIndex();
97 if (chargedPdgId > 0) {
98 chargedPdgIdStr = std::to_string(chargedPdgId);
100 chargedPdgIdStr =
"anti" + std::to_string(std::abs(chargedPdgId));
107 m_outputFile[chargedIdx] =
new TFile(fname.c_str(),
"RECREATE");
109 m_tree[chargedIdx] =
new TTree(
"ECLChargedPid",
"ECLChargedPid");
110 m_tree[chargedIdx]->Branch(
"p", &
m_p[chargedIdx],
"p/F");
111 m_tree[chargedIdx]->Branch(
"pt", &
m_pt[chargedIdx],
"pt/F");
112 m_tree[chargedIdx]->Branch(
"trkTheta", &
m_trkTheta[chargedIdx],
"trkTheta/F");
113 m_tree[chargedIdx]->Branch(
"trkPhi", &
m_trkPhi[chargedIdx],
"trkPhi/F");
118 m_tree[chargedIdx]->Branch(
"logl_sig", &
m_logl_sig[chargedIdx],
"logl_sig/F");
119 m_tree[chargedIdx]->Branch(
"logl_bkg", &
m_logl_bkg[chargedIdx],
"logl_bkg/F");
142 auto chargedIdx = chargedHypo.
getIndex();
144 if (chargedPdgId < 0) {
150 m_p[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
151 m_pt[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
152 m_trkTheta[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
153 m_trkPhi[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
154 m_clusterTheta[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
155 m_clusterPhi[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
156 m_clusterReg[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
158 m_logl_sig[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
159 m_logl_bkg[chargedIdx] = std::numeric_limits<float>::quiet_NaN();
162 m_pids_glob[chargedIdx][chargedStable.getIndex()] = std::numeric_limits<float>::quiet_NaN();
175 if (std::abs(particle.getPDG()) != std::abs(chargedPdgId))
continue;
178 if (particle.getPDG() != chargedPdgId)
continue;
184 double p_max(-999.0);
185 for (
const auto& track : particle.getRelationsFrom<
Track>()) {
186 const auto fitRes = track.getTrackFitResultWithClosestMass(
Const::pion);
187 if (!fitRes)
continue;
188 if (fitRes->getMomentum().R() > p_max) {
189 p_max = fitRes->getMomentum().R();
194 if (itrack_max < 0)
continue;
196 const auto track = particle.getRelationsFrom<
Track>()[itrack_max];
200 if (not eclLikelihood)
202 const auto fitRes = track->getTrackFitResultWithClosestMass(
Const::pion);
204 m_p[chargedIdx] = p_max;
205 m_pt[chargedIdx] = fitRes->get4Momentum().Pt();
206 m_trkTheta[chargedIdx] = fitRes->get4Momentum().Theta();
207 m_trkPhi[chargedIdx] = fitRes->get4Momentum().Phi();
210 int icluster_match(-1);
211 auto eclClusters = track->getRelationsTo<
ECLCluster>();
212 for (
unsigned int icluster(0); icluster < eclClusters.size(); ++icluster) {
213 const auto eclCluster = eclClusters[icluster];
215 if (!eclCluster->isTrack())
continue;
216 icluster_match = icluster;
220 if (icluster_match < 0) {
225 const auto eclCluster = eclClusters[icluster_match];
229 m_clusterReg[chargedIdx] = eclCluster->getDetectorRegion();
239 double lh_sig = eclLikelihood->getLikelihood(chargedStableSig);
240 double lh_bkg = eclLikelihood->getLikelihood(chargedStableBkg);
249 lh_all += eclLikelihood->getLikelihood(chargedStable);
252 m_pids_glob[chargedIdx][chargedStable.getIndex()] = eclLikelihood->getLikelihood(chargedStable) / lh_all;
257 m_tree[chargedIdx]->Fill();
277 if (mergeCharge && chargedPdgId <= 0)
continue;
280 const auto chargeSign =
static_cast<int>(chargedPdgId / std::abs(chargedPdgId));
283 const auto chargedStableSig = chargedStableSample;
290 auto chargedSampleIdx = (chargeSign > 0) ? chargedStableSig.
getIndex() : chargedStableSig.getIndex() +
295 auto pdgIdDesc = (mergeCharge) ? std::to_string(chargedPdgId) +
" and -" + std::to_string(chargedPdgId) : std::to_string(
299 TNamed(
"Description", TString::Format(
"ECL Charged PID control plots for charged stable particles/antiparticles ; Sample PDG = %s",
300 pdgIdDesc.c_str()).Data()).Write();
303 dumpPIDVars(
m_tree[chargedSampleIdx], chargedStableSig, chargeSign, chargedStableBkg, mergeCharge);
316 m_tree[chargedSampleIdx]->Write();
330 const auto sigHypoIdx = sigHypo.
getIndex();
331 const auto sigHypoPdgId = sigHypo.
getPDGCode();
334 const auto bkgHypoPdgId = bkgHypo.
getPDGCode();
338 TString pidSigBranch = TString::Format(
"pids_glob[%i]", sigHypoIdx);
341 TString h_pid_name = TString::Format(
"h_pid_sig_%i", sigHypoPdgId);
342 TH1F* h_pid =
new TH1F(h_pid_name.Data(), h_pid_name.Data(), 50, -0.5, 1.2);
343 h_pid->GetXaxis()->SetTitle(TString::Format(
"Likelihood ratio (%i/ALL) (ECL)", sigHypoPdgId).Data());
346 TString h_deltalogl_name = TString::Format(
"h_deltalogl_bkg_%i_sig_%i", bkgHypoPdgId, sigHypoPdgId);
347 double deltalogl_min = -20.0;
348 double deltalogl_max = 20.0;
349 TH1F* h_deltalogl =
new TH1F(h_deltalogl_name.Data(), h_deltalogl_name.Data(), 40, deltalogl_min, deltalogl_max);
350 h_deltalogl->GetXaxis()->SetTitle(TString::Format(
"#Deltaln(L) (%i/%i) (ECL)", bkgHypoPdgId, sigHypoPdgId).Data());
353 TString h_trkclusmatch_name = TString::Format(
"h_trkclusmatch_sig_%i", sigHypoPdgId);
354 TH1F* h_trkclusmatch =
new TH1F(h_trkclusmatch_name.Data(), h_trkclusmatch_name.Data(), 4, -1.5, 2.5);
355 h_trkclusmatch->GetXaxis()->SetTitle(TString::Format(
"Track-ECLCluster match (%i)", sigHypoPdgId).Data());
358 sampleTree->Project(h_pid_name.Data(), pidSigBranch.Data());
359 sampleTree->Project(h_deltalogl_name.Data(),
"deltalogl_sig_bkg");
360 sampleTree->Project(h_trkclusmatch_name.Data(),
"trackClusterMatch");
367 h_pid->SetOption(
"HIST");
368 h_deltalogl->SetOption(
"HIST");
369 h_trkclusmatch->SetOption(
"HIST");
372 std::string metaopts(
"pvalue-warn=0.1,pvalue-error=0.01");
373 std::string shifteropt(
"");
376 shifteropt =
"shifter,";
379 auto pdgIdDesc = (!mergeSigCharge) ? std::to_string(sigHypoPdgId * sigCharge) : std::to_string(
380 sigHypoPdgId) +
" and -" + std::to_string(sigHypoPdgId);
383 h_pid->GetListOfFunctions()->Add(
new TNamed(
"Description",
384 TString::Format(
"Sample PDG = %s ; ECL global PID(%i) distribution. U/O flow is added to first (last) bin.",
386 sigHypoPdgId).Data()));
387 h_pid->GetListOfFunctions()->Add(
new TNamed(
"Check",
388 "The more peaked at 1, the better. Non-zero O-flow indicates either failure of MC matching for reco tracks (unlikely), or failure of track-ECL-cluster matching (more likely). Both cases result in PID=nan."));
389 h_pid->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Marco Milesi. marco.milesi@desy.de"));
390 h_pid->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
392 h_deltalogl->GetListOfFunctions()->Add(
new TNamed(
"Description",
393 TString::Format(
"Sample PDG = %s ; ECL distribution of binary $\\Delta log(L)$ = log(L(%i)) - log(L(%i)). U/O flow is added to first (last) bin.",
396 sigHypoPdgId).Data()));
397 h_deltalogl->GetListOfFunctions()->Add(
new TNamed(
"Check",
398 "Basic metric for signal/bkg separation. The more negative, the better separation is achieved. Non-zero U-flow indicates a non-normal PDF value (of sig OR bkg) for some p,clusterTheta range, which might be due to a non-optimal definition of the x-axis range of the PDF templates. Non-zero O-flow indicates either failure of MC matching for reco tracks (unlikely), or failure of track-ECL-cluster matching (more likely)."));
399 h_deltalogl->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Marco Milesi. marco.milesi@desy.de"));
400 h_deltalogl->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
402 h_trkclusmatch->GetListOfFunctions()->Add(
new TNamed(
"Description",
403 TString::Format(
"Sample PDG = %s ; Track-ECLCluster match flag distribution.",
404 pdgIdDesc.c_str()).Data()));
405 h_trkclusmatch->GetListOfFunctions()->Add(
new TNamed(
"Check",
406 "The more peaked at 1, the better. Non-zero population in the bins w/ flag != 0|1 indicates failure of MC matching for reco tracks. In such cases, flag=nan."));
407 h_trkclusmatch->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Frank Meier. frank.meier@desy.de"));
408 h_trkclusmatch->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", metaopts.c_str()));
411 h_deltalogl->Write();
412 h_trkclusmatch->Write();
416 delete h_trkclusmatch;
426 const std::string ratioType = (sampleHypo == sigHypo) ?
"Efficiency" :
"FakeRate";
429 const int sampleHypoPdgId = sampleHypo.
getPDGCode() * sampleCharge;
432 const auto sigHypoIdx = sigHypo.
getIndex();
433 const auto sigHypoPdgId = sigHypo.
getPDGCode();
437 TString pidSigCut = TString::Format(
"pids_glob[%i] > %f", sigHypoIdx,
c_PID);
440 TString h_p_N_name = TString::Format(
"h_p_N_%i", sigHypoPdgId);
441 TString h_p_D_name = TString::Format(
"h_p_D_%i", sigHypoPdgId);
442 TH1F* h_p_N =
new TH1F(h_p_N_name.Data(),
"h_p_N", 10, 0.0, 5.0);
443 TH1F* h_p_D =
new TH1F(h_p_D_name.Data(),
"h_p_D", 10, 0.0, 5.0);
445 TString h_th_N_name = TString::Format(
"h_th_N_%i", sigHypoPdgId);
446 TString h_th_D_name = TString::Format(
"h_th_D_%i", sigHypoPdgId);
450 TString h_eclreg_N_name = TString::Format(
"h_eclreg_N_%i", sigHypoPdgId);
451 TString h_eclreg_D_name = TString::Format(
"h_eclreg_D_%i", sigHypoPdgId);
452 TH1F* h_eclreg_N =
new TH1F(h_eclreg_N_name.Data(),
"h_eclreg_N", 5, -0.5, 4.5);
453 TH1F* h_eclreg_D =
new TH1F(h_eclreg_D_name.Data(),
"h_eclreg_D", 5, -0.5, 4.5);
455 TString h_phi_N_name = TString::Format(
"h_phi_N_%i", sigHypoPdgId);
456 TString h_phi_D_name = TString::Format(
"h_phi_D_%i", sigHypoPdgId);
457 TH1F* h_phi_N =
new TH1F(h_phi_N_name.Data(),
"h_phi_N", 5, -3.14159, 3.14159);
458 TH1F* h_phi_D =
new TH1F(h_phi_D_name.Data(),
"h_phi_D", 5, -3.14159, 3.14159);
462 sampleTree->Project(h_p_N_name.Data(),
"p", pidSigCut.Data());
463 sampleTree->Project(h_p_D_name.Data(),
"p");
465 sampleTree->Project(h_th_N_name.Data(),
"clusterTheta", pidSigCut.Data());
466 sampleTree->Project(h_th_D_name.Data(),
"clusterTheta");
468 sampleTree->Project(h_eclreg_N_name.Data(),
"clusterReg", pidSigCut.Data());
469 sampleTree->Project(h_eclreg_D_name.Data(),
"clusterReg");
473 sampleTree->Project(h_phi_N_name.Data(),
"clusterPhi", pidSigCut.Data());
474 sampleTree->Project(h_phi_D_name.Data(),
"clusterPhi");
478 TString pid_glob_ratio_p_name = TString::Format(
"pid_glob_%i_%s__VS_p", sigHypoPdgId, ratioType.c_str());
479 TString pid_glob_ratio_th_name = TString::Format(
"pid_glob_%i_%s__VS_th", sigHypoPdgId, ratioType.c_str());
480 TString pid_glob_ratio_eclreg_name = TString::Format(
"pid_glob_%i_%s__VS_eclreg", sigHypoPdgId, ratioType.c_str());
481 TString pid_glob_ratio_phi_name = TString::Format(
"pid_glob_%i_%s__VS_phi", sigHypoPdgId, ratioType.c_str());
484 std::string metaopts(
"pvalue-warn=0.01,pvalue-error=0.001,nostats");
485 std::string shifteropt(
"");
488 shifteropt =
"shifter,";
491 auto pdgIdDesc = (!mergeSampleCharge) ? std::to_string(sampleHypoPdgId) : std::to_string(std::abs(
492 sampleHypoPdgId)) +
" and -" + std::to_string(std::abs(sampleHypoPdgId));
494 if (TEfficiency::CheckConsistency(*h_p_N, *h_p_D)) {
496 TEfficiency* t_pid_glob_ratio_p =
new TEfficiency(*h_p_N, *h_p_D);
497 t_pid_glob_ratio_p->SetName(pid_glob_ratio_p_name.Data());
498 t_pid_glob_ratio_p->SetTitle(TString::Format(
"%s;p [GeV/c];#varepsilon/f", pid_glob_ratio_p_name.Data()).Data());
500 t_pid_glob_ratio_p->SetConfidenceLevel(0.683);
501 t_pid_glob_ratio_p->SetStatisticOption(TEfficiency::kBUniform);
502 t_pid_glob_ratio_p->SetPosteriorMode();
504 t_pid_glob_ratio_p->GetListOfFunctions()->Add(
new TNamed(
"Description",
505 TString::Format(
"Sample PDG = %s ; %s of ECL global PID(%i) > %.2f as a function of $p_{trk}$.",
510 t_pid_glob_ratio_p->GetListOfFunctions()->Add(
new TNamed(
"Check",
511 "Shape should be consistent. Obviously, check for decreasing efficiency / increasing fake rate."));
512 t_pid_glob_ratio_p->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Marco Milesi. marco.milesi@desy.de"));
513 t_pid_glob_ratio_p->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
515 t_pid_glob_ratio_p->Write();
517 delete t_pid_glob_ratio_p;
520 if (TEfficiency::CheckConsistency(*h_th_N, *h_th_D)) {
522 TEfficiency* t_pid_glob_ratio_th =
new TEfficiency(*h_th_N, *h_th_D);
523 t_pid_glob_ratio_th->SetName(pid_glob_ratio_th_name.Data());
524 t_pid_glob_ratio_th->SetTitle(TString::Format(
"%s;#theta_{cluster} [rad];#varepsilon/f", pid_glob_ratio_th_name.Data()).Data());
526 t_pid_glob_ratio_th->SetConfidenceLevel(0.683);
527 t_pid_glob_ratio_th->SetStatisticOption(TEfficiency::kBUniform);
528 t_pid_glob_ratio_th->SetPosteriorMode();
530 t_pid_glob_ratio_th->GetListOfFunctions()->Add(
new TNamed(
"Description",
531 TString::Format(
"Sample PDG = %s ; %s of ECL global PID(%i) > %.2f as a function of $\\theta_{cluster}$.",
536 t_pid_glob_ratio_th->GetListOfFunctions()->Add(
new TNamed(
"Check",
537 "Shape should be consistent. Obviously, check for decreasing efficiency / increasing fake rate."));
538 t_pid_glob_ratio_th->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Marco Milesi. marco.milesi@desy.de"));
539 t_pid_glob_ratio_th->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
541 t_pid_glob_ratio_th->Write();
543 delete t_pid_glob_ratio_th;
545 if (TEfficiency::CheckConsistency(*h_eclreg_N, *h_eclreg_D)) {
547 TEfficiency* t_pid_glob_ratio_eclreg =
new TEfficiency(*h_eclreg_N, *h_eclreg_D);
548 t_pid_glob_ratio_eclreg->SetName(pid_glob_ratio_eclreg_name.Data());
549 t_pid_glob_ratio_eclreg->SetTitle(TString::Format(
"%s;ECL Region;#varepsilon/f", pid_glob_ratio_eclreg_name.Data()).Data());
551 t_pid_glob_ratio_eclreg->SetConfidenceLevel(0.683);
552 t_pid_glob_ratio_eclreg->SetStatisticOption(TEfficiency::kBUniform);
553 t_pid_glob_ratio_eclreg->SetPosteriorMode();
555 t_pid_glob_ratio_eclreg->GetListOfFunctions()->Add(
new TNamed(
"Description",
556 TString::Format(
"Sample PDG = %s ; %s of ECL global PID(%i) > %.2f as a function of ECL cluster region ($\\theta_{cluster}$). Regions are labelled: 0 (outside ECL acceptance), 1 (ECL FWD), 2 (ECL Barrel), 3 (ECL BWD), 4 (ECL FWD/BWD gaps).",
561 t_pid_glob_ratio_eclreg->GetListOfFunctions()->Add(
new TNamed(
"Check",
562 "Shape should be consistent. Obviously, check for decreasing efficiency / increasing fake rate."));
563 t_pid_glob_ratio_eclreg->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Marco Milesi. marco.milesi@desy.de"));
564 t_pid_glob_ratio_eclreg->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", metaopts.c_str()));
566 t_pid_glob_ratio_eclreg->Write();
568 delete t_pid_glob_ratio_eclreg;
571 if (TEfficiency::CheckConsistency(*h_phi_N, *h_phi_D)) {
573 TEfficiency* t_pid_glob_ratio_phi =
new TEfficiency(*h_phi_N, *h_phi_D);
574 t_pid_glob_ratio_phi->SetName(pid_glob_ratio_phi_name.Data());
575 t_pid_glob_ratio_phi->SetTitle(TString::Format(
"%s;#phi_{cluster} [rad];#varepsilon/f", pid_glob_ratio_phi_name.Data()).Data());
577 t_pid_glob_ratio_phi->SetConfidenceLevel(0.683);
578 t_pid_glob_ratio_phi->SetStatisticOption(TEfficiency::kBUniform);
579 t_pid_glob_ratio_phi->SetPosteriorMode();
581 t_pid_glob_ratio_phi->GetListOfFunctions()->Add(
new TNamed(
"Description",
582 TString::Format(
"Sample PDG = %s ; %s of ECL global PID(%i) > %.2f as a function of $\\phi_{cluster}$.",
587 t_pid_glob_ratio_phi->GetListOfFunctions()->Add(
new TNamed(
"Check",
588 "Shape should be consistent. Obviously, check for decreasing efficiency / increasing fake rate."));
589 t_pid_glob_ratio_phi->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Marco Milesi. marco.milesi@desy.de"));
590 t_pid_glob_ratio_phi->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
592 t_pid_glob_ratio_phi->Write();
594 delete t_pid_glob_ratio_phi;
610 const int sampleCharge,
bool mergeSampleCharge)
614 const auto sampleHypoPdgId = sampleHypo.
getPDGCode();
617 TString h_pt_N_name = TString::Format(
"h_pt_N_%i", sampleHypoPdgId);
618 TString h_pt_D_name = TString::Format(
"h_pt_D_%i", sampleHypoPdgId);
619 TH1F* h_pt_N =
new TH1F(h_pt_N_name.Data(),
"h_pt_N", 10, 0.0, 5.0);
620 TH1F* h_pt_D =
new TH1F(h_pt_D_name.Data(),
"h_pt_D", 10, 0.0, 5.0);
622 TString h_th_N_name = TString::Format(
"h_th_N_%i", sampleHypoPdgId);
623 TString h_th_D_name = TString::Format(
"h_th_D_%i", sampleHypoPdgId);
627 TString h_phi_N_name = TString::Format(
"h_phi_N_%i", sampleHypoPdgId);
628 TString h_phi_D_name = TString::Format(
"h_phi_D_%i", sampleHypoPdgId);
629 TH1F* h_phi_N =
new TH1F(h_phi_N_name.Data(),
"h_phi_N", 5, -3.14159, 3.14159);
630 TH1F* h_phi_D =
new TH1F(h_phi_D_name.Data(),
"h_phi_D", 5, -3.14159, 3.14159);
632 TString match_cut_N(
"trackClusterMatch == 1");
633 TString match_cut_D(
"trackClusterMatch >= 0");
637 tree->Project(h_pt_N_name.Data(),
"pt", match_cut_N.Data());
638 tree->Project(h_pt_D_name.Data(),
"pt", match_cut_D.Data());
640 tree->Project(h_th_N_name.Data(),
"trkTheta", match_cut_N.Data());
641 tree->Project(h_th_D_name.Data(),
"trkTheta", match_cut_D.Data());
643 tree->Project(h_phi_N_name.Data(),
"trkPhi", match_cut_N.Data());
644 tree->Project(h_phi_D_name.Data(),
"trkPhi", match_cut_D.Data());
648 TString match_eff_pt_name = TString::Format(
"trkclusmatch_%i_Efficiency__VS_pt", sampleHypoPdgId);
649 TString match_eff_th_name = TString::Format(
"trkclusmatch_%i_Efficiency__VS_th", sampleHypoPdgId);
650 TString match_eff_phi_name = TString::Format(
"trkclusmatch_%i_Efficiency__VS_phi", sampleHypoPdgId);
653 std::string metaopts(
"pvalue-warn=0.01,pvalue-error=0.001,nostats");
654 std::string shifteropt(
"");
657 shifteropt =
"shifter,";
660 auto pdgIdDesc = (!mergeSampleCharge) ? std::to_string(sampleHypoPdgId * sampleCharge) : std::to_string(
661 sampleHypoPdgId) +
" and -" + std::to_string(sampleHypoPdgId);
663 if (TEfficiency::CheckConsistency(*h_pt_N, *h_pt_D)) {
665 TEfficiency* t_match_eff_pt =
new TEfficiency(*h_pt_N, *h_pt_D);
666 t_match_eff_pt->SetName(match_eff_pt_name.Data());
667 t_match_eff_pt->SetTitle(TString::Format(
"%s;p_{T}^{trk} [GeV/c];#varepsilon", match_eff_pt_name.Data()).Data());
668 t_match_eff_pt->SetTitle(match_eff_pt_name.Data());
670 t_match_eff_pt->SetConfidenceLevel(0.683);
671 t_match_eff_pt->SetStatisticOption(TEfficiency::kBUniform);
672 t_match_eff_pt->SetPosteriorMode();
674 t_match_eff_pt->GetListOfFunctions()->Add(
new TNamed(
"Description",
675 TString::Format(
"Sample PDG = %s ; Efficiency of track-ECL-cluster matching as a function of $p_{T}^{trk}$.",
676 pdgIdDesc.c_str()).Data()));
677 t_match_eff_pt->GetListOfFunctions()->Add(
new TNamed(
"Check",
678 "Shape should be consistent. Obviously, check for decreasing efficiency."));
679 t_match_eff_pt->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Frank Meier. frank.meier@desy.de"));
680 t_match_eff_pt->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
682 t_match_eff_pt->Write();
684 delete t_match_eff_pt;
687 if (TEfficiency::CheckConsistency(*h_th_N, *h_th_D)) {
689 TEfficiency* t_match_eff_th =
new TEfficiency(*h_th_N, *h_th_D);
690 t_match_eff_th->SetName(match_eff_th_name.Data());
691 t_match_eff_th->SetTitle(TString::Format(
"%s;#theta_{trk} [rad];#varepsilon", match_eff_th_name.Data()).Data());
692 t_match_eff_th->SetTitle(match_eff_th_name.Data());
694 t_match_eff_th->SetConfidenceLevel(0.683);
695 t_match_eff_th->SetStatisticOption(TEfficiency::kBUniform);
696 t_match_eff_th->SetPosteriorMode();
698 t_match_eff_th->GetListOfFunctions()->Add(
new TNamed(
"Description",
699 TString::Format(
"Sample PDG = %s ; Efficiency of track-ECL-cluster matching as a function of $\\theta_{trk}$.",
700 pdgIdDesc.c_str()).Data()));
701 t_match_eff_th->GetListOfFunctions()->Add(
new TNamed(
"Check",
702 "Shape should be consistent. Obviously, check for decreasing efficiency."));
703 t_match_eff_th->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Frank Meier. frank.meier@desy.de"));
704 t_match_eff_th->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
706 t_match_eff_th->Write();
708 delete t_match_eff_th;
711 if (TEfficiency::CheckConsistency(*h_phi_N, *h_phi_D)) {
713 TEfficiency* t_match_eff_phi =
new TEfficiency(*h_phi_N, *h_phi_D);
714 t_match_eff_phi->SetName(match_eff_phi_name.Data());
715 t_match_eff_phi->SetTitle(TString::Format(
"%s;#phi_{trk} [rad];#varepsilon", match_eff_phi_name.Data()).Data());
717 t_match_eff_phi->SetConfidenceLevel(0.683);
718 t_match_eff_phi->SetStatisticOption(TEfficiency::kBUniform);
719 t_match_eff_phi->SetPosteriorMode();
721 t_match_eff_phi->GetListOfFunctions()->Add(
new TNamed(
"Description",
722 TString::Format(
"Sample PDG = %s ; Efficiency of track-ECL-cluster matching as a function of $\\phi_{trk}$.",
723 pdgIdDesc.c_str()).Data()));
724 t_match_eff_phi->GetListOfFunctions()->Add(
new TNamed(
"Check",
725 "Shape should be consistent. Obviously, check for decreasing efficiency."));
726 t_match_eff_phi->GetListOfFunctions()->Add(
new TNamed(
"Contact",
"Frank Meier. frank.meier@desy.de"));
727 t_match_eff_phi->GetListOfFunctions()->Add(
new TNamed(
"MetaOptions", (shifteropt + metaopts).c_str()));
729 t_match_eff_phi->Write();
731 delete t_match_eff_phi;
747 auto nentries = h->GetEntries();
748 auto nbins_vis = h->GetNbinsX();
751 float bin_vis_first = h->GetBinContent(1);
752 float bin_vis_last = h->GetBinContent(nbins_vis);
753 float bin_vis_first_err = h->GetBinError(1);
754 float bin_vis_last_err = h->GetBinError(nbins_vis);
757 float bin_uflow = h->GetBinContent(0);
758 float bin_oflow = h->GetBinContent(nbins_vis + 1);
759 float bin_uflow_err = h->GetBinError(0);
760 float bin_oflow_err = h->GetBinError(nbins_vis + 1);
763 h->SetBinContent(1, bin_vis_first + bin_uflow);
764 h->SetBinError(1,
sqrt(bin_vis_first_err * bin_vis_first_err + bin_uflow_err * bin_uflow_err));
765 h->SetBinContent(nbins_vis, bin_vis_last + bin_oflow);
766 h->SetBinError(nbins_vis,
sqrt(bin_vis_last_err * bin_vis_last_err + bin_oflow_err * bin_oflow_err));
769 h->SetEntries(nentries);
Provides a type-safe way to pass members of the chargedStableSet set.
static const unsigned int c_SetSize
Number of elements (for use in array bounds etc.)
const ParticleType & find(int pdg) const
Returns particle in set with given PDG code, or invalidParticle if not found.
int getPDGCode() const
PDG code.
int getIndex() const
This particle's index in the associated set.
static const ChargedStable muon
muon particle
static const ParticleSet chargedStableSet
set of charged stable particles
static const ChargedStable pion
charged pion particle
static const ChargedStable kaon
charged kaon particle
static const ChargedStable electron
electron particle
std::vector< float > m_trackClusterMatch
Flag for track-cluster matching condition.
ECLChargedPIDDataAnalysisValidationModule()
Constructor of the module.
bool isValidChargedPdg(const int pdg) const
Check if the input pdgId is that of a valid charged stable particle.
std::vector< float > m_th_binedges
Binning w/ variable bin size for track polar angle (in [rad]).
std::set< int > m_inputPdgIdSet
The pdgId set of the charged stable particles of interest.
virtual void initialize() override
Initializes the module.
virtual void event() override
Called once for each event.
std::vector< float > m_p
Track momentum in [GeV/c].
virtual void endRun() override
Called once when a run ends.
std::vector< float > m_deltalogl_sig_bkg
Delta Log-likelihood "signal" vs.
void paintUnderOverflow(TH1F *h)
Draw u/oflow content on top of first/last visible bin.
virtual void terminate() override
Termination action.
static constexpr float c_PID
Definition of the PID cut threshold to compute the efficiency.
std::vector< float > m_pt
Track transverse momentum in [GeV/c].
void dumpPIDEfficiencyFakeRate(TTree *sampleTree, const Const::ChargedStable &sampleHypo, const int sampleCharge, const Const::ChargedStable &sigHypo, bool mergeSampleCharge=false)
Dump PID efficiency / fake rate vs clusterTheta, clusterPhi, p...
bool m_saveValidationTree
Save the TTree in the output file alongside the histograms.
std::vector< float > m_logl_bkg
Log-likelihood for the "background" particle hypothesis.
virtual void beginRun() override
Called once before a new run begins.
std::vector< float > m_clusterPhi
Cluster azimuthal angle in [rad].
std::vector< TFile * > m_outputFile
Output ROOT::TFile that contains the info to plot.
std::vector< float > m_clusterTheta
Cluster polar angle in [rad].
std::map< Const::ChargedStable, bool > m_mergeChargeFlagByHypo
A map to tell for each charged stable particle hypothesis whether particle and antiparticle should be...
std::vector< TTree * > m_tree
A ROOT::TTree filled with the info to make control plots.
std::vector< unsigned int > m_mergeChargeOfPdgIds
The (unsigned) pdgId list of the charged stable particles for which particle and antiparticle should ...
void dumpPIDVars(TTree *sampleTree, const Const::ChargedStable &sigHypo, const int sigCharge, const Const::ChargedStable &bkgHypo, bool mergeSigCharge=false)
Dump PID vars.
virtual ~ECLChargedPIDDataAnalysisValidationModule()
Destructor of the module.
std::vector< std::vector< float > > m_pids_glob
List of global PIDs, defined by the likelihood ratio:
std::vector< float > m_clusterReg
Cluster ECL region.
void dumpTrkClusMatchingEfficiency(TTree *sampleTree, const Const::ChargedStable &sampleHypo, const int sampleCharge, bool mergeSampleCharge=false)
Dump track-to-ECL-cluster matching efficiency vs clusterTheta, clusterPhi, pt....
StoreArray< MCParticle > m_MCParticles
MCParticles.
std::vector< float > m_trkPhi
Track azimuthal angle in [rad].
std::vector< float > m_trkTheta
Track polar angle in [rad].
std::vector< float > m_logl_sig
Log-likelihood for the "signal" particle hypothesis.
std::string m_outputFileName
Base name of the output ROOT::TFile.
std::vector< int > m_inputPdgIdList
The pdgId list of the charged stable particles of interest.
@ c_nPhotons
CR is split into n photons (N1)
Container for likelihoods with ECL PID (ECLChargedPIDModule)
@ c_Initial
bit 5: Particle is initial such as e+ or e- and not going to Geant4
@ c_PrimaryParticle
bit 0: Particle is primary particle.
@ c_IsVirtual
bit 4: Particle is virtual and not going to Geant4.
void setDescription(const std::string &description)
Sets the description of the module.
Class that bundles various TrackFitResults.
REG_MODULE(arichBtest)
Register the Module.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
double sqrt(double a)
sqrt for double
std::vector< std::vector< double > > merge(std::vector< std::vector< std::vector< double >>> toMerge)
merge { vector<double> a, vector<double> b} into {a, b}
Abstract base class for different kinds of events.