Belle II Software  release-08-01-10
PrintMCParticlesModule.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/PrintMCParticles/PrintMCParticlesModule.h>
10 #include <analysis/dataobjects/StringWrapper.h>
11 
12 #include <mdst/dataobjects/MCParticle.h>
13 
14 #include <framework/geometry/B2Vector3.h>
15 
16 #include <framework/logging/LogConnectionConsole.h>
17 
18 #include <boost/format.hpp>
19 #include <boost/algorithm/string.hpp>
20 
21 #include <TDatabasePDG.h>
22 #include <Math/Vector3D.h>
23 
24 using namespace Belle2;
25 
26 //-----------------------------------------------------------------
27 // Register the Module
28 //-----------------------------------------------------------------
29 REG_MODULE(PrintMCParticles);
30 
31 //-----------------------------------------------------------------
32 // Implementation
33 //-----------------------------------------------------------------
34 
35 namespace {
37  std::string statusToString(const MCParticle& mc)
38  {
39  static std::map<int, std::string> names {
40  {MCParticle::c_PrimaryParticle, "PrimaryParticle"},
41  {MCParticle::c_StableInGenerator, "StableInGenerator"},
42  {MCParticle::c_LeftDetector, "LeftDetector"},
43  {MCParticle::c_StoppedInDetector, "StoppedInDetector"},
44  {MCParticle::c_IsVirtual, "IsVirtual"},
45  {MCParticle::c_Initial, "Initial"},
46  {MCParticle::c_IsISRPhoton, "IsISRPhoton"},
47  {MCParticle::c_IsFSRPhoton, "IsFSRPhoton"},
48  {MCParticle::c_IsPHOTOSPhoton, "IsPHOTOSPhoton"},
49  };
50  std::vector<std::string> set;
51  for (auto&& [status, name] : names) {
52  if (mc.hasStatus(status)) set.emplace_back(name);
53  }
54  return boost::join(set, ", ");
55  }
56 
58  std::string g4ProcessToName(int process)
59  {
60  static std::map<int, std::string> translation{
61  {1, "CoulombScattering"},
62  {2, "Ionisation"},
63  {3, "Bremsstrahlung"},
64  {4, "PairProdByCharged"},
65  {5, "Annihilation"},
66  {6, "AnnihilationToMuMu"},
67  {7, "AnnihilationToHadrons"},
68  {8, "NuclearStopping"},
69  {9, "ElectronGeneralProcess"},
70  {10, "MultipleScattering"},
71  {11, "Rayleigh"},
72  {12, "PhotoElectricEffect"},
73  {13, "ComptonScattering"},
74  {14, "GammaConversion"},
75  {15, "GammaConversionToMuMu"},
76  {16, "GammaGeneralProcess"},
77  {17, "PositronGeneralProcess"},
78  {18, "AnnihilationToTauTau"},
79  {21, "Cerenkov"},
80  {22, "Scintillation"},
81  {23, "SynchrotronRadiation"},
82  {24, "TransitionRadiation"},
83  {25, "SurfaceReflection"},
84  {40, "DarkBremsstrahlung"},
85  {49, "MuonPairProdByCharged"},
86  {111, "HadronElastic"},
87  {116, "NeutronGeneral"},
88  {121, "HadronInelastic"},
89  {131, "Capture"},
90  {132, "MuAtomicCapture"},
91  {141, "Fission"},
92  {151, "HadronAtRest"},
93  {152, "LeptonAtRest"},
94  {161, "ChargeExchange"},
95  // {210, "RadioactiveDecay"},
96  {201, "Decay"},
97  {202, "Decay_WithSpin"},
98  {203, "Decay_PionMakeSpin"},
99  {210, "Decay_Radioactive"},
100  {211, "Decay_Unknown"},
101  {221, "Decay_MuAtom "},
102  {231, "Decay_External"},
103  {310, "EMDissociation"},
104  };
105  if (auto it = translation.find(process); it != translation.end()) {
106  return it->second;
107  }
108  return "[Unknown process]";
109  }
110 }
111 
113 {
114  //Set module properties
115  setDescription("Print an MCParticle List");
116 
117  //Parameter definition
118  addParam("storeName", m_particleList, "Name of the StoreArray to print", m_particleList);
119  addParam("onlyPrimaries", m_onlyPrimaries, "Show only primary particles", true);
120  addParam("maxLevel", m_maxLevel, "Show only up to specified depth level, -1 means no limit", -1);
121  addParam("showVertices", m_showVertices, "Show also the particle production vertices and times", false);
122  addParam("showMomenta", m_showMomenta, "Show also the particle momenta", false);
123  addParam("showProperties", m_showProperties, "Show the basic particle properties", false);
124  addParam("showStatus", m_showStatus, "Show extendend status information of the particle", false);
125  addParam("suppressPrint", m_suppressPrint, "Suppress print the information", false);
126 }
127 
129 {
131  m_stringWrapper.registerInDataStore("MCDecayString");
132 }
133 
135 {
136  // clear any previous outputs
137  m_output.str(std::string());
138 
139  if (not m_particleList.empty()) {
140  m_output << "Content from MCParticle list '" << m_mcparticles.getName() << "'" << std::endl;
141  } else {
142  m_output << "Content of MCParticle list" << std::endl;
143  }
144 
145  //Loop over the top level particles (no mother particle exists)
146  std::vector<MCParticle*> first_gen;
147  for (MCParticle& mc : m_mcparticles) {
148  if (mc.getMother() != nullptr) continue;
149  first_gen.emplace_back(&mc);
150  }
151  filterPrimaryOnly(first_gen);
152  printTree(first_gen);
153 
154  if (!m_suppressPrint)
155  B2INFO(m_output.str());
156 
157  if (not m_stringWrapper.isValid())
158  m_stringWrapper.create();
159 
160  m_stringWrapper->setString(std::string(m_output.str()));
161 }
162 
163 void PrintMCParticlesModule::filterPrimaryOnly(std::vector<MCParticle*>& particles) const
164 {
165  if (!m_onlyPrimaries or particles.empty()) return;
166  particles.erase(std::remove_if(particles.begin(), particles.end(), [](MCParticle * mc) {
167  return not mc->hasStatus(MCParticle::c_PrimaryParticle);
168  }), particles.end());
169 }
170 
171 void PrintMCParticlesModule::printTree(const std::vector<MCParticle*>& particles, int level, const std::string& indent)
172 {
173  //If we show extra content make the particle name and pdg code bold if supported
174  //And if we also show secondaries make those red to distinguish
175  const bool useColor = LogConnectionConsole::terminalSupportsColors(STDOUT_FILENO);
176  const bool anyExtraInfo = m_showProperties or m_showMomenta or m_showVertices or m_showStatus;
177  std::string colorStart[] = {"", ""};
178  std::string colorEnd = "";
179  if (useColor) {
180  // make it bold if we have extra info, otherwise no need
181  colorStart[0] = anyExtraInfo ? "\x1b[31;1m" : "\x1b[31m";
182  colorStart[1] = anyExtraInfo ? "\x1b[1m" : "";
183  colorEnd = "\x1b[m";
184  }
185 
186  TDatabasePDG* pdb = TDatabasePDG::Instance();
187 
188  // ok, go over all particles and print them
189  const auto num_particles = particles.size();
190  size_t particle_index{0};
191  for (const auto* mc : particles) {
192  // are we the last in the list? if so we need a different box char
193  const bool last = ++particle_index == num_particles;
194  m_output << indent << (last ? "╰" : "├");
195  m_output << (mc->hasStatus(MCParticle::c_PrimaryParticle) ? "── " : "╶╶ ");
196  // now print the name and pdg code. Optionally with color
197  TParticlePDG* pdef = pdb->GetParticle(mc->getPDG());
198  m_output << colorStart[mc->hasStatus(MCParticle::c_PrimaryParticle)] << (pdef ? pdef->GetTitle() : "[UNKNOWN]");
199  m_output << " (" << mc->getPDG() << ")" << colorEnd;
200 
201  // Particle itself is done but we might need to show more things like properties and daughters so ...
202  auto daughters = mc->getDaughters();
203  filterPrimaryOnly(daughters);
204  const bool showDaughters = (not daughters.empty()) and (m_maxLevel <= 0 or level < m_maxLevel);
205 
206  // new indent level for any information related to this particle.
207  const std::string newIndent = indent + (last ? " " : "│") + " ";
208  // and the indent level for any properties associated to this particle
209  const std::string propIndent = "\n" + newIndent + (showDaughters ? "│ " : "");
210  // limited by level restriction? add an indicator that something is skipped
211  if ((not showDaughters) and (not daughters.empty())) {
212  m_output << " → …";
213  }
214  // Now show whatever the user wants
215  if (m_showProperties) {
216  m_output << propIndent;
217  m_output << boost::format("mass=%.3g energy=%.3g charge=%d") % mc->getMass() % mc->getEnergy() % mc->getCharge();
218  if (not mc->hasStatus(MCParticle::c_LeftDetector)) m_output << boost::format(" lifetime=%.3g") % mc->getLifetime();
219  }
220  if (m_showMomenta) {
221  const B2Vector3F& p = mc->getMomentum();
222  m_output << propIndent;
223  m_output << boost::format("p=(%.3g, %.3g, %.3g) |p|=%.3g") % p.X() % p.Y() % p.Z() % p.Mag();
224  }
225  if (m_showVertices) {
226  const ROOT::Math::XYZVector& v = mc->getVertex();
227  m_output << propIndent;
228  m_output << boost::format("production vertex=(%.3g, %.3g, %.3g), time=%.3g") % v.X() % v.Y() % v.Z() % mc->getProductionTime();
229  }
230  if (m_showStatus) {
231  m_output << propIndent;
232  m_output << "status flags=" << statusToString(*mc);
233  if (not mc->hasStatus(MCParticle::c_PrimaryParticle)) {
234  m_output << propIndent;
235  m_output << "creation process=" << g4ProcessToName(mc->getSecondaryPhysicsProcess());
236  }
237  m_output << propIndent;
238  m_output << "list index=" << mc->getIndex();
239  }
240  // and if we have shown any extra info and have daughters leave a blank line
241  if (showDaughters and anyExtraInfo) m_output << propIndent;
242  // now we're done with the particle ...
243  m_output << std::endl;
244  // but maybe we need to show the daughters
245  if (showDaughters) {
246  printTree(daughters, level + 1, newIndent);
247  }
248  // and if we show any extra info also leave blank line to sibling
249  if (anyExtraInfo and not last) m_output << newIndent << std::endl;
250  }
251 }
static bool terminalSupportsColors(int fileDescriptor)
Returns true if the given file descriptor is a tty and supports colors.
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
@ c_IsFSRPhoton
bit 7: Particle is from finial state radiation
Definition: MCParticle.h:61
@ c_Initial
bit 5: Particle is initial such as e+ or e- and not going to Geant4
Definition: MCParticle.h:57
@ c_IsPHOTOSPhoton
bit 8: Particle is an radiative photon from PHOTOS
Definition: MCParticle.h:63
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:47
@ c_LeftDetector
bit 2: Particle left the detector (the simulation volume).
Definition: MCParticle.h:51
@ c_IsVirtual
bit 4: Particle is virtual and not going to Geant4.
Definition: MCParticle.h:55
@ c_StableInGenerator
bit 1: Particle is stable, i.e., not decaying in the generator.
Definition: MCParticle.h:49
@ c_StoppedInDetector
bit 3: Particle was stopped in the detector (the simulation volume).
Definition: MCParticle.h:53
@ c_IsISRPhoton
bit 6: Particle is from initial state radiation
Definition: MCParticle.h:59
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
std::stringstream m_output
Buffer to keep all the output while building the tree.
virtual void initialize() override
init.
bool m_showProperties
Show remaining properties.
virtual void event() override
Method is called for each event.
StoreArray< MCParticle > m_mcparticles
store array for the MCParticles
bool m_showStatus
Show extended status information.
int m_maxLevel
Show only up to specified depth level.
bool m_showVertices
Show particle production vertices.
void filterPrimaryOnly(std::vector< MCParticle * > &particles) const
if m_onlyPrimary is set remove all non primary particles from the given vector inplace
StoreObjPtr< StringWrapper > m_stringWrapper
string wrapper to store the MCDecayString
void printTree(const std::vector< MCParticle * > &particles, int level=1, const std::string &indent="")
Loops recursively over the MCParticle list and prints information about each particle.
bool m_showMomenta
Show particle momenta.
std::string m_particleList
The name of the MCParticle collection.
bool m_suppressPrint
Suppress print the information.
bool m_onlyPrimaries
Print only primary particles.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
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
Abstract base class for different kinds of events.