9#include <analysis/modules/TrackIsoCalculator/TrackIsoCalculatorModule.h>
10#include <analysis/DecayDescriptor/DecayDescriptorParticle.h>
11#include <analysis/VariableManager/Manager.h>
12#include <analysis/utility/DetectorSurface.h>
15#include <boost/algorithm/string.hpp>
26 R
"DOC(Calculate track isolation variables on the charged stable particles, or selected charged daughters, of the input ParticleList.)DOC");
32 "The name of the input charged stable particle list, e.g. ``mu+:all``, or a composite particle w/ charged stable daughters for which distances are to be calculated, e.g. ``D0 -> ^K- pi+``. Note that in the latter case we allow only one daughter to be selected in the decay string per module instance.");
35 "The name of the input ParticleList of reference tracks. Must be a charged stable particle as defined in Const::chargedStableSet.");
38 "The list of names of the detectors at whose (cylindrical) surface(s) we extrapolate each helix's polar and azimuthal angle. Allowed values: {CDC, TOP, ARICH, ECL, KLM}.",
39 std::vector<std::string>());
42 "If this option is set, the helix extrapolation for the target and reference particles will use the track fit result for the most probable mass hypothesis, namely, the one that gives the highest chi2Prob of the fit.",
46 "The name of the database payload object with the PID detector weights.",
47 std::string(
"PIDDetectorWeights"));
50 "If set to true, will not use the PID detector weights for the score definition.",
77 B2ERROR(
"More than one daughter is selected in the decay string " <<
m_decayString <<
".");
82 B2INFO(
"Calculating track-based isolation variables for the decay string: "
84 <<
" using the reference ParticleList: "
89 B2ERROR(
"Selected ParticleList in decay string:"
91 <<
" and/or reference ParticleList: "
93 <<
" is not that of a valid particle in Const::chargedStableSet!");
97 B2INFO(
"Will use track fit result for the most probable mass hypothesis in helix extrapolation.");
100 std::string detNamesConcat(
"");
105 boost::to_upper(detName);
107 detNamesConcat +=
"_" + detName;
113 auto iDetLayer = detName + std::to_string(iLayer);
117 distVarName +=
"__useHighestProbMassForExt";
147 std::unordered_map<int, const Particle*> targetParticles;
148 targetParticles.reserve(nMotherParticles);
150 for (
unsigned int iPart(0); iPart < nMotherParticles; ++iPart) {
160 auto iDetLayer = detName + std::to_string(iLayer);
169 targetParticles.insert({iDaughter->getMdstSource(), iDaughter});
175 targetParticles.insert({iParticle->getMdstSource(), iParticle});
182 const auto nParticlesTarget = targetParticles.size();
191 auto iDetLayer = detName + std::to_string(iLayer);
194 <<
"Detector surface: " << iDetLayer <<
"\n"
195 <<
"nMotherParticles: " << nMotherParticles <<
"\n"
196 <<
"nParticlesTarget: " << nParticlesTarget <<
"\n"
197 <<
"nParticlesReference: " << nParticlesReference);
199 double dummyDist(-1.0);
203 std::map<std::pair<int, int>,
double> particleMdstSourcePairsToDist;
206 for (
const auto& targetParticle : targetParticles) {
208 auto iMdstSource = targetParticle.first;
209 auto iParticle = targetParticle.second;
211 for (
unsigned int jPart(0); jPart < nParticlesReference; ++jPart) {
214 auto jMdstSource = jParticle->getMdstSource();
216 auto partMdstSourcePair = std::make_pair(iMdstSource, jMdstSource);
219 if (iMdstSource == jMdstSource) {
220 particleMdstSourcePairsToDist[partMdstSourcePair] = dummyDist;
230 if (particleMdstSourcePairsToDist.count({jMdstSource, iMdstSource})) {
231 particleMdstSourcePairsToDist[partMdstSourcePair] = particleMdstSourcePairsToDist[ {jMdstSource, iMdstSource}];
236 particleMdstSourcePairsToDist[partMdstSourcePair] = this->
getDistAtDetSurface(iParticle, jParticle, iDetLayer);
242 for (
const auto& targetParticle : targetParticles) {
244 auto iMdstSource = targetParticle.first;
245 auto iParticle = targetParticle.second;
248 std::vector<std::pair<double, int>> iDistancesAndRefMdstSources;
249 for (
const auto& [mdstIdxs, dist] : particleMdstSourcePairsToDist) {
250 if (mdstIdxs.first == iMdstSource) {
251 if (!std::isnan(dist) && dist >= 0) {
252 iDistancesAndRefMdstSources.push_back(std::make_pair(dist, mdstIdxs.second));
257 if (!iDistancesAndRefMdstSources.size()) {
258 B2DEBUG(12,
"The container of distances is empty. Perhaps the target and reference lists contain the same exact particles?");
262 const auto minDist = *std::min_element(std::begin(iDistancesAndRefMdstSources), std::end(iDistancesAndRefMdstSources),
263 [](
const auto & l,
const auto & r) {
return l.first < r.first;});
265 auto jParticle =
m_pListReference->getParticleWithMdstSource(minDist.second);
268 <<
"Particle w/ mdstSource[" << iMdstSource <<
"] (PDG = "
269 << iParticle->getPDGCode() <<
"). Closest charged particle w/ mdstSource["
271 <<
"] (PDG = " << jParticle->getPDGCode()
272 <<
") at " << iDetLayer
273 <<
" surface is found at D = " << minDist.first
275 <<
"Storing extraInfo variables:\n"
292 for (
const auto& targetParticle : targetParticles) {
294 auto iMdstSource = targetParticle.first;
295 auto iParticle = targetParticle.second;
298 double isoScore(0.0);
299 double isoScoreAsWeightedAvg(0.0);
300 double sumWeights(0.0);
302 B2DEBUG(11,
"Particle w/ mdstSource[" << iMdstSource <<
"] (PDG = " << iParticle->getPDGCode() <<
").");
311 isoScore += weightedSumNonIsoLayers;
312 isoScoreAsWeightedAvg += weightedSumInvDists;
313 sumWeights += detWeight;
320 isoScore = (isoScore - minScore) / (maxScore - minScore);
322 isoScoreAsWeightedAvg /= sumWeights;
326 isoScoreAsWeightedAvg = 1. - ((std::min(isoScoreAsWeightedAvg, 1e2) - minScore) / (1e2 - minScore));
329 <<
"Isolation score: " << isoScore
331 <<
"Isolation score (as weighted avg): " << isoScoreAsWeightedAvg
333 <<
"Storing extraInfo variable:\n"
356 auto p = iParticle->
getP();
360 auto detWeight = (*
m_DBWeights.get())->getWeight(hypo, det, p, theta);
364 detWeight = (detWeight < 0 || std::isnan(detWeight)) ? detWeight : 0.0;
372 const float detWeight)
const
380 auto iDetLayer = detName + std::to_string(iLayer);
393 B2DEBUG(12,
"\nNo close-enough neighbours to this particle in the " << detName <<
" were found.");
397 B2FATAL(
"\nTotal layers in " << detName <<
": N=" << nLayers
399 <<
"Layers w/ a close-enough particle: n=" << n
401 <<
"n > N ?? Abort...");
404 return 1. - (-detWeight * (n / nLayers));
410 const float detWeight)
const
415 double sumInvDists(0.);
418 auto iDetLayer = detName + std::to_string(iLayer);
423 sumInvDists += threshDist / iParticle->
getExtraInfo(distVar);
428 return detWeight * sumInvDists;
435 const std::string& detLayerName)
const
448 std::string nameExtTheta =
"helixExtTheta(" + std::to_string(rho) +
"," + std::to_string(zfwd) +
"," + std::to_string(zbwd) +
")";
450 nameExtTheta.replace(nameExtTheta.size() - 1, 1,
", 1)");
455 std::string nameExtPhi =
"helixExtPhi(" + std::to_string(rho) +
"," + std::to_string(zfwd) +
"," + std::to_string(zbwd) +
")";
457 nameExtPhi.replace(nameExtPhi.size() - 1, 1,
", 1)");
462 const auto iExtInBarrel = (iExtTheta >= th_fwd_brl && iExtTheta < th_bwd_brl);
463 const auto jExtInBarrel = (jExtTheta >= th_fwd_brl && jExtTheta < th_bwd_brl);
465 const auto iExtInFWDEndcap = (iExtTheta >= th_fwd && iExtTheta < th_fwd_brl);
466 const auto jExtInFWDEndcap = (jExtTheta >= th_fwd && jExtTheta < th_fwd_brl);
468 const auto iExtInBWDEndcap = (iExtTheta >= th_bwd_brl && iExtTheta < th_bwd);
469 const auto jExtInBWDEndcap = (jExtTheta >= th_bwd_brl && jExtTheta < th_bwd);
471 if (boost::contains(detLayerName,
"CDC") || boost::contains(detLayerName,
"TOP")) {
474 if (!iExtInBarrel || !jExtInBarrel) {
475 return std::numeric_limits<double>::quiet_NaN();
482 auto diffPhi = jExtPhi - iExtPhi;
483 if (std::abs(diffPhi) > M_PI) {
484 diffPhi = (diffPhi > M_PI) ? diffPhi - 2 * M_PI : 2 * M_PI + diffPhi;
487 return 2.0 * rho * sin(std::abs(diffPhi) / 2.0);
491 if (boost::contains(detLayerName,
"ARICH")) {
493 if (!iExtInFWDEndcap || !jExtInFWDEndcap) {
494 return std::numeric_limits<double>::quiet_NaN();
497 if (boost::contains(detLayerName,
"ECL") || boost::contains(detLayerName,
"KLM")) {
502 !(iExtInBarrel && jExtInBarrel) &&
503 !(iExtInFWDEndcap && jExtInFWDEndcap) &&
504 !(iExtInBWDEndcap && jExtInBWDEndcap)
506 return std::numeric_limits<double>::quiet_NaN();
520 const auto iExtR = (iExtTheta >= th_fwd_brl && iExtTheta < th_bwd_brl) ? rho / sin(iExtTheta) : ((iExtTheta >= th_fwd
521 && iExtTheta < th_fwd_brl) ? zfwd / cos(iExtTheta) : zbwd / cos(iExtTheta));
522 const auto jExtR = (jExtTheta >= th_fwd_brl && jExtTheta < th_bwd_brl) ? rho / sin(jExtTheta) : ((jExtTheta >= th_fwd
523 && jExtTheta < th_fwd_brl) ? zfwd / cos(jExtTheta) : zbwd / cos(jExtTheta));
525 return sqrt((iExtR * iExtR) + (jExtR * jExtR) - 2 * iExtR * jExtR * (sin(iExtTheta) * sin(jExtTheta) * cos(iExtPhi - jExtPhi)
526 + cos(iExtTheta) * cos(jExtTheta)));
530 return std::numeric_limits<double>::quiet_NaN();
537 bool checkPList =
false;
551 bool checkPListReference =
false;
556 return (checkPList and checkPListReference);
Provides a type-safe way to pass members of the chargedStableSet set.
const ParticleType & find(int pdg) const
Returns particle in set with given PDG code, or invalidParticle if not found.
static const ParticleSet chargedStableSet
set of charged stable particles
static const ParticleType invalidParticle
Invalid particle, used internally.
Represents a particle in the DecayDescriptor.
int getPDGCode() const
Return PDG code.
std::string getFullName() const
returns the full name of the particle full_name = name:label
The DecayDescriptor stores information about a decay tree or parts of a decay tree.
bool init(const std::string &str)
Initialise the DecayDescriptor from given string.
std::vector< int > getSelectionPDGCodes()
Return list of PDG codes of selected particles.
std::vector< std::string > getSelectionNames()
Return list of human readable names of selected particles.
std::vector< const Particle * > getSelectionParticles(const Particle *particle)
Get a vector of pointers with selected daughters in the decay tree.
const DecayDescriptorParticle * getMother() const
return mother.
void setDescription(const std::string &description)
Sets the description of the module.
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Class to store reconstructed particles.
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
int getPDGCode(void) const
Returns PDG code.
ROOT::Math::XYZVector getMomentum() const
Returns momentum vector.
double getP() const
Returns momentum magnitude (same as getMomentumMagnitude but with shorter name)
double getExtraInfo(const std::string &name) const
Return given value if set.
StoreObjPtr< EventMetaData > m_event_metadata
The event information.
std::unique_ptr< DBObjPtr< PIDDetectorWeights > > m_DBWeights
Interface to get the database payload with the PID detector weights.
~TrackIsoCalculatorModule() override
Destructor, use this to clean up anything you created in the constructor.
void initialize() override
Use this to initialize resources or memory your module needs.
double getDistAtDetSurface(const Particle *iParticle, const Particle *jParticle, const std::string &detLayerName) const
Calculate the distance between the points where the two input extrapolated track helices cross the gi...
void event() override
Called once for each event.
std::unordered_map< std::string, std::string > m_detLayerToDistVariable
Map that associates to each detector layer (e.g., 'CDC6') the name of the variable representing the d...
std::string m_decayString
The name of the input charged stable particle list, or composite particle w/ charged stable daughters...
StoreObjPtr< ParticleList > m_pListTarget
The input ParticleList object for which distances are to be calculated.
std::string m_isoScoreVariable
The name of the variable representing the track isolation score.
double getWeightedSumInvDists(const Particle *iParticle, const std::string &detName, const float detWeight) const
Get the sum of the inverse (scaled) minimum distances over the given detector layers,...
StoreArray< Particle > m_particles
StoreArray of Particles.
std::string m_payloadName
The name of the database payload object with the MVA weights.
std::vector< std::string > m_detNames
The list of names of the detectors at whose inner (cylindrical) surface we extrapolate each track's p...
Const::EDetector getDetEnum(const std::string &detName) const
Get the enum type for this detector name.
std::string m_pListReferenceName
The name of the input ParticleList of reference tracks.
std::unordered_map< std::string, std::string > m_detLayerToRefPartIdxVariable
Map that associates to each detector layer (e.g, 'CDC6') the name of the variable representing the md...
double getDistThreshold(Const::EDetector det, int layer) const
Get the threshold value per detector layer for the distance to closest ext.
bool onlySelectedStdChargedInDecay()
Check whether input particle list and reference list are of a valid charged stable particle.
double getDetectorWeight(const Particle *iParticle, const std::string &detName) const
Get the PID weight, , for this particle and detector reading it from the payload, if selected.
bool m_excludePIDDetWeights
Exclude the PID detector weights for the isolation score definition.
DecayDescriptor m_decaydescriptor
< Decay descriptor of decays to look for.
TrackIsoCalculatorModule()
Constructor: Sets the description, the properties and the parameters of the module.
double getWeightedSumNonIsoLayers(const Particle *iParticle, const std::string &detName, const float detWeight) const
Get the sum of layers with a close-by track, divided by the total number of layers,...
unsigned short m_nSelectedDaughters
The number of selected daughters in the decay string.
StoreObjPtr< ParticleList > m_pListReference
The input ParticleList object of reference tracks.
std::string m_isoScoreVariableAsWeightedAvg
The name of the variable representing the track isolation score.
bool m_useHighestProbMassForExt
If this option is set, the helix extrapolation for the target and reference particles will use the tr...
static Manager & Instance()
get singleton instance.
void addParam(const std::string &name, T ¶mVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
double sqrt(double a)
sqrt for double
Abstract base class for different kinds of events.
static const std::unordered_map< std::string, DetSurfCylBoundaries > detLayerToSurfBoundaries
Map that associates to each detector layer its valid cylindrical surface's boundaries.
static const std::unordered_map< std::string, std::vector< int > > detToLayers
Map that associates to each detector its list of valid layers.