Belle II Software  light-2212-foldex
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 <analysis/utility/ReferenceFrame.h>
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 // database
22 //#include <framework/database/DBObjPtr.h>
23 #include <analysis/dbobjects/PIDCalibrationWeight.h>
24 #include <analysis/utility/PIDCalibrationWeightUtil.h>
25 
26 #include <boost/algorithm/string.hpp>
27 
28 #include <iostream>
29 #include <cmath>
30 
31 using namespace std;
32 
33 namespace Belle2 {
38  namespace Variable {
39 
40 
41 
42  //*************
43  // Utilities
44  //*************
45 
46  // converts Belle numbering scheme for charged final state particles
47  // to Belle II ChargedStable
48  Const::ChargedStable hypothesisConversion(const int hypothesis)
49  {
50  switch (hypothesis) {
51  case 0:
52  return Const::electron;
53  case 1:
54  return Const::muon;
55  case 2:
56  return Const::pion;
57  case 3:
58  return Const::kaon;
59  case 4:
60  return Const::proton;
61  }
62 
63  return Const::pion;
64  }
65 
66 
67  Const::PIDDetectorSet parseDetectors(const std::vector<std::string>& arguments)
68  {
69  Const::PIDDetectorSet result;
70  for (std::string val : arguments) {
71  boost::to_lower(val);
72  if (val == "all") return Const::PIDDetectors::set();
73  else if (val == "svd") result += Const::SVD;
74  else if (val == "cdc") result += Const::CDC;
75  else if (val == "top") result += Const::TOP;
76  else if (val == "arich") result += Const::ARICH;
77  else if (val == "ecl") result += Const::ECL;
78  else if (val == "klm") result += Const::KLM;
79  else B2ERROR("Unknown detector component: " << val);
80  }
81  return result;
82  }
83 
84  // Specialisation of valid detectors parser for ChargedBDT.
85  Const::PIDDetectorSet parseDetectorsChargedBDT(const std::vector<std::string>& arguments)
86  {
87  Const::PIDDetectorSet result;
88  for (std::string val : arguments) {
89  boost::to_lower(val);
90  if (val == "all") return Const::PIDDetectors::set();
91  else if (val == "ecl") result += Const::ECL;
92  else B2ERROR("Invalid detector component: " << val << " for charged BDT.");
93  }
94  return result;
95  }
96 
97  //*************
98  // Belle II
99  //*************
100 
101  // a "smart" variable:
102  // finds the global probability based on the PDG code of the input particle
103  double particleID(const Particle* p)
104  {
105  int pdg = abs(p->getPDGCode());
106  if (pdg == Const::electron.getPDGCode()) return electronID(p);
107  else if (pdg == Const::muon.getPDGCode()) return muonID(p);
108  else if (pdg == Const::pion.getPDGCode()) return pionID(p);
109  else if (pdg == Const::kaon.getPDGCode()) return kaonID(p);
110  else if (pdg == Const::proton.getPDGCode()) return protonID(p);
111  else if (pdg == Const::deuteron.getPDGCode()) return deuteronID(p);
112  else return std::numeric_limits<float>::quiet_NaN();
113  }
114 
115  Manager::FunctionPtr pidLogLikelihoodValueExpert(const std::vector<std::string>& arguments)
116  {
117  if (arguments.size() < 2) {
118  B2ERROR("Need at least two arguments to pidLogLikelihoodValueExpert");
119  return nullptr;
120  }
121  int pdgCode;
122  try {
123  pdgCode = Belle2::convertString<int>(arguments[0]);
124  } catch (std::invalid_argument& e) {
125  B2ERROR("First argument of pidLogLikelihoodValueExpert must be a PDG code");
126  return nullptr;
127  }
128  std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
129 
130  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
131  auto hypType = Const::ChargedStable(abs(pdgCode));
132 
133  auto func = [hypType, detectorSet](const Particle * part) -> double {
134  const PIDLikelihood* pid = part->getPIDLikelihood();
135  if (!pid)
136  return std::numeric_limits<float>::quiet_NaN();
137  // No information from any subdetector in the list
138  if (pid->getLogL(hypType, detectorSet) == 0)
139  return std::numeric_limits<float>::quiet_NaN();
140 
141  return pid->getLogL(hypType, detectorSet);
142  };
143  return func;
144  }
145 
146 
147 
148  Manager::FunctionPtr pidDeltaLogLikelihoodValueExpert(const std::vector<std::string>& arguments)
149  {
150  if (arguments.size() < 3) {
151  B2ERROR("Need at least three arguments to pidDeltaLogLikelihoodValueExpert");
152  return nullptr;
153  }
154  int pdgCodeHyp, pdgCodeTest;
155  try {
156  pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
157  } catch (std::invalid_argument& e) {
158  B2ERROR("First argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
159  return nullptr;
160  }
161  try {
162  pdgCodeTest = Belle2::convertString<int>(arguments[1]);
163  } catch (std::invalid_argument& e) {
164  B2ERROR("Second argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
165  return nullptr;
166  }
167 
168  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
169  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
170  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
171  auto testType = Const::ChargedStable(abs(pdgCodeTest));
172 
173  auto func = [hypType, testType, detectorSet](const Particle * part) -> double {
174  const PIDLikelihood* pid = part->getPIDLikelihood();
175  if (!pid) return std::numeric_limits<float>::quiet_NaN();
176  // No information from any subdetector in the list
177  if (pid->getLogL(hypType, detectorSet) == 0)
178  return std::numeric_limits<float>::quiet_NaN();
179 
180  return (pid->getLogL(hypType, detectorSet) - pid->getLogL(testType, detectorSet));
181  };
182  return func;
183  }
184 
185 
186  Manager::FunctionPtr pidPairProbabilityExpert(const std::vector<std::string>& arguments)
187  {
188  if (arguments.size() < 3) {
189  B2ERROR("Need at least three arguments to pidPairProbabilityExpert");
190  return nullptr;
191  }
192  int pdgCodeHyp = 0, pdgCodeTest = 0;
193  try {
194  pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
195  } catch (std::invalid_argument& e) {
196  B2ERROR("First argument of pidPairProbabilityExpert must be PDG code");
197  return nullptr;
198  }
199  try {
200  pdgCodeTest = Belle2::convertString<int>(arguments[1]);
201  } catch (std::invalid_argument& e) {
202  B2ERROR("Second argument of pidPairProbabilityExpert must be PDG code");
203  return nullptr;
204  }
205 
206  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
207 
208  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
209  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
210  auto testType = Const::ChargedStable(abs(pdgCodeTest));
211  auto func = [hypType, testType, detectorSet](const Particle * part) -> double {
212  const PIDLikelihood* pid = part->getPIDLikelihood();
213  if (!pid) return std::numeric_limits<float>::quiet_NaN();
214  // No information from any subdetector in the list
215  if (pid->getLogL(hypType, detectorSet) == 0)
216  return std::numeric_limits<float>::quiet_NaN();
217 
218  return pid->getProbability(hypType, testType, detectorSet);
219  };
220  return func;
221  }
222 
223 
224  Manager::FunctionPtr pidProbabilityExpert(const std::vector<std::string>& arguments)
225  {
226  if (arguments.size() < 2) {
227  B2ERROR("Need at least two arguments for pidProbabilityExpert");
228  return nullptr;
229  }
230  int pdgCodeHyp = 0;
231  try {
232  pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
233  } catch (std::invalid_argument& e) {
234  B2ERROR("First argument of pidProbabilityExpert must be PDG code");
235  return nullptr;
236  }
237 
238  std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
239  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
240  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
241 
242  // Placeholder for the priors
243  const unsigned int n = Const::ChargedStable::c_SetSize;
244  double frac[n];
245  for (double& i : frac) i = 1.0; // flat priors
246 
247  auto func = [hypType, frac, detectorSet](const Particle * part) -> double {
248  const PIDLikelihood* pid = part->getPIDLikelihood();
249  if (!pid) return std::numeric_limits<float>::quiet_NaN();
250  // No information from any subdetector in the list
251  if (pid->getLogL(hypType, detectorSet) == 0)
252  return std::numeric_limits<float>::quiet_NaN();
253 
254  return pid->getProbability(hypType, frac, detectorSet);
255  };
256  return func;
257  }
258 
259 
260  Manager::FunctionPtr pidMissingProbabilityExpert(const std::vector<std::string>& arguments)
261  {
262  if (arguments.size() < 1) {
263  B2ERROR("Need at least one argument to pidMissingProbabilityExpert");
264  return nullptr;
265  }
266 
267  std::vector<std::string> detectors(arguments.begin(), arguments.end());
268  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
269 
270  auto func = [detectorSet](const Particle * part) -> double {
271  const PIDLikelihood* pid = part->getPIDLikelihood();
272  if (!pid) return std::numeric_limits<double>::quiet_NaN();
273  if (not pid->isAvailable(detectorSet))
274  return 1;
275  else return 0;
276  };
277  return func;
278  }
279 
280  Manager::FunctionPtr pidWeightedLogLikelihoodValueExpert(const std::vector<std::string>& arguments)
281  {
282  if (arguments.size() < 3) {
283  B2ERROR("Need at least three arguments to pidWeightedLogLikelihoodValueExpert");
284  return nullptr;
285  }
286  std::string matrixName = arguments[0];
287 
288  int pdgCode;
289  try {
290  pdgCode = Belle2::convertString<int>(arguments[1]);
291  } catch (std::invalid_argument& e) {
292  B2ERROR("Second argument of pidWeightedLogLikelihoodValueExpert must be a PDG code");
293  return nullptr;
294  }
295  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
296  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
297  auto hypType = Const::ChargedStable(abs(pdgCode));
298 
299  auto func = [hypType, detectorSet, matrixName](const Particle * part) -> double {
300  PIDCalibrationWeightUtil weightMatrix(matrixName);
301  const PIDLikelihood* pid = part->getPIDLikelihood();
302  if (!pid)
303  return std::numeric_limits<float>::quiet_NaN();
304  // No information from any subdetector in the list
305  if (pid->getLogL(hypType, detectorSet) == 0)
306  return std::numeric_limits<float>::quiet_NaN();
307 
308  const auto& frame = ReferenceFrame::GetCurrent();
309  auto mom = frame.getMomentum(part);
310  auto p = mom.P();
311  auto theta = mom.Theta();
312 
313  double LogL = 0;
314  for (const Const::EDetector& detector : Const::PIDDetectorSet::set())
315  {
316  if (detectorSet.contains(detector))
317  LogL += pid->getLogL(hypType, detector) * weightMatrix.getWeight(hypType.getPDGCode(), detector, p, theta);
318  }
319  return LogL;
320  };
321 
322  return func;
323  }
324 
325  Manager::FunctionPtr pidWeightedProbabilityExpert(const std::vector<std::string>& arguments)
326  {
327  if (arguments.size() < 3) {
328  B2ERROR("Need at least three arguments for pidWeightedProbabilityExpert");
329  return nullptr;
330  }
331  std::string matrixName = arguments[0];
332 
333  int pdgCodeHyp = 0;
334  try {
335  pdgCodeHyp = Belle2::convertString<int>(arguments[1]);
336  } catch (std::invalid_argument& e) {
337  B2ERROR("Second argument of pidWeightedProbabilityExpert must be PDG code");
338  return nullptr;
339  }
340 
341  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
342  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
343  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
344 
345  auto func = [hypType, detectorSet, matrixName](const Particle * part) -> double {
346  PIDCalibrationWeightUtil weightMatrix(matrixName);
347  const PIDLikelihood* pid = part->getPIDLikelihood();
348  if (!pid) return std::numeric_limits<float>::quiet_NaN();
349  // No information from any subdetector in the list
350  if (pid->getLogL(hypType, detectorSet) == 0)
351  return std::numeric_limits<float>::quiet_NaN();
352 
353  const auto& frame = ReferenceFrame::GetCurrent();
354  auto mom = frame.getMomentum(part);
355  auto p = mom.P();
356  auto theta = mom.Theta();
357 
358  double LogL[Const::ChargedStable::c_SetSize];
359  double LogL_max = 0;
360  bool hasMax = false;
361  for (const auto& pdgIter : Const::chargedStableSet)
362  {
363  const int index_pdg = pdgIter.getIndex();
364 
365  LogL[index_pdg] = 0;
366  for (const Const::EDetector& detector : Const::PIDDetectorSet::set()) {
367  if (detectorSet.contains(detector))
368  LogL[index_pdg] += pid->getLogL(pdgIter, detector) * weightMatrix.getWeight(pdgIter.getPDGCode(), detector, p, theta);
369  }
370 
371  if (!hasMax || (LogL[index_pdg] > LogL_max)) {
372  LogL_max = LogL[index_pdg];
373  hasMax = true;
374  }
375  }
376 
377  double norm = 0;
378  for (unsigned i = 0; i < Const::ChargedStable::c_SetSize; ++i)
379  norm += exp(LogL[i] - LogL_max);
380 
381  if (norm > 0)
382  return exp(LogL[hypType.getIndex()] - LogL_max) / norm;
383  else
384  return -1;
385  };
386  return func;
387  }
388 
389 
390  Manager::FunctionPtr pidWeightedPairProbabilityExpert(const std::vector<std::string>& arguments)
391  {
392  if (arguments.size() < 4) {
393  B2ERROR("Need at least four arguments to pidWeightedPairProbabilityExpert");
394  return nullptr;
395  }
396  std::string matrixName = arguments[0];
397 
398  int pdgCodeHyp = 0, pdgCodeTest = 0;
399  try {
400  pdgCodeHyp = Belle2::convertString<int>(arguments[1]);
401  } catch (std::invalid_argument& e) {
402  B2ERROR("Second argument of pidWeightedPairProbabilityExpert must be PDG code");
403  return nullptr;
404  }
405  try {
406  pdgCodeTest = Belle2::convertString<int>(arguments[2]);
407  } catch (std::invalid_argument& e) {
408  B2ERROR("Third argument of pidWeightedPairProbabilityExpert must be PDG code");
409  return nullptr;
410  }
411 
412  std::vector<std::string> detectors(arguments.begin() + 3, arguments.end());
413 
414  Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
415  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
416  auto testType = Const::ChargedStable(abs(pdgCodeTest));
417 
418  auto func = [hypType, testType, detectorSet, matrixName](const Particle * part) -> double {
419  PIDCalibrationWeightUtil weightMatrix(matrixName);
420 
421  const PIDLikelihood* pid = part->getPIDLikelihood();
422  if (!pid) return std::numeric_limits<float>::quiet_NaN();
423  // No information from any subdetector in the list
424  if (pid->getLogL(hypType, detectorSet) == 0)
425  return std::numeric_limits<float>::quiet_NaN();
426 
427  const auto& frame = ReferenceFrame::GetCurrent();
428  auto mom = frame.getMomentum(part);
429  auto p = mom.P();
430  auto theta = mom.Theta();
431 
432  double LogL_hypType(0), LogL_testType(0);
433  for (const Const::EDetector& detector : Const::PIDDetectorSet::set())
434  {
435  if (detectorSet.contains(detector)) {
436  LogL_hypType += pid->getLogL(hypType, detector) * weightMatrix.getWeight(hypType.getPDGCode(), detector, p, theta);
437  LogL_testType += pid->getLogL(testType, detector) * weightMatrix.getWeight(testType.getPDGCode(), detector, p, theta);
438  }
439  }
440 
441  double deltaLogL = LogL_testType - LogL_hypType;
442  double res;
443  if (deltaLogL < 0)
444  {
445  double eLogL = exp(deltaLogL);
446  res = 1. / (1. + eLogL);
447  } else
448  {
449  double eLogL = exp(-deltaLogL);
450  res = eLogL / (1.0 + eLogL);
451  }
452 
453  if (std::isfinite(res))
454  return res;
455 
456  return 0;
457  };
458  return func;
459  }
460 
461  double electronID(const Particle* part)
462  {
463  static Manager::FunctionPtr pidFunction =
464  pidProbabilityExpert({"11", "ALL"});
465  return std::get<double>(pidFunction(part));
466  }
467 
468  double muonID(const Particle* part)
469  {
470  static Manager::FunctionPtr pidFunction =
471  pidProbabilityExpert({"13", "ALL"});
472  return std::get<double>(pidFunction(part));
473  }
474 
475  double pionID(const Particle* part)
476  {
477  static Manager::FunctionPtr pidFunction =
478  pidProbabilityExpert({"211", "ALL"});
479  return std::get<double>(pidFunction(part));
480  }
481 
482  double kaonID(const Particle* part)
483  {
484  static Manager::FunctionPtr pidFunction =
485  pidProbabilityExpert({"321", "ALL"});
486  return std::get<double>(pidFunction(part));
487  }
488 
489  double protonID(const Particle* part)
490  {
491  static Manager::FunctionPtr pidFunction =
492  pidProbabilityExpert({"2212", "ALL"});
493  return std::get<double>(pidFunction(part));
494  }
495 
496  double deuteronID(const Particle* part)
497  {
498  static Manager::FunctionPtr pidFunction =
499  pidProbabilityExpert({"1000010020", "ALL"});
500  return std::get<double>(pidFunction(part));
501  }
502 
503  double binaryPID(const Particle* part, const std::vector<double>& arguments)
504  {
505  if (arguments.size() != 2) {
506  B2ERROR("The variable binaryPID needs exactly two arguments: the PDG codes of two hypotheses.");
507  return std::numeric_limits<float>::quiet_NaN();;
508  }
509  int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
510  int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
511  return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
512  pdgCodeHyp) + ", " + std::to_string(
513  pdgCodeTest) + ", ALL)")->function(part));
514  }
515 
516  double electronID_noSVD(const Particle* part)
517  {
518  // Excluding SVD for electron ID. This variable is temporary. BII-8760
519  static Manager::FunctionPtr pidFunction =
520  pidProbabilityExpert({"11", "CDC", "TOP", "ARICH", "ECL", "KLM"});
521  return std::get<double>(pidFunction(part));
522  }
523 
524  double muonID_noSVD(const Particle* part)
525  {
526  // Excluding SVD for muon ID. This variable is temporary. BII-8760
527  static Manager::FunctionPtr pidFunction =
528  pidProbabilityExpert({"13", "CDC", "TOP", "ARICH", "ECL", "KLM"});
529  return std::get<double>(pidFunction(part));
530  }
531 
532  double pionID_noSVD(const Particle* part)
533  {
534  // Excluding SVD for pion ID. This variable is temporary. BII-8760
535  static Manager::FunctionPtr pidFunction =
536  pidProbabilityExpert({"211", "CDC", "TOP", "ARICH", "ECL", "KLM"});
537  return std::get<double>(pidFunction(part));
538  }
539 
540  double kaonID_noSVD(const Particle* part)
541  {
542  // Excluding SVD for kaon ID. This variable is temporary. BII-8760
543  static Manager::FunctionPtr pidFunction =
544  pidProbabilityExpert({"321", "CDC", "TOP", "ARICH", "ECL", "KLM"});
545  return std::get<double>(pidFunction(part));
546  }
547 
548  double protonID_noSVD(const Particle* part)
549  {
550  // Excluding SVD for proton ID. This variable is temporary. BII-8760
551  static Manager::FunctionPtr pidFunction =
552  pidProbabilityExpert({"2212", "CDC", "TOP", "ARICH", "ECL", "KLM"});
553  return std::get<double>(pidFunction(part));
554  }
555 
556  double deuteronID_noSVD(const Particle* part)
557  {
558  // Excluding SVD for deuteron ID. This variable is temporary. BII-8760
559  static Manager::FunctionPtr pidFunction =
560  pidProbabilityExpert({"1000010020", "CDC", "TOP", "ARICH", "ECL", "KLM"});
561  return std::get<double>(pidFunction(part));
562  }
563 
564  double binaryPID_noSVD(const Particle* part, const std::vector<double>& arguments)
565  {
566  // Excluding SVD for binary ID. This variable is temporary. BII-8760
567  if (arguments.size() != 2) {
568  B2ERROR("The variable binaryPID_noSVD needs exactly two arguments: the PDG codes of two hypotheses.");
569  return std::numeric_limits<float>::quiet_NaN();;
570  }
571  int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
572  int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
573  return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
574  pdgCodeHyp) + ", " + std::to_string(
575  pdgCodeTest) + ", CDC, TOP, ARICH, ECL, KLM)")->function(part));
576  }
577 
578  double electronID_noTOP(const Particle* part)
579  {
580  // Excluding TOP for electron ID. This variable is temporary. BII-8444
581  static Manager::FunctionPtr pidFunction =
582  pidProbabilityExpert({"11", "SVD", "CDC", "ARICH", "ECL", "KLM"});
583  return std::get<double>(pidFunction(part));
584  }
585 
586  double binaryElectronID_noTOP(const Particle* part, const std::vector<double>& arguments)
587  {
588  // Excluding TOP for electron ID. This is temporary. BII-8444
589  if (arguments.size() != 1) {
590  B2ERROR("The variable binaryElectronID_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
591  return std::numeric_limits<float>::quiet_NaN();;
592  }
593 
594  int pdgCodeHyp = Const::electron.getPDGCode();
595  int pdgCodeTest = std::abs(int(std::lround(arguments[0])));
596 
597  const auto var = "pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) + ", " +
598  std::to_string(pdgCodeTest) + ", SVD, CDC, ARICH, ECL, KLM)";
599 
600  return std::get<double>(Manager::Instance().getVariable(var)->function(part));
601  }
602 
603  double electronID_noSVD_noTOP(const Particle* part)
604  {
605  // Excluding SVD and TOP for electron ID. This variable is temporary. BII-8444, BII-8760.
606  static Manager::FunctionPtr pidFunction =
607  pidProbabilityExpert({"11", "CDC", "ARICH", "ECL", "KLM"});
608  return std::get<double>(pidFunction(part));
609  }
610 
611  double binaryElectronID_noSVD_noTOP(const Particle* part, const std::vector<double>& arguments)
612  {
613  // Excluding SVD and TOP for electron ID. This is temporary. BII-8444, BII-8760.
614  if (arguments.size() != 1) {
615  B2ERROR("The variable binaryElectronID_noSVD_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
616  return std::numeric_limits<float>::quiet_NaN();;
617  }
618 
619  int pdgCodeHyp = Const::electron.getPDGCode();
620  int pdgCodeTest = std::abs(int(std::lround(arguments[0])));
621 
622  const auto var = "pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) + ", " +
623  std::to_string(pdgCodeTest) + ", CDC, ARICH, ECL, KLM)";
624 
625  return std::get<double>(Manager::Instance().getVariable(var)->function(part));
626  }
627 
628 
629  double pionID_noARICHwoECL(const Particle* part)
630  {
631  // remove arich if no ecl cluster + identified as kaon in arich
632  const ECLCluster* cluster = part->getECLCluster();
633  if (!cluster) {
634  const PIDLikelihood* pid = part->getPIDLikelihood();
635  if (!pid) return std::numeric_limits<float>::quiet_NaN();
636  if (pid->getLogL(Const::kaon, Const::ARICH) > pid->getLogL(Const::pion, Const::ARICH)) {
637  static Manager::FunctionPtr pidFunction =
638  pidProbabilityExpert({"211", "SVD", "CDC", "TOP", "ECL", "KLM"});
639  return std::get<double>(pidFunction(part));
640  }
641  }
642  return pionID(part);
643  }
644 
645 
646  double kaonID_noARICHwoECL(const Particle* part)
647  {
648  // remove arich if no ecl cluster + identified as kaon in arich
649  const ECLCluster* cluster = part->getECLCluster();
650  if (!cluster) {
651  const PIDLikelihood* pid = part->getPIDLikelihood();
652  if (!pid) return std::numeric_limits<float>::quiet_NaN();
653  if (pid->getLogL(Const::kaon, Const::ARICH) > pid->getLogL(Const::pion, Const::ARICH)) {
654  static Manager::FunctionPtr pidFunction =
655  pidProbabilityExpert({"321", "SVD", "CDC", "TOP", "ECL", "KLM"});
656  return std::get<double>(pidFunction(part));
657  }
658  }
659  return kaonID(part);
660  }
661 
662 
663  double binaryPID_noARICHwoECL(const Particle* part, const std::vector<double>& arguments)
664  {
665  // Excluding ARICH for tracks without ECL cluster and identified as heavier of the two hypotheses from binary ID.
666  if (arguments.size() != 2) {
667  B2ERROR("The variable binaryPID_noARICHwoECL needs exactly two arguments: the PDG codes of two hypotheses.");
668  return std::numeric_limits<float>::quiet_NaN();;
669  }
670  int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
671  int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
672  auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
673  auto testType = Const::ChargedStable(abs(pdgCodeTest));
674 
675  const ECLCluster* cluster = part->getECLCluster();
676  if (!cluster) {
677  const PIDLikelihood* pid = part->getPIDLikelihood();
678  if (!pid) return std::numeric_limits<float>::quiet_NaN();
679  double lkhdiff = pid->getLogL(hypType, Const::ARICH) - pid->getLogL(testType, Const::ARICH);
680  if ((lkhdiff > 0 && pdgCodeHyp > pdgCodeTest) || (lkhdiff < 0 && pdgCodeHyp < pdgCodeTest)) {
681  return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
682  pdgCodeHyp) + ", " + std::to_string(
683  pdgCodeTest) + ", SVD, CDC, TOP, ECL, KLM)")->function(part));
684  }
685  }
686 
687  return binaryPID(part, arguments);
688 
689  }
690 
691 
692 
693  double antineutronID(const Particle* particle)
694  {
695  if (particle->hasExtraInfo("nbarID")) {
696  return particle->getExtraInfo("nbarID");
697  } else {
698  if (particle->getPDGCode() == -Const::neutron.getPDGCode()) {
699  B2WARNING("The extraInfo nbarID is not registered! \n"
700  "Please use function getNbarIDMVA in modularAnalysis.");
701  }
702  return std::numeric_limits<float>::quiet_NaN();
703  }
704  }
705 
706  Manager::FunctionPtr pidChargedBDTScore(const std::vector<std::string>& arguments)
707  {
708  if (arguments.size() != 2) {
709  B2ERROR("Need exactly two arguments for pidChargedBDTScore: pdgCodeHyp, detector");
710  return nullptr;
711  }
712 
713  int hypPdgId;
714  try {
715  hypPdgId = Belle2::convertString<int>(arguments.at(0));
716  } catch (std::invalid_argument& e) {
717  B2ERROR("First argument of pidChargedBDTScore must be an integer (PDG code).");
718  return nullptr;
719  }
720  Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
721 
722  std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
723  Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
724 
725  auto func = [hypType, detectorSet](const Particle * part) -> double {
726  auto name = "pidChargedBDTScore_" + std::to_string(hypType.getPDGCode());
727  for (const Const::EDetector& detector : detectorSet)
728  {
729  name += "_" + std::to_string(detector);
730  }
731  return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : std::numeric_limits<float>::quiet_NaN();
732  };
733  return func;
734  }
735 
736  Manager::FunctionPtr pidPairChargedBDTScore(const std::vector<std::string>& arguments)
737  {
738  if (arguments.size() != 3) {
739  B2ERROR("Need exactly three arguments for pidPairChargedBDTScore: pdgCodeHyp, pdgCodeTest, detector.");
740  return nullptr;
741  }
742 
743  int hypPdgId, testPdgId;
744  try {
745  hypPdgId = Belle2::convertString<int>(arguments.at(0));
746  } catch (std::invalid_argument& e) {
747  B2ERROR("First argument of pidPairChargedBDTScore must be an integer (PDG code).");
748  return nullptr;
749  }
750  try {
751  testPdgId = Belle2::convertString<int>(arguments.at(1));
752  } catch (std::invalid_argument& e) {
753  B2ERROR("First argument of pidPairChargedBDTScore must be an integer (PDG code).");
754  return nullptr;
755  }
756  Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
757  Const::ChargedStable testType = Const::ChargedStable(testPdgId);
758 
759  std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
760  Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
761 
762  auto func = [hypType, testType, detectorSet](const Particle * part) -> double {
763  auto name = "pidPairChargedBDTScore_" + std::to_string(hypType.getPDGCode()) + "_VS_" + std::to_string(testType.getPDGCode());
764  for (const Const::EDetector& detector : detectorSet)
765  {
766  name += "_" + std::to_string(detector);
767  }
768  return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : std::numeric_limits<float>::quiet_NaN();
769  };
770  return func;
771  }
772 
773  double mostLikelyPDG(const Particle* part, const std::vector<double>& arguments)
774  {
775  if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
776  B2ERROR("Need zero or exactly " << Const::ChargedStable::c_SetSize << " arguments for pidMostLikelyPDG");
777  return std::numeric_limits<double>::quiet_NaN();
778  }
779  double prob[Const::ChargedStable::c_SetSize];
780  if (arguments.size() == 0) {
781  for (unsigned int i = 0; i < Const::ChargedStable::c_SetSize; i++) prob[i] = 1. / Const::ChargedStable::c_SetSize;
782  } else {
783  copy(arguments.begin(), arguments.end(), prob);
784  }
785 
786  auto* pid = part->getPIDLikelihood();
787  if (!pid) return std::numeric_limits<double>::quiet_NaN();
788  return pid->getMostLikely(prob).getPDGCode();
789  }
790 
791  bool isMostLikely(const Particle* part, const std::vector<double>& arguments)
792  {
793  if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
794  B2ERROR("Need zero or exactly " << Const::ChargedStable::c_SetSize << " arguments for pidIsMostLikely");
795  return false;
796  }
797  return mostLikelyPDG(part, arguments) == abs(part->getPDGCode());
798  }
799 
800  Manager::FunctionPtr weightedElectronID(const std::vector<std::string>& arguments)
801  {
802  std::string varName;
803  if (arguments.size() == 0) {
804  varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 11, ALL)";
805  } else if (arguments.size() == 1) {
806  varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 11, ALL)";
807  } else {
808  B2ERROR("Need zero or one argument for weightedElectronID");
809  return nullptr;
810  }
811 
812  const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
813  auto func = [var](const Particle * particle) -> double {
814  return std::get<double>(var->function(particle));
815  };
816  return func;
817  };
818 
819  Manager::FunctionPtr weightedMuonID(const std::vector<std::string>& arguments)
820  {
821  std::string varName;
822  if (arguments.size() == 0) {
823  varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 13, ALL)";
824  } else if (arguments.size() == 1) {
825  varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 13, ALL)";
826  } else {
827  B2ERROR("Need zero or one argument for weightedMuonID");
828  return nullptr;
829  }
830 
831  const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
832  auto func = [var](const Particle * particle) -> double {
833  return std::get<double>(var->function(particle));
834  };
835  return func;
836  };
837 
838  Manager::FunctionPtr weightedPionID(const std::vector<std::string>& arguments)
839  {
840  std::string varName;
841  if (arguments.size() == 0) {
842  varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 211, ALL)";
843  } else if (arguments.size() == 1) {
844  varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 211, ALL)";
845  } else {
846  B2ERROR("Need zero or one argument for weightedPionID");
847  return nullptr;
848  }
849 
850  const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
851  auto func = [var](const Particle * particle) -> double {
852  return std::get<double>(var->function(particle));
853  };
854  return func;
855  };
856 
857  Manager::FunctionPtr weightedKaonID(const std::vector<std::string>& arguments)
858  {
859  std::string varName;
860  if (arguments.size() == 0) {
861  varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 321, ALL)";
862  } else if (arguments.size() == 1) {
863  varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 321, ALL)";
864  } else {
865  B2ERROR("Need zero or one argument for weightedKaonID");
866  return nullptr;
867  }
868 
869  const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
870  auto func = [var](const Particle * particle) -> double {
871  return std::get<double>(var->function(particle));
872  };
873  return func;
874  };
875 
876  Manager::FunctionPtr weightedProtonID(const std::vector<std::string>& arguments)
877  {
878  std::string varName;
879  if (arguments.size() == 0) {
880  varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 2212, ALL)";
881  } else if (arguments.size() == 1) {
882  varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 2212, ALL)";
883  } else {
884  B2ERROR("Need zero or one argument for weightedProtonID");
885  return nullptr;
886  }
887 
888  const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
889  auto func = [var](const Particle * particle) -> double {
890  return std::get<double>(var->function(particle));
891  };
892  return func;
893  };
894 
895  Manager::FunctionPtr weightedDeuteronID(const std::vector<std::string>& arguments)
896  {
897  std::string varName;
898  if (arguments.size() == 0) {
899  varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 1000010020, ALL)";
900  } else if (arguments.size() == 1) {
901  varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 1000010020, ALL)";
902  } else {
903  B2ERROR("Need zero or one argument for weightedDeuteronID");
904  return nullptr;
905  }
906 
907  const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
908  auto func = [var](const Particle * particle) -> double {
909  return std::get<double>(var->function(particle));
910  };
911  return func;
912  };
913 
914  //*************
915  // B2BII
916  //*************
917 
918  double muIDBelle(const Particle* particle)
919  {
920  const PIDLikelihood* pid = particle->getPIDLikelihood();
921  if (!pid) return 0.5; // Belle standard
922 
923  if (pid->isAvailable(Const::KLM))
924  return exp(pid->getLogL(Const::muon, Const::KLM));
925  else
926  return 0; // Belle standard
927  }
928 
929  double muIDBelleQuality(const Particle* particle)
930  {
931  const PIDLikelihood* pid = particle->getPIDLikelihood();
932  if (!pid) return 0;// Belle standard
933 
934  return pid->isAvailable(Const::KLM);
935  }
936 
937  double atcPIDBelle(const Particle* particle, const std::vector<double>& sigAndBkgHyp)
938  {
939  int sigHyp = int(std::lround(sigAndBkgHyp[0]));
940  int bkgHyp = int(std::lround(sigAndBkgHyp[1]));
941 
942  const PIDLikelihood* pid = particle->getPIDLikelihood();
943  if (!pid) return 0.5; // Belle standard
944 
945  // ACC = ARICH
946  Const::PIDDetectorSet set = Const::ARICH;
947  double acc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
948  double acc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
949  double acc = 0.5; // Belle standard
950  if (acc_sig + acc_bkg > 0.0)
951  acc = acc_sig / (acc_sig + acc_bkg);
952 
953  // TOF = TOP
954  set = Const::TOP;
955  double tof_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
956  double tof_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
957  double tof = 0.5; // Belle standard
958  double tof_all = tof_sig + tof_bkg;
959  if (tof_all != 0) {
960  tof = tof_sig / tof_all;
961  if (tof < 0.001) tof = 0.001;
962  if (tof > 0.999) tof = 0.999;
963  }
964 
965  // dE/dx = CDC
966  set = Const::CDC;
967  double cdc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
968  double cdc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
969  double cdc = 0.5; // Belle standard
970  double cdc_all = cdc_sig + cdc_bkg;
971  if (cdc_all != 0) {
972  cdc = cdc_sig / cdc_all;
973  if (cdc < 0.001) cdc = 0.001;
974  if (cdc > 0.999) cdc = 0.999;
975  }
976 
977  // Combined
978  double pid_sig = acc * tof * cdc;
979  double pid_bkg = (1. - acc) * (1. - tof) * (1. - cdc);
980 
981  return pid_sig / (pid_sig + pid_bkg);
982  }
983 
984 
985  double eIDBelle(const Particle* part)
986  {
987  const PIDLikelihood* pid = part->getPIDLikelihood();
988  if (!pid) return 0.5; // Belle standard
989 
990  Const::PIDDetectorSet set = Const::ECL;
991  return pid->getProbability(Const::electron, Const::pion, set);
992  }
993 
994 
995  // PID variables to be used for analysis
996  VARIABLE_GROUP("PID");
997  REGISTER_VARIABLE("particleID", particleID,
998  "the particle identification probability under the particle's own hypothesis, using info from all available detectors");
999  REGISTER_VARIABLE("electronID", electronID,
1000  "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");
1001  REGISTER_VARIABLE("muonID", muonID,
1002  "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");
1003  REGISTER_VARIABLE("pionID", pionID,
1004  "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");
1005  REGISTER_VARIABLE("kaonID", kaonID,
1006  "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");
1007  REGISTER_VARIABLE("protonID", protonID,
1008  "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");
1009  REGISTER_VARIABLE("deuteronID", deuteronID,
1010  "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");
1011  REGISTER_METAVARIABLE("binaryPID(pdgCode1, pdgCode2)", binaryPID,
1012  "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components",
1013  Manager::VariableDataType::c_double);
1014  REGISTER_METAVARIABLE("pidChargedBDTScore(pdgCodeHyp, detector)", pidChargedBDTScore,
1015  "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.",
1016  Manager::VariableDataType::c_double);
1017  REGISTER_METAVARIABLE("pidPairChargedBDTScore(pdgCodeHyp, pdgCodeTest, detector)", pidPairChargedBDTScore,
1018  "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.",
1019  Manager::VariableDataType::c_double);
1020  REGISTER_VARIABLE("nbarID", antineutronID, R"DOC(
1021 Returns MVA classifier for antineutron PID.
1022 
1023  - 1 signal(antineutron) like
1024  - 0 background like
1025  - -1 invalid using this PID due to some ECL variables used unavailable
1026 
1027 This PID is only for antineutron. Neutron is also considered as background.
1028 The variables used are `clusterPulseShapeDiscriminationMVA`, `clusterE`, `clusterLAT`, `clusterE1E9`, `clusterE9E21`,
1029 `clusterAbsZernikeMoment40`, `clusterAbsZernikeMoment51`, `clusterZernikeMVA`.)DOC");
1030 
1031  // Special temporary variables defined for users' convenience.
1032  REGISTER_VARIABLE("electronID_noSVD", electronID_noSVD,
1033  "**(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*");
1034  REGISTER_VARIABLE("muonID_noSVD", muonID_noSVD,
1035  "**(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*");
1036  REGISTER_VARIABLE("pionID_noSVD", pionID_noSVD,
1037  "**(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*");
1038  REGISTER_VARIABLE("kaonID_noSVD", kaonID_noSVD,
1039  "**(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*");
1040  REGISTER_VARIABLE("protonID_noSVD", protonID_noSVD,
1041  "**(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*");
1042  REGISTER_VARIABLE("deuteronID_noSVD", deuteronID_noSVD,
1043  "**(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*");
1044  REGISTER_METAVARIABLE("binaryPID_noSVD(pdgCode1, pdgCode2)", binaryPID_noSVD,
1045  "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components, *excluding the SVD*.",
1046  Manager::VariableDataType::c_double);
1047  REGISTER_VARIABLE("electronID_noTOP", electronID_noTOP,
1048  "**(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*");
1049  REGISTER_METAVARIABLE("binaryElectronID_noTOP(pdgCodeTest)", binaryElectronID_noTOP,
1050  "**(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**",
1051  Manager::VariableDataType::c_double);
1052  REGISTER_VARIABLE("electronID_noSVD_noTOP", electronID_noSVD_noTOP,
1053  "**(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*");
1054  REGISTER_METAVARIABLE("binaryElectronID_noSVD_noTOP(pdgCodeTest)", binaryElectronID_noSVD_noTOP,
1055  "**(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**",
1056  Manager::VariableDataType::c_double);
1057  REGISTER_VARIABLE("pionID_noARICHwoECL", pionID_noARICHwoECL,
1058  "**(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 but ARICH info excluded for tracks without associated ECL cluster");
1059  REGISTER_VARIABLE("kaonID_noARICHwoECL", kaonID_noARICHwoECL,
1060  "**(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 but ARICH info excluded for tracks without associated ECL cluster");
1061  REGISTER_METAVARIABLE("binaryPID_noARICHwoECL(pdgCode1, pdgCode2)", binaryPID_noARICHwoECL,
1062  "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components, but ARICH info excluded for tracks without associated ECL cluster",
1063  Manager::VariableDataType::c_double);
1064 
1065 
1066  REGISTER_METAVARIABLE("weightedElectronID(weightMatrixName)", weightedElectronID,
1067  R"DOC(
1068 weighted electron identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_e}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1069 where :math:`\mathcal{\tilde{L}}_i` is defined as :math:`\log\mathcal{\tilde{L}}_i = \sum_{j={\mathrm{SVD, CDC, TOP, ARICH, ECL, KLM}}} \mathcal{w}_{ij}\log\mathcal{L}_{ij}`.
1070 The :math:`\mathcal{L}_{ij}` is the original likelihood and :math:`\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.
1071 One can provide the name of the weight matrix as the argument.
1072 )DOC",
1073  Manager::VariableDataType::c_double);
1074  REGISTER_METAVARIABLE("weightedMuonID(weightMatrixName)", weightedMuonID,
1075  R"DOC(
1076 weighted muon identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_\mu}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1077 where :math:`\mathcal{\tilde{L}}_i` is defined as :math:`\log\mathcal{\tilde{L}}_i = \sum_{j={\mathrm{SVD, CDC, TOP, ARICH, ECL, KLM}}} \mathcal{w}_{ij}\log\mathcal{L}_{ij}`.
1078 The :math:`\mathcal{L}_{ij}` is the original likelihood and :math:`\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.
1079 One can provide the name of the weight matrix as the argument.
1080 )DOC",
1081  Manager::VariableDataType::c_double);
1082  REGISTER_METAVARIABLE("weightedPionID(weightMatrixName)", weightedPionID,
1083  R"DOC(
1084 weighted pion identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_\pi}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1085 where :math:`\mathcal{\tilde{L}}_i` is defined as :math:`\log\mathcal{\tilde{L}}_i = \sum_{j={\mathrm{SVD, CDC, TOP, ARICH, ECL, KLM}}} \mathcal{w}_{ij}\log\mathcal{L}_{ij}`.
1086 The :math:`\mathcal{L}_{ij}` is the original likelihood and :math:`\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.
1087 One can provide the name of the weight matrix as the argument.
1088 )DOC",
1089  Manager::VariableDataType::c_double);
1090  REGISTER_METAVARIABLE("weightedKaonID(weightMatrixName)", weightedKaonID,
1091  R"DOC(
1092 weighted kaon identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_K}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1093 where :math:`\mathcal{\tilde{L}}_i` is defined as :math:`\log\mathcal{\tilde{L}}_i = \sum_{j={\mathrm{SVD, CDC, TOP, ARICH, ECL, KLM}}} \mathcal{w}_{ij}\log\mathcal{L}_{ij}`.
1094 The :math:`\mathcal{L}_{ij}` is the original likelihood and :math:`\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.
1095 One can provide the name of the weight matrix as the argument.
1096 )DOC",
1097  Manager::VariableDataType::c_double);
1098  REGISTER_METAVARIABLE("weightedProtonID(weightMatrixName)", weightedProtonID,
1099  R"DOC(
1100 weighted proton identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_p}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1101 where :math:`\mathcal{\tilde{L}}_i` is defined as :math:`\log\mathcal{\tilde{L}}_i = \sum_{j={\mathrm{SVD, CDC, TOP, ARICH, ECL, KLM}}} \mathcal{w}_{ij}\log\mathcal{L}_{ij}`.
1102 The :math:`\mathcal{L}_{ij}` is the original likelihood and :math:`\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.
1103 One can provide the name of the weight matrix as the argument.
1104 )DOC",
1105  Manager::VariableDataType::c_double);
1106  REGISTER_METAVARIABLE("weightedDeuteronID(weightMatrixName)", weightedDeuteronID,
1107  R"DOC(
1108 weighted deuteron identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_d}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1109 where :math:`\mathcal{\tilde{L}}_i` is defined as :math:`\log\mathcal{\tilde{L}}_i = \sum_{j={\mathrm{SVD, CDC, TOP, ARICH, ECL, KLM}}} \mathcal{w}_{ij}\log\mathcal{L}_{ij}`.
1110 The :math:`\mathcal{L}_{ij}` is the original likelihood and :math:`\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.
1111 One can provide the name of the weight matrix as the argument.
1112 )DOC",
1113  Manager::VariableDataType::c_double);
1114 
1115  // Metafunctions for experts to access the basic PID quantities
1116  VARIABLE_GROUP("PID_expert");
1117  REGISTER_METAVARIABLE("pidLogLikelihoodValueExpert(pdgCode, detectorList)", pidLogLikelihoodValueExpert,
1118  "returns the log likelihood value of for a specific mass hypothesis and set of detectors.", Manager::VariableDataType::c_double);
1119  REGISTER_METAVARIABLE("pidDeltaLogLikelihoodValueExpert(pdgCode1, pdgCode2, detectorList)", pidDeltaLogLikelihoodValueExpert,
1120  "returns LogL(hyp1) - LogL(hyp2) (aka DLL) for two mass hypotheses and a set of detectors.", Manager::VariableDataType::c_double);
1121  REGISTER_METAVARIABLE("pidPairProbabilityExpert(pdgCodeHyp, pdgCodeTest, detectorList)", pidPairProbabilityExpert,
1122  "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})`",
1123  Manager::VariableDataType::c_double);
1124  REGISTER_METAVARIABLE("pidProbabilityExpert(pdgCodeHyp, detectorList)", pidProbabilityExpert,
1125  "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})`. ",
1126  Manager::VariableDataType::c_double);
1127  REGISTER_METAVARIABLE("pidMissingProbabilityExpert(detectorList)", pidMissingProbabilityExpert,
1128  "returns 1 if the PID probabiliy is missing for the provided detector list, otherwise 0. ", Manager::VariableDataType::c_double);
1129  REGISTER_VARIABLE("pidMostLikelyPDG(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", mostLikelyPDG,
1130  R"DOC(
1131 Returns PDG code of the largest PID likelihood, or NaN if PID information is not available.
1132 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
1133 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
1134  REGISTER_VARIABLE("pidIsMostLikely(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", isMostLikely, R"DOC(
1135 Returns True if the largest PID likelihood of a given particle corresponds to its particle hypothesis.
1136 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
1137 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
1138 
1139  REGISTER_METAVARIABLE("pidWeightedLogLikelihoodValueExpert(weightMatrixName, pdgCode, detectorList)",
1140  pidWeightedLogLikelihoodValueExpert,
1141  "returns the weighted log likelihood value of for a specific mass hypothesis and set of detectors, "
1142  ":math:`\\log\\mathcal{\\tilde{L}}_{hyp} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{hyp,j}\\log\\mathcal{L}_{hyp,j}`. "
1143  "The :math:`\\mathcal{L}_{ij}` is the original likelihood and :math:`\\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.",
1144  Manager::VariableDataType::c_double);
1145  REGISTER_METAVARIABLE("pidWeightedPairProbabilityExpert(weightMatrixName, pdgCodeHyp, pdgCodeTest, detectorList)",
1146  pidWeightedPairProbabilityExpert,
1147  "Weighted pair (or binary) probability for the pdgCodeHyp mass hypothesis with respect to the pdgCodeTest one, using an arbitrary set of detectors, "
1148  ":math:`\\mathcal{\\tilde{L}}_{hyp}/(\\mathcal{\\tilde{L}}_{test}+\\mathcal{\\tilde{L}}_{hyp})` where :math:`\\mathcal{\\tilde{L}}_{i}` is defined as "
1149  ":math:`\\log\\mathcal{\\tilde{L}}_{i} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{i,j}\\log\\mathcal{L}_{i,j}`. "
1150  "The :math:`\\mathcal{L}_{ij}` is the original likelihood and :math:`\\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.",
1151  Manager::VariableDataType::c_double);
1152  REGISTER_METAVARIABLE("pidWeightedProbabilityExpert(weightMatrixName, pdgCodeHyp, detectorList)",
1153  pidWeightedProbabilityExpert,
1154  "Weighted probability for the pdgCodeHyp mass hypothesis with respect to all the other ones, using an arbitrary set of detectors, "
1155  ":math:`\\mathcal{\\tilde{L}}_{hyp}/\\sum_{i=e,\\mu,\\pi,K,p,d} \\mathcal{\\tilde{L}}_i` where :math:`\\mathcal{\\tilde{L}}_{i}` is defined as "
1156  ":math:`\\log\\mathcal{\\tilde{L}}_{i} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{i,j}\\log\\mathcal{L}_{i,j}`. "
1157  "The :math:`\\mathcal{L}_{ij}` is the original likelihood and :math:`\\mathcal{w}_{ij}` is the PID calibration weight of i-th particle type and j-th detector.",
1158  Manager::VariableDataType::c_double);
1159 
1160  // B2BII PID
1161  VARIABLE_GROUP("Belle PID variables");
1162  REGISTER_METAVARIABLE("atcPIDBelle(i,j)", atcPIDBelle, R"DOC(
1163 [Legacy] Returns Belle's PID atc variable: ``atc_pid(3,1,5,i,j).prob()``.
1164 Parameters i,j are signal and background hypothesis: (0 = electron, 1 = muon, 2 = pion, 3 = kaon, 4 = proton)
1165 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).
1166 
1167 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1168  )DOC", Manager::VariableDataType::c_double);
1169  REGISTER_VARIABLE("muIDBelle", muIDBelle, R"DOC(
1170 [Legacy] Returns Belle's PID ``Muon_likelihood()`` variable.
1171 Returns 0.5 in case there is no likelihood found and returns zero if the muon likelihood is not usable (Belle behaviour).
1172 
1173 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1174  )DOC");
1175  REGISTER_VARIABLE("muIDBelleQuality", muIDBelleQuality, R"DOC(
1176 [Legacy] Returns true if Belle's PID ``Muon_likelihood()`` is usable (reliable).
1177 Returns zero/false if not usable or if there is no PID found.
1178  )DOC");
1179  REGISTER_VARIABLE("eIDBelle", eIDBelle, R"DOC(
1180 [Legacy] Returns Belle's electron ID ``eid(3,-1,5).prob()`` variable.
1181 Returns 0.5 in case there is no likelihood found (Belle behaviour).
1182 
1183 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1184  )DOC");
1185  }
1187 }
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23