Belle II Software  release-08-01-10
MCMatcherParticlesModule.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/MCMatcherParticles/MCMatcherParticlesModule.h>
10 
11 // utility
12 #include <analysis/utility/MCMatching.h>
13 #include <analysis/utility/AnalysisConfiguration.h>
14 
15 // map
16 #include <unordered_map>
17 #include <algorithm>
18 typedef std::unordered_map<unsigned int, unsigned int> CounterMap;
19 
20 using namespace std;
21 using namespace Belle2;
22 
23 //-----------------------------------------------------------------
24 // Register module
25 //-----------------------------------------------------------------
26 
27 REG_MODULE(MCMatcherParticles);
28 
29 //-----------------------------------------------------------------
30 // Implementation
31 //-----------------------------------------------------------------
32 
33 MCMatcherParticlesModule::MCMatcherParticlesModule() : Module()
34 {
35  setDescription("Performs MC matching (sets relation Particle->MCParticle) for all particles\n"
36  "(and its (grand)^N-daughter particles) in the ParticleList. The relation can\n"
37  "be used in conjunction with MCMatching::MCErrorFlags flags, e.g. using the\n"
38  "isSignal or mcPDG & mcErrors variables.\n"
39  "\n"
40  "In addition to the usual mc matching algorithm the module can run also loose mc\n"
41  "matching. The difference between loose and normal mc matching algorithm is that\n"
42  "the loose algorithm will find the common mother of the majority of daughter\n"
43  "particles while the normal algorithm finds the common mother of all daughters.\n"
44  "The results of loose mc matching algorithm are stored to the following extraInfo\n"
45  "items:\n\n"
46  " - looseMCMotherPDG: PDG code of most common mother\n"
47  " - looseMCMotherIndex: 1-based StoreArray<MCParticle> index of most common mother\n"
48  " - looseMCWrongDaughterN: number of daughters that don't originate from the most\n"
49  " common mother\n"
50  " - looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from\n"
51  " the most common mother \n"
52  " (only if looseMCWrongDaughterN = 1)\n"
53  " - looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background\n"
54  " Particle\n\n");
55 
57 
58  addParam("listName", m_listName, "Name of the input ParticleList.");
59  addParam("looseMCMatching", m_looseMatching, "Perform loose mc matching", false);
60 }
61 
62 
64 {
65  // check that there are MCParticles: shout if not
66  if (!m_mcparticles.isValid()) {
67  B2WARNING("No MCParticles array found!"
68  << " This is obvously fine if you're analysing real data,"
69  << " but you have added the MCMatcher module to your path,"
70  << " did you mean to do this?");
71  return;
72  }
73 
74  // if we have MCParticles then continue with the initialisation
75  m_particles.isRequired();
76  m_particles.registerRelationTo(m_mcparticles);
77  m_plist.isRequired(m_listName);
78 
79  bool legacyAlgorithm = AnalysisConfiguration::instance()->useLegacyMCMatching();
80  B2INFO("MCMatcher module will search for Particle -> MCParticle associations for the ParticleList " << m_listName << ".");
81  if (legacyAlgorithm)
82  B2INFO(" - The MCMatcher will use legacy algorithm suitable for analysis of Belle MC.");
83  else
84  B2INFO(" - The MCMatcher will use default algorithm suitable for analysis of Belle II MC.");
85 }
86 
87 
89 {
90  // if no MCParticles then silently skip
91  if (!m_mcparticles.isValid())
92  return;
93  if (!m_plist) {
94  B2ERROR("ParticleList " << m_listName << " not found");
95  return;
96  }
97 
98  const unsigned int n = m_plist->getListSize();
99  for (unsigned i = 0; i < n; i++) {
100  const Particle* part = m_plist->getParticle(i);
101 
103 
104  if (m_looseMatching)
105  setLooseMCMatch(part);
106  }
107 }
108 
110 {
111  if (particle->hasExtraInfo("looseMCMotherPDG")) // nothing to do; already set
112  return;
113 
114  // get all FS daughters
115  vector<const Belle2::Particle*> fsDaughters = particle->getFinalStateDaughters();
116 
117  // map for counting how many times given mcparticle is mother of daughters
118  CounterMap motherCount;
119 
120  for (auto daughter : fsDaughters) {
121  const MCParticle* mcDaughter = daughter->getRelatedTo<MCParticle>();
122  if (!mcDaughter)
123  continue;
124 
125  vector<int> genMothers;
126  MCMatching::fillGenMothers(mcDaughter, genMothers);
127 
128  for (auto motherIndex : genMothers) {
129  // exclude ROOT particles: Upsilon(nS), virtual photon
130  int motherPDG = m_mcparticles[motherIndex - 1]->getPDG();
131  if ((motherPDG == 553) ||
132  (motherPDG == 100553) ||
133  (motherPDG == 200553) ||
134  (motherPDG == 300553) ||
135  (motherPDG == 9000553) ||
136  (motherPDG == 9010553) ||
137  (motherPDG == 10022))
138  continue;
139 
140  motherCount[motherIndex]++;
141  }
142  }
143 
144  // find first most common mother
145  auto commonMother = std::max_element
146  (
147  std::begin(motherCount), std::end(motherCount),
148  [](std::pair <unsigned int, unsigned int> p1, std::pair <unsigned int, unsigned int> p2) {
149  bool returnValue = false;
150  if (p1.second < p2.second)
151  returnValue = true;
152  else if (p1.second == p2.second)
153  returnValue = p2.first > p1.first;
154 
155  return returnValue;
156  }
157  );
158 
159  // No common mother found, all daughters have no associated MC Particle
160  if (commonMother == std::end(motherCount)) {
161  Particle* thisParticle = m_particles[particle->getArrayIndex()];
162  thisParticle->addExtraInfo("looseMCMotherPDG", -1);
163  thisParticle->addExtraInfo("looseMCMotherIndex", -1);
164  thisParticle->addExtraInfo("looseMCWrongDaughterN", -1);
165  thisParticle->addExtraInfo("looseMCWrongDaughterPDG", -1);
166  thisParticle->addExtraInfo("looseMCWrongDaughterBiB", -1);
167  return;
168  }
169 
170  const MCParticle* mcMother = m_mcparticles[commonMother->first - 1];
171 
172  Particle* thisParticle = m_particles[particle->getArrayIndex()];
173  thisParticle->addExtraInfo("looseMCMotherPDG", mcMother->getPDG());
174  thisParticle->addExtraInfo("looseMCMotherIndex", mcMother->getArrayIndex());
175  thisParticle->addExtraInfo("looseMCWrongDaughterN", fsDaughters.size() - commonMother->second);
176 
177  // find out what kind of particle was wrongly added
178  // only for the case where there is only one such particle
179  // This is the most interesting case. If two or more
180  // particles are wrongly added, then a candidate looks
181  // like background
182  int wrongParticlePDG = 0; // PDG code of the wrongly matched particle
183  int wrongParticleBiB = 0; // true (false) if particle doesn't (does) have MCParticle relation
184  if (fsDaughters.size() - commonMother->second == 1) {
185  for (auto daughter : fsDaughters) {
186  const MCParticle* mcDaughter = daughter->getRelatedTo<MCParticle>();
187  if (!mcDaughter) {
188  wrongParticlePDG = daughter->getPDGCode();
189  wrongParticleBiB = 1;
190  }
191 
192  vector<int> genMothers;
193  MCMatching::fillGenMothers(mcDaughter, genMothers);
194 
195  // check if current daughter descends from common mother
196  if (find(genMothers.begin(), genMothers.end(), commonMother->first) != genMothers.end())
197  continue;
198 
199  // daughter is not a child of common mother
200  wrongParticlePDG = daughter->getPDGCode();
201  }
202  }
203 
204  thisParticle->addExtraInfo("looseMCWrongDaughterPDG", wrongParticlePDG);
205  thisParticle->addExtraInfo("looseMCWrongDaughterBiB", wrongParticleBiB);
206 
207 }
void useLegacyMCMatching(const bool flag)
Determines whether to use the legacy MCMatching algorithm (true) or not (false).
static AnalysisConfiguration * instance()
Returns a pointer to the singleton instance.
virtual void initialize() override
Initialize the Module.
virtual void event() override
Event processor.
StoreArray< MCParticle > m_mcparticles
the array of MCParticles.
std::string m_listName
steering variable: name of the input ParticleList
StoreArray< Particle > m_particles
the array of Particles.
bool m_looseMatching
perform loose mc matching
void setLooseMCMatch(const Particle *particle)
Finds common mother of the majority of daughters.
StoreObjPtr< ParticleList > m_plist
the input ParticleList.
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition: Module.cc:208
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition: Module.h:80
Class to store reconstructed particles.
Definition: Particle.h:75
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition: Particle.cc:1337
bool isValid() const
Check wether the array was registered.
Definition: StoreArray.h:288
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
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.
static bool setMCTruth(const Belle2::Particle *particle)
This is the main function of MC matching algorithm.
Definition: MCMatching.cc:86
static void fillGenMothers(const Belle2::MCParticle *mcP, std::vector< int > &genMCPMothers)
Fills vector with array (1-based) indices of all generator ancestors of given MCParticle.
Definition: MCMatching.cc:61