10 #include <analysis/variables/PIDVariables.h>
12 #include <analysis/dataobjects/Particle.h>
13 #include <mdst/dataobjects/PIDLikelihood.h>
16 #include <framework/logging/Logger.h>
17 #include <framework/utilities/Conversion.h>
18 #include <framework/gearbox/Const.h>
20 #include <boost/algorithm/string.hpp>
42 Const::ChargedStable hypothesisConversion(
const int hypothesis)
46 return Const::electron;
61 Const::PIDDetectorSet parseDetectors(
const std::vector<std::string>& arguments)
63 Const::PIDDetectorSet result;
64 for (std::string val : arguments) {
66 if (val ==
"all")
return Const::PIDDetectors::set();
67 else if (val ==
"svd") result += Const::SVD;
68 else if (val ==
"cdc") result += Const::CDC;
69 else if (val ==
"top") result += Const::TOP;
70 else if (val ==
"arich") result += Const::ARICH;
71 else if (val ==
"ecl") result += Const::ECL;
72 else if (val ==
"klm") result += Const::KLM;
73 else B2ERROR(
"Unknown detector component: " << val);
79 Const::PIDDetectorSet parseDetectorsChargedBDT(
const std::vector<std::string>& arguments)
81 Const::PIDDetectorSet result;
82 for (std::string val : arguments) {
84 if (val ==
"all")
return Const::PIDDetectors::set();
85 else if (val ==
"ecl") result += Const::ECL;
86 else B2ERROR(
"Invalid detector component: " << val <<
" for charged BDT.");
97 double particleID(
const Particle* p)
99 int pdg = abs(p->getPDGCode());
100 if (pdg == Const::electron.getPDGCode())
return electronID(p);
101 else if (pdg == Const::muon.getPDGCode())
return muonID(p);
102 else if (pdg == Const::pion.getPDGCode())
return pionID(p);
103 else if (pdg == Const::kaon.getPDGCode())
return kaonID(p);
104 else if (pdg == Const::proton.getPDGCode())
return protonID(p);
105 else if (pdg == Const::deuteron.getPDGCode())
return deuteronID(p);
106 else return std::numeric_limits<float>::quiet_NaN();
109 Manager::FunctionPtr pidLogLikelihoodValueExpert(
const std::vector<std::string>& arguments)
111 if (arguments.size() < 2) {
112 B2ERROR(
"Need at least two arguments to pidLogLikelihoodValueExpert");
117 pdgCode = Belle2::convertString<int>(arguments[0]);
118 }
catch (std::invalid_argument& e) {
119 B2ERROR(
"First argument of pidLogLikelihoodValueExpert must be a PDG code");
122 std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
124 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
125 auto hypType = Const::ChargedStable(abs(pdgCode));
127 auto func = [hypType, detectorSet](
const Particle * part) ->
double {
128 const PIDLikelihood* pid = part->getPIDLikelihood();
130 return std::numeric_limits<float>::quiet_NaN();
132 if (pid->getLogL(hypType, detectorSet) == 0)
133 return std::numeric_limits<float>::quiet_NaN();
135 return pid->getLogL(hypType, detectorSet);
142 Manager::FunctionPtr pidDeltaLogLikelihoodValueExpert(
const std::vector<std::string>& arguments)
144 if (arguments.size() < 3) {
145 B2ERROR(
"Need at least three arguments to pidDeltaLogLikelihoodValueExpert");
148 int pdgCodeHyp, pdgCodeTest;
150 pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
151 }
catch (std::invalid_argument& e) {
152 B2ERROR(
"First argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
156 pdgCodeTest = Belle2::convertString<int>(arguments[1]);
157 }
catch (std::invalid_argument& e) {
158 B2ERROR(
"Second argument of pidDeltaLogLikelihoodValueExpert must be a PDG code");
162 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
163 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
164 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
165 auto testType = Const::ChargedStable(abs(pdgCodeTest));
167 auto func = [hypType, testType, detectorSet](
const Particle * part) ->
double {
168 const PIDLikelihood* pid = part->getPIDLikelihood();
169 if (!pid)
return std::numeric_limits<float>::quiet_NaN();
171 if (pid->getLogL(hypType, detectorSet) == 0)
172 return std::numeric_limits<float>::quiet_NaN();
174 return (pid->getLogL(hypType, detectorSet) - pid->getLogL(testType, detectorSet));
180 Manager::FunctionPtr pidPairProbabilityExpert(
const std::vector<std::string>& arguments)
182 if (arguments.size() < 3) {
183 B2ERROR(
"Need at least three arguments to pidPairProbabilityExpert");
186 int pdgCodeHyp = 0, pdgCodeTest = 0;
188 pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
189 }
catch (std::invalid_argument& e) {
190 B2ERROR(
"First argument of pidPairProbabilityExpert must be PDG code");
194 pdgCodeTest = Belle2::convertString<int>(arguments[1]);
195 }
catch (std::invalid_argument& e) {
196 B2ERROR(
"Second argument of pidPairProbabilityExpert must be PDG code");
200 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
202 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
203 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
204 auto testType = Const::ChargedStable(abs(pdgCodeTest));
205 auto func = [hypType, testType, detectorSet](
const Particle * part) ->
double {
206 const PIDLikelihood* pid = part->getPIDLikelihood();
207 if (!pid)
return std::numeric_limits<float>::quiet_NaN();
209 if (pid->getLogL(hypType, detectorSet) == 0)
210 return std::numeric_limits<float>::quiet_NaN();
212 return pid->getProbability(hypType, testType, detectorSet);
218 Manager::FunctionPtr pidProbabilityExpert(
const std::vector<std::string>& arguments)
220 if (arguments.size() < 2) {
221 B2ERROR(
"Need at least two arguments for pidProbabilityExpert");
226 pdgCodeHyp = Belle2::convertString<int>(arguments[0]);
227 }
catch (std::invalid_argument& e) {
228 B2ERROR(
"First argument of pidProbabilityExpert must be PDG code");
232 std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
233 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
234 auto hypType = Const::ChargedStable(abs(pdgCodeHyp));
237 const unsigned int n = Const::ChargedStable::c_SetSize;
239 for (
double& i : frac) i = 1.0;
241 auto func = [hypType, frac, detectorSet](
const Particle * part) ->
double {
242 const PIDLikelihood* pid = part->getPIDLikelihood();
243 if (!pid)
return std::numeric_limits<float>::quiet_NaN();
245 if (pid->getLogL(hypType, detectorSet) == 0)
246 return std::numeric_limits<float>::quiet_NaN();
248 return pid->getProbability(hypType, frac, detectorSet);
254 Manager::FunctionPtr pidMissingProbabilityExpert(
const std::vector<std::string>& arguments)
256 if (arguments.size() < 1) {
257 B2ERROR(
"Need at least one argument to pidMissingProbabilityExpert");
261 std::vector<std::string> detectors(arguments.begin(), arguments.end());
262 Const::PIDDetectorSet detectorSet = parseDetectors(detectors);
264 auto func = [detectorSet](
const Particle * part) ->
double {
265 const PIDLikelihood* pid = part->getPIDLikelihood();
266 if (!pid)
return std::numeric_limits<double>::quiet_NaN();
267 if (not pid->isAvailable(detectorSet))
274 double electronID(
const Particle* part)
276 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(11, ALL)")->
function(part));
279 double muonID(
const Particle* part)
281 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(13, ALL)")->
function(part));
284 double pionID(
const Particle* part)
286 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(211, ALL)")->
function(part));
289 double kaonID(
const Particle* part)
291 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(321, ALL)")->
function(part));
294 double protonID(
const Particle* part)
296 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(2212, ALL)")->
function(part));
299 double deuteronID(
const Particle* part)
301 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(1000010020, ALL)")->
function(part));
304 double binaryPID(
const Particle* part,
const std::vector<double>& arguments)
306 if (arguments.size() != 2) {
307 B2ERROR(
"The variable binaryPID needs exactly two arguments: the PDG codes of two hypotheses.");
308 return std::numeric_limits<float>::quiet_NaN();;
310 int pdgCodeHyp = std::abs(
int(std::lround(arguments[0])));
311 int pdgCodeTest = std::abs(
int(std::lround(arguments[1])));
312 return std::get<double>(Manager::Instance().getVariable(
"pidPairProbabilityExpert(" + std::to_string(
313 pdgCodeHyp) +
", " + std::to_string(
314 pdgCodeTest) +
", ALL)")->
function(part));
317 double electronID_noSVD(
const Particle* part)
320 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(11, CDC, TOP, ARICH, ECL, KLM)")->
function(part));
323 double muonID_noSVD(
const Particle* part)
326 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(13, CDC, TOP, ARICH, ECL, KLM)")->
function(part));
329 double pionID_noSVD(
const Particle* part)
332 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(211, CDC, TOP, ARICH, ECL, KLM)")->
function(part));
335 double kaonID_noSVD(
const Particle* part)
338 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(321, CDC, TOP, ARICH, ECL, KLM)")->
function(part));
341 double protonID_noSVD(
const Particle* part)
344 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(2212, CDC, TOP, ARICH, ECL, KLM)")->
function(part));
347 double deuteronID_noSVD(
const Particle* part)
350 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(1000010020, CDC, TOP, ARICH, ECL, KLM)")->
function(
354 double binaryPID_noSVD(
const Particle* part,
const std::vector<double>& arguments)
357 if (arguments.size() != 2) {
358 B2ERROR(
"The variable binaryPID_noSVD needs exactly two arguments: the PDG codes of two hypotheses.");
359 return std::numeric_limits<float>::quiet_NaN();;
361 int pdgCodeHyp = std::abs(
int(std::lround(arguments[0])));
362 int pdgCodeTest = std::abs(
int(std::lround(arguments[1])));
363 return std::get<double>(Manager::Instance().getVariable(
"pidPairProbabilityExpert(" + std::to_string(
364 pdgCodeHyp) +
", " + std::to_string(
365 pdgCodeTest) +
", CDC, TOP, ARICH, ECL, KLM)")->
function(part));
368 double electronID_noTOP(
const Particle* part)
371 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(11, SVD, CDC, ARICH, ECL, KLM)")->
function(part));
374 double binaryElectronID_noTOP(
const Particle* part,
const std::vector<double>& arguments)
377 if (arguments.size() != 1) {
378 B2ERROR(
"The variable binaryElectronID_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
379 return std::numeric_limits<float>::quiet_NaN();;
382 int pdgCodeHyp = Const::electron.getPDGCode();
383 int pdgCodeTest = std::abs(
int(std::lround(arguments[0])));
385 const auto var =
"pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) +
", " +
386 std::to_string(pdgCodeTest) +
", SVD, CDC, ARICH, ECL, KLM)";
388 return std::get<double>(Manager::Instance().getVariable(var)->
function(part));
391 double electronID_noSVD_noTOP(
const Particle* part)
394 return std::get<double>(Manager::Instance().getVariable(
"pidProbabilityExpert(11, CDC, ARICH, ECL, KLM)")->
function(part));
397 double binaryElectronID_noSVD_noTOP(
const Particle* part,
const std::vector<double>& arguments)
400 if (arguments.size() != 1) {
401 B2ERROR(
"The variable binaryElectronID_noSVD_noTOP needs exactly one argument: the PDG code of the test hypothesis.");
402 return std::numeric_limits<float>::quiet_NaN();;
405 int pdgCodeHyp = Const::electron.getPDGCode();
406 int pdgCodeTest = std::abs(
int(std::lround(arguments[0])));
408 const auto var =
"pidPairProbabilityExpert(" + std::to_string(pdgCodeHyp) +
", " +
409 std::to_string(pdgCodeTest) +
", CDC, ARICH, ECL, KLM)";
411 return std::get<double>(Manager::Instance().getVariable(var)->
function(part));
414 double antineutronID(
const Particle* particle)
416 if (particle->hasExtraInfo(
"nbarID")) {
417 return particle->getExtraInfo(
"nbarID");
419 if (particle->getPDGCode() == -Const::neutron.getPDGCode()) {
420 B2WARNING(
"The extraInfo nbarID is not registered! \n"
421 "Please use function getNbarIDMVA in modularAnalysis.");
423 return std::numeric_limits<float>::quiet_NaN();
427 Manager::FunctionPtr pidChargedBDTScore(
const std::vector<std::string>& arguments)
429 if (arguments.size() != 2) {
430 B2ERROR(
"Need exactly two arguments for pidChargedBDTScore: pdgCodeHyp, detector");
436 hypPdgId = Belle2::convertString<int>(arguments.at(0));
437 }
catch (std::invalid_argument& e) {
438 B2ERROR(
"First argument of pidChargedBDTScore must be an integer (PDG code).");
441 Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
443 std::vector<std::string> detectors(arguments.begin() + 1, arguments.end());
444 Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
446 auto func = [hypType, detectorSet](
const Particle * part) ->
double {
447 auto name =
"pidChargedBDTScore_" + std::to_string(hypType.getPDGCode());
448 for (
size_t iDet(0); iDet < detectorSet.size(); ++iDet)
450 auto det = detectorSet[iDet];
451 name +=
"_" + std::to_string(det);
453 return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : std::numeric_limits<float>::quiet_NaN();
458 Manager::FunctionPtr pidPairChargedBDTScore(
const std::vector<std::string>& arguments)
460 if (arguments.size() != 3) {
461 B2ERROR(
"Need exactly three arguments for pidPairChargedBDTScore: pdgCodeHyp, pdgCodeTest, detector.");
465 int hypPdgId, testPdgId;
467 hypPdgId = Belle2::convertString<int>(arguments.at(0));
468 }
catch (std::invalid_argument& e) {
469 B2ERROR(
"First argument of pidPairChargedBDTScore must be an integer (PDG code).");
473 testPdgId = Belle2::convertString<int>(arguments.at(1));
474 }
catch (std::invalid_argument& e) {
475 B2ERROR(
"First argument of pidPairChargedBDTScore must be an integer (PDG code).");
478 Const::ChargedStable hypType = Const::ChargedStable(hypPdgId);
479 Const::ChargedStable testType = Const::ChargedStable(testPdgId);
481 std::vector<std::string> detectors(arguments.begin() + 2, arguments.end());
482 Const::PIDDetectorSet detectorSet = parseDetectorsChargedBDT(detectors);
484 auto func = [hypType, testType, detectorSet](
const Particle * part) ->
double {
485 auto name =
"pidPairChargedBDTScore_" + std::to_string(hypType.getPDGCode()) +
"_VS_" + std::to_string(testType.getPDGCode());
486 for (
size_t iDet(0); iDet < detectorSet.size(); ++iDet)
488 auto det = detectorSet[iDet];
489 name +=
"_" + std::to_string(det);
491 return (part->hasExtraInfo(name)) ? part->getExtraInfo(name) : std::numeric_limits<float>::quiet_NaN();
496 double mostLikelyPDG(
const Particle* part,
const std::vector<double>& arguments)
498 if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
499 B2ERROR(
"Need zero or exactly " << Const::ChargedStable::c_SetSize <<
" arguments for pidMostLikelyPDG");
500 return std::numeric_limits<double>::quiet_NaN();
502 double prob[Const::ChargedStable::c_SetSize];
503 if (arguments.size() == 0) {
504 for (
unsigned int i = 0; i < Const::ChargedStable::c_SetSize; i++) prob[i] = 1. / Const::ChargedStable::c_SetSize;
506 copy(arguments.begin(), arguments.end(), prob);
509 auto* pid = part->getPIDLikelihood();
510 if (!pid)
return std::numeric_limits<double>::quiet_NaN();
511 return pid->getMostLikely(prob).getPDGCode();
514 bool isMostLikely(
const Particle* part,
const std::vector<double>& arguments)
516 if (arguments.size() != 0 and arguments.size() != Const::ChargedStable::c_SetSize) {
517 B2ERROR(
"Need zero or exactly " << Const::ChargedStable::c_SetSize <<
" arguments for pidIsMostLikely");
520 return mostLikelyPDG(part, arguments) == abs(part->getPDGCode());
527 double muIDBelle(
const Particle* particle)
529 const PIDLikelihood* pid = particle->getPIDLikelihood();
530 if (!pid)
return 0.5;
532 if (pid->isAvailable(Const::KLM))
533 return exp(pid->getLogL(Const::muon, Const::KLM));
538 double muIDBelleQuality(
const Particle* particle)
540 const PIDLikelihood* pid = particle->getPIDLikelihood();
543 return pid->isAvailable(Const::KLM);
546 double atcPIDBelle(
const Particle* particle,
const std::vector<double>& sigAndBkgHyp)
548 int sigHyp = int(std::lround(sigAndBkgHyp[0]));
549 int bkgHyp = int(std::lround(sigAndBkgHyp[1]));
551 const PIDLikelihood* pid = particle->getPIDLikelihood();
552 if (!pid)
return 0.5;
555 Const::PIDDetectorSet set = Const::ARICH;
556 double acc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
557 double acc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
559 if (acc_sig + acc_bkg > 0.0)
560 acc = acc_sig / (acc_sig + acc_bkg);
564 double tof_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
565 double tof_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
567 double tof_all = tof_sig + tof_bkg;
569 tof = tof_sig / tof_all;
570 if (tof < 0.001) tof = 0.001;
571 if (tof > 0.999) tof = 0.999;
576 double cdc_sig = exp(pid->getLogL(hypothesisConversion(sigHyp), set));
577 double cdc_bkg = exp(pid->getLogL(hypothesisConversion(bkgHyp), set));
579 double cdc_all = cdc_sig + cdc_bkg;
581 cdc = cdc_sig / cdc_all;
582 if (cdc < 0.001) cdc = 0.001;
583 if (cdc > 0.999) cdc = 0.999;
587 double pid_sig = acc * tof * cdc;
588 double pid_bkg = (1. - acc) * (1. - tof) * (1. - cdc);
590 return pid_sig / (pid_sig + pid_bkg);
594 double eIDBelle(
const Particle* part)
596 const PIDLikelihood* pid = part->getPIDLikelihood();
597 if (!pid)
return 0.5;
599 Const::PIDDetectorSet set = Const::ECL;
600 return pid->getProbability(Const::electron, Const::pion, set);
605 VARIABLE_GROUP(
"PID");
606 REGISTER_VARIABLE(
"particleID", particleID,
607 "the particle identification probability under the particle's own hypothesis, using info from all available detectors");
608 REGISTER_VARIABLE(
"electronID", electronID,
609 "electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
610 REGISTER_VARIABLE(
"muonID", muonID,
611 "muon identification probability defined as :math:`\\mathcal{L}_\\mu/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
612 REGISTER_VARIABLE(
"pionID", pionID,
613 "pion identification probability defined as :math:`\\mathcal{L}_\\pi/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
614 REGISTER_VARIABLE(
"kaonID", kaonID,
615 "kaon identification probability defined as :math:`\\mathcal{L}_K/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
616 REGISTER_VARIABLE(
"protonID", protonID,
617 "proton identification probability defined as :math:`\\mathcal{L}_p/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
618 REGISTER_VARIABLE(
"deuteronID", deuteronID,
619 "deuteron identification probability defined as :math:`\\mathcal{L}_d/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors");
620 REGISTER_METAVARIABLE(
"binaryPID(pdgCode1, pdgCode2)", binaryPID,
621 "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components",
622 Manager::VariableDataType::c_double);
623 REGISTER_METAVARIABLE(
"pidChargedBDTScore(pdgCodeHyp, detector)", pidChargedBDTScore,
624 "Returns the charged Pid BDT score for a certain mass hypothesis with respect to all other charged stable particle hypotheses. The second argument specifies which BDT training to use: based on 'ALL' PID detectors (NB: 'SVD' is currently excluded), or 'ECL' only. The choice depends on the ChargedPidMVAMulticlassModule's configuration.",
625 Manager::VariableDataType::c_double);
626 REGISTER_METAVARIABLE(
"pidPairChargedBDTScore(pdgCodeHyp, pdgCodeTest, detector)", pidPairChargedBDTScore,
627 "Returns the charged Pid BDT score for a certain mass hypothesis with respect to an alternative hypothesis. The second argument specifies which BDT training to use: based on 'ALL' PID detectors (NB: 'SVD' is currently excluded), or 'ECL' only. The choice depends on the ChargedPidMVAModule's configuration.",
628 Manager::VariableDataType::c_double);
629 REGISTER_VARIABLE(
"nbarID", antineutronID, R
"DOC(
630 Returns MVA classifier for antineutron PID.
632 - 1 signal(antineutron) like
634 - -1 invalid using this PID due to some ECL variables used unavailable
636 This PID is only for antineutron. Neutron is also considered as background.
637 The variables used are `clusterPulseShapeDiscriminationMVA`, `clusterE`, `clusterLAT`, `clusterE1E9`, `clusterE9E21`,
638 `clusterAbsZernikeMoment40`, `clusterAbsZernikeMoment51`, `clusterZernikeMVA`.)DOC");
641 REGISTER_VARIABLE(
"electronID_noSVD", electronID_noSVD,
642 "**(SPECIAL (TEMP) variable)** electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
643 REGISTER_VARIABLE(
"muonID_noSVD", muonID_noSVD,
644 "**(SPECIAL (TEMP) variable)** muon identification probability defined as :math:`\\mathcal{L}_\\mu/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
645 REGISTER_VARIABLE(
"pionID_noSVD", pionID_noSVD,
646 "**(SPECIAL (TEMP) variable)** pion identification probability defined as :math:`\\mathcal{L}_\\pi/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
647 REGISTER_VARIABLE(
"kaonID_noSVD", kaonID_noSVD,
648 "**(SPECIAL (TEMP) variable)** kaon identification probability defined as :math:`\\mathcal{L}_K/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
649 REGISTER_VARIABLE(
"protonID_noSVD", protonID_noSVD,
650 "**(SPECIAL (TEMP) variable)** proton identification probability defined as :math:`\\mathcal{L}_p/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
651 REGISTER_VARIABLE(
"deuteronID_noSVD", deuteronID_noSVD,
652 "**(SPECIAL (TEMP) variable)** deuteron identification probability defined as :math:`\\mathcal{L}_d/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD*");
653 REGISTER_METAVARIABLE(
"binaryPID_noSVD(pdgCode1, pdgCode2)", binaryPID_noSVD,
654 "Returns the binary probability for the first provided mass hypothesis with respect to the second mass hypothesis using all detector components, *excluding the SVD*.",
655 Manager::VariableDataType::c_double);
656 REGISTER_VARIABLE(
"electronID_noTOP", electronID_noTOP,
657 "**(SPECIAL (TEMP) variable)** electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the TOP*. *NB:* this variable must be used in place of `electronID` when analysing data (MC) processed (simulated) in *release 6*");
658 REGISTER_METAVARIABLE(
"binaryElectronID_noTOP(pdgCodeTest)", binaryElectronID_noTOP,
659 "**(SPECIAL (TEMP) variable)** Returns the binary probability for the electron mass hypothesis with respect to another mass hypothesis using all detector components, *excluding the TOP*. *NB:* this variable must be used in place of `binaryPID` (``pdgCode1=11``) when analysing data (MC) processed (simulated) in **release 6**",
660 Manager::VariableDataType::c_double);
661 REGISTER_VARIABLE(
"electronID_noSVD_noTOP", electronID_noSVD_noTOP,
662 "**(SPECIAL (TEMP) variable)** electron identification probability defined as :math:`\\mathcal{L}_e/(\\mathcal{L}_e+\\mathcal{L}_\\mu+\\mathcal{L}_\\pi+\\mathcal{L}_K+\\mathcal{L}_p+\\mathcal{L}_d)`, using info from all available detectors *excluding the SVD and the TOP*. *NB:* this variable must be used in place of `electronID` when analysing data (MC) processed (simulated) in *release 5*");
663 REGISTER_METAVARIABLE(
"binaryElectronID_noSVD_noTOP(pdgCodeTest)", binaryElectronID_noSVD_noTOP,
664 "**(SPECIAL (TEMP) variable)** Returns the binary probability for the electron mass hypothesis with respect to another mass hypothesis using all detector components, *excluding the SVD and the TOP*. *NB:* this variable must be used in place of `binaryPID` (``pdgCode1=11``) when analysing data (MC) processed (simulated) in **release 5**",
665 Manager::VariableDataType::c_double);
668 VARIABLE_GROUP(
"PID_expert");
669 REGISTER_METAVARIABLE(
"pidLogLikelihoodValueExpert(pdgCode, detectorList)", pidLogLikelihoodValueExpert,
670 "returns the log likelihood value of for a specific mass hypothesis and set of detectors.", Manager::VariableDataType::c_double);
671 REGISTER_METAVARIABLE(
"pidDeltaLogLikelihoodValueExpert(pdgCode1, pdgCode2, detectorList)", pidDeltaLogLikelihoodValueExpert,
672 "returns LogL(hyp1) - LogL(hyp2) (aka DLL) for two mass hypotheses and a set of detectors.", Manager::VariableDataType::c_double);
673 REGISTER_METAVARIABLE(
"pidPairProbabilityExpert(pdgCodeHyp, pdgCodeTest, detectorList)", pidPairProbabilityExpert,
674 "Pair (or binary) probability for the pdgCodeHyp mass hypothesis respect to the pdgCodeTest one, using an arbitrary set of detectors. :math:`\\mathcal{L}_{hyp}/(\\mathcal{L}_{test}+\\mathcal{L}_{hyp}`",
675 Manager::VariableDataType::c_double);
676 REGISTER_METAVARIABLE(
"pidProbabilityExpert(pdgCodeHyp, detectorList)", pidProbabilityExpert,
677 "probability for the pdgCodeHyp mass hypothesis respect to all the other ones, using an arbitrary set of detectors :math:`\\mathcal{L}_{hyp}/(\\Sigma_{\\text{all~hyp}}\\mathcal{L}_{i}`. ",
678 Manager::VariableDataType::c_double);
679 REGISTER_METAVARIABLE(
"pidMissingProbabilityExpert(detectorList)", pidMissingProbabilityExpert,
680 "returns 1 if the PID probabiliy is missing for the provided detector list, otherwise 0. ", Manager::VariableDataType::c_double);
681 REGISTER_VARIABLE(
"pidMostLikelyPDG(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", mostLikelyPDG,
683 Returns PDG code of the largest PID likelihood, or NaN if PID information is not available.
684 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
685 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
686 REGISTER_VARIABLE("pidIsMostLikely(ePrior=1/6, muPrior=1/6, piPrior=1/6, KPrior=1/6, pPrior=1/6, dPrior=1/6)", isMostLikely, R
"DOC(
687 Returns True if the largest PID likelihood of a given particle corresponds to its particle hypothesis.
688 This function accepts either no arguments, or 6 floats as priors for the charged particle hypotheses
689 following the order shown in the metavariable's declaration. Flat priors are assumed as default.)DOC");
692 VARIABLE_GROUP(
"Belle PID variables");
693 REGISTER_METAVARIABLE(
"atcPIDBelle(i,j)", atcPIDBelle, R
"DOC(
694 [Legacy] Returns Belle's PID atc variable: ``atc_pid(3,1,5,i,j).prob()``.
695 Parameters i,j are signal and background hypothesis: (0 = electron, 1 = muon, 2 = pion, 3 = kaon, 4 = proton)
696 Returns 0.5 in case there is no likelihood found and a factor of 0.5 will appear in the product if any of the subdetectors don't report a likelihood (Belle behaviour).
698 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
699 )DOC", Manager::VariableDataType::c_double);
700 REGISTER_VARIABLE("muIDBelle", muIDBelle, R
"DOC(
701 [Legacy] Returns Belle's PID ``Muon_likelihood()`` variable.
702 Returns 0.5 in case there is no likelihood found and returns zero if the muon likelihood is not usable (Belle behaviour).
704 .. warning:: The behaviour is different from Belle II PID variables which typically return NaN in case of error.
706 REGISTER_VARIABLE("muIDBelleQuality", muIDBelleQuality, R
"DOC(
707 [Legacy] Returns true if Belle's PID ``Muon_likelihood()`` is usable (reliable).
708 Returns zero/false if not usable or if there is no PID found.
710 REGISTER_VARIABLE("eIDBelle", eIDBelle, R
"DOC(
711 [Legacy] Returns Belle's electron ID ``eid(3,-1,5).prob()`` variable.
712 Returns 0.5 in case there is no likelihood found (Belle behaviour).
714 .. 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.