9#include <analysis/modules/MCMatcherParticles/MCMatcherParticlesModule.h>
12#include <analysis/utility/MCMatching.h>
13#include <analysis/utility/AnalysisConfiguration.h>
16#include <unordered_map>
18typedef std::unordered_map<unsigned int, unsigned int> CounterMap;
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"
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"
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"
50 "- looseMCWrongDaughterPDG: PDG code of the daughter that doesn't originate from\n"
51 " the most common mother (only if looseMCWrongDaughterN = 1)\n"
52 "- looseMCWrongDaughterBiB: 1 if the wrong daughter is Beam Induced Background Particle\n"
54 "Can also perform tag matching for (ccbar) tags. Requires that normal MC\n"
55 "matching has already been performed and set relations.\n"
56 "Low energy photons with energy < 0.1 GeV and ISR are ignored.\n"
57 "The results of (ccbar) tag matching algorithm are stored to the following extraInfo\n"
59 "- ccbarTagSignal: 1st digit is status of signal particle, 2nd digit is Nleft-1, 3rd digit is NextraFSP.\n"
60 "- ccbarTagMCpdg: PDG code of (charm) hadron outside tag (signal side).\n"
61 "- ccbarTagMCpdgMother: PDG code of the mother of the (charm) hadron outside tag (signal side).\n"
62 "- ccbarTagNleft: number of particles (composites have priority) left outisde tag.\n"
63 "- ccbarTagNextraFSP: number of extra FSP particles attached to the tag.\n"
64 "- ccbarTagSignalStatus: status of the targeted signal side particle.\n"
65 "- ccbarTagNwoMC: number of daughters without MC match.\n"
66 "- ccbarTagNwoMCMother: number of daughters without MC mother.\n"
67 "- ccbarTagNnoAllMother: number of daughters without common allmother.\n"
68 "- ccbarTagNmissGamma: number of daughters with missing gamma mc error.\n"
69 "- ccbarTagNmissNeutrino: number of daughters with missing neutrino mc error.\n"
70 "- ccbarTagNdecayInFlight: number of daughters with decay in flight mc error.\n"
71 "- ccbarTagNsevereMCError: number of daughters with severe mc error.\n"
72 "- ccbarTagNmissRecoDaughters: number of daughters with any mc error.\n"
73 "- ccbarTagNleft2ndPDG: PDG of one particle left additionally to the signal particle.\n"
74 "- ccbarTagAllMotherPDG: PDG code of the allmother (Z0 or virtual photon).");
88 B2WARNING(
"No MCParticles array found!"
89 <<
" This is obvously fine if you're analysing real data,"
90 <<
" but you have added the MCMatcher module to your path,"
91 <<
" did you mean to do this?");
101 B2INFO(
"MCMatcher module will search for Particle -> MCParticle associations for the ParticleList " <<
m_listName <<
".");
103 B2INFO(
" - The MCMatcher will use legacy algorithm suitable for analysis of Belle MC.");
105 B2INFO(
" - The MCMatcher will use default algorithm suitable for analysis of Belle II MC.");
115 B2ERROR(
"ParticleList " <<
m_listName <<
" not found");
119 const unsigned int n =
m_plist->getListSize();
120 for (
unsigned i = 0; i < n; i++) {
142 CounterMap motherCount;
144 for (
auto daughter : fsDaughters) {
149 vector<int> genMothers;
152 for (
auto motherIndex : genMothers) {
155 if ((motherPDG == 553) ||
156 (motherPDG == 100553) ||
157 (motherPDG == 200553) ||
158 (motherPDG == 300553) ||
159 (motherPDG == 9000553) ||
160 (motherPDG == 9010553) ||
161 (motherPDG == 10022))
164 motherCount[motherIndex]++;
169 auto commonMother = std::max_element
171 motherCount.begin(), motherCount.end(),
172 [](std::pair <unsigned int, unsigned int> p1, std::pair <unsigned int, unsigned int> p2) {
173 bool returnValue = false;
174 if (p1.second < p2.second)
176 else if (p1.second == p2.second)
177 returnValue = p2.first > p1.first;
184 if (commonMother == motherCount.end()) {
188 thisParticle->
addExtraInfo(
"looseMCWrongDaughterN", -1);
189 thisParticle->
addExtraInfo(
"looseMCWrongDaughterPDG", -1);
190 thisParticle->
addExtraInfo(
"looseMCWrongDaughterBiB", -1);
197 thisParticle->
addExtraInfo(
"looseMCMotherPDG", mcMother->getPDG());
198 thisParticle->
addExtraInfo(
"looseMCMotherIndex", mcMother->getArrayIndex());
199 thisParticle->
addExtraInfo(
"looseMCWrongDaughterN", fsDaughters.size() - commonMother->second);
206 int wrongParticlePDG = 0;
207 int wrongParticleBiB = 0;
208 if (fsDaughters.size() - commonMother->second == 1) {
209 for (
auto daughter : fsDaughters) {
212 wrongParticlePDG = daughter->getPDGCode();
213 wrongParticleBiB = 1;
216 vector<int> genMothers;
220 if (find(genMothers.begin(), genMothers.end(), commonMother->first) != genMothers.end())
224 wrongParticlePDG = daughter->getPDGCode();
228 thisParticle->
addExtraInfo(
"looseMCWrongDaughterPDG", wrongParticlePDG);
229 thisParticle->
addExtraInfo(
"looseMCWrongDaughterBiB", wrongParticleBiB);
236 std::vector<const Particle*>& fspParticles,
237 std::vector<const MCParticle*>& missedParticles
240 bool CaughtAll =
true;
241 bool missedAll =
true;
244 auto it = std::find_if(fspParticles.begin(), fspParticles.end(), [mcDaughter](
const Particle * fsp) { return fsp->getMCParticle() == mcDaughter; });
245 if (it != fspParticles.end()) {
246 fspParticles.erase(it);
249 if (mcDaughter->getPDG() ==
Const::photon.getPDGCode() && (mcDaughter->getEnergy() < 0.1
254 if (abs(mcDaughter->getPDG()) == 21)
continue;
255 if (abs(mcDaughter->getPDG()) == 1)
continue;
256 if (abs(mcDaughter->getPDG()) == 2)
continue;
257 if (abs(mcDaughter->getPDG()) == 3)
continue;
258 if (abs(mcDaughter->getPDG()) == 4)
continue;
259 if (abs(mcDaughter->getPDG()) == 5)
continue;
260 if (abs(mcDaughter->getPDG()) == 6)
continue;
263 else if (mcDaughter->getNDaughters() == 0) {
264 missedParticles.push_back(mcDaughter);
267 std::vector<const MCParticle*> tempMissedParticles;
270 missedParticles.push_back(mcDaughter);
272 }
else if (status == 1) {
277 missedParticles.insert(missedParticles.end(), tempMissedParticles.begin(), tempMissedParticles.end());
284 if (missedAll)
return 0;
285 else if (CaughtAll)
return 1;
292 const std::vector<const Particle*>& fspParticles
295 bool CaughtAll =
true;
296 bool missedAll =
true;
299 && mcDaughter->getEnergy() < 0.1)
continue;
300 auto it = std::find_if(fspParticles.begin(), fspParticles.end(), [mcDaughter](
const Particle * fsp) { return fsp->getMCParticle() == mcDaughter; });
301 if (it != fspParticles.end()) missedAll =
false;
302 else if (mcDaughter->getNDaughters() == 0) CaughtAll =
false;
305 if (status == 0) CaughtAll =
false;
306 else if (status == 1) missedAll =
false;
313 if (missedAll)
return 0;
314 else if (CaughtAll)
return 1;
323 int ccbarTagSignal = 0;
329 for (
int i = 0; i < mcparticles.
getEntries(); i++) {
330 if (abs(mcparticles[i]->getPDG()) == 23 ||
331 abs(mcparticles[i]->getPDG()) == 553 ||
332 abs(mcparticles[i]->getPDG()) == 100553 ||
333 abs(mcparticles[i]->getPDG()) == 200553 ||
334 abs(mcparticles[i]->getPDG()) == 300553 ||
335 abs(mcparticles[i]->getPDG()) == 9000553 ||
336 abs(mcparticles[i]->getPDG()) == 9010553 ||
337 abs(mcparticles[i]->getPDG()) == 10022) {
338 allMother = mcparticles[i];
343 B2WARNING(
"MCMatcherParticlesModule; tag matching - event has no AllMother?");
348 int sigPDGCode = particle->
getPDGCode() * (-1);
350 for (
int i = 0; i < mcparticles.
getEntries(); i++) {
351 if (mcparticles[i]->getPDG() == sigPDGCode) {
353 if (recStatus == 0) {
356 }
else if (recStatus == 2) eventStatus = 2;
357 else if (recStatus == 1 && eventStatus != 2) eventStatus = 3;
360 thisParticle->
addExtraInfo(
"ccbarTagSignalStatus", eventStatus);
361 ccbarTagSignal += eventStatus;
365 std::vector<const MCParticle*> missedParticles;
367 bool foundCharm =
false;
368 for (
auto* mcpart : missedParticles) {
369 int pdg = abs(mcpart->getPDG());
370 if ((pdg > 400 && pdg < 500) || (pdg > 4000 && pdg < 5000) || (pdg > 10400 && pdg < 10500) || (pdg > 20400 && pdg < 20500)) {
372 thisParticle->
addExtraInfo(
"ccbarTagMCpdg", mcpart->getPDG());
374 int mcpartMotherPDG = 0;
375 if (mcpartMother) mcpartMotherPDG = mcpartMother->
getPDG();
376 thisParticle->
addExtraInfo(
"ccbarTagMCpdgMother", mcpartMotherPDG);
384 thisParticle->
addExtraInfo(
"ccbarTagNextraFSP", fspDaughters.size());
385 ccbarTagSignal += 10 * fspDaughters.size();
386 thisParticle->
addExtraInfo(
"ccbarTagNleft", missedParticles.size());
387 ccbarTagSignal += 100 * (missedParticles.size() - 1);
388 thisParticle->
addExtraInfo(
"ccbarTagSignal", ccbarTagSignal);
391 int secondLeftParticle = 0;
392 if (missedParticles.size() == 2) {
393 if (missedParticles[0]->getPDG() == sigPDGCode) secondLeftParticle = missedParticles[1]->getPDG();
394 else if (missedParticles[1]->getPDG() == sigPDGCode) secondLeftParticle = missedParticles[0]->getPDG();
396 thisParticle->
addExtraInfo(
"ccbarTagNleft2ndPDG", secondLeftParticle);
400 int nWOmcParticles = 0;
402 int nNonCommonAllMother = 0;
404 if (!daughter->getMCParticle()) {
408 const MCParticle* curMCMother = daughter->getMCParticle()->getMother();
409 if (curMCMother ==
nullptr) {
415 while (grandMother !=
nullptr) {
416 curMCMother = grandMother;
420 && curMCMother->
getPDG() != 10022) nNonCommonAllMother++;
421 else if (allMother != curMCMother) nNonCommonAllMother++;
423 thisParticle->
addExtraInfo(
"ccbarTagNwoMC", nWOmcParticles);
424 thisParticle->
addExtraInfo(
"ccbarTagNwoMCMother", nWOmother);
425 thisParticle->
addExtraInfo(
"ccbarTagNnoAllMother", nNonCommonAllMother);
428 int nHasMissingGamma = 0;
429 int nHasMissingNeutrino = 0;
430 int nHasDecayInFlight = 0;
431 int nHasSevereMCError = 0;
432 int nMissRecoDaughters = 0;
434 if (daughter->hasExtraInfo(
"ccbarTagNmissRecoDaughters")) {
435 nHasMissingGamma += daughter->getExtraInfo(
"ccbarTagNmissGamma");
436 nHasMissingNeutrino += daughter->getExtraInfo(
"ccbarTagNmissNeutrino");
437 nHasDecayInFlight += daughter->getExtraInfo(
"ccbarTagNdecayInFlight");
438 nHasSevereMCError += daughter->getExtraInfo(
"ccbarTagNsevereMCError");
439 nMissRecoDaughters += daughter->getExtraInfo(
"ccbarTagNmissRecoDaughters");
444 nMissRecoDaughters += 1;
446 nMissRecoDaughters -= 1;
452 else nHasSevereMCError += 1;
454 thisParticle->
addExtraInfo(
"ccbarTagNmissGamma", nHasMissingGamma);
455 thisParticle->
addExtraInfo(
"ccbarTagNmissNeutrino", nHasMissingNeutrino);
456 thisParticle->
addExtraInfo(
"ccbarTagNdecayInFlight", nHasDecayInFlight);
457 thisParticle->
addExtraInfo(
"ccbarTagNsevereMCError", nHasSevereMCError);
458 thisParticle->
addExtraInfo(
"ccbarTagNmissRecoDaughters", nMissRecoDaughters);
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.
static const ParticleType photon
photon particle
void setCCbarTagMatch(const Particle *particle)
Investigates the composition of the tag and remaining signal side and saves the inforamtion to extraI...
int ccbarTagPartialHelper(const MCParticle *mcParticle, std::vector< const Particle * > &fspParticles, std::vector< const MCParticle * > &missedParticles)
returns 1 if the eventParticle daughters were all caught in recParticles, 2 if partially and 0 if non...
virtual void initialize() override
Initialize the Module.
bool m_ccbarTagMatching
perform ccbar tag matching
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.
MCMatcherParticlesModule()
Constructor.
StoreObjPtr< ParticleList > m_plist
the input ParticleList.
A Class to store the Monte Carlo particle information.
@ c_IsISRPhoton
bit 6: Particle is from initial state radiation
std::vector< Belle2::MCParticle * > getDaughters() const
Get vector of all daughter particles, empty vector if none.
int getPDG() const
Return PDG code of particle.
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.
std::vector< const Particle * > getFinalStateDaughters() const
Returns a vector of pointers to Final State daughter 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.
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
std::vector< Particle * > getDaughters() const
Returns a vector of pointers to daughter particles.
int getArrayIndex() const
Returns this object's array index (in StoreArray), or -1 if not found.
Accessor to arrays stored in the data store.
int getEntries() const
Get the number of objects in the array.
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.
MCParticle * getMother() const
Returns a pointer to the mother particle.
Abstract base class for different kinds of events.
static bool setMCTruth(const Particle *particle)
This is the main function of MC matching algorithm.
@ c_MissFSR
A Final State Radiation (FSR) photon is not reconstructed (based on MCParticle::c_IsFSRPhoton).
@ c_MissNeutrino
A neutrino is missing (not reconstructed).
@ c_Correct
This Particle and all its daughters are perfectly reconstructed.
@ c_DecayInFlight
A Particle was reconstructed from the secondary decay product of the actual particle.
@ c_MissingResonance
The associated MCParticle decay contained additional non-final-state particles (e....
@ c_MissPHOTOS
A photon created by PHOTOS was not reconstructed (based on MCParticle::c_IsPHOTOSPhoton)
@ c_MissGamma
A photon (not FSR) is missing (not reconstructed).
static void fillGenMothers(const MCParticle *mcP, std::vector< int > &genMCPMothers)
Fills vector with array (1-based) indices of all generator ancestors of given MCParticle.
static int getMCErrors(const Particle *particle, const MCParticle *mcParticle=nullptr)
Returns quality indicator of the match as a bit pattern where the individual bits indicate the the ty...