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