Belle II Software  release-06-00-14
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 
11 #include <mdst/dataobjects/MCParticle.h>
12 
13 #include <framework/logging/LogConnectionConsole.h>
14 
15 #include <boost/format.hpp>
16 #include <boost/algorithm/string.hpp>
17 
18 #include <TDatabasePDG.h>
19 
20 using namespace Belle2;
21 
22 //-----------------------------------------------------------------
23 // Register the Module
24 //-----------------------------------------------------------------
25 REG_MODULE(PrintMCParticles)
26 
27 //-----------------------------------------------------------------
28 // Implementation
29 //-----------------------------------------------------------------
30 
31 namespace {
33  std::string statusToString(const MCParticle& mc)
34  {
35  static std::map<int, std::string> names {
36  {MCParticle::c_PrimaryParticle, "PrimaryParticle"},
37  {MCParticle::c_StableInGenerator, "StableInGenerator"},
38  {MCParticle::c_LeftDetector, "LeftDetector"},
39  {MCParticle::c_StoppedInDetector, "StoppedInDetector"},
40  {MCParticle::c_IsVirtual, "IsVirtual"},
41  {MCParticle::c_Initial, "Initial"},
42  {MCParticle::c_IsISRPhoton, "IsISRPhoton"},
43  {MCParticle::c_IsFSRPhoton, "IsFSRPhoton"},
44  {MCParticle::c_IsPHOTOSPhoton, "IsPHOTOSPhoton"},
45  };
46  std::vector<std::string> set;
47  for (auto && [status, name] : names) {
48  if (mc.hasStatus(status)) set.emplace_back(name);
49  }
50  return boost::join(set, ", ");
51  }
52 
54  std::string g4ProcessToName(int process)
55  {
56  // Just copy all the values from the enums given by MCParticle.h documentation ...
57  // This was made from the externals version v01-09-01 so we might
58  static std::map<int, std::string> translation{
59  {1, "CoulombScattering"},
60  {2, "Ionisation"},
61  {3, "Bremsstrahlung"},
62  {4, "PairProdByCharged"},
63  {5, "Annihilation"},
64  {6, "AnnihilationToMuMu"},
65  {7, "AnnihilationToHadrons"},
66  {8, "NuclearStopping"},
67  {9, "ElectronGeneralProcess"},
68  {10, "MultipleScattering"},
69  {11, "Rayleigh"},
70  {12, "PhotoElectricEffect"},
71  {13, "ComptonScattering"},
72  {14, "GammaConversion"},
73  {15, "GammaConversionToMuMu"},
74  {16, "GammaGeneralProcess"},
75  {21, "Cerenkov"},
76  {22, "Scintillation"},
77  {23, "SynchrotronRadiation"},
78  {24, "TransitionRadiation"},
79  {111, "HadronElastic"},
80  {121, "HadronInelastic"},
81  {131, "Capture"},
82  {132, "MuAtomicCapture"},
83  {141, "Fission"},
84  {151, "HadronAtRest"},
85  {152, "LeptonAtRest"},
86  {161, "ChargeExchange"},
87  {210, "RadioactiveDecay"},
88  {201, "Decay"} ,
89  {202, "Decay_WithSpin"} ,
90  {203, "Decay_PionMakeSpin"} ,
91  {210, "Decay_Radioactive"},
92  {211, "Decay_Unknown"},
93  {221, "Decay_MuAtom "},
94  {231, "Decay_External"},
95  };
96  if (auto it = translation.find(process); it != translation.end()) {
97  return it->second;
98  }
99  return "[Unknown process]";
100  }
101 }
102 
104 {
105  //Set module properties
106  setDescription("Print an MCParticle List");
107 
108  //Parameter definition
109  addParam("storeName", m_particleList, "Name of the StoreArray to print", m_particleList);
110  addParam("onlyPrimaries", m_onlyPrimaries, "Show only primary particles", true);
111  addParam("maxLevel", m_maxLevel, "Show only up to specified depth level, -1 means no limit", -1);
112  addParam("showVertices", m_showVertices, "Show also the particle production vertices and times", false);
113  addParam("showMomenta", m_showMomenta, "Show also the particle momenta", false);
114  addParam("showProperties", m_showProperties, "Show the basic particle properties", false);
115  addParam("showStatus", m_showStatus, "Show extendend status information of the particle", false);
116 }
117 
119 {
121 }
122 
124 {
125  // clear any previous outputs
126  m_output.str(std::string());
127 
128  if (not m_particleList.empty()) {
129  m_output << "Content from MCParticle list '" << m_mcparticles.getName() << "'" << std::endl;
130  } else {
131  m_output << "Content of MCParticle list" << std::endl;
132  }
133 
134  //Loop over the top level particles (no mother particle exists)
135  std::vector<MCParticle*> first_gen;
136  for (MCParticle& mc : m_mcparticles) {
137  if (mc.getMother() != nullptr) continue;
138  first_gen.emplace_back(&mc);
139  }
140  filterPrimaryOnly(first_gen);
141  printTree(first_gen);
142 
143  B2INFO(m_output.str());
144 }
145 
146 void PrintMCParticlesModule::filterPrimaryOnly(std::vector<MCParticle*>& particles) const
147 {
148  if (!m_onlyPrimaries or particles.empty()) return;
149  particles.erase(std::remove_if(particles.begin(), particles.end(), [](MCParticle * mc) {
150  return not mc->hasStatus(MCParticle::c_PrimaryParticle);
151  }), particles.end());
152 }
153 
154 void PrintMCParticlesModule::printTree(const std::vector<MCParticle*>& particles, int level, const std::string& indent)
155 {
156  //If we show extra content make the particle name and pdg code bold if supported
157  //And if we also show secondaries make those red to distinguish
158  const bool useColor = LogConnectionConsole::terminalSupportsColors(STDOUT_FILENO);
159  const bool anyExtraInfo = m_showProperties or m_showMomenta or m_showVertices or m_showStatus;
160  std::string colorStart[] = {"", ""};
161  std::string colorEnd = "";
162  if (useColor) {
163  // make it bold if we have extra info, otherwise no need
164  colorStart[0] = anyExtraInfo ? "\x1b[31;1m" : "\x1b[31m";
165  colorStart[1] = anyExtraInfo ? "\x1b[1m" : "";
166  colorEnd = "\x1b[m";
167  }
168 
169  TDatabasePDG* pdb = TDatabasePDG::Instance();
170 
171  // ok, go over all particles and print them
172  const auto num_particles = particles.size();
173  size_t particle_index{0};
174  for (const auto* mc : particles) {
175  // are we the last in the list? if so we need a different box char
176  const bool last = ++particle_index == num_particles;
177  m_output << indent << (last ? "╰" : "├");
178  m_output << (mc->hasStatus(MCParticle::c_PrimaryParticle) ? "── " : "╶╶ ");
179  // now print the name and pdg code. Optionally with color
180  TParticlePDG* pdef = pdb->GetParticle(mc->getPDG());
181  m_output << colorStart[mc->hasStatus(MCParticle::c_PrimaryParticle)] << (pdef ? pdef->GetTitle() : "[UNKNOWN]");
182  m_output << " (" << mc->getPDG() << ")" << colorEnd;
183 
184  // Particle itself is done but we might need to show more things like properties and daughters so ...
185  auto daughters = mc->getDaughters();
186  filterPrimaryOnly(daughters);
187  const bool showDaughters = (not daughters.empty()) and (m_maxLevel <= 0 or level < m_maxLevel);
188 
189  // new indent level for any information related to this particle.
190  const std::string newIndent = indent + (last ? " " : "│") + " ";
191  // and the indent level for any properties associated to this particle
192  const std::string propIndent = "\n" + newIndent + (showDaughters ? "│ " : "");
193  // limited by level restriction? add an indicator that something is skipped
194  if ((not showDaughters) and (not daughters.empty())) {
195  m_output << " → …";
196  }
197  // Now show whatever the user wants
198  if (m_showProperties) {
199  m_output << propIndent;
200  m_output << boost::format("mass=%.3g energy=%.3g charge=%d") % mc->getMass() % mc->getEnergy() % mc->getCharge();
201  if (not mc->hasStatus(MCParticle::c_LeftDetector)) m_output << boost::format(" lifetime=%.3g") % mc->getLifetime();
202  }
203  if (m_showMomenta) {
204  const TVector3& p = mc->getMomentum();
205  m_output << propIndent;
206  m_output << boost::format("p=(%.3g, %.3g, %.3g) |p|=%.3g") % p.X() % p.Y() % p.Z() % p.Mag();
207  }
208  if (m_showVertices) {
209  const TVector3& v = mc->getVertex();
210  m_output << propIndent;
211  m_output << boost::format("production vertex=(%.3g, %.3g, %.3g), time=%.3g") % v.X() % v.Y() % v.Z() % mc->getProductionTime();
212  }
213  if (m_showStatus) {
214  m_output << propIndent;
215  m_output << "status flags=" << statusToString(*mc);
216  if (not mc->hasStatus(MCParticle::c_PrimaryParticle)) {
217  m_output << propIndent;
218  m_output << "creation process=" << g4ProcessToName(mc->getSecondaryPhysicsProcess());
219  }
220  m_output << propIndent;
221  m_output << "list index=" << mc->getIndex();
222  }
223  // and if we have shown any extra info and have daughters leave a blank line
224  if (showDaughters and anyExtraInfo) m_output << propIndent;
225  // now we're done with the particle ...
226  m_output << std::endl;
227  // but maybe we need to show the daughters
228  if (showDaughters) {
229  printTree(daughters, level + 1, newIndent);
230  }
231  // and if we show any extra info also leave blank line to sibling
232  if (anyExtraInfo and not last) m_output << newIndent << std::endl;
233  }
234 }
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
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_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.
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
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
Abstract base class for different kinds of events.