10 #include <analysis/variables/PIDVariables.h>
12 #include <analysis/dataobjects/Particle.h>
13 #include <analysis/utility/ReferenceFrame.h>
14 #include <mdst/dataobjects/PIDLikelihood.h>
15 #include <mdst/dataobjects/TrackFitResult.h>
18 #include <framework/logging/Logger.h>
19 #include <framework/utilities/Conversion.h>
20 #include <framework/gearbox/Const.h>
24 #include <analysis/dbobjects/PIDCalibrationWeight.h>
25 #include <analysis/utility/PIDCalibrationWeightUtil.h>
26 #include <analysis/utility/PIDNeuralNetwork.h>
28 #include <boost/algorithm/string.hpp>
50 Const::ChargedStable hypothesisConversion(
const int hypothesis)
54 return Const::electron;
69 Const::PIDDetectorSet parseDetectors(
const std::vector<std::string>& arguments)
71 Const::PIDDetectorSet result;
72 for (std::string val : arguments) {
74 if (val ==
"all")
return Const::PIDDetectors::set();
75 else if (val ==
"svd") result += Const::SVD;
76 else if (val ==
"cdc") result += Const::CDC;
77 else if (val ==
"top") result += Const::TOP;
78 else if (val ==
"arich") result += Const::ARICH;
79 else if (val ==
"ecl") result += Const::ECL;
80 else if (val ==
"klm") result += Const::KLM;
81 else B2ERROR(
"Unknown detector component: " << val);
87 Const::PIDDetectorSet parseDetectorsChargedBDT(
const std::vector<std::string>& arguments)
89 Const::PIDDetectorSet result;
90 for (std::string val : arguments) {
92 if (val ==
"all")
return Const::PIDDetectors::set();
93 else if (val ==
"ecl") result += Const::ECL;
94 else B2ERROR(
"Invalid detector component: " << val <<
" for charged BDT.");
105 double particleID(
const Particle* p)
107 int pdg = abs(p->getPDGCode());
108 if (pdg == Const::electron.getPDGCode())
return electronID(p);
109 else if (pdg == Const::muon.getPDGCode())
return muonID(p);
110 else if (pdg == Const::pion.getPDGCode())
return pionID(p);
111 else if (pdg == Const::kaon.getPDGCode())
return kaonID(p);
112 else if (pdg == Const::proton.getPDGCode())
return protonID(p);
113 else if (pdg == Const::deuteron.getPDGCode())
return deuteronID(p);
114 else return Const::doubleNaN;
117 Manager::FunctionPtr pidLogLikelihoodValueExpert(
const std::vector<std::string>& arguments)
119 if (arguments.size() < 2) {
120 B2ERROR(
"Need at least two arguments to pidLogLikelihoodValueExpert");
125 pdgCode = Belle2::convertString<int>(arguments[0]);
126 }
catch (std::invalid_argument& e) {
127 B2ERROR(
"First argument of pidLogLikelihoodValueExpert must be a PDG code");
130 std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
132 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
133 auto hypType = Const::ChargedStable(abs(pdgCode));
135 auto func = [hypType, detectorSet](
const Particle * part) ->
double {
136 const PIDLikelihood* pid = part->getPIDLikelihood();
138 return Const::doubleNaN;
140 if (pid->getLogL(hypType, detectorSet) == 0)
141 return Const::doubleNaN;
143 return pid->getLogL(hypType, detectorSet);
150 Manager::FunctionPtr pidDeltaLogLikelihoodValueExpert(
const std::vector<std::string>& arguments)
152 if (arguments.size() < 3) {
153 B2ERROR(
"Need at least three arguments to pidDeltaLogLikelihoodValueExpert");
156 int pdgCodeHyp, pdgCodeTest;
158 pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
159 }
catch (std::invalid_argument& e) {
160 B2ERROR(
"First argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
164 pdgCodeTest = Belle2::convertString<int>(arguments[1]);
165 }
catch (std::invalid_argument& e) {
166 B2ERROR(
"Second argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
170 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
171 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
172 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
173 auto testType = Const::ChargedStable(abs(pdgCodeTest));
175 auto func = [hypType, testType, detectorSet](
const Particle * part) ->
double {
176 const PIDLikelihood* pid = part->getPIDLikelihood();
177 if (!pid)
return Const::doubleNaN;
179 if (pid->getLogL(hypType, detectorSet) == 0)
180 return Const::doubleNaN;
182 return (pid->getLogL(hypType, detectorSet) - pid->getLogL(testType, detectorSet));
188 Manager::FunctionPtr pidPairProbabilityExpert(
const std::vector<std::string>& arguments)
190 if (arguments.size() < 3) {
191 B2ERROR(
"Need at least three arguments to pidPairProbabilityExpert");
194 int pdgCodeHyp = 0, pdgCodeTest = 0;
196 pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
197 }
catch (std::invalid_argument& e) {
198 B2ERROR(
"First argument of pidPairProbabilityExpert must be PDG code");
202 pdgCodeTest = Belle2::convertString<int>(arguments[1]);
203 }
catch (std::invalid_argument& e) {
204 B2ERROR(
"Second argument of pidPairProbabilityExpert must be PDG code");
208 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
210 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
211 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
212 auto testType = Const::ChargedStable(abs(pdgCodeTest));
213 auto func = [hypType, testType, detectorSet](
const Particle * part) ->
double {
214 const PIDLikelihood* pid = part->getPIDLikelihood();
215 if (!pid)
return Const::doubleNaN;
217 if (pid->getLogL(hypType, detectorSet) == 0)
218 return Const::doubleNaN;
220 return pid->getProbability(hypType, testType, detectorSet);
226 Manager::FunctionPtr pidProbabilityExpert(
const std::vector<std::string>& arguments)
228 if (arguments.size() < 2) {
229 B2ERROR(
"Need at least two arguments for pidProbabilityExpert");
234 pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
235 }
catch (std::invalid_argument& e) {
236 B2ERROR(
"First argument of pidProbabilityExpert must be PDG code");
240 std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
241 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
242 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
245 const unsigned int n = Const::ChargedStable::c_SetSize;
247 for (
double& i : frac) i = 1.0;
249 auto func = [hypType, frac, detectorSet](
const Particle * part) ->
double {
250 const PIDLikelihood* pid = part->getPIDLikelihood();
251 if (!pid)
return Const::doubleNaN;
253 if (pid->getLogL(hypType, detectorSet) == 0)
254 return Const::doubleNaN;
256 return pid->getProbability(hypType, frac, detectorSet);
262 Manager::FunctionPtr pidMissingProbabilityExpert(
const std::vector<std::string>& arguments)
264 if (arguments.size() < 1) {
265 B2ERROR(
"Need at least one argument to pidMissingProbabilityExpert");
269 std::vector<std::string> detectors(arguments.begin(), arguments.end());
270 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
272 auto func = [detectorSet](
const Particle * part) ->
double {
273 const PIDLikelihood* pid = part->getPIDLikelihood();
274 if (!pid)
return Const::doubleNaN;
275 if (not pid->isAvailable(detectorSet))
282 Manager::FunctionPtr pidWeightedLogLikelihoodValueExpert(
const std::vector<std::string>& arguments)
284 if (arguments.size() < 3) {
285 B2ERROR(
"Need at least three arguments to pidWeightedLogLikelihoodValueExpert");
288 std::string matrixName = arguments[0];
292 pdgCode = Belle2::convertString<int>(arguments[1]);
293 }
catch (std::invalid_argument& e) {
294 B2ERROR(
"Second argument of pidWeightedLogLikelihoodValueExpert must be a PDG code");
297 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
298 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
299 auto hypType = Const::ChargedStable(abs(pdgCode));
301 auto func = [hypType, detectorSet, matrixName](
const Particle * part) ->
double {
302 PIDCalibrationWeightUtil weightMatrix(matrixName);
303 const PIDLikelihood* pid = part->getPIDLikelihood();
305 return Const::doubleNaN;
307 if (pid->getLogL(hypType, detectorSet) == 0)
308 return Const::doubleNaN;
310 const auto& frame = ReferenceFrame::GetCurrent();
311 auto mom = frame.getMomentum(part);
313 auto theta = mom.Theta();
316 for (
const Const::EDetector& detector : Const::PIDDetectorSet::set())
318 if (detectorSet.contains(detector))
319 LogL += pid->getLogL(hypType, detector) * weightMatrix.getWeight(hypType.getPDGCode(), detector, p, theta);
327 Manager::FunctionPtr pidWeightedProbabilityExpert(
const std::vector<std::string>& arguments)
329 if (arguments.size() < 3) {
330 B2ERROR(
"Need at least three arguments for pidWeightedProbabilityExpert");
333 std::string matrixName = arguments[0];
337 pdgCodeHyp = Belle2::convertString<int>(arguments[1]);
338 }
catch (std::invalid_argument& e) {
339 B2ERROR(
"Second argument of pidWeightedProbabilityExpert must be PDG code");
343 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
344 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
345 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
347 auto func = [hypType, detectorSet, matrixName](
const Particle * part) ->
double {
348 PIDCalibrationWeightUtil weightMatrix(matrixName);
349 const PIDLikelihood* pid = part->getPIDLikelihood();
350 if (!pid)
return Const::doubleNaN;
352 if (pid->getLogL(hypType, detectorSet) == 0)
353 return Const::doubleNaN;
355 const auto& frame = ReferenceFrame::GetCurrent();
356 auto mom = frame.getMomentum(part);
358 auto theta = mom.Theta();
360 std::vector<double> LogL(Const::ChargedStable::c_SetSize);
363 for (
const auto& pdgIter : Const::chargedStableSet)
365 const int index_pdg = pdgIter.getIndex();
368 for (
const Const::EDetector& detector : Const::PIDDetectorSet::set()) {
369 if (detectorSet.contains(detector))
370 LogL[index_pdg] += pid->getLogL(pdgIter, detector) * weightMatrix.getWeight(pdgIter.getPDGCode(), detector, p, theta);
373 if (!hasMax || (LogL[index_pdg] > LogL_max)) {
374 LogL_max = LogL[index_pdg];
380 for (
auto LogL_i : LogL)
381 norm += exp(LogL_i - LogL_max);
384 return exp(LogL[hypType.getIndex()] - LogL_max) / norm;
392 Manager::FunctionPtr pidNeuralNetworkValueExpert(
const std::vector<std::string>& arguments)
394 if (arguments.size() == 0) {
395 B2ERROR(
"Need pdg code for pidNeuralNetworkValueExpert");
398 if (arguments.size() > 2) {
399 B2ERROR(
"pidNeuralNetworkValueExpert expects at most two arguments, i.e. the pdg code and the pidNeuralNetworkName");
404 pdgCode = abs(Belle2::convertString<int>(arguments[0]));
405 }
catch (std::invalid_argument& e) {
406 B2ERROR(
"First argument of pidNeuralNetworkValueExpert must be a PDG code");
410 std::shared_ptr<PIDNeuralNetwork> neuralNetworkPtr;
411 if (arguments.size() == 2) {
412 std::string parameterSetName = arguments[1];
413 neuralNetworkPtr = std::make_shared<PIDNeuralNetwork>(parameterSetName);
415 neuralNetworkPtr = std::make_shared<PIDNeuralNetwork>();
418 neuralNetworkPtr->hasPdgCode(pdgCode,
true);
434 std::vector<std::string> inputsAllNames;
435 for (
const Const::EDetector& detector : Const::PIDDetectorSet::set()) {
436 for (
const auto& hypeType : Const::chargedStableSet) {
437 inputsAllNames.push_back(
"pidLogLikelihood_Of_" + std::to_string(abs(hypeType.getPDGCode())) +
"_From_" + Const::parseDetectors(
441 inputsAllNames.push_back(
"momentum");
442 inputsAllNames.push_back(
"cosTheta");
443 inputsAllNames.push_back(
"phi");
444 inputsAllNames.push_back(
"charge");
445 const size_t inputsAllSize = inputsAllNames.size();
448 std::vector<size_t> mapInputsNN2InputsAll;
449 for (
const auto& inputName : neuralNetworkPtr->getInputNames()) {
450 const auto itr = std::find(inputsAllNames.begin(), inputsAllNames.end(), inputName);
451 if (itr == inputsAllNames.end()) {
452 B2ERROR(
"Neural network needs input '" + inputName +
"', but this input is not (yet) available!");
455 mapInputsNN2InputsAll.push_back(
static_cast<size_t>(itr - inputsAllNames.begin()));
458 std::map<int, std::string> extraInfoNames;
459 for (
const auto outputPdgCode : neuralNetworkPtr->getOutputSpeciesPdg()) {
460 extraInfoNames[outputPdgCode] =
"pidNeuralNetworkValueExpert(" + std::to_string(outputPdgCode) \
461 + ((arguments.size() == 2) ? (
"," + arguments[1]) :
"") +
")";
465 auto func = [neuralNetworkPtr, pdgCode, mapInputsNN2InputsAll, inputsAllSize, extraInfoNames](
const Particle * part) ->
double {
466 const std::string extraInfoName = extraInfoNames.at(pdgCode);
467 if (part->hasExtraInfo(extraInfoName))
468 return part->getExtraInfo(extraInfoName);
470 const auto& neuralNetwork = *neuralNetworkPtr;
471 const PIDLikelihood* pid = part->getPIDLikelihood();
473 return Const::doubleNaN;
475 auto hypType = Const::ChargedStable(pdgCode);
476 if (pid->getLogL(hypType) == 0)
477 return Const::doubleNaN;
486 std::vector<float> inputsAll;
487 inputsAll.reserve(inputsAllSize);
488 const auto mom = part->getTrackFitResult()->getMomentum();
489 for (
const Const::EDetector& detector : Const::PIDDetectorSet::set())
491 for (
const auto& hypType : Const::chargedStableSet) {
492 const float logL = pid->getLogL(hypType, detector);
493 if (logL == 0) inputsAll.push_back(Const::doubleNaN);
494 else inputsAll.push_back(logL);
497 inputsAll.push_back(mom.R());
498 inputsAll.push_back(cos(mom.Theta()));
499 inputsAll.push_back(mom.Phi());
500 inputsAll.push_back(part->getCharge());
503 std::vector<float> inputsNN;
504 inputsNN.reserve(neuralNetwork.getInputSize());
505 for (
const auto& indexAll : mapInputsNN2InputsAll)
507 inputsNN.push_back(inputsAll[indexAll]);
510 const auto probabilities = neuralNetwork.predict(inputsNN);
513 for (
const auto element : probabilities)
515 const auto [pdgCodeElement, probability] = element;
516 const_cast<Particle*
>(part)->addExtraInfo(extraInfoNames.at(pdgCodeElement), probability);
519 return probabilities.at(pdgCode);
526 Manager::FunctionPtr pidWeightedPairProbabilityExpert(
const std::vector<std::string>& arguments)
528 if (arguments.size() < 4) {
529 B2ERROR(
"Need at least four arguments to pidWeightedPairProbabilityExpert");
532 std::string matrixName = arguments[0];
534 int pdgCodeHyp = 0, pdgCodeTest = 0;
536 pdgCodeHyp = Belle2::convertString<int>(arguments[1]);
537 }
catch (std::invalid_argument& e) {
538 B2ERROR(
"Second argument of pidWeightedPairProbabilityExpert must be PDG code");
542 pdgCodeTest = Belle2::convertString<int>(arguments[2]);
543 }
catch (std::invalid_argument& e) {
544 B2ERROR(
"Third argument of pidWeightedPairProbabilityExpert must be PDG code");
548 std::vector<std::string> detectors(arguments.begin() + 3, arguments.end());
550 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
551 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
552 auto testType = Const::ChargedStable(abs(pdgCodeTest));
554 auto func = [hypType, testType, detectorSet, matrixName](
const Particle * part) ->
double {
555 PIDCalibrationWeightUtil weightMatrix(matrixName);
557 const PIDLikelihood* pid = part->getPIDLikelihood();
558 if (!pid)
return Const::doubleNaN;
560 if (pid->getLogL(hypType, detectorSet) == 0)
561 return Const::doubleNaN;
563 const auto& frame = ReferenceFrame::GetCurrent();
564 auto mom = frame.getMomentum(part);
566 auto theta = mom.Theta();
568 double LogL_hypType(0), LogL_testType(0);
569 for (
const Const::EDetector& detector : Const::PIDDetectorSet::set())
571 if (detectorSet.contains(detector)) {
572 LogL_hypType += pid->getLogL(hypType, detector) * weightMatrix.getWeight(hypType.getPDGCode(), detector, p, theta);
573 LogL_testType += pid->getLogL(testType, detector) * weightMatrix.getWeight(testType.getPDGCode(), detector, p, theta);
577 double deltaLogL = LogL_testType - LogL_hypType;
581 double eLogL = exp(deltaLogL);
582 res = 1. / (1. + eLogL);
585 double eLogL = exp(-deltaLogL);
586 res = eLogL / (1.0 + eLogL);
589 if (std::isfinite(res))
597 double electronID(
const Particle* part)
599 static Manager::FunctionPtr pidFunction =
600 pidProbabilityExpert({
"11",
"ALL"});
601 return std::get<double>(pidFunction(part));
604 double muonID(
const Particle* part)
606 static Manager::FunctionPtr pidFunction =
607 pidProbabilityExpert({
"13",
"ALL"});
608 return std::get<double>(pidFunction(part));
611 double pionID(
const Particle* part)
613 static Manager::FunctionPtr pidFunction =
614 pidProbabilityExpert({
"211",
"ALL"});
615 return std::get<double>(pidFunction(part));
618 double kaonID(
const Particle* part)
620 static Manager::FunctionPtr pidFunction =
621 pidProbabilityExpert({
"321",
"ALL"});
622 return std::get<double>(pidFunction(part));
625 double protonID(
const Particle* part)
627 static Manager::FunctionPtr pidFunction =
628 pidProbabilityExpert({
"2212",
"ALL"});
629 return std::get<double>(pidFunction(part));
632 double deuteronID(
const Particle* part)
634 static Manager::FunctionPtr pidFunction =
635 pidProbabilityExpert({
"1000010020",
"ALL"});
636 return std::get<double>(pidFunction(part));
639 double binaryPID(
const Particle* part,
const std::vector<double>& arguments)
641 if (arguments.size() != 2) {
642 B2ERROR(
"The variable binaryPID needs exactly two arguments: the PDG codes of two hypotheses.");
643 return Const::doubleNaN;;
645 int pdgCodeHyp = std::abs(
int(std::lround(arguments[0])));
646 int pdgCodeTest = std::abs(
int(std::lround(arguments[1])));
647 return std::get<double>(Manager::Instance().getVariable(
"pidPairProbabilityExpert(" + std::to_string(
648 pdgCodeHyp) +
", " + std::to_string(
649 pdgCodeTest) +
", ALL)")->
function(part));
652 double electronID_noSVD(
const Particle* part)
655 static Manager::FunctionPtr pidFunction =
656 pidProbabilityExpert({
"11",
"CDC",
"TOP",
"ARICH",
"ECL",
"KLM"});
657 return std::get<double>(pidFunction(part));
660 double muonID_noSVD(
const Particle* part)
663 static Manager::FunctionPtr pidFunction =
664 pidProbabilityExpert({
"13",
"CDC",
"TOP",
"ARICH",
"ECL",
"KLM"});
665 return std::get<double>(pidFunction(part));
668 double pionID_noSVD(
const Particle* part)
671 static Manager::FunctionPtr pidFunction =
672 pidProbabilityExpert({
"211",
"CDC",
"TOP",
"ARICH",
"ECL",
"KLM"});
673 return std::get<double>(pidFunction(part));
676 double kaonID_noSVD(
const Particle* part)
679 static Manager::FunctionPtr pidFunction =
680 pidProbabilityExpert({
"321",
"CDC",
"TOP",
"ARICH",
"ECL",
"KLM"});
681 return std::get<double>(pidFunction(part));
684 double protonID_noSVD(
const Particle* part)
687 static Manager::FunctionPtr pidFunction =
688 pidProbabilityExpert({
"2212",
"CDC",
"TOP",
"ARICH",
"ECL",
"KLM"});
689 return std::get<double>(pidFunction(part));
692 double deuteronID_noSVD(
const Particle* part)
695 static Manager::FunctionPtr pidFunction =
696 pidProbabilityExpert({
"1000010020",
"CDC",
"TOP",
"ARICH",
"ECL",
"KLM"});
697 return std::get<double>(pidFunction(part));
700 double binaryPID_noSVD(
const Particle* part,
const std::vector<double>& arguments)
703 if (arguments.size() != 2) {
704 B2ERROR(
"The variable binaryPID_noSVD needs exactly two arguments: the PDG codes of two hypotheses.");
705 return Const::doubleNaN;;
707 int pdgCodeHyp = std::abs(
int(std::lround(arguments[0])));
708 int pdgCodeTest = std::abs(
int(std::lround(arguments[1])));
709 return std::get<double>(Manager::Instance().getVariable(
"pidPairProbabilityExpert(" + std::to_string(
710 pdgCodeHyp) +
", " + std::to_string(
711 pdgCodeTest) +
", CDC, TOP, ARICH, ECL, KLM)")->
function(part));
714 double electronID_noTOP(
const Particle* part)
717 static Manager::FunctionPtr pidFunction =
718 pidProbabilityExpert({
"11",
"SVD",
"CDC",
"ARICH",
"ECL",
"KLM"});
719 return std::get<double>(pidFunction(part));
722 double binaryElectronID_noTOP(
const Particle* part,
const std::vector<double>& arguments)
725 if (arguments.size() != 1) {
726 B2ERROR(
"The variable binaryElectronID_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
727 return Const::doubleNaN;;
730 int pdgCodeHyp = Const::electron.getPDGCode();
731 int pdgCodeTest = std::abs(
int(std::lround(arguments[0])));
733 const auto var =
"pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) +
", " +
734 std::to_string(pdgCodeTest) +
", SVD, CDC, ARICH, ECL, KLM)";
736 return std::get<double>(Manager::Instance().getVariable(var)->
function(part));
739 double electronID_noSVD_noTOP(
const Particle* part)
742 static Manager::FunctionPtr pidFunction =
743 pidProbabilityExpert({
"11",
"CDC",
"ARICH",
"ECL",
"KLM"});
744 return std::get<double>(pidFunction(part));
747 double binaryElectronID_noSVD_noTOP(
const Particle* part,
const std::vector<double>& arguments)
750 if (arguments.size() != 1) {
751 B2ERROR(
"The variable binaryElectronID_noSVD_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
752 return Const::doubleNaN;;
755 int pdgCodeHyp = Const::electron.getPDGCode();
756 int pdgCodeTest = std::abs(
int(std::lround(arguments[0])));
758 const auto var =
"pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) +
", " +
759 std::to_string(pdgCodeTest) +
", CDC, ARICH, ECL, KLM)";
761 return std::get<double>(Manager::Instance().getVariable(var)->
function(part));
765 double pionID_noARICHwoECL(
const Particle* part)
768 const ECLCluster* cluster = part->getECLCluster();
770 const PIDLikelihood* pid = part->getPIDLikelihood();
771 if (!pid)
return Const::doubleNaN;
772 if (pid->getLogL(Const::kaon, Const::ARICH) > pid->getLogL(Const::pion, Const::ARICH)) {
773 static Manager::FunctionPtr pidFunction =
774 pidProbabilityExpert({
"211",
"SVD",
"CDC",
"TOP",
"ECL",
"KLM"});
775 return std::get<double>(pidFunction(part));
782 double kaonID_noARICHwoECL(
const Particle* part)
785 const ECLCluster* cluster = part->getECLCluster();
787 const PIDLikelihood* pid = part->getPIDLikelihood();
788 if (!pid)
return Const::doubleNaN;
789 if (pid->getLogL(Const::kaon, Const::ARICH) > pid->getLogL(Const::pion, Const::ARICH)) {
790 static Manager::FunctionPtr pidFunction =
791 pidProbabilityExpert({
"321",
"SVD",
"CDC",
"TOP",
"ECL",
"KLM"});
792 return std::get<double>(pidFunction(part));
799 double binaryPID_noARICHwoECL(
const Particle* part,
const std::vector<double>& arguments)
802 if (arguments.size() != 2) {
803 B2ERROR(
"The variable binaryPID_noARICHwoECL needs exactly two arguments: the PDG codes of two hypotheses.");
804 return Const::doubleNaN;;
806 int pdgCodeHyp = std::abs(
int(std::lround(arguments[0])));
807 int pdgCodeTest = std::abs(
int(std::lround(arguments[1])));
808 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
809 auto testType = Const::ChargedStable(abs(pdgCodeTest));
811 const ECLCluster* cluster = part->getECLCluster();
813 const PIDLikelihood* pid = part->getPIDLikelihood();
814 if (!pid)
return Const::doubleNaN;
815 double lkhdiff = pid->getLogL(hypType, Const::ARICH) - pid->getLogL(testType, Const::ARICH);
816 if ((lkhdiff > 0 && pdgCodeHyp > pdgCodeTest) || (lkhdiff < 0 && pdgCodeHyp < pdgCodeTest)) {
817 return std::get<double>(Manager::Instance().getVariable(
"pidPairProbabilityExpert(" + std::to_string(
818 pdgCodeHyp) +
", " + std::to_string(
819 pdgCodeTest) +
", SVD, CDC, TOP, ECL, KLM)")->
function(part));
823 return binaryPID(part, arguments);
829 double antineutronID(
const Particle* particle)
831 if (particle->hasExtraInfo(
"nbarID")) {
832 return particle->getExtraInfo(
"nbarID");
834 if (particle->getPDGCode() == -Const::neutron.getPDGCode()) {
835 B2WARNING(
"The extraInfo nbarID is not registered! \n"
836 "Please use function getNbarIDMVA in modularAnalysis.");
838 return Const::doubleNaN;
842 Manager::FunctionPtr pidChargedBDTScore(
const std::vector<std::string>& arguments)
844 if (arguments.size() != 2) {
845 B2ERROR(
"Need exactly two arguments for pidChargedBDTScore: pdgCodeHyp, detector");
851 hypPdgId = Belle2::convertString<int>(arguments.at(0));
852 }
catch (std::invalid_argument& e) {
853 B2ERROR(
"First argument of pidChargedBDTScore must be an integer (PDG code).");
856 Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
858 std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
859 Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
861 auto func = [hypType, detectorSet](
const Particle * part) ->
double {
862 auto name =
"pidChargedBDTScore_" + std::to_string(hypType.getPDGCode());
863 for (
const Const::EDetector& detector : detectorSet)
865 name +=
"_" + std::to_string(detector);
867 return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : Const::doubleNaN;
872 Manager::FunctionPtr pidPairChargedBDTScore(
const std::vector<std::string>& arguments)
874 if (arguments.size() != 3) {
875 B2ERROR(
"Need exactly three arguments for pidPairChargedBDTScore: pdgCodeHyp, pdgCodeTest, detector.");
879 int hypPdgId, testPdgId;
881 hypPdgId = Belle2::convertString<int>(arguments.at(0));
882 }
catch (std::invalid_argument& e) {
883 B2ERROR(
"First argument of pidPairChargedBDTScore must be an integer (PDG code).");
887 testPdgId = Belle2::convertString<int>(arguments.at(1));
888 }
catch (std::invalid_argument& e) {
889 B2ERROR(
"First argument of pidPairChargedBDTScore must be an integer (PDG code).");
892 Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
893 Const::ChargedStable testType = Const::ChargedStable(testPdgId);
895 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
896 Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
898 auto func = [hypType, testType, detectorSet](
const Particle * part) ->
double {
899 auto name =
"pidPairChargedBDTScore_" + std::to_string(hypType.getPDGCode()) +
"_VS_" + std::to_string(testType.getPDGCode());
900 for (
const Const::EDetector& detector : detectorSet)
902 name +=
"_" + std::to_string(detector);
904 return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : Const::doubleNaN;
909 double mostLikelyPDG(
const Particle* part,
const std::vector<double>& arguments)
911 if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
912 B2ERROR(
"Need zero or exactly " << Const::ChargedStable::c_SetSize <<
" arguments for pidMostLikelyPDG");
913 return Const::doubleNaN;
915 double prob[Const::ChargedStable::c_SetSize];
916 if (arguments.size() == 0) {
917 for (
unsigned int i = 0; i < Const::ChargedStable::c_SetSize; i++) prob[i] = 1. / Const::ChargedStable::c_SetSize;
919 copy(arguments.begin(), arguments.end(), prob);
922 auto* pid = part->getPIDLikelihood();
923 if (!pid)
return Const::doubleNaN;
924 return pid->getMostLikely(prob).getPDGCode();
927 bool isMostLikely(
const Particle* part,
const std::vector<double>& arguments)
929 if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
930 B2ERROR(
"Need zero or exactly " << Const::ChargedStable::c_SetSize <<
" arguments for pidIsMostLikely");
933 return mostLikelyPDG(part, arguments) == abs(part->getPDGCode());
936 Manager::FunctionPtr weightedElectronID(
const std::vector<std::string>& arguments)
939 if (arguments.size() == 0) {
940 varName =
"pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 11, ALL)";
941 }
else if (arguments.size() == 1) {
942 varName =
"pidWeightedProbabilityExpert(" + arguments[0] +
", 11, ALL)";
944 B2ERROR(
"Need zero or one argument for weightedElectronID");
948 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
949 auto func = [var](
const Particle * particle) ->
double {
950 return std::get<double>(var->function(particle));
955 Manager::FunctionPtr weightedMuonID(
const std::vector<std::string>& arguments)
958 if (arguments.size() == 0) {
959 varName =
"pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 13, ALL)";
960 }
else if (arguments.size() == 1) {
961 varName =
"pidWeightedProbabilityExpert(" + arguments[0] +
", 13, ALL)";
963 B2ERROR(
"Need zero or one argument for weightedMuonID");
967 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
968 auto func = [var](
const Particle * particle) ->
double {
969 return std::get<double>(var->function(particle));
974 Manager::FunctionPtr weightedPionID(
const std::vector<std::string>& arguments)
977 if (arguments.size() == 0) {
978 varName =
"pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 211, ALL)";
979 }
else if (arguments.size() == 1) {
980 varName =
"pidWeightedProbabilityExpert(" + arguments[0] +
", 211, ALL)";
982 B2ERROR(
"Need zero or one argument for weightedPionID");
986 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
987 auto func = [var](
const Particle * particle) ->
double {
988 return std::get<double>(var->function(particle));
993 Manager::FunctionPtr weightedKaonID(
const std::vector<std::string>& arguments)
996 if (arguments.size() == 0) {
997 varName =
"pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 321, ALL)";
998 }
else if (arguments.size() == 1) {
999 varName =
"pidWeightedProbabilityExpert(" + arguments[0] +
", 321, ALL)";
1001 B2ERROR(
"Need zero or one argument for weightedKaonID");
1005 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
1006 auto func = [var](
const Particle * particle) ->
double {
1007 return std::get<double>(var->function(particle));
1012 Manager::FunctionPtr weightedProtonID(
const std::vector<std::string>& arguments)
1014 std::string varName;
1015 if (arguments.size() == 0) {
1016 varName =
"pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 2212, ALL)";
1017 }
else if (arguments.size() == 1) {
1018 varName =
"pidWeightedProbabilityExpert(" + arguments[0] +
", 2212, ALL)";
1020 B2ERROR(
"Need zero or one argument for weightedProtonID");
1024 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
1025 auto func = [var](
const Particle * particle) ->
double {
1026 return std::get<double>(var->function(particle));
1031 Manager::FunctionPtr weightedDeuteronID(
const std::vector<std::string>& arguments)
1033 std::string varName;
1034 if (arguments.size() == 0) {
1035 varName =
"pidWeightedProbabilityExpert(PIDCalibrationWeightMatrix, 1000010020, ALL)";
1036 }
else if (arguments.size() == 1) {
1037 varName =
"pidWeightedProbabilityExpert(" + arguments[0] +
", 1000010020, ALL)";
1039 B2ERROR(
"Need zero or one argument for weightedDeuteronID");
1043 const Variable::Manager::Var* var = Manager::Instance().getVariable(varName);
1044 auto func = [var](
const Particle * particle) ->
double {
1045 return std::get<double>(var->function(particle));
1051 double pionIDNN(
const Particle* particle)
1053 if (particle->hasExtraInfo(
"pidNeuralNetworkValueExpert(211)"))
1054 return particle->getExtraInfo(
"pidNeuralNetworkValueExpert(211)");
1055 static auto func = pidNeuralNetworkValueExpert({
"211"});
1056 return std::get<double>(func(particle));
1059 double kaonIDNN(
const Particle* particle)
1061 if (particle->hasExtraInfo(
"pidNeuralNetworkValueExpert(321)"))
1062 return particle->getExtraInfo(
"pidNeuralNetworkValueExpert(321)");
1063 static auto func = pidNeuralNetworkValueExpert({
"321"});
1064 return std::get<double>(func(particle));
1072 double muIDBelle(
const Particle* particle)
1074 const PIDLikelihood* pid = particle->getPIDLikelihood();
1075 if (!pid)
return 0.5;
1077 if (pid->isAvailable(Const::KLM))
1078 return exp(pid->getLogL(Const::muon, Const::KLM));
1083 double muIDBelleQuality(
const Particle* particle)
1085 const PIDLikelihood* pid = particle->getPIDLikelihood();
1088 return pid->isAvailable(Const::KLM);
1091 double atcPIDBelle(
const Particle* particle,
const std::vector<double>& sigAndBkgHyp)
1093 int sigHyp = int(std::lround(sigAndBkgHyp[0]));
1094 int bkgHyp = int(std::lround(sigAndBkgHyp[1]));
1096 const PIDLikelihood* pid = particle->getPIDLikelihood();
1097 if (!pid)
return 0.5;
1100 Const::PIDDetectorSet set = Const::ARICH;
1101 double acc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
1102 double acc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
1104 if (acc_sig + acc_bkg > 0.0)
1105 acc = acc_sig / (acc_sig + acc_bkg);
1109 double tof_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
1110 double tof_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
1112 double tof_all = tof_sig + tof_bkg;
1114 tof = tof_sig / tof_all;
1115 if (tof < 0.001) tof = 0.001;
1116 if (tof > 0.999) tof = 0.999;
1121 double cdc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
1122 double cdc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
1124 double cdc_all = cdc_sig + cdc_bkg;
1126 cdc = cdc_sig / cdc_all;
1127 if (cdc < 0.001) cdc = 0.001;
1128 if (cdc > 0.999) cdc = 0.999;
1132 double pid_sig = acc * tof * cdc;
1133 double pid_bkg = (1. - acc) * (1. - tof) * (1. - cdc);
1135 return pid_sig / (pid_sig + pid_bkg);
1139 double eIDBelle(
const Particle* part)
1141 const PIDLikelihood* pid = part->getPIDLikelihood();
1142 if (!pid)
return 0.5;
1144 Const::PIDDetectorSet set = Const::ECL;
1145 return pid->getProbability(Const::electron, Const::pion, set);
1150 VARIABLE_GROUP(
"PID");
1151 REGISTER_VARIABLE(
"particleID", particleID,
1152 "the particle identification probability under the particle's own hypothesis, using info from all available detectors");
1153 REGISTER_VARIABLE(
"electronID", electronID,
1154 "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");
1155 REGISTER_VARIABLE(
"muonID", muonID,
1156 "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");
1157 REGISTER_VARIABLE(
"pionID", pionID,
1158 "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");
1159 REGISTER_VARIABLE(
"kaonID", kaonID,
1160 "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");
1161 REGISTER_VARIABLE(
"protonID", protonID,
1162 "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");
1163 REGISTER_VARIABLE(
"deuteronID", deuteronID,
1164 "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");
1165 REGISTER_METAVARIABLE(
"binaryPID(pdgCode1, pdgCode2)", binaryPID,
1166 "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components",
1167 Manager::VariableDataType::c_double);
1168 REGISTER_METAVARIABLE(
"pidChargedBDTScore(pdgCodeHyp, detector)", pidChargedBDTScore,
1169 "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.",
1170 Manager::VariableDataType::c_double);
1171 REGISTER_METAVARIABLE(
"pidPairChargedBDTScore(pdgCodeHyp, pdgCodeTest, detector)", pidPairChargedBDTScore,
1172 "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.",
1173 Manager::VariableDataType::c_double);
1174 REGISTER_VARIABLE(
"nbarID", antineutronID, R
"DOC(
1175 Returns MVA classifier for antineutron PID.
1177 - 1 signal(antineutron) like
1179 - -1 invalid using this PID due to some ECL variables used unavailable
1181 This PID is only for antineutron. Neutron is also considered as background.
1182 The variables used are `clusterPulseShapeDiscriminationMVA`, `clusterE`, `clusterLAT`, `clusterE1E9`, `clusterE9E21`,
1183 `clusterAbsZernikeMoment40`, `clusterAbsZernikeMoment51`, `clusterZernikeMVA`.)DOC");
1186 REGISTER_VARIABLE(
"electronID_noSVD", electronID_noSVD,
1187 "**(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*");
1188 REGISTER_VARIABLE(
"muonID_noSVD", muonID_noSVD,
1189 "**(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*");
1190 REGISTER_VARIABLE(
"pionID_noSVD", pionID_noSVD,
1191 "**(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*");
1192 REGISTER_VARIABLE(
"kaonID_noSVD", kaonID_noSVD,
1193 "**(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*");
1194 REGISTER_VARIABLE(
"protonID_noSVD", protonID_noSVD,
1195 "**(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*");
1196 REGISTER_VARIABLE(
"deuteronID_noSVD", deuteronID_noSVD,
1197 "**(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*");
1198 REGISTER_METAVARIABLE(
"binaryPID_noSVD(pdgCode1, pdgCode2)", binaryPID_noSVD,
1199 "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components, *excluding the SVD*.",
1200 Manager::VariableDataType::c_double);
1201 REGISTER_VARIABLE(
"electronID_noTOP", electronID_noTOP,
1202 "**(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*");
1203 REGISTER_METAVARIABLE(
"binaryElectronID_noTOP(pdgCodeTest)", binaryElectronID_noTOP,
1204 "**(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**",
1205 Manager::VariableDataType::c_double);
1206 REGISTER_VARIABLE(
"electronID_noSVD_noTOP", electronID_noSVD_noTOP,
1207 "**(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*");
1208 REGISTER_METAVARIABLE(
"binaryElectronID_noSVD_noTOP(pdgCodeTest)", binaryElectronID_noSVD_noTOP,
1209 "**(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**",
1210 Manager::VariableDataType::c_double);
1211 REGISTER_VARIABLE(
"pionID_noARICHwoECL", pionID_noARICHwoECL,
1212 "**(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");
1213 REGISTER_VARIABLE(
"kaonID_noARICHwoECL", kaonID_noARICHwoECL,
1214 "**(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");
1215 REGISTER_METAVARIABLE(
"binaryPID_noARICHwoECL(pdgCode1, pdgCode2)", binaryPID_noARICHwoECL,
1216 "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",
1217 Manager::VariableDataType::c_double);
1220 REGISTER_METAVARIABLE(
"weightedElectronID(weightMatrixName)", weightedElectronID,
1222 weighted electron identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_e}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1223 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}`.
1224 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.
1225 One can provide the name of the weight matrix as the argument.
1227 Manager::VariableDataType::c_double);
1228 REGISTER_METAVARIABLE("weightedMuonID(weightMatrixName)", weightedMuonID,
1230 weighted muon identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_\mu}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1231 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}`.
1232 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.
1233 One can provide the name of the weight matrix as the argument.
1235 Manager::VariableDataType::c_double);
1236 REGISTER_METAVARIABLE("weightedPionID(weightMatrixName)", weightedPionID,
1238 weighted pion identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_\pi}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1239 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}`.
1240 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.
1241 One can provide the name of the weight matrix as the argument.
1243 Manager::VariableDataType::c_double);
1244 REGISTER_METAVARIABLE("weightedKaonID(weightMatrixName)", weightedKaonID,
1246 weighted kaon identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_K}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1247 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}`.
1248 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.
1249 One can provide the name of the weight matrix as the argument.
1251 Manager::VariableDataType::c_double);
1252 REGISTER_METAVARIABLE("weightedProtonID(weightMatrixName)", weightedProtonID,
1254 weighted proton identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_p}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1255 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}`.
1256 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.
1257 One can provide the name of the weight matrix as the argument.
1259 Manager::VariableDataType::c_double);
1260 REGISTER_METAVARIABLE("weightedDeuteronID(weightMatrixName)", weightedDeuteronID,
1262 weighted deuteron identification probability defined as :math:`\frac{\mathcal{\tilde{L}}_d}{\sum_{i=e,\mu,\pi,K,p,d} \mathcal{\tilde{L}}_i}`,
1263 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}`.
1264 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.
1265 One can provide the name of the weight matrix as the argument.
1267 Manager::VariableDataType::c_double);
1270 REGISTER_VARIABLE("pionIDNN", pionIDNN,
1272 pion identification probability as calculated from the PID neural network.
1274 REGISTER_VARIABLE("kaonIDNN", kaonIDNN,
1276 kaon identification probability as calculated from the PID neural network.
1281 VARIABLE_GROUP(
"PID_expert");
1282 REGISTER_METAVARIABLE(
"pidLogLikelihoodValueExpert(pdgCode, detectorList)", pidLogLikelihoodValueExpert,
1283 "returns the log likelihood value of for a specific mass hypothesis and set of detectors.", Manager::VariableDataType::c_double);
1284 REGISTER_METAVARIABLE(
"pidDeltaLogLikelihoodValueExpert(pdgCode1, pdgCode2, detectorList)", pidDeltaLogLikelihoodValueExpert,
1285 "returns LogL(hyp1) - LogL(hyp2) (aka DLL) for two mass hypotheses and a set of detectors.", Manager::VariableDataType::c_double);
1286 REGISTER_METAVARIABLE(
"pidPairProbabilityExpert(pdgCodeHyp, pdgCodeTest, detectorList)", pidPairProbabilityExpert,
1287 "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})`",
1288 Manager::VariableDataType::c_double);
1289 REGISTER_METAVARIABLE(
"pidProbabilityExpert(pdgCodeHyp, detectorList)", pidProbabilityExpert,
1290 "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})`. ",
1291 Manager::VariableDataType::c_double);
1292 REGISTER_METAVARIABLE(
"pidMissingProbabilityExpert(detectorList)", pidMissingProbabilityExpert,
1293 "returns 1 if the PID probabiliy is missing for the provided detector list, otherwise 0. ", Manager::VariableDataType::c_double);
1294 REGISTER_VARIABLE(
"pidMostLikelyPDG(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", mostLikelyPDG,
1296 Returns PDG code of the largest PID likelihood, or NaN if PID information is not available.
1297 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
1298 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
1299 REGISTER_VARIABLE("pidIsMostLikely(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", isMostLikely, R
"DOC(
1300 Returns True if the largest PID likelihood of a given particle corresponds to its particle hypothesis.
1301 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
1302 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
1304 REGISTER_METAVARIABLE("pidWeightedLogLikelihoodValueExpert(weightMatrixName, pdgCode, detectorList)",
1305 pidWeightedLogLikelihoodValueExpert,
1306 "returns the weighted log likelihood value of for a specific mass hypothesis and set of detectors, "
1307 ":math:`\\log\\mathcal{\\tilde{L}}_{hyp} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{hyp,j}\\log\\mathcal{L}_{hyp,j}`. "
1308 "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.",
1309 Manager::VariableDataType::c_double);
1310 REGISTER_METAVARIABLE(
"pidWeightedPairProbabilityExpert(weightMatrixName, pdgCodeHyp, pdgCodeTest, detectorList)",
1311 pidWeightedPairProbabilityExpert,
1312 "Weighted pair (or binary) probability for the pdgCodeHyp mass hypothesis with respect to the pdgCodeTest one, using an arbitrary set of detectors, "
1313 ":math:`\\mathcal{\\tilde{L}}_{hyp}/(\\mathcal{\\tilde{L}}_{test}+\\mathcal{\\tilde{L}}_{hyp})` where :math:`\\mathcal{\\tilde{L}}_{i}` is defined as "
1314 ":math:`\\log\\mathcal{\\tilde{L}}_{i} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{i,j}\\log\\mathcal{L}_{i,j}`. "
1315 "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.",
1316 Manager::VariableDataType::c_double);
1317 REGISTER_METAVARIABLE(
"pidWeightedProbabilityExpert(weightMatrixName, pdgCodeHyp, detectorList)",
1318 pidWeightedProbabilityExpert,
1319 "Weighted probability for the pdgCodeHyp mass hypothesis with respect to all the other ones, using an arbitrary set of detectors, "
1320 ":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 "
1321 ":math:`\\log\\mathcal{\\tilde{L}}_{i} = \\sum_{j\\in\\mathrm{detectorList}} \\mathcal{w}_{i,j}\\log\\mathcal{L}_{i,j}`. "
1322 "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.",
1323 Manager::VariableDataType::c_double);
1324 REGISTER_METAVARIABLE(
"pidNeuralNetworkValueExpert(pdgCodeHyp, PIDNeuralNetworkName)",
1325 pidNeuralNetworkValueExpert,
1326 "Probability for the particle hypothesis pdgCodeHype calculated from a neural network, which uses high-level information as inputs, "
1327 "such as the likelihood from the 6 subdetectors for PID for all 6 hypotheses, "
1328 ":math:`\\mathcal{\\tilde{L}}_{hyp}^{det}`, or the track momentum and charge",
1329 Manager::VariableDataType::c_double);
1332 VARIABLE_GROUP(
"Belle PID variables");
1333 REGISTER_METAVARIABLE(
"atcPIDBelle(i,j)", atcPIDBelle, R
"DOC(
1334 [Legacy] Returns Belle's PID atc variable: ``atc_pid(3,1,5,i,j).prob()``.
1335 Parameters i,j are signal and background hypothesis: (0 = electron, 1 = muon, 2 = pion, 3 = kaon, 4 = proton)
1336 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).
1338 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1339 )DOC", Manager::VariableDataType::c_double);
1340 REGISTER_VARIABLE("muIDBelle", muIDBelle, R
"DOC(
1341 [Legacy] Returns Belle's PID ``Muon_likelihood()`` variable.
1342 Returns 0.5 in case there is no likelihood found and returns zero if the muon likelihood is not usable (Belle behaviour).
1344 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
1346 REGISTER_VARIABLE("muIDBelleQuality", muIDBelleQuality, R
"DOC(
1347 [Legacy] Returns true if Belle's PID ``Muon_likelihood()`` is usable (reliable).
1348 Returns zero/false if not usable or if there is no PID found.
1350 REGISTER_VARIABLE("eIDBelle", eIDBelle, R
"DOC(
1351 [Legacy] Returns Belle's electron ID ``eid(3,-1,5).prob()`` variable.
1352 Returns 0.5 in case there is no likelihood found (Belle behaviour).
1354 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
Abstract base class for different kinds of events.