Belle II Software  light-2212-foldex
TrackIsoCalculatorModule.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <analysis/modules/TrackIsoCalculator/TrackIsoCalculatorModule.h>
10 #include <analysis/DecayDescriptor/DecayDescriptorParticle.h>
11 
12 #include <cmath>
13 #include <iomanip>
14 #include <boost/algorithm/string.hpp>
15 
16 
17 using namespace Belle2;
18 
19 REG_MODULE(TrackIsoCalculator);
20 
22 {
23  // Set module properties
25  R"DOC(Calculate track isolation variables on the charged stable particles, or selected charged daughters, of the input ParticleList.)DOC");
26 
27  // Parameter definitions
28  addParam("decayString",
30  "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.");
31  addParam("particleListReference",
33  "The name of the input ParticleList of reference tracks. Must be a charged stable particle as defined in Const::chargedStableSet.");
34  addParam("detectorName",
35  m_detName,
36  "The name of the detector at whose (cylindrical) surface(s) we extrapolate each helix's polar and azimuthal angle. Allowed values: {CDC, TOP, ARICH, ECL, KLM}.");
37  addParam("useHighestProbMassForExt",
39  "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.",
40  bool(false));
41  addParam("payloadName",
43  "The name of the database payload object with the PID detector weights.",
44  std::string("PIDDetectorWeights"));
45  addParam("excludePIDDetWeights",
47  "If set to true, will not use the PID detector weights for the score definition.",
48  bool(false));
49 }
50 
52 {
53 }
54 
56 {
57  m_event_metadata.isRequired();
58 
60  m_DBWeights = std::make_unique<DBObjPtr<PIDDetectorWeights>>(m_payloadName);
61  }
62 
63  bool valid = m_decaydescriptor.init(m_decayString);
64  if (!valid) {
65  B2ERROR("Decay string " << m_decayString << " is invalid.");
66  }
67 
69 
70  m_pListTarget.isRequired(mother->getFullName());
72 
73  if (m_nSelectedDaughters > 1) {
74  B2ERROR("More than one daughter is selected in the decay string " << m_decayString << ".");
75  }
76 
78 
79  B2INFO("Calculating track-based isolation variables at "
80  << m_detName
81  << " surface(s) for the decay string: "
82  << m_decayString
83  << " using the reference ParticleList: "
85  << ".");
86 
88  B2ERROR("Selected ParticleList in decay string:"
89  << m_decayString
90  << " and/or reference ParticleList: "
92  << " is not that of a valid particle in Const::chargedStableSet!");
93  }
94 
96  B2INFO("Will use track fit result for the most probable mass hypothesis in helix extrapolation.");
97  }
98 
99  // Ensure we use uppercase detector labels.
100  boost::to_upper(m_detName);
101 
102  // The total number of layers of this detector.
104 
105  // Define the name(s) of the variables for this detector to be stored as extraInfo.
106  for (const auto& iLayer : m_detToLayers[m_detName]) {
107 
108  auto iDetLayer = m_detName + std::to_string(iLayer);
109 
110  auto distVarName = "distToClosestTrkAt" + iDetLayer + "_VS_" + m_pListReferenceName;
112  distVarName += "__useHighestProbMassForExt";
113  }
114  auto refPartIdxVarName = "idxOfClosestPartAt" + iDetLayer + "In_" + m_pListReferenceName;
115 
116  m_detLayerToDistVariable.insert(std::make_pair(iDetLayer, distVarName));
117  m_detLayerToRefPartIdxVariable.insert(std::make_pair(iDetLayer, refPartIdxVarName));
118 
119  }
120  // Isolation score variable per detector.
121  m_isoScoreVariable = "trkIsoScore" + m_detName + "_VS_" + m_pListReferenceName;
123  m_isoScoreVariable += "__useHighestProbMassForExt";
124  }
125 
126 }
127 
129 {
130  B2DEBUG(11, "Start processing EVENT: " << m_event_metadata->getEvent());
131 
132  const auto nMotherParticles = m_pListTarget->getListSize();
133 
134  // Fill transient container of all selected charged particles in the decay
135  // for which the distance to nearest neighbour is to be calculated.
136  // If the input ParticleList is that of standard charged particles, just copy
137  // the whole list over, otherwise loop over the selected charged daughters.
138  std::unordered_map<unsigned int, const Particle*> targetParticles;
139  targetParticles.reserve(nMotherParticles);
140 
141  // Loop over the layer of the input detector.
142  for (const auto& iLayer : m_detToLayers[m_detName]) {
143 
144  auto iDetLayer = m_detName + std::to_string(iLayer);
145 
146  for (unsigned int iPart(0); iPart < nMotherParticles; ++iPart) {
147 
148  auto iParticle = m_pListTarget->getParticle(iPart);
149 
150  if (m_nSelectedDaughters) {
151  for (auto* iDaughter : m_decaydescriptor.getSelectionParticles(iParticle)) {
152  // Check if the distance for this target particle has been set already,
153  // e.g. by a previous instance of this module.
154  if (iDaughter->hasExtraInfo(m_detLayerToDistVariable[iDetLayer])) {
155  continue;
156  }
157  targetParticles.insert({iDaughter->getMdstArrayIndex(), iDaughter});
158  }
159  } else {
160  if (iParticle->hasExtraInfo(m_detLayerToDistVariable[iDetLayer])) {
161  continue;
162  }
163  targetParticles.insert({iParticle->getMdstArrayIndex(), iParticle});
164  }
165 
166  }
167  }
168 
169  const auto nParticlesTarget = targetParticles.size();
170  const auto nParticlesReference = m_pListReference->getListSize();
171 
172  // Loop over the layer of the input detector.
173  for (const auto& iLayer : m_detToLayers[m_detName]) {
174 
175  auto iDetLayer = m_detName + std::to_string(iLayer);
176 
177  B2DEBUG(11, "\n"
178  << "Detector surface: " << iDetLayer << "\n"
179  << "nMotherParticles: " << nMotherParticles << "\n"
180  << "nParticlesTarget: " << nParticlesTarget << "\n"
181  << "nParticlesReference: " << nParticlesReference);
182 
183  double dummyDist(-1.0);
184 
185  // Store the pair-wise distances in a map,
186  // where the keys are pairs of mdst indexes.
187  std::map<std::pair<unsigned int, unsigned int>, double> particleMdstIdxPairsToDist;
188 
189  // Loop over input particle list
190  for (const auto& targetParticle : targetParticles) {
191 
192  auto iMdstIdx = targetParticle.first;
193  auto iParticle = targetParticle.second;
194 
195  for (unsigned int jPart(0); jPart < nParticlesReference; ++jPart) {
196 
197  auto jParticle = m_pListReference->getParticle(jPart);
198  auto jMdstIdx = jParticle->getMdstArrayIndex();
199 
200  auto partMdstIdxPair = std::make_pair(iMdstIdx, jMdstIdx);
201 
202  // Set dummy distance if same particle.
203  if (iMdstIdx == jMdstIdx) {
204  particleMdstIdxPairsToDist[partMdstIdxPair] = dummyDist;
205  continue;
206  }
207  // If:
208  //
209  // - the mass hypothesis of the best fit is used, OR
210  // - the mass hypothesis of the 'default' fit of the two particles is the same,
211  //
212  // avoid re-doing the calculation if a pair with the flipped mdst indexes in the map already exists.
213  if (m_useHighestProbMassForExt || (iParticle->getPDGCodeUsedForFit() == jParticle->getPDGCodeUsedForFit())) {
214  if (particleMdstIdxPairsToDist.count({jMdstIdx, iMdstIdx})) {
215  particleMdstIdxPairsToDist[partMdstIdxPair] = particleMdstIdxPairsToDist[ {jMdstIdx, iMdstIdx}];
216  continue;
217  }
218  }
219  // Calculate the pair-wise distance.
220  particleMdstIdxPairsToDist[partMdstIdxPair] = this->getDistAtDetSurface(iParticle, jParticle, iDetLayer);
221  }
222 
223  }
224 
225  // For each particle in the input list, find the minimum among all distances to the reference particles.
226  for (const auto& targetParticle : targetParticles) {
227 
228  auto iMdstIdx = targetParticle.first;
229  auto iParticle = targetParticle.second;
230 
231  // Save the distances and the mdst indexes of the reference particles.
232  std::vector<std::pair<double, unsigned int>> iDistancesAndRefMdstIdxs;
233  for (const auto& [mdstIdxs, dist] : particleMdstIdxPairsToDist) {
234  if (mdstIdxs.first == iMdstIdx) {
235  if (!std::isnan(dist) && dist >= 0) {
236  iDistancesAndRefMdstIdxs.push_back(std::make_pair(dist, mdstIdxs.second));
237  }
238  }
239  }
240 
241  if (!iDistancesAndRefMdstIdxs.size()) {
242  B2DEBUG(12, "The container of distances is empty. Perhaps the target and reference lists contain the same exact particles?");
243  continue;
244  }
245 
246  const auto minDist = *std::min_element(std::begin(iDistancesAndRefMdstIdxs), std::end(iDistancesAndRefMdstIdxs),
247  [](const auto & l, const auto & r) {return l.first < r.first;});
248 
249  auto jParticle = m_pListReference->getParticleWithMdstIdx(minDist.second);
250 
251  B2DEBUG(11, "\n"
252  << "Particle w/ mdstIndex[" << iMdstIdx << "] (PDG = "
253  << iParticle->getPDGCode() << "). Closest charged particle w/ mdstIndex["
254  << minDist.second
255  << "] (PDG = " << jParticle->getPDGCode()
256  << ") at " << iDetLayer
257  << " surface is found at D = " << minDist.first
258  << " [cm]\n"
259  << "Storing extraInfo variables:\n"
260  << m_detLayerToDistVariable[iDetLayer]
261  << "\n"
262  << m_detLayerToRefPartIdxVariable[iDetLayer]);
263 
264  if (!iParticle->hasExtraInfo(m_detLayerToDistVariable[iDetLayer])) {
265  m_particles[iParticle->getArrayIndex()]->addExtraInfo(m_detLayerToDistVariable[iDetLayer], minDist.first);
266  }
267  m_particles[iParticle->getArrayIndex()]->writeExtraInfo(m_detLayerToRefPartIdxVariable[iDetLayer], minDist.second);
268 
269  } // end loop over input particle list.
270 
271  } // end loop over detector layers.
272 
273  // Store the isolation score per target particle for the given detector.
274  for (const auto& targetParticle : targetParticles) {
275 
276  auto iMdstIdx = targetParticle.first;
277  auto iParticle = targetParticle.second;
278 
279  auto score = this->getIsoScore(iParticle);
280  m_particles[iParticle->getArrayIndex()]->writeExtraInfo(m_isoScoreVariable, score);
281 
282  B2DEBUG(11, "\n"
283  << "Particle w/ mdstIndex[" << iMdstIdx << "] (PDG = " << iParticle->getPDGCode() << ").\n"
284  << "Isolation score in the " << m_detName << ": s = " << score
285  << "\n"
286  << "Storing extraInfo variable:\n"
287  << m_isoScoreVariable);
288 
289  }
290 
291  B2DEBUG(11, "Finished processing EVENT: " << m_event_metadata->getEvent());
292 
293 }
294 
295 
296 double TrackIsoCalculatorModule::getIsoScore(const Particle* iParticle) const
297 {
298 
299  auto hypo = Const::ChargedStable(std::abs(iParticle->getPDGCode()));
300  auto det = this->getDetEnum(m_detName);
301  auto p = iParticle->getP();
302  auto theta = std::get<double>(Variable::Manager::Instance().getVariable("theta")->function(iParticle));
303 
304  double detWeight(-1.0);
305  if (!m_excludePIDDetWeights) {
306  detWeight = (*m_DBWeights.get())->getWeight(hypo, det, p, theta);
307  // If w > 0, the detector has detrimental impact on PID:
308  // the value is set to zero to prevent the detector from contributing to the score.
309  // NB: NaN should stay NaN.
310  detWeight = (detWeight < 0 || std::isnan(detWeight)) ? detWeight : 0.0;
311  }
312 
313  unsigned int n(0);
314  for (const auto& iLayer : m_detToLayers.at(m_detName)) {
315  auto iDetLayer = m_detName + std::to_string(iLayer);
316  auto distVar = m_detLayerToDistVariable.at(iDetLayer);
317  auto threshDist = this->getDistThreshold(det, iLayer);
318  if (iParticle->hasExtraInfo(distVar)) {
319  if (iParticle->getExtraInfo(distVar) < threshDist) {
320  n++;
321  }
322  }
323  }
324 
325  if (!n) {
326  B2DEBUG(12, "\nNo close-enough neighbours to this particle in the " << m_detName << " were found.");
327  }
328 
329  if (n > m_nLayers) {
330  B2FATAL("\nTotal layers in " << m_detName << ": N=" << m_nLayers
331  << "\n"
332  << "Layers w/ a close-enough particle: n=" << n
333  << "\n"
334  << "n > N ?? Abort...");
335  }
336 
337  return 1. - (-detWeight * (n / m_nLayers));
338 
339 }
340 
341 
343  const Particle* jParticle,
344  const std::string& detLayerName) const
345 {
346 
347  // Radius and z boundaries of the cylinder describing this detector's surface.
348  const auto rho = m_detLayerToSurfBoundaries.at(detLayerName).m_rho;
349  const auto zfwd = m_detLayerToSurfBoundaries.at(detLayerName).m_zfwd;
350  const auto zbwd = m_detLayerToSurfBoundaries.at(detLayerName).m_zbwd;
351  // Polar angle boundaries between barrel and endcaps.
352  const auto th_fwd = m_detLayerToSurfBoundaries.at(detLayerName).m_th_fwd;
353  const auto th_fwd_brl = m_detLayerToSurfBoundaries.at(detLayerName).m_th_fwd_brl;
354  const auto th_bwd_brl = m_detLayerToSurfBoundaries.at(detLayerName).m_th_bwd_brl;
355  const auto th_bwd = m_detLayerToSurfBoundaries.at(detLayerName).m_th_bwd;
356 
357  std::string nameExtTheta = "helixExtTheta(" + std::to_string(rho) + "," + std::to_string(zfwd) + "," + std::to_string(zbwd) + ")";
359  nameExtTheta.replace(nameExtTheta.size() - 1, 1, ", 1)");
360  }
361  const auto iExtTheta = std::get<double>(Variable::Manager::Instance().getVariable(nameExtTheta)->function(iParticle));
362  const auto jExtTheta = std::get<double>(Variable::Manager::Instance().getVariable(nameExtTheta)->function(jParticle));
363 
364  std::string nameExtPhi = "helixExtPhi(" + std::to_string(rho) + "," + std::to_string(zfwd) + "," + std::to_string(zbwd) + ")";
366  nameExtPhi.replace(nameExtPhi.size() - 1, 1, ", 1)");
367  }
368  const auto iExtPhi = std::get<double>(Variable::Manager::Instance().getVariable(nameExtPhi)->function(iParticle));
369  const auto jExtPhi = std::get<double>(Variable::Manager::Instance().getVariable(nameExtPhi)->function(jParticle));
370 
371  const auto iExtInBarrel = (iExtTheta >= th_fwd_brl && iExtTheta < th_bwd_brl);
372  const auto jExtInBarrel = (jExtTheta >= th_fwd_brl && jExtTheta < th_bwd_brl);
373 
374  const auto iExtInFWDEndcap = (iExtTheta >= th_fwd && iExtTheta < th_fwd_brl);
375  const auto jExtInFWDEndcap = (jExtTheta >= th_fwd && jExtTheta < th_fwd_brl);
376 
377  const auto iExtInBWDEndcap = (iExtTheta >= th_bwd_brl && iExtTheta < th_bwd);
378  const auto jExtInBWDEndcap = (jExtTheta >= th_bwd_brl && jExtTheta < th_bwd);
379 
380  if (m_detName == "CDC" || m_detName == "TOP") {
381 
382  // If any of the two extrapolated tracks is not in the barrel region of the CDC/TOP, the distance is undefined.
383  if (!iExtInBarrel || !jExtInBarrel) {
384  return std::numeric_limits<double>::quiet_NaN();
385  }
386 
387  // For CDC and TOP, we calculate the distance between the points where the two input
388  // extrapolated track helices cross the input detector's cylindrical surface
389  // on the (rho, phi) plane. Namely, this is the cord length of the arc
390  // that subtends deltaPhi.
391  auto diffPhi = jExtPhi - iExtPhi;
392  if (std::abs(diffPhi) > M_PI) {
393  diffPhi = (diffPhi > M_PI) ? diffPhi - 2 * M_PI : 2 * M_PI + diffPhi;
394  }
395 
396  return 2.0 * rho * sin(std::abs(diffPhi) / 2.0);
397 
398  } else {
399 
400  if (m_detName == "ARICH") {
401  // If any of the two tracks is not in the ARICH theta acceptance, the distance is undefined.
402  if (!iExtInFWDEndcap || !jExtInFWDEndcap) {
403  return std::numeric_limits<double>::quiet_NaN();
404  }
405  }
406  if (m_detName == "ECL" || m_detName == "KLM") {
407 
408  // For ECL and KLM, we require track pairs to be both in the barrel,
409  // both in the FWD endcap, or both in the FWD endcap. Otherwise, the distance is undefined.
410  if (
411  !(iExtInBarrel && jExtInBarrel) &&
412  !(iExtInFWDEndcap && jExtInFWDEndcap) &&
413  !(iExtInBWDEndcap && jExtInBWDEndcap)
414  ) {
415  return std::numeric_limits<double>::quiet_NaN();
416  }
417  }
418 
419  // Ok, we know theta and phi.
420  // Let's extract (spherical) R by using the transformation:
421  //
422  // 1. rho = r * sin(theta)
423  // 2. phi = phi
424  // 3. z = r * cos(theta)
425  //
426  // The formula to be inverted depends on where each extrapolated track's theta is found:
427  // if in barrel, use 1. (rho is known), if in fwd/bwd endcap, use 3. (zfwd/zbwd is known).
428 
429  const auto iExtR = (iExtTheta >= th_fwd_brl && iExtTheta < th_bwd_brl) ? rho / sin(iExtTheta) : ((iExtTheta >= th_fwd
430  && iExtTheta < th_fwd_brl) ? zfwd / cos(iExtTheta) : zbwd / cos(iExtTheta));
431  const auto jExtR = (jExtTheta >= th_fwd_brl && jExtTheta < th_bwd_brl) ? rho / sin(jExtTheta) : ((jExtTheta >= th_fwd
432  && jExtTheta < th_fwd_brl) ? zfwd / cos(jExtTheta) : zbwd / cos(jExtTheta));
433 
434  return sqrt((iExtR * iExtR) + (jExtR * jExtR) - 2 * iExtR * jExtR * (sin(iExtTheta) * sin(jExtTheta) * cos(iExtPhi - jExtPhi)
435  + cos(iExtTheta) * cos(jExtTheta)));
436 
437  }
438 
439  return std::numeric_limits<double>::quiet_NaN();
440 
441 }
442 
444 {
445 
446  bool checkPList = false;
447 
448  if (!m_nSelectedDaughters) {
450  } else {
451  for (int pdgcode : m_decaydescriptor.getSelectionPDGCodes()) {
452  checkPList = Const::chargedStableSet.find(abs(pdgcode)) != Const::invalidParticle;
453  if (!checkPList) {
454  break;
455  }
456  }
457  }
458 
459  DecayDescriptor dd;
460  bool checkPListReference = false;
461  if (dd.init(m_pListReferenceName)) {
462  checkPListReference = Const::chargedStableSet.find(abs(dd.getMother()->getPDGCode())) != Const::invalidParticle;
463  }
464 
465  return (checkPList and checkPListReference);
466 
467 };
Provides a type-safe way to pass members of the chargedStableSet set.
Definition: Const.h:580
const ParticleType & find(int pdg) const
Returns particle in set with given PDG code, or invalidParticle if not found.
Definition: Const.h:562
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:609
static const ParticleType invalidParticle
Invalid particle, used internally.
Definition: Const.h:671
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.
const DecayDescriptorParticle * getMother() const
return mother.
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.
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
Class to store reconstructed particles.
Definition: Particle.h:74
bool hasExtraInfo(const std::string &name) const
Return whether the extra info with the given name is set.
Definition: Particle.cc:1293
int getPDGCode(void) const
Returns PDG code.
Definition: Particle.h:441
double getP() const
Returns momentum magnitude (same as getMomentumMagnitude but with shorter name)
Definition: Particle.h:559
double getExtraInfo(const std::string &name) const
Return given value if set.
Definition: Particle.cc:1316
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.
std::unordered_map< std::string, std::vector< int > > m_detToLayers
Map that associates to each detector its list of valid layers.
~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 the name of the variable representing the distance to the ...
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 in this detector.
StoreArray< Particle > m_particles
StoreArray of Particles.
std::string m_payloadName
The name of the database payload object with the MVA weights.
Const::EDetector getDetEnum(const std::string &detName) const
Get the enum type for this detector name.
std::string m_detName
The name of the detector at whose inner (cylindrical) surface we extrapolate each track's polar and a...
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 the name of the variable representing the mdst array index...
double getDistThreshold(Const::EDetector det, int layer) const
Get the threshold value per detctor layer for the distance to closest ext.
bool onlySelectedStdChargedInDecay()
Check whether input particle list and reference list are of a valid charged stable particle.
bool m_excludePIDDetWeights
Exclude the PID detector weights for the isolation score definition.
double getIsoScore(const Particle *iParticle) const
Define a semi-continuous variable to quantify the isolation of a standard charged particle in the giv...
DecayDescriptor m_decaydescriptor
< Decay descriptor of decays to look for.
std::unordered_map< std::string, DetSurfCylBoundaries > m_detLayerToSurfBoundaries
Map that associates to each detector layer its valid cylindrical surface's boundaries.
TrackIsoCalculatorModule()
Constructor: Sets the description, the properties and the parameters of the module.
unsigned int m_nLayers
The number of layers for the input detector.
unsigned short m_nSelectedDaughters
The number of selected daughters in the decay string.
StoreObjPtr< ParticleList > m_pListReference
The input ParticleList object of reference tracks.
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.
Definition: Manager.cc:25
REG_MODULE(B2BIIConvertBeamParams)
Register the module.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition: Module.h:560
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23