Belle II Software development
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
24using namespace Belle2;
25
26//-----------------------------------------------------------------
27// Register the Module
28//-----------------------------------------------------------------
29REG_MODULE(PrintMCParticles);
30
31//-----------------------------------------------------------------
32// Implementation
33//-----------------------------------------------------------------
34
35namespace {
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
163void 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
171void 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.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
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.