76 std::map<int, std::string> debugStr = {
86 decayDescriptor.init(decayString);
87 auto pListName = decayDescriptor.getMother()->getFullName();
89 unsigned short m_nSelectedDaughters = decayDescriptor.getSelectionNames().size();
93 B2FATAL(
"ParticleList: " << pListName <<
" could not be found. Aborting...");
96 auto pListSize = pList->getListSize();
98 B2DEBUG(11,
"ParticleList: " << pList->getParticleListName() <<
" - N = " << pListSize <<
" particles.");
100 const auto nTargetParticles = (m_nSelectedDaughters == 0) ? pListSize : pListSize * m_nSelectedDaughters;
103 std::vector<int> pdgs;
104 if (m_nSelectedDaughters == 0) {
105 pdgs.push_back(pList->getPDGCode());
107 pdgs = decayDescriptor.getSelectionPDGCodes();
109 for (
auto pdg : pdgs) {
112 B2FATAL(
"PDG: " << pdg <<
" of ParticleList: " << pListName <<
113 " is not that of a valid particle in Const::chargedStableSet! Aborting...");
116 std::vector<const Particle*> targetParticles;
117 if (m_nSelectedDaughters > 0) {
118 for (
unsigned int iPart(0); iPart < pListSize; ++iPart) {
119 auto* iParticle = pList->getParticle(iPart);
120 auto daughters = decayDescriptor.getSelectionParticles(iParticle);
121 for (
auto* iDaughter : daughters) {
122 targetParticles.push_back(iDaughter);
127 for (
unsigned int ipart(0); ipart < nTargetParticles; ++ipart) {
129 const Particle* particle = (m_nSelectedDaughters > 0) ? targetParticles[ipart] : pList->getParticle(ipart);
135 B2DEBUG(11,
"\nParticle [" << ipart <<
"] has invalid Track-ECLCluster relation, skip MVA application...");
144 auto p = particle->
getP();
147 if (std::isnan(theta) or std::isnan(p) or std::isnan(charge)) {
148 B2DEBUG(11,
"\nParticle [" << ipart <<
"] has invalid input variable, skip MVA application..." <<
149 " polar angle: " << theta <<
", p: " << p <<
", charge: " << charge);
153 int idx_theta, idx_p, idx_charge;
156 auto hasMatch = std::isnormal(Variable::eclClusterTrackMatched(particle));
158 debugStr[11] +=
"\n";
159 debugStr[11] += (
"Particle [" + std::to_string(ipart) +
"]\n");
160 debugStr[11] += (
"Has ECL cluster match? " + std::to_string(hasMatch) +
"\n");
161 debugStr[11] += (
"polar angle: " + thVarName +
" = " + std::to_string(theta) +
" [rad]\n");
162 debugStr[11] += (
"p = " + std::to_string(p) +
" [GeV/c]\n");
164 debugStr[11] += (
"charge = " + std::to_string(charge) +
"\n");
166 debugStr[11] += (
"Is brems corrected ? " + std::to_string(particle->
hasExtraInfo(
"bremsCorrected")) +
"\n");
167 debugStr[11] += (
"Weightfile idx = " + std::to_string(index) +
" - (polar angle, p, charge) = (" + std::to_string(
168 idx_theta) +
", " + std::to_string(idx_p) +
", " +
169 std::to_string(idx_charge) +
")\n");
171 debugStr[11] += (
"Category cut: " +
m_cuts.at(index)->decompile() +
"\n");
174 B2DEBUG(11, debugStr[11]);
175 debugStr[11].clear();
179 if (!
m_cuts.at(index)->check(particle)) {
180 B2DEBUG(11,
"\nParticle [" << ipart <<
"] didn't pass MVA category cut, skip MVA application...");
187 debugStr[11] +=
"\n";
188 debugStr[11] +=
"MVA variables:\n";
191 for (
unsigned int ivar(0); ivar < nvars; ++ivar) {
195 double var = std::numeric_limits<double>::quiet_NaN();
196 auto var_result = varobj->function(particle);
197 if (std::holds_alternative<double>(var_result)) {
198 var = std::get<double>(var_result);
199 }
else if (std::holds_alternative<int>(var_result)) {
200 var = std::get<int>(var_result);
201 }
else if (std::holds_alternative<bool>(var_result)) {
202 var = std::get<bool>(var_result);
204 B2ERROR(
"Variable '" << varobj->name <<
"' has wrong data type! It must be one of double, integer, or bool.");
209 var = (std::isnan(var)) ? -999.0 : var;
212 debugStr[11] += (
"\tvar[" + std::to_string(ivar) +
"] : " + varobj->name +
" = " + std::to_string(var) +
"\n");
218 B2DEBUG(11, debugStr[11]);
219 debugStr[11].clear();
224 debugStr[12] +=
"\n";
225 debugStr[12] +=
"MVA spectators:\n";
228 for (
unsigned int ispec(0); ispec < nspecs; ++ispec) {
232 double spec = std::numeric_limits<double>::quiet_NaN();
233 auto spec_result = specobj->function(particle);
234 if (std::holds_alternative<double>(spec_result)) {
235 spec = std::get<double>(spec_result);
236 }
else if (std::holds_alternative<int>(spec_result)) {
237 spec = std::get<int>(spec_result);
238 }
else if (std::holds_alternative<bool>(spec_result)) {
239 spec = std::get<bool>(spec_result);
241 B2ERROR(
"Variable '" << specobj->name <<
"' has wrong data type! It must be one of double, integer, or bool.");
244 debugStr[12] += (
"\tspec[" + std::to_string(ispec) +
"] : " + specobj->name +
" = " + std::to_string(spec) +
"\n");
246 m_datasets.at(index)->m_spectators[ispec] = spec;
250 B2DEBUG(12, debugStr[12]);
251 debugStr[12].clear();
257 debugStr[11] +=
"\n";
258 debugStr[12] +=
"\n";
259 debugStr[11] +=
"MVA response:\n";
261 std::string score_varname(
"");
263 std::vector<float> scores =
m_experts.at(index)->applyMulticlass(*
m_datasets.at(index))[0];
265 for (
unsigned int classID(0); classID <
m_classes.size(); ++classID) {
267 const std::string className(
m_classes.at(classID));
269 score_varname =
"pidChargedBDTScore_" + className;
272 score_varname +=
"_" + std::to_string(Const::ECL);
275 score_varname +=
"_" + std::to_string(det);
279 debugStr[11] += (
"\tclass[" + std::to_string(classID) +
"] = " + className +
" - score = " + std::to_string(
280 scores[classID]) +
"\n");
281 debugStr[12] += (
"\textraInfo: " + score_varname +
"\n");
288 B2DEBUG(11, debugStr[11]);
289 B2DEBUG(12, debugStr[12]);
290 debugStr[11].clear();
291 debugStr[12].clear();
305 std::string epsilon(
"1e-8");
307 std::map<std::string, std::string> aliasesLegacy;
309 aliasesLegacy.insert(std::make_pair(
"__event__",
"evtNum"));
316 aliasesLegacy.insert(std::make_pair(
"missingLogL_" + detName,
"pidMissingProbabilityExpert(" + detName +
")"));
320 std::string alias = fullName +
"ID_" + detName;
321 std::string var =
"pidProbabilityExpert(" + std::to_string(pdgId) +
", " + detName +
")";
322 std::string aliasLogTrf = alias +
"_LogTransfo";
323 std::string varLogTrf =
"formula(-1. * log10(formula(((1. - " + alias +
") + " + epsilon +
") / (" + alias +
" + " + epsilon +
326 aliasesLegacy.insert(std::make_pair(alias, var));
327 aliasesLegacy.insert(std::make_pair(aliasLogTrf, varLogTrf));
329 if (it.getIndex() == 0) {
330 aliasLogTrf = fullName +
"ID_LogTransfo";
331 varLogTrf =
"formula(-1. * log10(formula(((1. - " + fullName +
"ID) + " + epsilon +
") / (" + fullName +
"ID + " + epsilon +
333 aliasesLegacy.insert(std::make_pair(aliasLogTrf, varLogTrf));
340 B2INFO(
"Setting hard-coded aliases for the ChargedPidMVA algorithm.");
342 std::string debugStr(
"\n");
343 for (
const auto& [alias, variable] : aliasesLegacy) {
344 debugStr += (alias +
" --> " + variable +
"\n");
346 B2ERROR(
"Something went wrong with setting alias: " << alias <<
" for variable: " << variable);
349 B2DEBUG(10, debugStr);
388 ". Load supported MVA interfaces for multi-class charged particle identification...");
397 B2INFO(
"\tLoading weightfiles from the payload class.");
400 auto nfiles = serialized_weightfiles->size();
402 B2INFO(
"\tConstruct the MVA experts and datasets from N = " << nfiles <<
" weightfiles...");
412 for (
unsigned int idx(0); idx < nfiles; idx++) {
414 B2DEBUG(12,
"\t\tweightfile[" << idx <<
"]");
417 std::stringstream ss(serialized_weightfiles->at(idx));
421 weightfile.getOptions(general_options);
425 m_variables[idx] = manager.getVariables(general_options.m_variables);
426 m_spectators[idx] = manager.getVariables(general_options.m_spectators);
428 B2DEBUG(12,
"\t\tRetrieved N = " << general_options.m_variables.size()
429 <<
" variables, N = " << general_options.m_spectators.size()
433 m_experts[idx] = supported_interfaces[general_options.m_method]->getExpert();
436 B2DEBUG(12,
"\t\tweightfile loaded successfully into expert[" << idx <<
"]!");
439 std::vector<float> v(general_options.m_variables.size(), 0.0);
440 std::vector<float> s(general_options.m_spectators.size(), 0.0);
441 m_datasets[idx] = std::make_unique<MVA::SingleDataset>(general_options, v, 1.0, s);
443 B2DEBUG(12,
"\t\tdataset[" << idx <<
"] created successfully!");
447 const auto cutstr = (!cuts->empty()) ? cuts->at(idx) :
"";
450 B2DEBUG(12,
"\t\tcut[" << idx <<
"] created successfully!");
458 weightfile.getOptions(specific_options);
460 if (specific_options.m_classes.empty()) {
461 B2FATAL(
"MVA::SpecificOptions of weightfile[" << idx <<
462 "] has no registered MVA classes! This shouldn't happen in multi-class mode. Aborting...");
466 for (
const auto& cls : specific_options.m_classes) {
Class to store reconstructed particles.
const ECLCluster * getECLCluster() const
Returns the pointer to the ECLCluster object that was used to create this Particle (if ParticleType =...
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
double getCharge(void) const
Returns particle charge.
double getP() const
Returns momentum magnitude (same as getMomentumMagnitude but with shorter name)