Belle II Software  release-08-01-10
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 <mdst/dataobjects/MCParticle.h>
12 
13 #include <framework/logging/Logger.h>
14 #include <framework/pcore/ProcHandler.h>
15 
16 #include <string>
17 #include <vector>
18 
19 #include <boost/algorithm/string.hpp>
20 
21 using namespace Belle2;
22 
23 REG_MODULE(ParticleMCDecayString);
24 
25 ParticleMCDecayStringModule::ParticleMCDecayStringModule() : Module(), m_tree("", DataStore::c_Persistent), m_hashset("",
26  DataStore::c_Persistent), m_decayHash(0.0), m_decayHashExtended(0.0)
27 {
28  setDescription("Creates the Monte Carlo decay string of a Particle and its daughters. "
29  "The MC decay string of the particle is hashed and saved as a 32bit pattern in the extra info field decayHash of the particle. "
30  "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. "
31  "The mapping hash <-> MC decay string in saved in a TTree by this module. "
32  "The 32bit pattern must be saved as a float (because our extra info field, variable manager and ntuple output only supports float) "
33  "but they just represent 32 bits of a hash! "
34  "The MC decay string can also be stored in an analysis ROOT file using the MCDecayString NtupleTool. "
35  "Details on the MC decay string format can be found here: `MCDecayString`");
37  addParam("listName", m_listName, "Particles from these ParticleList are used as input.");
38  addParam("fileName", m_fileName, "Filename in which the hash strings are saved, if empty the strings are not saved",
39  std::string(""));
40  addParam("treeName", m_treeName, "Tree name in which the hash strings are saved", std::string("hashtable"));
41  addParam("conciseString", m_useConciseString, "If set to true, the code will use a more concise format for the string.", false);
42  addParam("identifiers", m_identifiers, "Identifiers used to identify particles in the concise format.",
43  std::string("abcdefghijklmnopqrstuvwxyz"));
44 
45  m_file = nullptr;
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 != "") {
61  m_file = new TFile(m_fileName.c_str(), "RECREATE");
62  if (!m_file->IsOpen()) {
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 
75  m_tree.registerInDataStore(m_fileName + m_treeName, DataStore::c_DontWriteOut);
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;
118  particle->addExtraInfo(c_ExtraInfoName, m_decayHash);
119 
120  // cppcheck doesn't like this use of union and throws warnings
121  // cppcheck-suppress redundantAssignment
122  bitconverter.i = decayHashExtended;
123  m_decayHashExtended = bitconverter.f;
124  particle->addExtraInfo(c_ExtraInfoNameExtended, m_decayHashExtended);
125 
126  m_decayString = decayStringExtended;
127 
128  StringWrapper* stringWrapper = m_stringWrapperArray.appendNew();
129  particle->addRelationTo(stringWrapper);
130  stringWrapper->setString(m_decayString);
131 
132  auto it = m_hashset->get().find(m_decayHashFull);
133  if (it == m_hashset->get().end()) {
134  m_hashset->get().insert(m_decayHashFull);
135 
136  if (m_tree.isValid()) {
137  m_tree->get().Fill();
138  }
139  }
140 
141  }
142 }
143 
145 {
147  if (m_tree.isValid()) {
148  B2INFO("Writing NTuple " << m_treeName);
149  m_tree->write(m_file);
150 
151  const bool writeError = m_file->TestBit(TFile::kWriteError);
152  if (writeError) {
153  //m_file deleted first so we have a chance of closing it (though that will probably fail)
154  delete m_file;
155  B2FATAL("A write error occurred while saving '" << m_fileName << "', please check if enough disk space is available.");
156  }
157 
158  B2INFO("Closing file " << m_fileName);
159  delete m_file;
160  }
161  }
162 }
163 
164 
166 {
167  const MCParticle* mcPMother = mcP->getMother();
168  if (mcPMother == nullptr) {
169  return mcP;
170  } else {
171  return getInitialParticle(mcPMother);
172  }
173 }
174 
176 bool isFSP(int pdg)
177 {
178  switch (abs(pdg)) {
179  case 211: //pi^+
180  case 321: //K^+
181  case 11: //e
182  case 12: //nu_e
183  case 13: //mu
184  case 14: //nu_mu
185  case 16: //nu_tau
186  case 22: //gamma
187  case 310: //K_S
188  case 130: //K_L
189  case 2112: //n
190  case 2212: //p
191  return true;
192  default:
193  return false;
194  }
195 }
196 
198 {
199 
200  std::string output;
201  output += getDecayStringFromParticle(&p) + " | ";
202  output += getMCDecayStringFromParticle(&p);
203  return output;
204 
205 }
206 
208 {
209 
210  std::string output = " ";
211 
212  output += std::to_string(p->getPDGCode());
213 
214  if (not isFSP(p->getPDGCode())) {
215  output += " (-->";
216  for (auto daughter : p->getDaughters()) {
217  output += getDecayStringFromParticle(daughter);
218  }
219  output += ")";
220  }
221 
222  return output;
223 
224 }
225 
227 {
228 
229  std::string output;
230 
231  output = getMCDecayStringFromMCParticle(p->getRelatedTo<MCParticle>());
232  // Some FSPs can have daughters, e.g. converted Photons and K-Shorts
233  if (not isFSP(p->getPDGCode())) {
234  for (auto& daughter : p->getDaughters()) {
235  output += " | " + getMCDecayStringFromParticle(daughter);
236  }
237  }
238 
239  return output;
240 
241 }
242 
244 {
245 
246  if (mcPMatched == nullptr)
247  return "(No match)";
248 
249  // TODO Performance can be optimized, this mcPMother does not change during the construction
250  const MCParticle* mcPMother = getInitialParticle(mcPMatched);
251 
252  std::string decayString = buildMCDecayString(mcPMother, mcPMatched);
253 
254  if (mcPMatched->getPDG() == 10022)
255  return decayString + " (Virtual gamma match)";
256  return decayString;
257 }
258 
259 
260 std::string ParticleMCDecayStringModule::buildMCDecayString(const MCParticle* mcPMother, const MCParticle* mcPMatched)
261 {
262 
263  std::stringstream ss;
264  ss << " ";
265  if (mcPMother->getArrayIndex() == mcPMatched->getArrayIndex()) {
266  ss << "^";
267  }
268 
269  ss << mcPMother->getPDG();
270 
271  if (not isFSP(mcPMother->getPDG())) {
272  ss << " (-->";
273  for (auto daughter : mcPMother->getDaughters()) {
274  ss << buildMCDecayString(daughter, mcPMatched);
275  }
276  ss << ")";
277  }
278 
279  return ss.str();
280 }
281 
283 {
284 
285  std::vector<std::string> decayStrings;
286  boost::split(decayStrings, string, boost::is_any_of("|"));
287 
288  if (decayStrings.empty()) {
289  B2WARNING("ParticleMCDecayStringModule: unable to convert decay string to concise format.");
290  return;
291  }
292 
293  unsigned int nParticles(decayStrings.size() - 1);
294  if (nParticles > m_identifiers.size()) {
295  B2WARNING("ParticleMCDecayStringModule: not enough identifiers have been specified to use the concise string format:"
296  << std::endl << "Number of particles in your decay mode = " << nParticles << std::endl
297  << "Available identifiers: " << m_identifiers << std::endl
298  << "Standard format will be used instead.");
299  return;
300  }
301 
302  //Find positions of carets in original strings, store them, and then erase them.
303  std::string mode("");
304  std::vector<int> caretPositions;
305  for (auto& decayString : decayStrings) {
306  std::string thisString(decayString);
307  if ("" == mode) {
308  mode = thisString;
309  continue;
310  }
311 
312  int caretPosition(thisString.find('^')); // -1 if no match.
313  caretPositions.push_back(caretPosition);
314  if (caretPosition > -1) {
315  decayString.erase(caretPosition, 1);
316  }
317  }
318 
319  //Check if all of the decay strings are the same (except for No matches):
320  std::string theDecayString("");
321  for (auto thisString : decayStrings) {
322  if (thisString == mode) {continue;}
323 
324  //last decay string does not have a space at the end, don't want this to stop a match.
325  char finalChar(thisString.back());
326  if (finalChar != ' ') {thisString = thisString + " ";}
327 
328  if (" (No match) " != thisString) {
329  if ("" == theDecayString) {
330  theDecayString = thisString;
331  } else {
332  if (theDecayString != thisString) {
333  //TODO: add string format if multiple decay strings are present (e.g. pile-up events).
334  return;
335  }
336  }
337  }
338  }
339 
340  std::string modifiedString(theDecayString);
341 
342  //insert identifiers in positions where carets were:
343  int nStrings(caretPositions.size());
344  for (int iString(0); iString < nStrings; ++iString) {
345  std::string identifier(m_identifiers.substr(iString, 1));
346  int insertPosition(caretPositions.at(iString));
347  if (insertPosition > -1) {
348  for (int jString(0); jString < iString; ++jString) {
349  if (caretPositions.at(jString) > -1 && caretPositions.at(jString) <= caretPositions.at(iString)) {
350  ++insertPosition;
351  }
352  }
353  modifiedString.insert(insertPosition, identifier);
354  }
355  }
356 
357  modifiedString = mode + "|" + modifiedString;
358 
359  //add a list of the unmatched particles at the end of the string:
360  bool noMatchStringAdded(false);
361  for (int iString(0); iString < nStrings; ++iString) {
362  int insertPosition(caretPositions.at(iString));
363  if (-1 == insertPosition) {
364  if (!noMatchStringAdded) {
365  modifiedString += " | No match: ";
366  noMatchStringAdded = true;
367  }
368  modifiedString += m_identifiers.substr(iString, 1);
369  }
370  }
371 
372  string = modifiedString;
373  return;
374 }
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:52
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition: MCParticle.h:244
int getPDG() const
Return PDG code of particle.
Definition: MCParticle.h:112
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
@ 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.
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.
std::string getMCDecayStringFromMCParticle(const MCParticle *mcPMatched)
get mc decay string from mc particle
std::hash< std::string > m_hasher
Hash function.
TFile * m_file
ROOT file to store the hashes and strings.
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.
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.
std::string buildMCDecayString(const MCParticle *mcPMother, const MCParticle *mcPMatched)
return decay string for mcPMother, highlight mcPMatched.
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:75
static bool isOutputProcess()
Return true if the process is an output process.
Definition: ProcHandler.cc:232
static bool parallelProcessingUsed()
Returns true if multiple processes have been spawned, false in single-core mode.
Definition: ProcHandler.cc:226
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...
Definition: StringWrapper.h:23
void setString(const std::string &inputstring)
Set string.
Definition: StringWrapper.h:41
REG_MODULE(arichBtest)
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
MCParticle * getMother() const
Returns a pointer to the mother particle.
Definition: MCParticle.h:600
Abstract base class for different kinds of events.