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