Belle II Software  light-2205-abys
PIDVariables.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 // Own include
10 #include <analysis/variables/PIDVariables.h>
11 
12 #include <analysis/dataobjects/Particle.h>
13 #include <mdst/dataobjects/PIDLikelihood.h>
14 
15 // framework aux
16 #include <framework/logging/Logger.h>
17 #include <framework/utilities/Conversion.h>
18 #include <framework/gearbox/Const.h>
19 
20 #include <boost/algorithm/string.hpp>
21 
22 #include <iostream>
23 #include <cmath>
24 
25 using namespace std;
26 
27 namespace Belle2 {
32  namespace Variable {
33 
34 
35 
36  //*************
37  // Utilities
38  //*************
39 
40  // converts Belle numbering scheme for charged final state particles
41  // to Belle II ChargedStable
42  Const::ChargedStable hypothesisConversion(const int hypothesis)
43  {
44  switch (hypothesis) {
45  case 0:
46  return Const::electron;
47  case 1:
48  return Const::muon;
49  case 2:
50  return Const::pion;
51  case 3:
52  return Const::kaon;
53  case 4:
54  return Const::proton;
55  }
56 
57  return Const::pion;
58  }
59 
60 
61  Const::PIDDetectorSet parseDetectors(const std::vector<std::string>& arguments)
62  {
63  Const::PIDDetectorSet result;
64  for (std::string val : arguments) {
65  boost::to_lower(val);
66  if (val == "all") return Const::PIDDetectors::set();
67  else if (val == "svd") result += Const::SVD;
68  else if (val == "cdc") result += Const::CDC;
69  else if (val == "top") result += Const::TOP;
70  else if (val == "arich") result += Const::ARICH;
71  else if (val == "ecl") result += Const::ECL;
72  else if (val == "klm") result += Const::KLM;
73  else B2ERROR("Unknown detector component: " << val);
74  }
75  return result;
76  }
77 
78  // Specialisation of valid detectors parser for ChargedBDT.
79  Const::PIDDetectorSet parseDetectorsChargedBDT(const std::vector<std::string>& arguments)
80  {
81  Const::PIDDetectorSet result;
82  for (std::string val : arguments) {
83  boost::to_lower(val);
84  if (val == "all") return Const::PIDDetectors::set();
85  else if (val == "ecl") result += Const::ECL;
86  else B2ERROR("Invalid detector component: " << val << " for charged BDT.");
87  }
88  return result;
89  }
90 
91  //*************
92  // Belle II
93  //*************
94 
95  // a "smart" variable:
96  // finds the global probability based on the PDG code of the input particle
97  double particleID(const Particle* p)
98  {
99  int pdg = abs(p->getPDGCode());
100  if (pdg == Const::electron.getPDGCode()) return electronID(p);
101  else if (pdg == Const::muon.getPDGCode()) return muonID(p);
102  else if (pdg == Const::pion.getPDGCode()) return pionID(p);
103  else if (pdg == Const::kaon.getPDGCode()) return kaonID(p);
104  else if (pdg == Const::proton.getPDGCode()) return protonID(p);
105  else if (pdg == Const::deuteron.getPDGCode()) return deuteronID(p);
106  else return std::numeric_limits<float>::quiet_NaN();
107  }
108 
109  Manager::FunctionPtr pidLogLikelihoodValueExpert(const std::vector<std::string>& arguments)
110  {
111  if (arguments.size() < 2) {
112  B2ERROR("Need at least two arguments to pidLogLikelihoodValueExpert");
113  return nullptr;
114  }
115  int pdgCode;
116  try {
117  pdgCode = Belle2::convertString<int>(arguments[0]);
118  } catch (std::invalid_argument& e) {
119  B2ERROR("First argument of pidLogLikelihoodValueExpert must be a PDG code");
120  return nullptr;
121  }
122  std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
123 
124  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
125  auto hypType = Const::ChargedStable(abs(pdgCode));
126 
127  auto func = [hypType, detectorSet](const Particle * part) -> double {
128  const PIDLikelihood* pid = part->getPIDLikelihood();
129  if (!pid)
130  return std::numeric_limits<float>::quiet_NaN();
131  // No information form any subdetector in the list
132  if (pid->getLogL(hypType, detectorSet) == 0)
133  return std::numeric_limits<float>::quiet_NaN();
134 
135  return pid->getLogL(hypType, detectorSet);
136  };
137  return func;
138  }
139 
140 
141 
142  Manager::FunctionPtr pidDeltaLogLikelihoodValueExpert(const std::vector<std::string>& arguments)
143  {
144  if (arguments.size() < 3) {
145  B2ERROR("Need at least three arguments to pidDeltaLogLikelihoodValueExpert");
146  return nullptr;
147  }
148  int pdgCodeHyp, pdgCodeTest;
149  try {
150  pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
151  } catch (std::invalid_argument& e) {
152  B2ERROR("First argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
153  return nullptr;
154  }
155  try {
156  pdgCodeTest = Belle2::convertString<int>(arguments[1]);
157  } catch (std::invalid_argument& e) {
158  B2ERROR("Second argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
159  return nullptr;
160  }
161 
162  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
163  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
164  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
165  auto testType = Const::ChargedStable(abs(pdgCodeTest));
166 
167  auto func = [hypType, testType, detectorSet](const Particle * part) -> double {
168  const PIDLikelihood* pid = part->getPIDLikelihood();
169  if (!pid) return std::numeric_limits<float>::quiet_NaN();
170  // No information form any subdetector in the list
171  if (pid->getLogL(hypType, detectorSet) == 0)
172  return std::numeric_limits<float>::quiet_NaN();
173 
174  return (pid->getLogL(hypType, detectorSet) - pid->getLogL(testType, detectorSet));
175  };
176  return func;
177  }
178 
179 
180  Manager::FunctionPtr pidPairProbabilityExpert(const std::vector<std::string>& arguments)
181  {
182  if (arguments.size() < 3) {
183  B2ERROR("Need at least three arguments to pidPairProbabilityExpert");
184  return nullptr;
185  }
186  int pdgCodeHyp = 0, pdgCodeTest = 0;
187  try {
188  pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
189  } catch (std::invalid_argument& e) {
190  B2ERROR("First argument of pidPairProbabilityExpert must be PDG code");
191  return nullptr;
192  }
193  try {
194  pdgCodeTest = Belle2::convertString<int>(arguments[1]);
195  } catch (std::invalid_argument& e) {
196  B2ERROR("Second argument of pidPairProbabilityExpert must be PDG code");
197  return nullptr;
198  }
199 
200  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
201 
202  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
203  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
204  auto testType = Const::ChargedStable(abs(pdgCodeTest));
205  auto func = [hypType, testType, detectorSet](const Particle * part) -> double {
206  const PIDLikelihood* pid = part->getPIDLikelihood();
207  if (!pid) return std::numeric_limits<float>::quiet_NaN();
208  // No information from any subdetector in the list
209  if (pid->getLogL(hypType, detectorSet) == 0)
210  return std::numeric_limits<float>::quiet_NaN();
211 
212  return pid->getProbability(hypType, testType, detectorSet);
213  };
214  return func;
215  }
216 
217 
218  Manager::FunctionPtr pidProbabilityExpert(const std::vector<std::string>& arguments)
219  {
220  if (arguments.size() < 2) {
221  B2ERROR("Need at least two arguments for pidProbabilityExpert");
222  return nullptr;
223  }
224  int pdgCodeHyp = 0;
225  try {
226  pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
227  } catch (std::invalid_argument& e) {
228  B2ERROR("First argument of pidProbabilityExpert must be PDG code");
229  return nullptr;
230  }
231 
232  std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
233  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
234  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
235 
236  // Placeholder for the priors
237  const unsigned int n = Const::ChargedStable::c_SetSize;
238  double frac[n];
239  for (double& i : frac) i = 1.0; // flat priors
240 
241  auto func = [hypType, frac, detectorSet](const Particle * part) -> double {
242  const PIDLikelihood* pid = part->getPIDLikelihood();
243  if (!pid) return std::numeric_limits<float>::quiet_NaN();
244  // No information from any subdetector in the list
245  if (pid->getLogL(hypType, detectorSet) == 0)
246  return std::numeric_limits<float>::quiet_NaN();
247 
248  return pid->getProbability(hypType, frac, detectorSet);
249  };
250  return func;
251  }
252 
253 
254  Manager::FunctionPtr pidMissingProbabilityExpert(const std::vector<std::string>& arguments)
255  {
256  if (arguments.size() < 1) {
257  B2ERROR("Need at least one argument to pidMissingProbabilityExpert");
258  return nullptr;
259  }
260 
261  std::vector<std::string> detectors(arguments.begin(), arguments.end());
262  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
263 
264  auto func = [detectorSet](const Particle * part) -> double {
265  const PIDLikelihood* pid = part->getPIDLikelihood();
266  if (!pid) return std::numeric_limits<double>::quiet_NaN();
267  if (not pid->isAvailable(detectorSet))
268  return 1;
269  else return 0;
270  };
271  return func;
272  }
273 
274  double electronID(const Particle* part)
275  {
276  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(11, ALL)")->function(part));
277  }
278 
279  double muonID(const Particle* part)
280  {
281  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(13, ALL)")->function(part));
282  }
283 
284  double pionID(const Particle* part)
285  {
286  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, ALL)")->function(part));
287  }
288 
289  double kaonID(const Particle* part)
290  {
291  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(321, ALL)")->function(part));
292  }
293 
294  double protonID(const Particle* part)
295  {
296  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(2212, ALL)")->function(part));
297  }
298 
299  double deuteronID(const Particle* part)
300  {
301  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(1000010020, ALL)")->function(part));
302  }
303 
304  double binaryPID(const Particle* part, const std::vector<double>& arguments)
305  {
306  if (arguments.size() != 2) {
307  B2ERROR("The variable binaryPID needs exactly two arguments: the PDG codes of two hypotheses.");
308  return std::numeric_limits<float>::quiet_NaN();;
309  }
310  int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
311  int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
312  return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
313  pdgCodeHyp) + ", " + std::to_string(
314  pdgCodeTest) + ", ALL)")->function(part));
315  }
316 
317  double electronID_noSVD(const Particle* part)
318  {
319  // Excluding SVD for electron ID. This variable is temporary. BII-8760
320  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(11, CDC, TOP, ARICH, ECL, KLM)")->function(part));
321  }
322 
323  double muonID_noSVD(const Particle* part)
324  {
325  // Excluding SVD for muon ID. This variable is temporary. BII-8760
326  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(13, CDC, TOP, ARICH, ECL, KLM)")->function(part));
327  }
328 
329  double pionID_noSVD(const Particle* part)
330  {
331  // Excluding SVD for pion ID. This variable is temporary. BII-8760
332  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(211, CDC, TOP, ARICH, ECL, KLM)")->function(part));
333  }
334 
335  double kaonID_noSVD(const Particle* part)
336  {
337  // Excluding SVD for kaon ID. This variable is temporary. BII-8760
338  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(321, CDC, TOP, ARICH, ECL, KLM)")->function(part));
339  }
340 
341  double protonID_noSVD(const Particle* part)
342  {
343  // Excluding SVD for proton ID. This variable is temporary. BII-8760
344  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(2212, CDC, TOP, ARICH, ECL, KLM)")->function(part));
345  }
346 
347  double deuteronID_noSVD(const Particle* part)
348  {
349  // Excluding SVD for deuteron ID. This variable is temporary. BII-8760
350  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(1000010020, CDC, TOP, ARICH, ECL, KLM)")->function(
351  part));
352  }
353 
354  double binaryPID_noSVD(const Particle* part, const std::vector<double>& arguments)
355  {
356  // Excluding SVD for binary ID. This variable is temporary. BII-8760
357  if (arguments.size() != 2) {
358  B2ERROR("The variable binaryPID_noSVD needs exactly two arguments: the PDG codes of two hypotheses.");
359  return std::numeric_limits<float>::quiet_NaN();;
360  }
361  int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
362  int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
363  return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
364  pdgCodeHyp) + ", " + std::to_string(
365  pdgCodeTest) + ", CDC, TOP, ARICH, ECL, KLM)")->function(part));
366  }
367 
368  double electronID_noTOP(const Particle* part)
369  {
370  // Excluding TOP for electron ID. This variable is temporary. BII-8444
371  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(11, SVD, CDC, ARICH, ECL, KLM)")->function(part));
372  }
373 
374  double binaryElectronID_noTOP(const Particle* part, const std::vector<double>& arguments)
375  {
376  // Excluding TOP for electron ID. This is temporary. BII-8444
377  if (arguments.size() != 1) {
378  B2ERROR("The variable binaryElectronID_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
379  return std::numeric_limits<float>::quiet_NaN();;
380  }
381 
382  int pdgCodeHyp = Const::electron.getPDGCode();
383  int pdgCodeTest = std::abs(int(std::lround(arguments[0])));
384 
385  const auto var = "pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) + ", " +
386  std::to_string(pdgCodeTest) + ", SVD, CDC, ARICH, ECL, KLM)";
387 
388  return std::get<double>(Manager::Instance().getVariable(var)->function(part));
389  }
390 
391  double electronID_noSVD_noTOP(const Particle* part)
392  {
393  // Excluding SVD and TOP for electron ID. This variable is temporary. BII-8444, BII-8760.
394  return std::get<double>(Manager::Instance().getVariable("pidProbabilityExpert(11, CDC, ARICH, ECL, KLM)")->function(part));
395  }
396 
397  double binaryElectronID_noSVD_noTOP(const Particle* part, const std::vector<double>& arguments)
398  {
399  // Excluding SVD and TOP for electron ID. This is temporary. BII-8444, BII-8760.
400  if (arguments.size() != 1) {
401  B2ERROR("The variable binaryElectronID_noSVD_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
402  return std::numeric_limits<float>::quiet_NaN();;
403  }
404 
405  int pdgCodeHyp = Const::electron.getPDGCode();
406  int pdgCodeTest = std::abs(int(std::lround(arguments[0])));
407 
408  const auto var = "pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) + ", " +
409  std::to_string(pdgCodeTest) + ", CDC, ARICH, ECL, KLM)";
410 
411  return std::get<double>(Manager::Instance().getVariable(var)->function(part));
412  }
413 
414  double antineutronID(const Particle* particle)
415  {
416  if (particle->hasExtraInfo("nbarID")) {
417  return particle->getExtraInfo("nbarID");
418  } else {
419  if (particle->getPDGCode() == -Const::neutron.getPDGCode()) {
420  B2WARNING("The extraInfo nbarID is not registered! \n"
421  "Please use function getNbarIDMVA in modularAnalysis.");
422  }
423  return std::numeric_limits<float>::quiet_NaN();
424  }
425  }
426 
427  Manager::FunctionPtr pidChargedBDTScore(const std::vector<std::string>& arguments)
428  {
429  if (arguments.size() != 2) {
430  B2ERROR("Need exactly two arguments for pidChargedBDTScore: pdgCodeHyp, detector");
431  return nullptr;
432  }
433 
434  int hypPdgId;
435  try {
436  hypPdgId = Belle2::convertString<int>(arguments.at(0));
437  } catch (std::invalid_argument& e) {
438  B2ERROR("First argument of pidChargedBDTScore must be an integer (PDG code).");
439  return nullptr;
440  }
441  Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
442 
443  std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
444  Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
445 
446  auto func = [hypType, detectorSet](const Particle * part) -> double {
447  auto name = "pidChargedBDTScore_" + std::to_string(hypType.getPDGCode());
448  for (size_t iDet(0); iDet < detectorSet.size(); ++iDet)
449  {
450  auto det = detectorSet[iDet];
451  name += "_" + std::to_string(det);
452  }
453  return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : std::numeric_limits<float>::quiet_NaN();
454  };
455  return func;
456  }
457 
458  Manager::FunctionPtr pidPairChargedBDTScore(const std::vector<std::string>& arguments)
459  {
460  if (arguments.size() != 3) {
461  B2ERROR("Need exactly three arguments for pidPairChargedBDTScore: pdgCodeHyp, pdgCodeTest, detector.");
462  return nullptr;
463  }
464 
465  int hypPdgId, testPdgId;
466  try {
467  hypPdgId = Belle2::convertString<int>(arguments.at(0));
468  } catch (std::invalid_argument& e) {
469  B2ERROR("First argument of pidPairChargedBDTScore must be an integer (PDG code).");
470  return nullptr;
471  }
472  try {
473  testPdgId = Belle2::convertString<int>(arguments.at(1));
474  } catch (std::invalid_argument& e) {
475  B2ERROR("First argument of pidPairChargedBDTScore must be an integer (PDG code).");
476  return nullptr;
477  }
478  Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
479  Const::ChargedStable testType = Const::ChargedStable(testPdgId);
480 
481  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
482  Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
483 
484  auto func = [hypType, testType, detectorSet](const Particle * part) -> double {
485  auto name = "pidPairChargedBDTScore_" + std::to_string(hypType.getPDGCode()) + "_VS_" + std::to_string(testType.getPDGCode());
486  for (size_t iDet(0); iDet < detectorSet.size(); ++iDet)
487  {
488  auto det = detectorSet[iDet];
489  name += "_" + std::to_string(det);
490  }
491  return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : std::numeric_limits<float>::quiet_NaN();
492  };
493  return func;
494  }
495 
496  double mostLikelyPDG(const Particle* part, const std::vector<double>& arguments)
497  {
498  if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
499  B2ERROR("Need zero or exactly " << Const::ChargedStable::c_SetSize << " arguments for pidMostLikelyPDG");
500  return std::numeric_limits<double>::quiet_NaN();
501  }
502  double prob[Const::ChargedStable::c_SetSize];
503  if (arguments.size() == 0) {
504  for (unsigned int i = 0; i < Const::ChargedStable::c_SetSize; i++) prob[i] = 1. / Const::ChargedStable::c_SetSize;
505  } else {
506  copy(arguments.begin(), arguments.end(), prob);
507  }
508 
509  auto* pid = part->getPIDLikelihood();
510  if (!pid) return std::numeric_limits<double>::quiet_NaN();
511  return pid->getMostLikely(prob).getPDGCode();
512  }
513 
514  bool isMostLikely(const Particle* part, const std::vector<double>& arguments)
515  {
516  if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
517  B2ERROR("Need zero or exactly " << Const::ChargedStable::c_SetSize << " arguments for pidIsMostLikely");
518  return false;
519  }
520  return mostLikelyPDG(part, arguments) == abs(part->getPDGCode());
521  }
522 
523  //*************
524  // B2BII
525  //*************
526 
527  double muIDBelle(const Particle* particle)
528  {
529  const PIDLikelihood* pid = particle->getPIDLikelihood();
530  if (!pid) return 0.5; // Belle standard
531 
532  if (pid->isAvailable(Const::KLM))
533  return exp(pid->getLogL(Const::muon, Const::KLM));
534  else
535  return 0; // Belle standard
536  }
537 
538  double muIDBelleQuality(const Particle* particle)
539  {
540  const PIDLikelihood* pid = particle->getPIDLikelihood();
541  if (!pid) return 0;// Belle standard
542 
543  return pid->isAvailable(Const::KLM);
544  }
545 
546  double atcPIDBelle(const Particle* particle, const std::vector<double>& sigAndBkgHyp)
547  {
548  int sigHyp = int(std::lround(sigAndBkgHyp[0]));
549  int bkgHyp = int(std::lround(sigAndBkgHyp[1]));
550 
551  const PIDLikelihood* pid = particle->getPIDLikelihood();
552  if (!pid) return 0.5; // Belle standard
553 
554  // ACC = ARICH
555  Const::PIDDetectorSet set = Const::ARICH;
556  double acc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
557  double acc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
558  double acc = 0.5; // Belle standard
559  if (acc_sig + acc_bkg > 0.0)
560  acc = acc_sig / (acc_sig + acc_bkg);
561 
562  // TOF = TOP
563  set = Const::TOP;
564  double tof_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
565  double tof_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
566  double tof = 0.5; // Belle standard
567  double tof_all = tof_sig + tof_bkg;
568  if (tof_all != 0) {
569  tof = tof_sig / tof_all;
570  if (tof < 0.001) tof = 0.001;
571  if (tof > 0.999) tof = 0.999;
572  }
573 
574  // dE/dx = CDC
575  set = Const::CDC;
576  double cdc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
577  double cdc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
578  double cdc = 0.5; // Belle standard
579  double cdc_all = cdc_sig + cdc_bkg;
580  if (cdc_all != 0) {
581  cdc = cdc_sig / cdc_all;
582  if (cdc < 0.001) cdc = 0.001;
583  if (cdc > 0.999) cdc = 0.999;
584  }
585 
586  // Combined
587  double pid_sig = acc * tof * cdc;
588  double pid_bkg = (1. - acc) * (1. - tof) * (1. - cdc);
589 
590  return pid_sig / (pid_sig + pid_bkg);
591  }
592 
593 
594  double eIDBelle(const Particle* part)
595  {
596  const PIDLikelihood* pid = part->getPIDLikelihood();
597  if (!pid) return 0.5; // Belle standard
598 
599  Const::PIDDetectorSet set = Const::ECL;
600  return pid->getProbability(Const::electron, Const::pion, set);
601  }
602 
603 
604  // PID variables to be used for analysis
605  VARIABLE_GROUP("PID");
606  REGISTER_VARIABLE("particleID", particleID,
607  "the particle identification probability under the particle's own hypothesis, using info from all available detectors");
608  REGISTER_VARIABLE("electronID", electronID,
609  "electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
610  REGISTER_VARIABLE("muonID", muonID,
611  "muon identification probability defined as :math:`\\mathcal{L}_\\mu/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
612  REGISTER_VARIABLE("pionID", pionID,
613  "pion identification probability defined as :math:`\\mathcal{L}_\\pi/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
614  REGISTER_VARIABLE("kaonID", kaonID,
615  "kaon identification probability defined as :math:`\\mathcal{L}_K/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
616  REGISTER_VARIABLE("protonID", protonID,
617  "proton identification probability defined as :math:`\\mathcal{L}_p/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
618  REGISTER_VARIABLE("deuteronID", deuteronID,
619  "deuteron identification probability defined as :math:`\\mathcal{L}_d/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
620  REGISTER_METAVARIABLE("binaryPID(pdgCode1, pdgCode2)", binaryPID,
621  "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components",
622  Manager::VariableDataType::c_double);
623  REGISTER_METAVARIABLE("pidChargedBDTScore(pdgCodeHyp, detector)", pidChargedBDTScore,
624  "Returns the charged Pid BDT score for a certain mass hypothesis with respect to all other charged stable particle hypotheses. The second argument specifies which BDT training to use: based on 'ALL' PID detectors (NB: 'SVD' is currently excluded), or 'ECL' only. The choice depends on the ChargedPidMVAMulticlassModule's configuration.",
625  Manager::VariableDataType::c_double);
626  REGISTER_METAVARIABLE("pidPairChargedBDTScore(pdgCodeHyp, pdgCodeTest, detector)", pidPairChargedBDTScore,
627  "Returns the charged Pid BDT score for a certain mass hypothesis with respect to an alternative hypothesis. The second argument specifies which BDT training to use: based on 'ALL' PID detectors (NB: 'SVD' is currently excluded), or 'ECL' only. The choice depends on the ChargedPidMVAModule's configuration.",
628  Manager::VariableDataType::c_double);
629  REGISTER_VARIABLE("nbarID", antineutronID, R"DOC(
630 Returns MVA classifier for antineutron PID.
631 
632  - 1 signal(antineutron) like
633  - 0 background like
634  - -1 invalid using this PID due to some ECL variables used unavailable
635 
636 This PID is only for antineutron. Neutron is also considered as background.
637 The variables used are `clusterPulseShapeDiscriminationMVA`, `clusterE`, `clusterLAT`, `clusterE1E9`, `clusterE9E21`,
638 `clusterAbsZernikeMoment40`, `clusterAbsZernikeMoment51`, `clusterZernikeMVA`.)DOC");
639 
640  // Special temporary variables defined for users' convenience.
641  REGISTER_VARIABLE("electronID_noSVD", electronID_noSVD,
642  "**(SPECIAL (TEMP) variable)** electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
643  REGISTER_VARIABLE("muonID_noSVD", muonID_noSVD,
644  "**(SPECIAL (TEMP) variable)** muon identification probability defined as :math:`\\mathcal{L}_\\mu/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
645  REGISTER_VARIABLE("pionID_noSVD", pionID_noSVD,
646  "**(SPECIAL (TEMP) variable)** pion identification probability defined as :math:`\\mathcal{L}_\\pi/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
647  REGISTER_VARIABLE("kaonID_noSVD", kaonID_noSVD,
648  "**(SPECIAL (TEMP) variable)** kaon identification probability defined as :math:`\\mathcal{L}_K/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
649  REGISTER_VARIABLE("protonID_noSVD", protonID_noSVD,
650  "**(SPECIAL (TEMP) variable)** proton identification probability defined as :math:`\\mathcal{L}_p/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
651  REGISTER_VARIABLE("deuteronID_noSVD", deuteronID_noSVD,
652  "**(SPECIAL (TEMP) variable)** deuteron identification probability defined as :math:`\\mathcal{L}_d/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
653  REGISTER_METAVARIABLE("binaryPID_noSVD(pdgCode1, pdgCode2)", binaryPID_noSVD,
654  "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components, *excluding the SVD*.",
655  Manager::VariableDataType::c_double);
656  REGISTER_VARIABLE("electronID_noTOP", electronID_noTOP,
657  "**(SPECIAL (TEMP) variable)** electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the TOP*. *NB:* this variable must be used in place of `electronID` when analysing data (MC) processed (simulated) in *release 6*");
658  REGISTER_METAVARIABLE("binaryElectronID_noTOP(pdgCodeTest)", binaryElectronID_noTOP,
659  "**(SPECIAL (TEMP) variable)** Returns the binary probability for the electron mass hypothesis with respect to another mass hypothesis using all detector components, *excluding the TOP*. *NB:* this variable must be used in place of `binaryPID` (``pdgCode1=11``) when analysing data (MC) processed (simulated) in **release 6**",
660  Manager::VariableDataType::c_double);
661  REGISTER_VARIABLE("electronID_noSVD_noTOP", electronID_noSVD_noTOP,
662  "**(SPECIAL (TEMP) variable)** electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD and the TOP*. *NB:* this variable must be used in place of `electronID` when analysing data (MC) processed (simulated) in *release 5*");
663  REGISTER_METAVARIABLE("binaryElectronID_noSVD_noTOP(pdgCodeTest)", binaryElectronID_noSVD_noTOP,
664  "**(SPECIAL (TEMP) variable)** Returns the binary probability for the electron mass hypothesis with respect to another mass hypothesis using all detector components, *excluding the SVD and the TOP*. *NB:* this variable must be used in place of `binaryPID` (``pdgCode1=11``) when analysing data (MC) processed (simulated) in **release 5**",
665  Manager::VariableDataType::c_double);
666 
667  // Metafunctions for experts to access the basic PID quantities
668  VARIABLE_GROUP("PID_expert");
669  REGISTER_METAVARIABLE("pidLogLikelihoodValueExpert(pdgCode, detectorList)", pidLogLikelihoodValueExpert,
670  "returns the log likelihood value of for a specific mass hypothesis and set of detectors.", Manager::VariableDataType::c_double);
671  REGISTER_METAVARIABLE("pidDeltaLogLikelihoodValueExpert(pdgCode1, pdgCode2, detectorList)", pidDeltaLogLikelihoodValueExpert,
672  "returns LogL(hyp1) - LogL(hyp2) (aka DLL) for two mass hypotheses and a set of detectors.", Manager::VariableDataType::c_double);
673  REGISTER_METAVARIABLE("pidPairProbabilityExpert(pdgCodeHyp, pdgCodeTest, detectorList)", pidPairProbabilityExpert,
674  "Pair (or binary) probability for the pdgCodeHyp mass hypothesis respect to the pdgCodeTest one, using an arbitrary set of detectors. :math:`\\mathcal{L}_{hyp}/(\\mathcal{L}_{test}+\\mathcal{L}_{hyp}`",
675  Manager::VariableDataType::c_double);
676  REGISTER_METAVARIABLE("pidProbabilityExpert(pdgCodeHyp, detectorList)", pidProbabilityExpert,
677  "probability for the pdgCodeHyp mass hypothesis respect to all the other ones, using an arbitrary set of detectors :math:`\\mathcal{L}_{hyp}/(\\Sigma_{\\text{all~hyp}}\\mathcal{L}_{i}`. ",
678  Manager::VariableDataType::c_double);
679  REGISTER_METAVARIABLE("pidMissingProbabilityExpert(detectorList)", pidMissingProbabilityExpert,
680  "returns 1 if the PID probabiliy is missing for the provided detector list, otherwise 0. ", Manager::VariableDataType::c_double);
681  REGISTER_VARIABLE("pidMostLikelyPDG(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", mostLikelyPDG,
682  R"DOC(
683 Returns PDG code of the largest PID likelihood, or NaN if PID information is not available.
684 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
685 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
686  REGISTER_VARIABLE("pidIsMostLikely(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", isMostLikely, R"DOC(
687 Returns True if the largest PID likelihood of a given particle corresponds to its particle hypothesis.
688 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
689 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
690 
691  // B2BII PID
692  VARIABLE_GROUP("Belle PID variables");
693  REGISTER_METAVARIABLE("atcPIDBelle(i,j)", atcPIDBelle, R"DOC(
694 [Legacy] Returns Belle's PID atc variable: ``atc_pid(3,1,5,i,j).prob()``.
695 Parameters i,j are signal and background hypothesis: (0 = electron, 1 = muon, 2 = pion, 3 = kaon, 4 = proton)
696 Returns 0.5 in case there is no likelihood found and a factor of 0.5 will appear in the product if any of the subdetectors don't report a likelihood (Belle behaviour).
697 
698 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
699  )DOC", Manager::VariableDataType::c_double);
700  REGISTER_VARIABLE("muIDBelle", muIDBelle, R"DOC(
701 [Legacy] Returns Belle's PID ``Muon_likelihood()`` variable.
702 Returns 0.5 in case there is no likelihood found and returns zero if the muon likelihood is not usable (Belle behaviour).
703 
704 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
705  )DOC");
706  REGISTER_VARIABLE("muIDBelleQuality", muIDBelleQuality, R"DOC(
707 [Legacy] Returns true if Belle's PID ``Muon_likelihood()`` is usable (reliable).
708 Returns zero/false if not usable or if there is no PID found.
709  )DOC");
710  REGISTER_VARIABLE("eIDBelle", eIDBelle, R"DOC(
711 [Legacy] Returns Belle's electron ID ``eid(3,-1,5).prob()`` variable.
712 Returns 0.5 in case there is no likelihood found (Belle behaviour).
713 
714 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
715  )DOC");
716  }
718 }
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23