75 std::map<int, std::string> debugStr = {
85 decayDescriptor.init(decayString);
86 auto pListName = decayDescriptor.getMother()->getFullName();
88 unsigned short m_nSelectedDaughters = decayDescriptor.getSelectionNames().size();
92 B2FATAL(
"ParticleList: " << pListName <<
" could not be found. Aborting...");
95 auto pListSize = pList->getListSize();
97 B2DEBUG(11,
"ParticleList: " << pList->getParticleListName() <<
" - N = " << pListSize <<
" particles.");
99 const auto nTargetParticles = (m_nSelectedDaughters == 0) ? pListSize : pListSize * m_nSelectedDaughters;
102 std::vector<int> pdgs;
103 if (m_nSelectedDaughters == 0) {
104 pdgs.push_back(pList->getPDGCode());
106 pdgs = decayDescriptor.getSelectionPDGCodes();
108 for (
auto pdg : pdgs) {
111 B2FATAL(
"PDG: " << pdg <<
" of ParticleList: " << pListName <<
112 " is not that of a valid particle in Const::chargedStableSet! Aborting...");
115 std::vector<const Particle*> targetParticles;
116 if (m_nSelectedDaughters > 0) {
117 for (
unsigned int iPart(0); iPart < pListSize; ++iPart) {
118 auto* iParticle = pList->getParticle(iPart);
119 auto daughters = decayDescriptor.getSelectionParticles(iParticle);
120 for (
auto* iDaughter : daughters) {
121 targetParticles.push_back(iDaughter);
126 for (
unsigned int ipart(0); ipart < nTargetParticles; ++ipart) {
128 const Particle* particle = (m_nSelectedDaughters > 0) ? targetParticles[ipart] : pList->getParticle(ipart);
134 B2DEBUG(11,
"\nParticle [" << ipart <<
"] has invalid Track-ECLCluster relation, skip MVA application...");
143 auto p = particle->
getP();
146 if (std::isnan(theta) or std::isnan(p) or std::isnan(charge)) {
147 B2DEBUG(11,
"\nParticle [" << ipart <<
"] has invalid input variable, skip MVA application..." <<
148 " polar angle: " << theta <<
", p: " << p <<
", charge: " << charge);
152 int idx_theta, idx_p, idx_charge;
155 auto hasMatch = std::isnormal(Variable::eclClusterTrackMatched(particle));
157 debugStr[11] +=
"\n";
158 debugStr[11] += (
"Particle [" + std::to_string(ipart) +
"]\n");
159 debugStr[11] += (
"Has ECL cluster match? " + std::to_string(hasMatch) +
"\n");
160 debugStr[11] += (
"polar angle: " + thVarName +
" = " + std::to_string(theta) +
" [rad]\n");
161 debugStr[11] += (
"p = " + std::to_string(p) +
" [GeV/c]\n");
163 debugStr[11] += (
"charge = " + std::to_string(charge) +
"\n");
165 debugStr[11] += (
"Is brems corrected ? " + std::to_string(particle->
hasExtraInfo(
"bremsCorrected")) +
"\n");
166 debugStr[11] += (
"Weightfile idx = " + std::to_string(index) +
" - (polar angle, p, charge) = (" + std::to_string(
167 idx_theta) +
", " + std::to_string(idx_p) +
", " +
168 std::to_string(idx_charge) +
")\n");
170 debugStr[11] += (
"Category cut: " +
m_cuts.at(index)->decompile() +
"\n");
173 B2DEBUG(11, debugStr[11]);
174 debugStr[11].clear();
178 if (!
m_cuts.at(index)->check(particle)) {
179 B2DEBUG(11,
"\nParticle [" << ipart <<
"] didn't pass MVA category cut, skip MVA application...");
186 debugStr[11] +=
"\n";
187 debugStr[11] +=
"MVA variables:\n";
190 for (
unsigned int ivar(0); ivar < nvars; ++ivar) {
194 double var = std::numeric_limits<double>::quiet_NaN();
195 auto var_result = varobj->function(particle);
196 if (std::holds_alternative<double>(var_result)) {
197 var = std::get<double>(var_result);
198 }
else if (std::holds_alternative<int>(var_result)) {
199 var = std::get<int>(var_result);
200 }
else if (std::holds_alternative<bool>(var_result)) {
201 var = std::get<bool>(var_result);
203 B2ERROR(
"Variable '" << varobj->name <<
"' has wrong data type! It must be one of double, integer, or bool.");
208 var = (std::isnan(var)) ? -999.0 : var;
211 debugStr[11] += (
"\tvar[" + std::to_string(ivar) +
"] : " + varobj->name +
" = " + std::to_string(var) +
"\n");
217 B2DEBUG(11, debugStr[11]);
218 debugStr[11].clear();
223 debugStr[12] +=
"\n";
224 debugStr[12] +=
"MVA spectators:\n";
227 for (
unsigned int ispec(0); ispec < nspecs; ++ispec) {
231 double spec = std::numeric_limits<double>::quiet_NaN();
232 auto spec_result = specobj->function(particle);
233 if (std::holds_alternative<double>(spec_result)) {
234 spec = std::get<double>(spec_result);
235 }
else if (std::holds_alternative<int>(spec_result)) {
236 spec = std::get<int>(spec_result);
237 }
else if (std::holds_alternative<bool>(spec_result)) {
238 spec = std::get<bool>(spec_result);
240 B2ERROR(
"Variable '" << specobj->name <<
"' has wrong data type! It must be one of double, integer, or bool.");
243 debugStr[12] += (
"\tspec[" + std::to_string(ispec) +
"] : " + specobj->name +
" = " + std::to_string(spec) +
"\n");
245 m_datasets.at(index)->m_spectators[ispec] = spec;
249 B2DEBUG(12, debugStr[12]);
250 debugStr[12].clear();
256 debugStr[11] +=
"\n";
257 debugStr[12] +=
"\n";
258 debugStr[11] +=
"MVA response:\n";
260 std::string score_varname(
"");
262 std::vector<float> scores =
m_experts.at(index)->applyMulticlass(*
m_datasets.at(index))[0];
264 for (
unsigned int classID(0); classID <
m_classes.size(); ++classID) {
266 const std::string className(
m_classes.at(classID));
268 score_varname =
"pidChargedBDTScore_" + className;
271 score_varname +=
"_" + std::to_string(Const::ECL);
274 score_varname +=
"_" + std::to_string(det);
278 debugStr[11] += (
"\tclass[" + std::to_string(classID) +
"] = " + className +
" - score = " + std::to_string(
279 scores[classID]) +
"\n");
280 debugStr[12] += (
"\textraInfo: " + score_varname +
"\n");
287 B2DEBUG(11, debugStr[11]);
288 B2DEBUG(12, debugStr[12]);
289 debugStr[11].clear();
290 debugStr[12].clear();
304 std::string epsilon(
"1e-8");
306 std::map<std::string, std::string> aliasesLegacy;
308 aliasesLegacy.insert(std::make_pair(
"__event__",
"evtNum"));
315 aliasesLegacy.insert(std::make_pair(
"missingLogL_" + detName,
"pidMissingProbabilityExpert(" + detName +
")"));
319 std::string alias = fullName +
"ID_" + detName;
320 std::string var =
"pidProbabilityExpert(" + std::to_string(pdgId) +
", " + detName +
")";
321 std::string aliasLogTrf = alias +
"_LogTransfo";
322 std::string varLogTrf =
"formula(-1. * log10(formula(((1. - " + alias +
") + " + epsilon +
") / (" + alias +
" + " + epsilon +
325 aliasesLegacy.insert(std::make_pair(alias, var));
326 aliasesLegacy.insert(std::make_pair(aliasLogTrf, varLogTrf));
328 if (it.getIndex() == 0) {
329 aliasLogTrf = fullName +
"ID_LogTransfo";
330 varLogTrf =
"formula(-1. * log10(formula(((1. - " + fullName +
"ID) + " + epsilon +
") / (" + fullName +
"ID + " + epsilon +
332 aliasesLegacy.insert(std::make_pair(aliasLogTrf, varLogTrf));
339 B2INFO(
"Setting hard-coded aliases for the ChargedPidMVA algorithm.");
341 std::string debugStr(
"\n");
342 for (
const auto& [alias, variable] : aliasesLegacy) {
343 debugStr += (alias +
" --> " + variable +
"\n");
345 B2ERROR(
"Something went wrong with setting alias: " << alias <<
" for variable: " << variable);
348 B2DEBUG(10, debugStr);
387 ". Load supported MVA interfaces for multi-class charged particle identification...");
396 B2INFO(
"\tLoading weightfiles from the payload class.");
399 auto nfiles = serialized_weightfiles->size();
401 B2INFO(
"\tConstruct the MVA experts and datasets from N = " << nfiles <<
" weightfiles...");
411 for (
unsigned int idx(0); idx < nfiles; idx++) {
413 B2DEBUG(12,
"\t\tweightfile[" << idx <<
"]");
416 std::stringstream ss(serialized_weightfiles->at(idx));
420 weightfile.getOptions(general_options);
424 m_variables[idx] = manager.getVariables(general_options.m_variables);
425 m_spectators[idx] = manager.getVariables(general_options.m_spectators);
427 B2DEBUG(12,
"\t\tRetrieved N = " << general_options.m_variables.size()
428 <<
" variables, N = " << general_options.m_spectators.size()
432 m_experts[idx] = supported_interfaces[general_options.m_method]->getExpert();
435 B2DEBUG(12,
"\t\tweightfile loaded successfully into expert[" << idx <<
"]!");
438 std::vector<float> v(general_options.m_variables.size(), 0.0);
439 std::vector<float> s(general_options.m_spectators.size(), 0.0);
440 m_datasets[idx] = std::make_unique<MVA::SingleDataset>(general_options, v, 1.0, s);
442 B2DEBUG(12,
"\t\tdataset[" << idx <<
"] created successfully!");
446 const auto cutstr = (!cuts->empty()) ? cuts->at(idx) :
"";
449 B2DEBUG(12,
"\t\tcut[" << idx <<
"] created successfully!");
457 weightfile.getOptions(specific_options);
459 if (specific_options.m_classes.empty()) {
460 B2FATAL(
"MVA::SpecificOptions of weightfile[" << idx <<
461 "] has no registered MVA classes! This shouldn't happen in multi-class mode. Aborting...");
465 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)