Belle II Software light-2607-kasei
ParticleMCDecayStringModule.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/ParticleMCDecayString/ParticleMCDecayStringModule.h>
10
11#include <analysis/dataobjects/Particle.h>
12
13#include <mdst/dataobjects/MCParticle.h>
14
15#include <framework/logging/Logger.h>
16#include <framework/pcore/ProcHandler.h>
17#include <framework/utilities/RootFileCreationManager.h>
18
19#include <string>
20#include <vector>
21
22#include <boost/algorithm/string.hpp>
23
24using namespace Belle2;
25
26REG_MODULE(ParticleMCDecayString);
27
29 DataStore::c_Persistent), m_decayHash(0.0), m_decayHashExtended(0.0)
30{
31 setDescription("Creates the Monte Carlo decay string of a Particle and its daughters. "
32 "The MC decay string of the particle is hashed and saved as a 32bit pattern in the extra info field decayHash of the particle. "
33 "The MC decay string of the particle + its daughters is hashed as well and saved as another 32bit pattern in the extra info field decayHashExtended of the particle. "
34 "The mapping hash <-> MC decay string in saved in a TTree by this module. "
35 "The 32bit pattern must be saved as a float (because our extra info field, variable manager and ntuple output only supports float) "
36 "but they just represent 32 bits of a hash! "
37 "The MC decay string can also be stored in an analysis ROOT file using the MCDecayString NtupleTool. ");
39 addParam("listName", m_listName, "Particles from these ParticleList are used as input.");
40 addParam("fileName", m_fileName, "Filename in which the hash strings are saved, if empty the strings are not saved",
41 std::string(""));
42 addParam("treeName", m_treeName, "Tree name in which the hash strings are saved", std::string("hashtable"));
43 addParam("conciseString", m_useConciseString, "If set to true, the code will use a more concise format for the string.", false);
44 addParam("identifiers", m_identifiers, "Identifiers used to identify particles in the concise format.",
45 std::string("abcdefghijklmnopqrstuvwxyz"));
46}
47
49{
50 m_pList.isRequired(m_listName);
51
52 //This might not work for non-default names of Particle array:
54
55 m_stringWrapperArray.registerInDataStore();
57
58
59 // Initializing the output root file
60 if (m_fileName != "") {
62 if (!m_file) {
63 B2WARNING("Could not create file " << m_fileName);
64 return;
65 }
66
67 m_file->cd();
68
69 // check if TTree with that name already exists
70 if (m_file->Get(m_treeName.c_str())) {
71 B2WARNING("Tree with this name already exists: " << m_fileName);
72 return;
73 }
74
76 m_tree.construct(m_treeName.c_str(), "Decay Hash Map");
77 m_tree->get().Branch("decayHash", &m_decayHash);
78 m_tree->get().Branch("decayHashExtended", &m_decayHashExtended);
79 m_tree->get().Branch("decayString", &m_decayString);
80 m_tree->get().SetBasketSize("*", 1600);
81 m_tree->get().SetCacheSize(100000);
82 }
83
84 m_hashset.registerInDataStore(m_fileName + m_treeName + "_hashset", DataStore::c_DontWriteOut);
85 m_hashset.construct();
86
87}
88
90{
91
92 for (unsigned iParticle = 0; iParticle < m_pList->getListSize(); ++iParticle) {
93 Particle* particle = m_pList->getParticle(iParticle);
94
95 const std::string decayString = getMCDecayStringFromMCParticle(particle->getRelatedTo<MCParticle>());
96 std::string decayStringExtended = getDecayString(*particle); //removed const to allow string to be modified to a different format.
97
98 if (m_useConciseString) {convertToConciseString(decayStringExtended);}
99
100 uint32_t decayHash = m_hasher(decayString);
101 uint32_t decayHashExtended = m_hasher(decayStringExtended);
102
103 uint64_t m_decayHashFull = decayHash;
104 m_decayHashFull <<= 32;
105 m_decayHashFull += decayHashExtended;
106
107 // Convert unsigned int decay hash into a float keeping the same bit pattern
108 assert(sizeof(float) == sizeof(uint32_t));
109
110 union convert {
111 uint32_t i;
112 float f;
113 };
114 convert bitconverter;
115
116 bitconverter.i = decayHash;
117 m_decayHash = bitconverter.f;
119
120 bitconverter.i = decayHashExtended;
121 m_decayHashExtended = bitconverter.f;
123
124 m_decayString = decayStringExtended;
125
126 StringWrapper* stringWrapper = m_stringWrapperArray.appendNew();
127 particle->addRelationTo(stringWrapper);
128 stringWrapper->setString(m_decayString);
129
130 auto it = m_hashset->get().find(m_decayHashFull);
131 if (it == m_hashset->get().end()) {
132 m_hashset->get().insert(m_decayHashFull);
133
134 if (m_tree.isValid()) {
135 m_tree->get().Fill();
136 }
137 }
138
139 }
140}
141
143{
145 if (m_tree.isValid()) {
146 B2INFO("Writing NTuple " << m_treeName);
147 TDirectory::TContext directoryGuard(m_file.get());
148 m_tree->write(m_file.get());
149
150 const bool writeError = m_file->TestBit(TFile::kWriteError);
151 m_file.reset();
152 if (writeError) {
153 B2FATAL("A write error occurred while saving '" << m_fileName << "', please check if enough disk space is available.");
154 }
155 }
156 }
157}
158
159
161{
162 const MCParticle* mcPMother = mcP->getMother();
163 if (mcPMother == nullptr) {
164 return mcP;
165 } else {
167 }
168}
169
171bool isFSP(int pdg)
172{
173 switch (abs(pdg)) {
174 case 211: //pi^+
175 case 321: //K^+
176 case 11: //e
177 case 12: //nu_e
178 case 13: //mu
179 case 14: //nu_mu
180 case 16: //nu_tau
181 case 22: //gamma
182 case 310: //K_S
183 case 130: //K_L
184 case 2112: //n
185 case 2212: //p
186 return true;
187 default:
188 return false;
189 }
190}
191
193{
194
195 std::string output;
196 output += getDecayStringFromParticle(&p) + " | ";
197 output += getMCDecayStringFromParticle(&p);
198 return output;
199
200}
201
203{
204
205 std::string output = " ";
206
207 output += std::to_string(p->getPDGCode());
208
209 if (not isFSP(p->getPDGCode())) {
210 output += " (-->";
211 for (const auto* daughter : p->getDaughters()) {
212 output += getDecayStringFromParticle(daughter);
213 }
214 output += ")";
215 }
216
217 return output;
218
219}
220
222{
223
224 std::string output;
225
226 output = getMCDecayStringFromMCParticle(p->getRelatedTo<MCParticle>());
227 // Some FSPs can have daughters, e.g. converted Photons and K-Shorts
228 if (not isFSP(p->getPDGCode())) {
229 for (const auto* daughter : p->getDaughters()) {
230 output += " | " + getMCDecayStringFromParticle(daughter);
231 }
232 }
233
234 return output;
235
236}
237
239{
240
241 if (mcPMatched == nullptr)
242 return "(No match)";
243
244 // TODO Performance can be optimized, this mcPMother does not change during the construction
245 const MCParticle* mcPMother = getInitialParticle(mcPMatched);
246
247 std::string decayString = buildMCDecayString(mcPMother, mcPMatched);
248
249 if (mcPMatched->getPDG() == 10022)
250 return decayString + " (Virtual gamma match)";
251 return decayString;
252}
253
254
255std::string ParticleMCDecayStringModule::buildMCDecayString(const MCParticle* mcPMother, const MCParticle* mcPMatched)
256{
257
258 std::stringstream ss;
259 ss << " ";
260 if (mcPMother->getArrayIndex() == mcPMatched->getArrayIndex()) {
261 ss << "^";
262 }
263
264 ss << mcPMother->getPDG();
265
266 if (not isFSP(mcPMother->getPDG())) {
267 ss << " (-->";
268 for (const auto* daughter : mcPMother->getDaughters()) {
269 ss << buildMCDecayString(daughter, mcPMatched);
270 }
271 ss << ")";
272 }
273
274 return ss.str();
275}
276
278{
279
280 std::vector<std::string> decayStrings;
281 boost::split(decayStrings, string, boost::is_any_of("|"));
282
283 if (decayStrings.empty()) {
284 B2WARNING("ParticleMCDecayStringModule: unable to convert decay string to concise format.");
285 return;
286 }
287
288 unsigned int nParticles(decayStrings.size() - 1);
289 if (nParticles > m_identifiers.size()) {
290 B2WARNING("ParticleMCDecayStringModule: not enough identifiers have been specified to use the concise string format:"
291 << std::endl << "Number of particles in your decay mode = " << nParticles << std::endl
292 << "Available identifiers: " << m_identifiers << std::endl
293 << "Standard format will be used instead.");
294 return;
295 }
296
297 //Find positions of carets in original strings, store them, and then erase them.
298 std::string mode("");
299 std::vector<int> caretPositions;
300 for (auto& decayString : decayStrings) {
301 std::string thisString(decayString);
302 if ("" == mode) {
303 mode = thisString;
304 continue;
305 }
306
307 int caretPosition(thisString.find('^')); // -1 if no match.
308 caretPositions.push_back(caretPosition);
309 if (caretPosition > -1) {
310 decayString.erase(caretPosition, 1);
311 }
312 }
313
314 //Check if all of the decay strings are the same (except for No matches):
315 std::string theDecayString("");
316 for (auto thisString : decayStrings) {
317 if (thisString == mode) {continue;}
318
319 //last decay string does not have a space at the end, don't want this to stop a match.
320 char finalChar(thisString.back());
321 if (finalChar != ' ') {thisString = thisString + " ";}
322
323 if (" (No match) " != thisString) {
324 if ("" == theDecayString) {
325 theDecayString = thisString;
326 } else {
327 if (theDecayString != thisString) {
328 //TODO: add string format if multiple decay strings are present (e.g. pile-up events).
329 return;
330 }
331 }
332 }
333 }
334
335 std::string modifiedString(theDecayString);
336
337 //insert identifiers in positions where carets were:
338 int nStrings(caretPositions.size());
339 for (int iString(0); iString < nStrings; ++iString) {
340 std::string identifier(m_identifiers.substr(iString, 1));
341 int insertPosition(caretPositions.at(iString));
342 if (insertPosition > -1) {
343 for (int jString(0); jString < iString; ++jString) {
344 if (caretPositions.at(jString) > -1 && caretPositions.at(jString) <= caretPositions.at(iString)) {
345 ++insertPosition;
346 }
347 }
348 modifiedString.insert(insertPosition, identifier);
349 }
350 }
351
352 modifiedString = mode + "|" + modifiedString;
353
354 //add a list of the unmatched particles at the end of the string:
355 bool noMatchStringAdded(false);
356 for (int iString(0); iString < nStrings; ++iString) {
357 int insertPosition(caretPositions.at(iString));
358 if (-1 == insertPosition) {
359 if (!noMatchStringAdded) {
360 modifiedString += " | No match: ";
361 noMatchStringAdded = true;
362 }
363 modifiedString += m_identifiers.substr(iString, 1);
364 }
365 }
366
367 string = modifiedString;
368 return;
369}
In the store you can park objects that have to be accessed by various modules.
Definition DataStore.h:51
@ c_DontWriteOut
Object/array should be NOT saved by output modules.
Definition DataStore.h:71
A Class to store the Monte Carlo particle information.
Definition MCParticle.h:32
std::vector< Belle2::MCParticle * > getDaughters() const
Get vector of all daughter particles, empty vector if none.
Definition MCParticle.cc:50
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition MCParticle.h:234
int getPDG() const
Return PDG code of particle.
Definition MCParticle.h:101
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
Module()
Constructor.
Definition Module.cc:30
@ 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
@ c_TerminateInAllProcesses
When using parallel processing, call this module's terminate() function in all processes().
Definition Module.h:83
float m_decayHash
Decay hash -> The hash of the decay string of the mother particle.
static std::string getDecayStringFromParticle(const Particle *p)
get decay string of particle
virtual void initialize() override
Initialize the module.
const std::string c_ExtraInfoName
Name of the extraInfo, which is stored in each Particle.
virtual void event() override
Called for each event.
std::string m_decayString
The complete decay string.
std::string m_listName
Name of the particle list.
virtual void terminate() override
Terminate modules.
std::string m_fileName
Filename in which the hash strings are saved, if empty the strings are not saved.
static std::string getMCDecayStringFromMCParticle(const MCParticle *mcPMatched)
get mc decay string from mc particle
std::hash< std::string > m_hasher
Hash function.
bool m_useConciseString
Switch to use concise format for the extended string.
StoreObjPtr< RootMergeable< TTree > > m_tree
ROOT TNtuple containing the saved hashes and strings.
std::shared_ptr< TFile > m_file
ROOT file to store the hashes and strings.
const std::string c_ExtraInfoNameExtended
Name of the extraInfo, which is stored in each Particle.
StoreObjPtr< SetMergeable< std::unordered_set< uint64_t > > > m_hashset
Mergeable unordered set containing the encountered hashes.
StoreArray< StringWrapper > m_stringWrapperArray
StoreArray of StringWrappers.
std::string m_treeName
Tree name in which the hash strings are saved.
std::string m_identifiers
Characters used to identify particles in the concise decay string format (default: alphabet).
void convertToConciseString(std::string &string)
Convert the extended string to a more concise format.
static std::string buildMCDecayString(const MCParticle *mcPMother, const MCParticle *mcPMatched)
return decay string for mcPMother, highlight mcPMatched.
static const MCParticle * getInitialParticle(const MCParticle *mcP)
search from mcP upwards for a particle that matches specified mother PDG codes.
float m_decayHashExtended
Extended decay hash -> The hash of the decay string of all daughter particles.
std::string getMCDecayStringFromParticle(const Particle *p)
get mc decay string from particle
StoreObjPtr< ParticleList > m_pList
input particle list
std::string getDecayString(const Particle &p)
get the decay string for p.
Class to store reconstructed particles.
Definition Particle.h:76
void addExtraInfo(const std::string &name, double value)
Sets the user-defined data of given name to the given value.
Definition Particle.cc:1421
static bool isOutputProcess()
Return true if the process is an output process.
static bool parallelProcessingUsed()
Returns true if multiple processes have been spawned, false in single-core mode.
void addRelationTo(const RelationsInterface< BASE > *object, float weight=1.0, const std::string &namedRelation="") const
Add a relation from this object to another object (with caching).
TO * getRelatedTo(const std::string &name="", const std::string &namedRelation="") const
Get the object to which this object has a relation.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Accessor to arrays stored in the data store.
Definition StoreArray.h:113
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition StoreArray.h:140
This class is a wrapper for strings, such as MCDecayStrings, to allow them to be associated with part...
void setString(const std::string &inputstring)
Set string.
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:559
std::shared_ptr< TFile > getFile(const std::string &, bool ignoreErrors=false)
Get a file with a specific name, if is does not exist it will be created.
static RootFileCreationManager & getInstance()
Interface for the FileManager.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
MCParticle * getMother() const
Returns a pointer to the mother particle.
Definition MCParticle.h:591
Abstract base class for different kinds of events.