Belle II Software light-2405-quaxo
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 header.
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#include <mdst/dataobjects/TrackFitResult.h>
16
17// framework aux
18#include <framework/logging/Logger.h>
19#include <framework/utilities/Conversion.h>
20#include <framework/gearbox/Const.h>
21
22// database
23//#include <framework/database/DBObjPtr.h>
24#include <analysis/dbobjects/PIDCalibrationWeight.h>
25#include <analysis/utility/PIDCalibrationWeightUtil.h>
26#include <analysis/utility/PIDNeuralNetwork.h>
27
28#include <boost/algorithm/string.hpp>
29
30#include <iostream>
31#include <cmath>
32
33using namespace std;
34
35namespace Belle2 {
40 namespace Variable {
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 {
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 {
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 Const::doubleNaN;
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 Const::doubleNaN;
137 // No information from any subdetector in the list
138 if (pid->getLogL(hypType, detectorSet) == 0)
139 return Const::doubleNaN;
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 Const::doubleNaN;
176 // No information from any subdetector in the list
177 if (pid->getLogL(hypType, detectorSet) == 0)
178 return Const::doubleNaN;
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 Const::doubleNaN;
214 // No information from any subdetector in the list
215 if (pid->getLogL(hypType, detectorSet) == 0)
216 return Const::doubleNaN;
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 Const::doubleNaN;
250 // No information from any subdetector in the list
251 if (pid->getLogL(hypType, detectorSet) == 0)
252 return Const::doubleNaN;
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 Const::doubleNaN;
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 Const::doubleNaN;
304 // No information from any subdetector in the list
305 if (pid->getLogL(hypType, detectorSet) == 0)
306 return Const::doubleNaN;
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 Const::doubleNaN;
349 // No information from any subdetector in the list
350 if (pid->getLogL(hypType, detectorSet) == 0)
351 return Const::doubleNaN;
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 std::vector<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 (auto LogL_i : LogL)
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 pidNeuralNetworkValueExpert(const std::vector<std::string>& arguments)
391 {
392 if (arguments.size() == 0) {
393 B2ERROR("Need pdg code for pidNeuralNetworkValueExpert");
394 return nullptr;
395 }
396 if (arguments.size() > 2) {
397 B2ERROR("pidNeuralNetworkValueExpert expects at most two arguments, i.e. the pdg code and the pidNeuralNetworkName");
398 return nullptr;
399 }
400 int pdgCode;
401 try {
402 pdgCode = abs(Belle2::convertString<int>(arguments[0]));
403 } catch (std::invalid_argument& e) {
404 B2ERROR("First argument of pidNeuralNetworkValueExpert must be a PDG code");
405 return nullptr;
406 }
407
408 std::shared_ptr<PIDNeuralNetwork> neuralNetworkPtr;
409 if (arguments.size() == 2) {
410 std::string parameterSetName = arguments[1];
411 neuralNetworkPtr = std::make_shared<PIDNeuralNetwork>(parameterSetName);
412 } else {
413 neuralNetworkPtr = std::make_shared<PIDNeuralNetwork>();
414 }
415
416 neuralNetworkPtr->hasPdgCode(pdgCode, true); // raise exception if pdg code is not predicted
417
418 auto func = [neuralNetworkPtr, pdgCode](const Particle * part) -> double {
419 const auto& extraInfoName = neuralNetworkPtr->getExtraInfoName(pdgCode);
420 if (part->hasExtraInfo(extraInfoName))
421 return part->getExtraInfo(extraInfoName);
422
423 const PIDLikelihood* pid = part->getPIDLikelihood();
424 if (!pid)
425 return Const::doubleNaN;
426
427 {
428 auto hypType = Const::ChargedStable(pdgCode);
429 if (pid->getLogL(hypType) == 0)
430 return Const::doubleNaN;
431 }
432
433 // collect only those inputs needed for the neural network in the correct order
434 std::vector<float> inputsNN;
435 inputsNN.reserve(neuralNetworkPtr->getInputSize());
436 for (const auto& inputName : neuralNetworkPtr->getInputBasf2Names())
437 inputsNN.push_back(std::get<double>(Variable::Manager::Instance().getVariable(inputName)->function(part)));
438
439 const auto probabilities = neuralNetworkPtr->predict(inputsNN);
440
441 // store all probabilities for all hypotheses in extraInfo
442 for (const auto element : probabilities)
443 {
444 const auto [pdgCodeElement, probability] = element;
445 const_cast<Particle*>(part)->addExtraInfo(neuralNetworkPtr->getExtraInfoName(pdgCodeElement), probability);
446 }
447
448 return probabilities.at(pdgCode);
449 };
450
451 return func;
452 }
453
454
455 Manager::FunctionPtr pidWeightedPairProbabilityExpert(const std::vector<std::string>& arguments)
456 {
457 if (arguments.size() < 4) {
458 B2ERROR("Need at least four arguments to pidWeightedPairProbabilityExpert");
459 return nullptr;
460 }
461 std::string matrixName = arguments[0];
462
463 int pdgCodeHyp = 0, pdgCodeTest = 0;
464 try {
465 pdgCodeHyp = Belle2::convertString<int>(arguments[1]);
466 } catch (std::invalid_argument& e) {
467 B2ERROR("Second argument of pidWeightedPairProbabilityExpert must be PDG code");
468 return nullptr;
469 }
470 try {
471 pdgCodeTest = Belle2::convertString<int>(arguments[2]);
472 } catch (std::invalid_argument& e) {
473 B2ERROR("Third argument of pidWeightedPairProbabilityExpert must be PDG code");
474 return nullptr;
475 }
476
477 std::vector<std::string> detectors(arguments.begin() + 3, arguments.end());
478
479 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
480 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
481 auto testType = Const::ChargedStable(abs(pdgCodeTest));
482
483 auto func = [hypType, testType, detectorSet, matrixName](const Particle * part) -> double {
484 PIDCalibrationWeightUtil weightMatrix(matrixName);
485
486 const PIDLikelihood* pid = part->getPIDLikelihood();
487 if (!pid) return Const::doubleNaN;
488 // No information from any subdetector in the list
489 if (pid->getLogL(hypType, detectorSet) == 0)
490 return Const::doubleNaN;
491
492 const auto& frame = ReferenceFrame::GetCurrent();
493 auto mom = frame.getMomentum(part);
494 auto p = mom.P();
495 auto theta = mom.Theta();
496
497 double LogL_hypType(0), LogL_testType(0);
498 for (const Const::EDetector& detector : Const::PIDDetectorSet::set())
499 {
500 if (detectorSet.contains(detector)) {
501 LogL_hypType += pid->getLogL(hypType, detector) * weightMatrix.getWeight(hypType.getPDGCode(), detector, p, theta);
502 LogL_testType += pid->getLogL(testType, detector) * weightMatrix.getWeight(testType.getPDGCode(), detector, p, theta);
503 }
504 }
505
506 double deltaLogL = LogL_testType - LogL_hypType;
507 double res;
508 if (deltaLogL < 0)
509 {
510 double eLogL = exp(deltaLogL);
511 res = 1. / (1. + eLogL);
512 } else
513 {
514 double eLogL = exp(-deltaLogL);
515 res = eLogL / (1.0 + eLogL);
516 }
517
518 if (std::isfinite(res))
519 return res;
520
521 return 0;
522 };
523 return func;
524 }
525
526 double electronID(const Particle* part)
527 {
528 static Manager::FunctionPtr pidFunction =
529 pidProbabilityExpert({"11", "ALL"});
530 return std::get<double>(pidFunction(part));
531 }
532
533 double muonID(const Particle* part)
534 {
535 static Manager::FunctionPtr pidFunction =
536 pidProbabilityExpert({"13", "ALL"});
537 return std::get<double>(pidFunction(part));
538 }
539
540 double pionID(const Particle* part)
541 {
542 static Manager::FunctionPtr pidFunction =
543 pidProbabilityExpert({"211", "ALL"});
544 return std::get<double>(pidFunction(part));
545 }
546
547 double kaonID(const Particle* part)
548 {
549 static Manager::FunctionPtr pidFunction =
550 pidProbabilityExpert({"321", "ALL"});
551 return std::get<double>(pidFunction(part));
552 }
553
554 double protonID(const Particle* part)
555 {
556 static Manager::FunctionPtr pidFunction =
557 pidProbabilityExpert({"2212", "ALL"});
558 return std::get<double>(pidFunction(part));
559 }
560
561 double deuteronID(const Particle* part)
562 {
563 static Manager::FunctionPtr pidFunction =
564 pidProbabilityExpert({"1000010020", "ALL"});
565 return std::get<double>(pidFunction(part));
566 }
567
568 double binaryPID(const Particle* part, const std::vector<double>& arguments)
569 {
570 if (arguments.size() != 2) {
571 B2ERROR("The variable binaryPID needs exactly two arguments: the PDG codes of two hypotheses.");
572 return Const::doubleNaN;;
573 }
574 int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
575 int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
576 return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
577 pdgCodeHyp) + ", " + std::to_string(
578 pdgCodeTest) + ", ALL)")->function(part));
579 }
580
581 double electronID_noSVD(const Particle* part)
582 {
583 // Excluding SVD for electron ID. This variable is temporary. BII-8760
584 static Manager::FunctionPtr pidFunction =
585 pidProbabilityExpert({"11", "CDC", "TOP", "ARICH", "ECL", "KLM"});
586 return std::get<double>(pidFunction(part));
587 }
588
589 double muonID_noSVD(const Particle* part)
590 {
591 // Excluding SVD for muon ID. This variable is temporary. BII-8760
592 static Manager::FunctionPtr pidFunction =
593 pidProbabilityExpert({"13", "CDC", "TOP", "ARICH", "ECL", "KLM"});
594 return std::get<double>(pidFunction(part));
595 }
596
597 double pionID_noSVD(const Particle* part)
598 {
599 // Excluding SVD for pion ID. This variable is temporary. BII-8760
600 static Manager::FunctionPtr pidFunction =
601 pidProbabilityExpert({"211", "CDC", "TOP", "ARICH", "ECL", "KLM"});
602 return std::get<double>(pidFunction(part));
603 }
604
605 double kaonID_noSVD(const Particle* part)
606 {
607 // Excluding SVD for kaon ID. This variable is temporary. BII-8760
608 static Manager::FunctionPtr pidFunction =
609 pidProbabilityExpert({"321", "CDC", "TOP", "ARICH", "ECL", "KLM"});
610 return std::get<double>(pidFunction(part));
611 }
612
613 double protonID_noSVD(const Particle* part)
614 {
615 // Excluding SVD for proton ID. This variable is temporary. BII-8760
616 static Manager::FunctionPtr pidFunction =
617 pidProbabilityExpert({"2212", "CDC", "TOP", "ARICH", "ECL", "KLM"});
618 return std::get<double>(pidFunction(part));
619 }
620
621 double deuteronID_noSVD(const Particle* part)
622 {
623 // Excluding SVD for deuteron ID. This variable is temporary. BII-8760
624 static Manager::FunctionPtr pidFunction =
625 pidProbabilityExpert({"1000010020", "CDC", "TOP", "ARICH", "ECL", "KLM"});
626 return std::get<double>(pidFunction(part));
627 }
628
629 double binaryPID_noSVD(const Particle* part, const std::vector<double>& arguments)
630 {
631 // Excluding SVD for binary ID. This variable is temporary. BII-8760
632 if (arguments.size() != 2) {
633 B2ERROR("The variable binaryPID_noSVD needs exactly two arguments: the PDG codes of two hypotheses.");
634 return Const::doubleNaN;;
635 }
636 int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
637 int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
638 return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
639 pdgCodeHyp) + ", " + std::to_string(
640 pdgCodeTest) + ", CDC, TOP, ARICH, ECL, KLM)")->function(part));
641 }
642
643 double electronID_noTOP(const Particle* part)
644 {
645 // Excluding TOP for electron ID. This variable is temporary. BII-8444
646 static Manager::FunctionPtr pidFunction =
647 pidProbabilityExpert({"11", "SVD", "CDC", "ARICH", "ECL", "KLM"});
648 return std::get<double>(pidFunction(part));
649 }
650
651 double binaryElectronID_noTOP(const Particle* part, const std::vector<double>& arguments)
652 {
653 // Excluding TOP for electron ID. This is temporary. BII-8444
654 if (arguments.size() != 1) {
655 B2ERROR("The variable binaryElectronID_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
656 return Const::doubleNaN;;
657 }
658
659 int pdgCodeHyp = Const::electron.getPDGCode();
660 int pdgCodeTest = std::abs(int(std::lround(arguments[0])));
661
662 const auto var = "pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) + ", " +
663 std::to_string(pdgCodeTest) + ", SVD, CDC, ARICH, ECL, KLM)";
664
665 return std::get<double>(Manager::Instance().getVariable(var)->function(part));
666 }
667
668 double electronID_noSVD_noTOP(const Particle* part)
669 {
670 // Excluding SVD and TOP for electron ID. This variable is temporary. BII-8444, BII-8760.
671 static Manager::FunctionPtr pidFunction =
672 pidProbabilityExpert({"11", "CDC", "ARICH", "ECL", "KLM"});
673 return std::get<double>(pidFunction(part));
674 }
675
676 double binaryElectronID_noSVD_noTOP(const Particle* part, const std::vector<double>& arguments)
677 {
678 // Excluding SVD and TOP for electron ID. This is temporary. BII-8444, BII-8760.
679 if (arguments.size() != 1) {
680 B2ERROR("The variable binaryElectronID_noSVD_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
681 return Const::doubleNaN;;
682 }
683
684 int pdgCodeHyp = Const::electron.getPDGCode();
685 int pdgCodeTest = std::abs(int(std::lround(arguments[0])));
686
687 const auto var = "pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) + ", " +
688 std::to_string(pdgCodeTest) + ", CDC, ARICH, ECL, KLM)";
689
690 return std::get<double>(Manager::Instance().getVariable(var)->function(part));
691 }
692
693
694 double pionID_noARICHwoECL(const Particle* part)
695 {
696 // remove arich if no ecl cluster + identified as kaon in arich
697 const ECLCluster* cluster = part->getECLCluster();
698 if (!cluster) {
699 const PIDLikelihood* pid = part->getPIDLikelihood();
700 if (!pid) return Const::doubleNaN;
701 if (pid->getLogL(Const::kaon, Const::ARICH) > pid->getLogL(Const::pion, Const::ARICH)) {
702 static Manager::FunctionPtr pidFunction =
703 pidProbabilityExpert({"211", "SVD", "CDC", "TOP", "ECL", "KLM"});
704 return std::get<double>(pidFunction(part));
705 }
706 }
707 return pionID(part);
708 }
709
710
711 double kaonID_noARICHwoECL(const Particle* part)
712 {
713 // remove arich if no ecl cluster + identified as kaon in arich
714 const ECLCluster* cluster = part->getECLCluster();
715 if (!cluster) {
716 const PIDLikelihood* pid = part->getPIDLikelihood();
717 if (!pid) return Const::doubleNaN;
718 if (pid->getLogL(Const::kaon, Const::ARICH) > pid->getLogL(Const::pion, Const::ARICH)) {
719 static Manager::FunctionPtr pidFunction =
720 pidProbabilityExpert({"321", "SVD", "CDC", "TOP", "ECL", "KLM"});
721 return std::get<double>(pidFunction(part));
722 }
723 }
724 return kaonID(part);
725 }
726
727
728 double binaryPID_noARICHwoECL(const Particle* part, const std::vector<double>& arguments)
729 {
730 // Excluding ARICH for tracks without ECL cluster and identified as heavier of the two hypotheses from binary ID.
731 if (arguments.size() != 2) {
732 B2ERROR("The variable binaryPID_noARICHwoECL needs exactly two arguments: the PDG codes of two hypotheses.");
733 return Const::doubleNaN;;
734 }
735 int pdgCodeHyp = std::abs(int(std::lround(arguments[0])));
736 int pdgCodeTest = std::abs(int(std::lround(arguments[1])));
737 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
738 auto testType = Const::ChargedStable(abs(pdgCodeTest));
739
740 const ECLCluster* cluster = part->getECLCluster();
741 if (!cluster) {
742 const PIDLikelihood* pid = part->getPIDLikelihood();
743 if (!pid) return Const::doubleNaN;
744 double lkhdiff = pid->getLogL(hypType, Const::ARICH) - pid->getLogL(testType, Const::ARICH);
745 if ((lkhdiff > 0 && pdgCodeHyp > pdgCodeTest) || (lkhdiff < 0 && pdgCodeHyp < pdgCodeTest)) {
746 return std::get<double>(Manager::Instance().getVariable("pidPairProbabilityExpert(" + std::to_string(
747 pdgCodeHyp) + ", " + std::to_string(
748 pdgCodeTest) + ", SVD, CDC, TOP, ECL, KLM)")->function(part));
749 }
750 }
751
752 return binaryPID(part, arguments);
753
754 }
755
756
757
758 double antineutronID(const Particle* particle)
759 {
760 if (particle->hasExtraInfo("nbarID")) {
761 return particle->getExtraInfo("nbarID");
762 } else {
763 if (particle->getPDGCode() == -Const::neutron.getPDGCode()) {
764 B2WARNING("The extraInfo nbarID is not registered! \n"
765 "Please use function getNbarIDMVA in modularAnalysis.");
766 }
767 return Const::doubleNaN;
768 }
769 }
770
771 Manager::FunctionPtr pidChargedBDTScore(const std::vector<std::string>& arguments)
772 {
773 if (arguments.size() != 2) {
774 B2ERROR("Need exactly two arguments for pidChargedBDTScore: pdgCodeHyp, detector");
775 return nullptr;
776 }
777
778 int hypPdgId;
779 try {
780 hypPdgId = Belle2::convertString<int>(arguments.at(0));
781 } catch (std::invalid_argument& e) {
782 B2ERROR("First argument of pidChargedBDTScore must be an integer (PDG code).");
783 return nullptr;
784 }
785 Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
786
787 std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
788 Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
789
790 auto func = [hypType, detectorSet](const Particle * part) -> double {
791 auto name = "pidChargedBDTScore_" + std::to_string(hypType.getPDGCode());
792 for (const Const::EDetector& detector : detectorSet)
793 {
794 name += "_" + std::to_string(detector);
795 }
796 return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : Const::doubleNaN;
797 };
798 return func;
799 }
800
801 Manager::FunctionPtr pidPairChargedBDTScore(const std::vector<std::string>& arguments)
802 {
803 if (arguments.size() != 3) {
804 B2ERROR("Need exactly three arguments for pidPairChargedBDTScore: pdgCodeHyp, pdgCodeTest, detector.");
805 return nullptr;
806 }
807
808 int hypPdgId, testPdgId;
809 try {
810 hypPdgId = Belle2::convertString<int>(arguments.at(0));
811 } catch (std::invalid_argument& e) {
812 B2ERROR("First argument of pidPairChargedBDTScore must be an integer (PDG code).");
813 return nullptr;
814 }
815 try {
816 testPdgId = Belle2::convertString<int>(arguments.at(1));
817 } catch (std::invalid_argument& e) {
818 B2ERROR("First argument of pidPairChargedBDTScore must be an integer (PDG code).");
819 return nullptr;
820 }
821 Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
822 Const::ChargedStable testType = Const::ChargedStable(testPdgId);
823
824 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
825 Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
826
827 auto func = [hypType, testType, detectorSet](const Particle * part) -> double {
828 auto name = "pidPairChargedBDTScore_" + std::to_string(hypType.getPDGCode()) + "_VS_" + std::to_string(testType.getPDGCode());
829 for (const Const::EDetector& detector : detectorSet)
830 {
831 name += "_" + std::to_string(detector);
832 }
833 return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : Const::doubleNaN;
834 };
835 return func;
836 }
837
838 double mostLikelyPDG(const Particle* part, const std::vector<double>& arguments)
839 {
840 if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
841 B2ERROR("Need zero or exactly " << Const::ChargedStable::c_SetSize << " arguments for pidMostLikelyPDG");
842 return Const::doubleNaN;
843 }
845 if (arguments.size() == 0) {
846 for (unsigned int i = 0; i < Const::ChargedStable::c_SetSize; i++) prob[i] = 1. / Const::ChargedStable::c_SetSize;
847 } else {
848 copy(arguments.begin(), arguments.end(), prob);
849 }
850
851 auto* pid = part->getPIDLikelihood();
852 if (!pid) return Const::doubleNaN;
853 return pid->getMostLikely(prob).getPDGCode();
854 }
855
856 bool isMostLikely(const Particle* part, const std::vector<double>& arguments)
857 {
858 if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
859 B2ERROR("Need zero or exactly " << Const::ChargedStable::c_SetSize << " arguments for pidIsMostLikely");
860 return false;
861 }
862 return mostLikelyPDG(part, arguments) == abs(part->getPDGCode());
863 }
864
865 Manager::FunctionPtr weightedElectronID(const std::vector<std::string>& arguments)
866 {
867 std::string varName;
868 if (arguments.size() == 0) {
869 varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 11, ALL)";
870 } else if (arguments.size() == 1) {
871 varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 11, ALL)";
872 } else {
873 B2ERROR("Need zero or one argument for weightedElectronID");
874 return nullptr;
875 }
876
877 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
878 auto func = [var](const Particle * particle) -> double {
879 return std::get<double>(var->function(particle));
880 };
881 return func;
882 };
883
884 Manager::FunctionPtr weightedMuonID(const std::vector<std::string>& arguments)
885 {
886 std::string varName;
887 if (arguments.size() == 0) {
888 varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 13, ALL)";
889 } else if (arguments.size() == 1) {
890 varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 13, ALL)";
891 } else {
892 B2ERROR("Need zero or one argument for weightedMuonID");
893 return nullptr;
894 }
895
896 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
897 auto func = [var](const Particle * particle) -> double {
898 return std::get<double>(var->function(particle));
899 };
900 return func;
901 };
902
903 Manager::FunctionPtr weightedPionID(const std::vector<std::string>& arguments)
904 {
905 std::string varName;
906 if (arguments.size() == 0) {
907 varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 211, ALL)";
908 } else if (arguments.size() == 1) {
909 varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 211, ALL)";
910 } else {
911 B2ERROR("Need zero or one argument for weightedPionID");
912 return nullptr;
913 }
914
915 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
916 auto func = [var](const Particle * particle) -> double {
917 return std::get<double>(var->function(particle));
918 };
919 return func;
920 };
921
922 Manager::FunctionPtr weightedKaonID(const std::vector<std::string>& arguments)
923 {
924 std::string varName;
925 if (arguments.size() == 0) {
926 varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 321, ALL)";
927 } else if (arguments.size() == 1) {
928 varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 321, ALL)";
929 } else {
930 B2ERROR("Need zero or one argument for weightedKaonID");
931 return nullptr;
932 }
933
934 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
935 auto func = [var](const Particle * particle) -> double {
936 return std::get<double>(var->function(particle));
937 };
938 return func;
939 };
940
941 Manager::FunctionPtr weightedProtonID(const std::vector<std::string>& arguments)
942 {
943 std::string varName;
944 if (arguments.size() == 0) {
945 varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 2212, ALL)";
946 } else if (arguments.size() == 1) {
947 varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 2212, ALL)";
948 } else {
949 B2ERROR("Need zero or one argument for weightedProtonID");
950 return nullptr;
951 }
952
953 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
954 auto func = [var](const Particle * particle) -> double {
955 return std::get<double>(var->function(particle));
956 };
957 return func;
958 };
959
960 Manager::FunctionPtr weightedDeuteronID(const std::vector<std::string>& arguments)
961 {
962 std::string varName;
963 if (arguments.size() == 0) {
964 varName = "pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 1000010020, ALL)";
965 } else if (arguments.size() == 1) {
966 varName = "pidWeightedProbabilityExpert(" + arguments[0] + ", 1000010020, ALL)";
967 } else {
968 B2ERROR("Need zero or one argument for weightedDeuteronID");
969 return nullptr;
970 }
971
972 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
973 auto func = [var](const Particle * particle) -> double {
974 return std::get<double>(var->function(particle));
975 };
976 return func;
977 };
978
979
980 double pionIDNN(const Particle* particle)
981 {
982 if (particle->hasExtraInfo("pidNeuralNetworkValueExpert(211)"))
983 return particle->getExtraInfo("pidNeuralNetworkValueExpert(211)");
984 static auto func = pidNeuralNetworkValueExpert({"211"});
985 return std::get<double>(func(particle));
986 }
987
988 double kaonIDNN(const Particle* particle)
989 {
990 if (particle->hasExtraInfo("pidNeuralNetworkValueExpert(321)"))
991 return particle->getExtraInfo("pidNeuralNetworkValueExpert(321)");
992 static auto func = pidNeuralNetworkValueExpert({"321"});
993 return std::get<double>(func(particle));
994 }
995
996
997 //*************
998 // B2BII
999 //*************
1000
1001 double muIDBelle(const Particle* particle)
1002 {
1003 const PIDLikelihood* pid = particle->getPIDLikelihood();
1004 if (!pid) return 0.5; // Belle standard
1005
1006 if (pid->isAvailable(Const::KLM))
1007 return exp(pid->getLogL(Const::muon, Const::KLM));
1008 else
1009 return 0; // Belle standard
1010 }
1011
1012 double muIDBelleQuality(const Particle* particle)
1013 {
1014 const PIDLikelihood* pid = particle->getPIDLikelihood();
1015 if (!pid) return 0;// Belle standard
1016
1017 return pid->isAvailable(Const::KLM);
1018 }
1019
1020 double atcPIDBelle(const Particle* particle, const std::vector<double>& sigAndBkgHyp)
1021 {
1022 int sigHyp = int(std::lround(sigAndBkgHyp[0]));
1023 int bkgHyp = int(std::lround(sigAndBkgHyp[1]));
1024
1025 const PIDLikelihood* pid = particle->getPIDLikelihood();
1026 if (!pid) return 0.5; // Belle standard
1027
1028 // ACC = ARICH
1029 Const::PIDDetectorSet set = Const::ARICH;
1030 double acc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
1031 double acc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
1032 double acc = 0.5; // Belle standard
1033 if (acc_sig + acc_bkg > 0.0)
1034 acc = acc_sig / (acc_sig + acc_bkg);
1035
1036 // TOF = TOP
1037 set = Const::TOP;
1038 double tof_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
1039 double tof_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
1040 double tof = 0.5; // Belle standard
1041 double tof_all = tof_sig + tof_bkg;
1042 if (tof_all != 0) {
1043 tof = tof_sig / tof_all;
1044 if (tof < 0.001) tof = 0.001;
1045 if (tof > 0.999) tof = 0.999;
1046 }
1047
1048 // dE/dx = CDC
1049 set = Const::CDC;
1050 double cdc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
1051 double cdc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
1052 double cdc = 0.5; // Belle standard
1053 double cdc_all = cdc_sig + cdc_bkg;
1054 if (cdc_all != 0) {
1055 cdc = cdc_sig / cdc_all;
1056 if (cdc < 0.001) cdc = 0.001;
1057 if (cdc > 0.999) cdc = 0.999;
1058 }
1059
1060 // Combined
1061 double pid_sig = acc * tof * cdc;
1062 double pid_bkg = (1. - acc) * (1. - tof) * (1. - cdc);
1063
1064 return pid_sig / (pid_sig + pid_bkg);
1065 }
1066
1067
1068 double eIDBelle(const Particle* part)
1069 {
1070 const PIDLikelihood* pid = part->getPIDLikelihood();
1071 if (!pid) return 0.5; // Belle standard
1072
1073 Const::PIDDetectorSet set = Const::ECL;
1074 return pid->getProbability(Const::electron, Const::pion, set);
1075 }
1076
1077
1078 // PID variables to be used for analysis
1079 VARIABLE_GROUP("PID");
1080 REGISTER_VARIABLE("particleID", particleID,
1081 "the particle identification probability under the particle's own hypothesis, using info from all available detectors");
1082 REGISTER_VARIABLE("electronID", electronID,
1083 "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");
1084 REGISTER_VARIABLE("muonID", muonID,
1085 "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");
1086 REGISTER_VARIABLE("pionID", pionID,
1087 "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");
1088 REGISTER_VARIABLE("kaonID", kaonID,
1089 "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");
1090 REGISTER_VARIABLE("protonID", protonID,
1091 "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");
1092 REGISTER_VARIABLE("deuteronID", deuteronID,
1093 "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");
1094 REGISTER_METAVARIABLE("binaryPID(pdgCode1, pdgCode2)", binaryPID,
1095 "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components",
1096 Manager::VariableDataType::c_double);
1097 REGISTER_METAVARIABLE("pidChargedBDTScore(pdgCodeHyp, detector)", pidChargedBDTScore,
1098 "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.",
1099 Manager::VariableDataType::c_double);
1100 REGISTER_METAVARIABLE("pidPairChargedBDTScore(pdgCodeHyp, pdgCodeTest, detector)", pidPairChargedBDTScore,
1101 "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.",
1102 Manager::VariableDataType::c_double);
1103 REGISTER_VARIABLE("nbarID", antineutronID, R"DOC(
1104Returns MVA classifier for antineutron PID.
1105
1106- 1 signal(antineutron) like
1107- 0 background like
1108- -1 invalid using this PID due to some ECL variables used unavailable
1109
1110This PID is only for antineutron. Neutron is also considered as background.
1111The variables used are `clusterPulseShapeDiscriminationMVA`, `clusterE`, `clusterLAT`, `clusterE1E9`, `clusterE9E21`,
1112`clusterAbsZernikeMoment40`, `clusterAbsZernikeMoment51`, `clusterZernikeMVA`.)DOC");
1113
1114 // Special temporary variables defined for users' convenience.
1115 REGISTER_VARIABLE("electronID_noSVD", electronID_noSVD,
1116 "**(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*");
1117 REGISTER_VARIABLE("muonID_noSVD", muonID_noSVD,
1118 "**(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*");
1119 REGISTER_VARIABLE("pionID_noSVD", pionID_noSVD,
1120 "**(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*");
1121 REGISTER_VARIABLE("kaonID_noSVD", kaonID_noSVD,
1122 "**(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*");
1123 REGISTER_VARIABLE("protonID_noSVD", protonID_noSVD,
1124 "**(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*");
1125 REGISTER_VARIABLE("deuteronID_noSVD", deuteronID_noSVD,
1126 "**(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*");
1127 REGISTER_METAVARIABLE("binaryPID_noSVD(pdgCode1, pdgCode2)", binaryPID_noSVD,
1128 "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components, *excluding the SVD*.",
1129 Manager::VariableDataType::c_double);
1130 REGISTER_VARIABLE("electronID_noTOP", electronID_noTOP,
1131 "**(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*");
1132 REGISTER_METAVARIABLE("binaryElectronID_noTOP(pdgCodeTest)", binaryElectronID_noTOP,
1133 "**(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**",
1134 Manager::VariableDataType::c_double);
1135 REGISTER_VARIABLE("electronID_noSVD_noTOP", electronID_noSVD_noTOP,
1136 "**(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*");
1137 REGISTER_METAVARIABLE("binaryElectronID_noSVD_noTOP(pdgCodeTest)", binaryElectronID_noSVD_noTOP,
1138 "**(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**",
1139 Manager::VariableDataType::c_double);
1140 REGISTER_VARIABLE("pionID_noARICHwoECL", pionID_noARICHwoECL,
1141 "**(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");
1142 REGISTER_VARIABLE("kaonID_noARICHwoECL", kaonID_noARICHwoECL,
1143 "**(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");
1144 REGISTER_METAVARIABLE("binaryPID_noARICHwoECL(pdgCode1, pdgCode2)", binaryPID_noARICHwoECL,
1145 "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",
1146 Manager::VariableDataType::c_double);
1147
1148
1149 REGISTER_METAVARIABLE("weightedElectronID(weightMatrixName)", weightedElectronID,
1150 R"DOC(
1151weighted electron identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_e}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1152where :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}`.
1153The :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.
1154One can provide the name of the weight matrix as the argument.
1155)DOC",
1156 Manager::VariableDataType::c_double);
1157 REGISTER_METAVARIABLE("weightedMuonID(weightMatrixName)", weightedMuonID,
1158 R"DOC(
1159weighted muon identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_\mu}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1160where :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}`.
1161The :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.
1162One can provide the name of the weight matrix as the argument.
1163)DOC",
1164 Manager::VariableDataType::c_double);
1165 REGISTER_METAVARIABLE("weightedPionID(weightMatrixName)", weightedPionID,
1166 R"DOC(
1167weighted pion identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_\pi}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1168where :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}`.
1169The :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.
1170One can provide the name of the weight matrix as the argument.
1171)DOC",
1172 Manager::VariableDataType::c_double);
1173 REGISTER_METAVARIABLE("weightedKaonID(weightMatrixName)", weightedKaonID,
1174 R"DOC(
1175weighted kaon identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_K}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1176where :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}`.
1177The :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.
1178One can provide the name of the weight matrix as the argument.
1179)DOC",
1180 Manager::VariableDataType::c_double);
1181 REGISTER_METAVARIABLE("weightedProtonID(weightMatrixName)", weightedProtonID,
1182 R"DOC(
1183weighted proton identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_p}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1184where :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}`.
1185The :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.
1186One can provide the name of the weight matrix as the argument.
1187)DOC",
1188 Manager::VariableDataType::c_double);
1189 REGISTER_METAVARIABLE("weightedDeuteronID(weightMatrixName)", weightedDeuteronID,
1190 R"DOC(
1191weighted deuteron identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_d}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1192where :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}`.
1193The :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.
1194One can provide the name of the weight matrix as the argument.
1195)DOC",
1196 Manager::VariableDataType::c_double);
1197
1198
1199 REGISTER_VARIABLE("pionIDNN", pionIDNN,
1200 R"DOC(
1201pion identification probability as calculated from the PID neural network.
1202)DOC");
1203 REGISTER_VARIABLE("kaonIDNN", kaonIDNN,
1204 R"DOC(
1205kaon identification probability as calculated from the PID neural network.
1206)DOC");
1207
1208
1209 // Metafunctions for experts to access the basic PID quantities
1210 VARIABLE_GROUP("PID_expert");
1211 REGISTER_METAVARIABLE("pidLogLikelihoodValueExpert(pdgCode, detectorList)", pidLogLikelihoodValueExpert,
1212 "returns the log likelihood value of for a specific mass hypothesis and set of detectors.", Manager::VariableDataType::c_double);
1213 REGISTER_METAVARIABLE("pidDeltaLogLikelihoodValueExpert(pdgCode1, pdgCode2, detectorList)", pidDeltaLogLikelihoodValueExpert,
1214 "returns LogL(hyp1) - LogL(hyp2) (aka DLL) for two mass hypotheses and a set of detectors.", Manager::VariableDataType::c_double);
1215 REGISTER_METAVARIABLE("pidPairProbabilityExpert(pdgCodeHyp, pdgCodeTest, detectorList)", pidPairProbabilityExpert,
1216 "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})`",
1217 Manager::VariableDataType::c_double);
1218 REGISTER_METAVARIABLE("pidProbabilityExpert(pdgCodeHyp, detectorList)", pidProbabilityExpert,
1219 "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})`. ",
1220 Manager::VariableDataType::c_double);
1221 REGISTER_METAVARIABLE("pidMissingProbabilityExpert(detectorList)", pidMissingProbabilityExpert,
1222 "returns 1 if the PID probabiliy is missing for the provided detector list, otherwise 0. ", Manager::VariableDataType::c_double);
1223 REGISTER_VARIABLE("pidMostLikelyPDG(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", mostLikelyPDG,
1224 R"DOC(
1225Returns PDG code of the largest PID likelihood, or NaN if PID information is not available.
1226This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
1227following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
1228 REGISTER_VARIABLE("pidIsMostLikely(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", isMostLikely, R"DOC(
1229Returns True if the largest PID likelihood of a given particle corresponds to its particle hypothesis.
1230This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
1231following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
1232
1233 REGISTER_METAVARIABLE("pidWeightedLogLikelihoodValueExpert(weightMatrixName, pdgCode, detectorList)",
1234 pidWeightedLogLikelihoodValueExpert,
1235 "returns the weighted log likelihood value of for a specific mass hypothesis and set of detectors, "
1236 ":math:`\\log\\mathcal{\\tilde{L}}_{hyp} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{hyp,j}\\log\\mathcal{L}_{hyp,j}`. "
1237 "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.",
1238 Manager::VariableDataType::c_double);
1239 REGISTER_METAVARIABLE("pidWeightedPairProbabilityExpert(weightMatrixName, pdgCodeHyp, pdgCodeTest, detectorList)",
1240 pidWeightedPairProbabilityExpert,
1241 "Weighted pair (or binary) probability for the pdgCodeHyp mass hypothesis with respect to the pdgCodeTest one, using an arbitrary set of detectors, "
1242 ":math:`\\mathcal{\\tilde{L}}_{hyp}/(\\mathcal{\\tilde{L}}_{test}+\\mathcal{\\tilde{L}}_{hyp})` where :math:`\\mathcal{\\tilde{L}}_{i}` is defined as "
1243 ":math:`\\log\\mathcal{\\tilde{L}}_{i} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{i,j}\\log\\mathcal{L}_{i,j}`. "
1244 "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.",
1245 Manager::VariableDataType::c_double);
1246 REGISTER_METAVARIABLE("pidWeightedProbabilityExpert(weightMatrixName, pdgCodeHyp, detectorList)",
1247 pidWeightedProbabilityExpert,
1248 "Weighted probability for the pdgCodeHyp mass hypothesis with respect to all the other ones, using an arbitrary set of detectors, "
1249 ":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 "
1250 ":math:`\\log\\mathcal{\\tilde{L}}_{i} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{i,j}\\log\\mathcal{L}_{i,j}`. "
1251 "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.",
1252 Manager::VariableDataType::c_double);
1253 REGISTER_METAVARIABLE("pidNeuralNetworkValueExpert(pdgCodeHyp, PIDNeuralNetworkName)",
1254 pidNeuralNetworkValueExpert,
1255 "Probability for the particle hypothesis pdgCodeHype calculated from a neural network, which uses high-level information as inputs, "
1256 "such as the likelihood from the 6 subdetectors for PID for all 6 hypotheses, "
1257 ":math:`\\mathcal{\\tilde{L}}_{hyp}^{det}`, or the track momentum and charge",
1258 Manager::VariableDataType::c_double);
1259
1260 // B2BII PID
1261 VARIABLE_GROUP("Belle PID variables");
1262 REGISTER_METAVARIABLE("atcPIDBelle(i,j)", atcPIDBelle, R"DOC(
1263[Legacy] Returns Belle's PID atc variable: ``atc_pid(3,1,5,i,j).prob()``.
1264Parameters i,j are signal and background hypothesis: (0 = electron, 1 = muon, 2 = pion, 3 = kaon, 4 = proton)
1265Returns 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).
1266
1267.. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1268 )DOC", Manager::VariableDataType::c_double);
1269 REGISTER_VARIABLE("muIDBelle", muIDBelle, R"DOC(
1270[Legacy] Returns Belle's PID ``Muon_likelihood()`` variable.
1271Returns 0.5 in case there is no likelihood found and returns zero if the muon likelihood is not usable (Belle behaviour).
1272
1273.. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1274 )DOC");
1275 REGISTER_VARIABLE("muIDBelleQuality", muIDBelleQuality, R"DOC(
1276[Legacy] Returns true if Belle's PID ``Muon_likelihood()`` is usable (reliable).
1277Returns zero/false if not usable or if there is no PID found.
1278 )DOC");
1279 REGISTER_VARIABLE("eIDBelle", eIDBelle, R"DOC(
1280[Legacy] Returns Belle's electron ID ``eid(3,-1,5).prob()`` variable.
1281Returns 0.5 in case there is no likelihood found (Belle behaviour).
1282
1283.. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1284 )DOC");
1285 }
1287}
static const unsigned int c_SetSize
Number of elements (for use in array bounds etc.)
Definition: Const.h:606
static DetectorSet set()
Accessor function for the set of valid detectors.
Definition: Const.h:365
int getPDGCode() const
PDG code.
Definition: Const.h:464
static DetectorSet set()
Accessor for the set of valid detector IDs.
Definition: Const.h:324
static const ParticleType neutron
neutron particle
Definition: Const.h:666
static const ChargedStable muon
muon particle
Definition: Const.h:651
RestrictedDetectorSet< PIDDetectors > PIDDetectorSet
Typedef for set of PID detectors.
Definition: Const.h:370
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:609
EDetector
Enum for identifying the detector components (detector and subdetector).
Definition: Const.h:42
static const ChargedStable pion
charged pion particle
Definition: Const.h:652
static const ChargedStable proton
proton particle
Definition: Const.h:654
static const double doubleNaN
quiet_NaN
Definition: Const.h:694
static const ChargedStable kaon
charged kaon particle
Definition: Const.h:653
static const ChargedStable electron
electron particle
Definition: Const.h:650
static const ChargedStable deuteron
deuteron particle
Definition: Const.h:655
static const ReferenceFrame & GetCurrent()
Get current rest frame.
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
Definition: Manager.h:113
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:57
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:25
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:24
STL namespace.