Belle II Software  release-06-00-14
CombinedPIDPerformanceModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <reconstruction/modules/CombinedPIDPerformance/CombinedPIDPerformanceModule.h>
10 
11 #include <root/TObject.h>
12 
13 using namespace Belle2;
14 
15 //-----------------------------------------------------------------
16 // Register the Module
17 //-----------------------------------------------------------------
18 REG_MODULE(CombinedPIDPerformance)
19 
21 {
22  setDescription("This module evaluates the combined PID performance");
23 
24  addParam("outputFileName", m_rootFileName, "Name of output root file.",
25  std::string("CombinedPIDPerformance_output.root"));
26  addParam("mdstType", m_mdstType, "Type of mdst file (Belle/BelleII).",
27  std::string("BelleII"));
28 
29  addParam("numberOfBins", m_nbins, "Number of momentum bins.", int(100));
30  addParam("pLow", m_pLow, "Lower bound of momentum range.", double(0.0));
31  addParam("pHigh", m_pHigh, "Upper bound of momentum range.", double(5.0));
32 }
33 
35 
37 {
38 
39  B2INFO("Making PID Performance plots...");
40 
41  // required input
42  m_tracks.isRequired();
43  m_trackFitResults.isRequired();
44  m_pidLikelihoods.isRequired();
46 
47  // create list of histograms to be saved in the rootfile
48  m_histoList = new TList;
49 
50  // create the output ROOT File
51  m_rootFilePtr = new TFile(m_rootFileName.c_str(), "RECREATE");
52 
53  // determine which detectors to use
54  // cannot add more than one at a time...
55  if (m_mdstType == "BelleII") {
56  chargedSet += Const::SVD; detset.push_back(svd);
57  }
58  chargedSet += Const::CDC; detset.push_back(cdc);
59  chargedSet += Const::TOP; detset.push_back(top);
60  chargedSet += Const::ARICH; detset.push_back(arich);
61  chargedSet += Const::KLM; detset.push_back(klm);
62  detset.push_back(dedx);
63  detset.push_back(dedxtop);
64  detset.push_back(all);
65 
66  if (m_mdstType == "BelleII") {
67  electronSet += Const::SVD; edetset.push_back(svd);
68  }
69  electronSet += Const::CDC; edetset.push_back(cdc);
70  electronSet += Const::ECL; edetset.push_back(ecl);
71  edetset.push_back(dedx);
72  edetset.push_back(dedxecl);
73 
74  muonSet += Const::KLM;
75 
76  // parameters for ROCs
77  const int npbins = 18;
78  const int npidbins = 101;
79  const float pidlow = 0.;
80  const float pidhigh = 1.01;
81  const char* names[] = { "pi", "k", "e", "mu", "p" };
82 
83  // roc plots: h_ROC[Hypothesis][det](true particle id, pidvalue, momentum)
84  // pion=0, kaon=1, electron=2, muon=3, proton=4;
85  for (int Hypo = 0; Hypo < 5; Hypo++) {
86  for (int k = 0; k < 10; k++) {
87  h_ROC[Hypo][k] = new TH3F(Form("ROC_%s_%d", names[Hypo], k), Form(";PID(%s);N;p (GeV)", names[Hypo]), 5, 0, 5, npidbins, pidlow,
88  pidhigh, npbins, m_pLow, m_pHigh);
89  if (m_histoList) m_histoList->Add(h_ROC[Hypo][k]);
90  }
91  }
92 
93  // create the efficiency and fake rate objects for hadrons
94  for (unsigned int i = 0; i < chargedSet.size() + 3; ++i) {
95  m_piK_Efficiencies.push_back(createEfficiency(TString::Format("epik_%d", i), "#pi efficiency;p [GeV/c];Efficiency", m_nbins,
96  m_pLow,
98  m_Kpi_Efficiencies.push_back(createEfficiency(TString::Format("ekpi_%d", i), "K efficiency;p [GeV/c];Efficiency", m_nbins, m_pLow,
100  m_ppi_Efficiencies.push_back(createEfficiency(TString::Format("eppi_%d", i), "p efficiency;p [GeV/c];Efficiency", m_nbins, m_pLow,
101  m_pHigh, m_histoList));
102  m_pK_Efficiencies.push_back(createEfficiency(TString::Format("epk_%d", i), "p efficiency;p [GeV/c];Efficiency", m_nbins, m_pLow,
103  m_pHigh, m_histoList));
104  m_dpi_Efficiencies.push_back(createEfficiency(TString::Format("edpi_%d", i), "d efficiency;p [GeV/c];Efficiency", m_nbins, m_pLow,
105  m_pHigh, m_histoList));
106 
107  m_piK_FakeRates.push_back(createEfficiency(TString::Format("fpik_%d", i), "#pi fake rate;p [GeV/c];Fake Rate", m_nbins, m_pLow,
108  m_pHigh, m_histoList));
109  m_Kpi_FakeRates.push_back(createEfficiency(TString::Format("fkpi_%d", i), "K fake rate;p [GeV/c];Fake Rate", m_nbins, m_pLow,
110  m_pHigh,
111  m_histoList));
112  m_ppi_FakeRates.push_back(createEfficiency(TString::Format("fppi_%d", i), "p fake rate;p [GeV/c];Fake Rate", m_nbins, m_pLow,
113  m_pHigh,
114  m_histoList));
115  m_pK_FakeRates.push_back(createEfficiency(TString::Format("fpk_%d", i), "p fake rate;p [GeV/c];Fake Rate", m_nbins, m_pLow,
116  m_pHigh,
117  m_histoList));
118  m_dpi_FakeRates.push_back(createEfficiency(TString::Format("fdpi_%d", i), "d fake rate;p [GeV/c];Fake Rate", m_nbins, m_pLow,
119  m_pHigh,
120  m_histoList));
121  }
122 
123  // create the efficiency and fake rate objects for electrons
124  for (unsigned int i = 0; i < electronSet.size() + 2; ++i) {
125  m_epi_Efficiencies.push_back(createEfficiency(TString::Format("eepi_%d", i), "e efficiency;p [GeV/c];Efficiency", m_nbins, m_pLow,
126  m_pHigh, m_histoList));
127 
128  m_epi_FakeRates.push_back(createEfficiency(TString::Format("fepi_%d", i), "e fake rate;p [GeV/c];Fake Rate", m_nbins, m_pLow,
129  m_pHigh,
130  m_histoList));
131  }
132 
133  // create the efficiency and fake rate objects for muons
134  for (unsigned int i = 0; i < muonSet.size(); ++i) {
135  m_mpi_Efficiencies.push_back(createEfficiency(TString::Format("empi_%d", i), "#mu efficiency;p [GeV/c];Efficiency", m_nbins,
136  m_pLow,
137  m_pHigh, m_histoList));
138 
139  m_mpi_FakeRates.push_back(createEfficiency(TString::Format("fmpi_%d", i), "#mu fake rate;p [GeV/c];Fake Rate", m_nbins, m_pLow,
140  m_pHigh, m_histoList));
141  }
142 
143  // color the fake rate objects red here for simplicity later
144  for (unsigned int i = 0; i < chargedSet.size() + 3; ++i) {
145  m_piK_FakeRates[i]->SetMarkerColor(kRed);
146  m_piK_FakeRates[i]->SetLineColor(kRed);
147  m_Kpi_FakeRates[i]->SetMarkerColor(kRed);
148  m_Kpi_FakeRates[i]->SetLineColor(kRed);
149  m_ppi_FakeRates[i]->SetMarkerColor(kRed);
150  m_ppi_FakeRates[i]->SetLineColor(kRed);
151  m_pK_FakeRates[i]->SetMarkerColor(kRed);
152  m_pK_FakeRates[i]->SetLineColor(kRed);
153  m_dpi_FakeRates[i]->SetMarkerColor(kRed);
154  m_dpi_FakeRates[i]->SetLineColor(kRed);
155  if (i < electronSet.size() + 2) {
156  m_epi_FakeRates[i]->SetMarkerColor(kRed);
157  m_epi_FakeRates[i]->SetLineColor(kRed);
158  }
159  if (i < muonSet.size()) {
160  m_mpi_FakeRates[i]->SetMarkerColor(kRed);
161  m_mpi_FakeRates[i]->SetLineColor(kRed);
162  }
163  }
164 }
165 
167 {
168  for (const auto& track : m_tracks) {
169 
170  const TrackFitResult* trackFit = track.getTrackFitResultWithClosestMass(Const::pion);
171  if (!trackFit) {
172  B2WARNING("No track fit result... Skipping.");
173  continue;
174  }
175 
176  const PIDLikelihood* pid = track.getRelated<PIDLikelihood>();
177  if (!pid) {
178  B2WARNING("No PID information... Skipping.");
179  continue;
180  }
181 
182  const MCParticle* mcParticle = track.getRelated<MCParticle>();
183  if (!mcParticle) continue;
184  int pdg = mcParticle->getPDG();
185 
186  // apply some loose cuts on track quality and production vertex
187  if (trackFit->getPValue() < 0.001) continue;
188  if (mcParticle->getProductionVertex().Perp() > 1.0) continue;
189  if (!(mcParticle->getStatus(MCParticle::c_PrimaryParticle))) continue;
190 
191  // fill the efficiencies and fake rates
192  fillEfficiencyHistos(trackFit, pid, pdg);
193  }
194 }
195 
197 {
198 
199  // write out the objects
200  if (m_rootFilePtr != NULL) {
201  m_rootFilePtr->cd();
202 
203  TIter nextH(m_histoList);
204  TObject* obj;
205  while ((obj = nextH()))
206  obj->Write();
207 
208 
209  m_rootFilePtr->Close();
210  }
211 }
212 
214 {
215 
216  bool pass; // used to pass or fail events based on coverage
217 
218  // fill rocs, efficiencies, and fake rates for hadrons
219  for (unsigned int i = 0; i < chargedSet.size() + 3; ++i) {
220  float pidval = -1.0;
221  int detnum = detset[i];
222 
223  Const::DetectorSet det;
224  if (i < chargedSet.size()) det = chargedSet[i];
225  if (i == chargedSet.size()) { // Combined dE/dx
226  if (m_mdstType == "BelleII") det += Const::SVD;
227  det += Const::CDC;
228  }
229  if (i == chargedSet.size() + 1) { // Combined dE/dx, TOP
230  if (m_mdstType == "BelleII") det += Const::SVD;
231  det += Const::CDC;
232  det += Const::TOP;
233  }
234  if (i == chargedSet.size() + 2) { // Combined dE/dx, TOP, ARICH
235  if (m_mdstType == "BelleII") det += Const::SVD;
236  det += Const::CDC;
237  det += Const::TOP;
238  det += Const::ARICH;
239  }
240 
241  // get pid LogL values for hadrons
242  double logl_pi = 0, logl_k = 0, logl_p = 0;
243  if (pidavail(pid, det)) {
244  logl_pi = pid->getLogL(Const::pion, det);
245  logl_k = pid->getLogL(Const::kaon, det);
246  logl_p = pid->getLogL(Const::proton, det);
247  }
248 
249  // fill rocs, efficiencies, and fake rates for true pions
250  if (pidavail(pid, det) and abs(pdg) == Const::pion.getPDGCode()) {
251  pass = (pid->getDeltaLogL(Const::pion, Const::kaon, det) > 0) ? true : false;
252  m_piK_Efficiencies[i]->Fill(pass, trackFit->getMomentum().Mag());
253 
254  pass = (pid->getDeltaLogL(Const::kaon, Const::pion, det) > 0) ? true : false;
255  m_Kpi_FakeRates[i]->Fill(pass, trackFit->getMomentum().Mag());
256 
257  pass = (pid->getDeltaLogL(Const::proton, Const::pion, det) > 0) ? true : false;
258  m_ppi_FakeRates[i]->Fill(pass, trackFit->getMomentum().Mag());
259 
260  pass = (pid->getDeltaLogL(Const::deuteron, Const::pion, det) > 0) ? true : false;
261  m_dpi_FakeRates[i]->Fill(pass, trackFit->getMomentum().Mag());
262 
263  pidval = pidvalue(logl_pi, logl_k);
264  h_ROC[0][detnum]->Fill(0.0, pidval, trackFit->getMomentum().Mag()); // pion eff
265 
266  pidval = pidvalue(logl_k, logl_pi);
267  h_ROC[1][detnum]->Fill(0.0, pidval, trackFit->getMomentum().Mag()); // pion faking k
268 
269  pidval = pidvalue(logl_p, logl_pi);
270  h_ROC[4][detnum]->Fill(0.0, pidval, trackFit->getMomentum().Mag()); // pion faking proton
271  }
272 
273  // fill rocs, efficiencies, and fake rates for true kaons
274  if (pidavail(pid, det) and abs(pdg) == Const::kaon.getPDGCode()) {
275  pass = (pid->getDeltaLogL(Const::kaon, Const::pion, det) > 0) ? true : false;
276  m_Kpi_Efficiencies[i]->Fill(pass, trackFit->getMomentum().Mag());
277 
278  pass = (pid->getDeltaLogL(Const::pion, Const::kaon, det) > 0) ? true : false;
279  m_piK_FakeRates[i]->Fill(pass, trackFit->getMomentum().Mag());
280 
281  pass = (pid->getDeltaLogL(Const::proton, Const::kaon, det) > 0) ? true : false;
282  m_pK_FakeRates[i]->Fill(pass, trackFit->getMomentum().Mag());
283 
284  pidval = pidvalue(logl_k, logl_pi);
285  h_ROC[1][detnum]->Fill(1.0, pidval, trackFit->getMomentum().Mag()); // kaon eff
286 
287  pidval = pidvalue(logl_pi, logl_k);
288  h_ROC[0][detnum]->Fill(1.0, pidval, trackFit->getMomentum().Mag()); // kaon faking pion
289 
290  pidval = pidvalue(logl_p, logl_k);
291  h_ROC[4][detnum]->Fill(1.0, pidval, trackFit->getMomentum().Mag()); // kaon faking proton
292  }
293 
294  // fill rocs and efficiencies for true protons
295  if (pidavail(pid, det) and abs(pdg) == Const::proton.getPDGCode()) {
296  pass = (pid->getDeltaLogL(Const::proton, Const::pion, det) > 0) ? true : false;
297  m_ppi_Efficiencies[i]->Fill(pass, trackFit->getMomentum().Mag());
298 
299  pass = (pid->getDeltaLogL(Const::proton, Const::kaon, det) > 0) ? true : false;
300  m_pK_Efficiencies[i]->Fill(pass, trackFit->getMomentum().Mag());
301 
302  pidval = pidvalue(logl_p, logl_pi + logl_k);
303  h_ROC[4][detnum]->Fill(4.0, pidval, trackFit->getMomentum().Mag()); // proton eff vs. pion and kaon
304  }
305 
306  // fill efficiencies for true deuterons
307  if (pidavail(pid, det) and abs(pdg) == Const::deuteron.getPDGCode()) {
308  pass = (pid->getDeltaLogL(Const::deuteron, Const::pion, det) > 0) ? true : false;
309  m_dpi_Efficiencies[i]->Fill(pass, trackFit->getMomentum().Mag());
310  }
311  } // end of loop for hadrons
312 
313  // fill rocs, efficiencies, and fake rates for electrons
314  for (unsigned int i = 0; i <= electronSet.size() + 1; ++i) {
315  float pidval = -1.0;
316  int detnum = edetset[i];
317 
318  Const::DetectorSet det;
319  if (i < electronSet.size()) det = electronSet[i];
320  if (i == electronSet.size()) { // Combined dE/dx
321  if (m_mdstType == "BelleII") det += Const::SVD;
322  det += Const::CDC;
323  }
324  if (i == electronSet.size() + 1) // Combined dE/dx, ECL
325  det = electronSet;
326 
327  // get pid LogL values for electrons and pions
328  double logl_e = 0, logl_pi_e = 0;
329  if (pidavail(pid, det)) {
330  logl_e = pid->getLogL(Const::electron, det);
331  logl_pi_e = pid->getLogL(Const::pion, det);
332  }
333 
334  // fill rocs and efficiencies for true electrons
335  if (pidavail(pid, det) and abs(pdg) == Const::electron.getPDGCode()) {
336  pass = (pid->getDeltaLogL(Const::electron, Const::pion, det) > 0) ? true : false;
337  m_epi_Efficiencies[i]->Fill(pass, trackFit->getMomentum().Mag());
338 
339  pidval = pidvalue(logl_e, logl_pi_e);
340  h_ROC[2][detnum]->Fill(2.0, pidval, trackFit->getMomentum().Mag()); // electron eff vs pion
341  }
342 
343  // fill rocs and fake rates for true pions
344  if (pidavail(pid, det) and abs(pdg) == Const::pion.getPDGCode()) {
345  pass = (pid->getDeltaLogL(Const::electron, Const::pion, det) > 0) ? true : false;
346  m_epi_FakeRates[i]->Fill(pass, trackFit->getMomentum().Mag());
347 
348  pidval = pidvalue(logl_pi_e, logl_e);
349  h_ROC[0][detnum]->Fill(0.0, pidval, trackFit->getMomentum().Mag()); // pion faking electron
350  }
351  } // end of loop for electrons
352 
353  // fill rocs, efficiencies, and fake rates for muons
354  for (unsigned int i = 0; i < muonSet.size(); ++i) {
355  float pidval = -1.0;
356  Const::EDetector det = muonSet[i];
357 
358  // get pid LogL values for electrons and pions
359  double logl_mu = 0, logl_pi_mu = 0;
360  if (pidavail(pid, det)) {
361  logl_mu = pid->getLogL(Const::muon, det);
362  logl_pi_mu = pid->getLogL(Const::pion, det);
363  }
364 
365  // fill rocs and efficiencies for true muons
366  if (pidavail(pid, det) and abs(pdg) == Const::muon.getPDGCode()) {
367  pass = (pid->getDeltaLogL(Const::muon, Const::pion, det) > 0) ? true : false;
368  m_mpi_Efficiencies[i]->Fill(pass, trackFit->getMomentum().Mag());
369 
370  pidval = pidvalue(logl_mu, logl_pi_mu);
371  h_ROC[3][klm]->Fill(3.0, pidval, trackFit->getMomentum().Mag()); // muon eff vs. pion
372  }
373 
374  // fill rocs and fake ratesfor true pions
375  if (pidavail(pid, det) and abs(pdg) == Const::pion.getPDGCode()) {
376  pass = (pid->getDeltaLogL(Const::muon, Const::pion, det) > 0) ? true : false;
377  m_mpi_FakeRates[i]->Fill(pass, trackFit->getMomentum().Mag());
378 
379  pidval = pidvalue(logl_pi_mu, logl_mu);
380  h_ROC[3][klm]->Fill(0.0, pidval, trackFit->getMomentum().Mag()); // pion faking muon
381  }
382  } // end of loop for muons
383 }
384 
385 TEfficiency* CombinedPIDPerformanceModule::createEfficiency(const char* name, const char* title,
386  Int_t nbins, Double_t min, Double_t max, TList* histoList)
387 {
388 
389  TEfficiency* h = new TEfficiency(name, title, nbins, min, max);
390 
391  if (histoList)
392  histoList->Add(h);
393 
394  return h;
395 }
396 
397 
398 double CombinedPIDPerformanceModule::pidvalue(float logl_a, float logl_b)
399 {
400  // returns likelihood ratio
401 
402  double val = -1.0;
403  float dl = logl_b - logl_a;
404 
405  if (dl < 0) {
406  val = 1 / (1 + exp(dl));
407  } else {
408  val = exp(-1 * dl) / (1 + exp(-1 * dl));
409  }
410 
411  return val;
412 }
413 
415 {
416  // returns true if at least one detector in the detectors is available.
417 
418  bool avail = false;
419  for (unsigned int i = 0; i < dets.size(); ++i) {
420  if (pidl->isAvailable(dets[i])) {
421  avail = true;
422  }
423  }
424 
425  return avail;
426 }
427 
428 
This module takes the MCParticles, the Tracks, and the PIDLikelihoods as input and produces a root fi...
bool pidavail(const PIDLikelihood *pid, Const::DetectorSet dets)
determine the availability of the given detector(s)
std::vector< TEfficiency * > m_dpi_FakeRates
deuteron fake rates
TEfficiency * createEfficiency(const char *name, const char *title, Int_t nbins, Double_t min, Double_t max, TList *histoList=NULL)
method to create TEfficiencies
std::vector< TEfficiency * > m_dpi_Efficiencies
deuteron efficiencies
double m_pHigh
upper bound of momentum range
std::vector< TEfficiency * > m_epi_FakeRates
electron fake rates
virtual void initialize() override
Initialize the module.
std::vector< TEfficiency * > m_ppi_Efficiencies
proton efficiencies
std::vector< TEfficiency * > m_mpi_FakeRates
muon fake rates
virtual void event() override
This method is called for each event.
void fillEfficiencyHistos(const TrackFitResult *fitResult, const PIDLikelihood *pid, int pdg)
method to fill TEfficiencies
std::vector< TEfficiency * > m_pK_Efficiencies
proton efficiencies
std::vector< TEfficiency * > m_piK_FakeRates
pion fake rates
StoreArray< TrackFitResult > m_trackFitResults
Required array of input TrackFitResults.
virtual void terminate() override
End of the event processing.
double pidvalue(float pida, float pidb)
returns the likelihood ratio for given log likelihoods
std::vector< TEfficiency * > m_mpi_Efficiencies
muon efficiencies
std::vector< int > edetset
set of detectors used electrons
std::vector< TEfficiency * > m_ppi_FakeRates
proton fake rates
StoreArray< Track > m_tracks
Required array of input Tracks.
std::vector< int > detset
set of detectors used for hadrons
std::vector< TEfficiency * > m_Kpi_Efficiencies
kaon efficiencies
std::vector< TEfficiency * > m_epi_Efficiencies
electron efficiencies
std::vector< TEfficiency * > m_piK_Efficiencies
pion efficiencies
std::vector< TEfficiency * > m_pK_FakeRates
proton fake rates
StoreArray< MCParticle > m_mcParticles
Required array of input MCParticles.
StoreArray< PIDLikelihood > m_pidLikelihoods
Required array of input PIDLikelihoods.
std::string m_mdstType
flag for Belle/BelleII mdst files
std::vector< TEfficiency * > m_Kpi_FakeRates
kaon fake rates
TFile * m_rootFilePtr
pointer at root file used for storing histograms
double m_pLow
lower bound of momentum range
Const::DetectorSet chargedSet
pions, kaons, protons
The DetectorSet class for sets of detector IDs in the form of EDetector values.
Definition: Const.h:71
size_t size() const
Getter for number of detector IDs in this set.
Definition: UnitConst.cc:256
int getPDGCode() const
PDG code.
Definition: Const.h:354
static const ChargedStable muon
muon particle
Definition: Const.h:541
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
static const ChargedStable pion
charged pion particle
Definition: Const.h:542
static const ChargedStable proton
proton particle
Definition: Const.h:544
static const ChargedStable kaon
charged kaon particle
Definition: Const.h:543
static const ChargedStable electron
electron particle
Definition: Const.h:540
static const ChargedStable deuteron
deuteron particle
Definition: Const.h:545
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:47
unsigned int getStatus(unsigned short int bitmask=USHRT_MAX) const
Return status code of particle.
Definition: MCParticle.h:122
int getPDG() const
Return PDG code of particle.
Definition: MCParticle.h:112
TVector3 getProductionVertex() const
Return production vertex position.
Definition: MCParticle.h:189
Base class for Modules.
Definition: Module.h:72
Class to collect log likelihoods from TOP, ARICH, dEdx, ECL and KLM aimed for output to mdst includes...
Definition: PIDLikelihood.h:26
bool isAvailable(Const::PIDDetectorSet set) const
Check whether PID information from a given set of detectors is available.
Definition: PIDLikelihood.h:50
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Values of the result of a track fit with a given particle hypothesis.
double getPValue() const
Getter for Chi2 Probability of the track fit.
TVector3 getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.