Belle II Software  release-08-01-10
ParticleStatsModule.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/ParticleStats/ParticleStatsModule.h>
10 #include <analysis/dataobjects/ParticleList.h>
11 #include <framework/core/Environment.h>
12 #include <framework/datastore/StoreObjPtr.h>
13 #include <nlohmann/json.hpp>
14 #include <fstream>
15 
16 
17 using namespace Belle2;
18 
19 // Register module in the framework
20 REG_MODULE(ParticleStats);
21 
23 {
24  // Set module properties and parameters
25  setDescription("Make a summary of specific ParticleLists.");
26  addParam("outputFile", m_outputFile, "Name of output file", std::string());
27  addParam("printPassMatrix", m_printPassMatrix, "Should we also calculate and print the pass matrix?", true);
28  addParam("particleLists", m_strParticleLists, "List of ParticleLists", std::vector<std::string>());
29 }
30 
32 {
33  m_particles.isRequired();
35 
36  // check all particle lists are valid
37  for (unsigned i = 0; i < m_nLists; ++i) {
38  bool valid = m_decaydescriptor.init(m_strParticleLists[i]);
39  if (!valid)
40  B2ERROR("Invalid input list name: " << m_strParticleLists[i]);
41 
43  B2ERROR("ParticleStatsModule::initialize Invalid input DecayString " << m_strParticleLists[i]
44  << ". DecayString should not contain any daughters, only the mother particle.");
45  }
46  B2INFO("Number of ParticleLists to be studied: " << m_nLists << " ");
47 
48  m_PassMatrix = new TMatrix(m_nLists, m_nLists + 1);
49  m_MultiplicityMatrix = new TMatrix(m_nLists, 4); // 0 All particles; 1 Negative; 2 Positive; 3 SelfConjugated
50 }
51 
53 {
54  bool unique = true;
55  bool pass = false;
56 
57  // first loop over all particle lists we are interested in
58  for (unsigned iList = 0; iList < m_nLists; ++iList) {
59 
60  // check that the list exists and is not empty
61  StoreObjPtr<ParticleList> particlelist(m_strParticleLists[iList]);
62  if (!particlelist) {
63  B2ERROR("ParticleListi " << m_strParticleLists[iList] << " not found");
64  continue;
65  }
66  if (!particlelist->getListSize()) continue;
67 
68  pass = true;
69 
70  /**************************************************************************
71  * For the multiplicity table, count the number of candidates in each
72  * list. Add to the total for all events processed so far.
73  */
74 
75  // all particles and anti-particles, or self-conjugate
76  (*m_MultiplicityMatrix)(iList, 0) = (*m_MultiplicityMatrix)(iList, 0)
77  + particlelist->getNParticlesOfType(ParticleList::c_FlavorSpecificParticle)
78  + particlelist->getNParticlesOfType(ParticleList::c_FlavorSpecificParticle, true)
79  + particlelist->getNParticlesOfType(ParticleList::c_SelfConjugatedParticle);
80 
81  // particles alone
82  if (particlelist->getNParticlesOfType(ParticleList::c_FlavorSpecificParticle))
83  (*m_MultiplicityMatrix)(iList, 1) = (*m_MultiplicityMatrix)(iList, 1)
84  + particlelist->getNParticlesOfType(ParticleList::c_FlavorSpecificParticle);
85 
86  // anti-particles alone
87  if (particlelist->getNParticlesOfType(ParticleList::c_FlavorSpecificParticle, true))
88  (*m_MultiplicityMatrix)(iList, 2) = (*m_MultiplicityMatrix)(iList, 2)
89  + particlelist->getNParticlesOfType(ParticleList::c_FlavorSpecificParticle, true);
90 
91  // self-conjugate particles alone
92  if (particlelist->getNParticlesOfType(ParticleList::c_SelfConjugatedParticle))
93  (*m_MultiplicityMatrix)(iList, 3) = (*m_MultiplicityMatrix)(iList, 3)
94  + particlelist->getNParticlesOfType(ParticleList::c_SelfConjugatedParticle);
95 
96  /**************************************************************************
97  * Now, loop again over all particle lists to fill the pass matrix for this
98  * event. Add to the totals for all events processed so far.
99  */
100  for (unsigned jList = 0; jList < m_nLists; ++jList) {
101 
102  // check that the list exists and is not empty
103  StoreObjPtr<ParticleList> particlelistj(m_strParticleLists[jList]);
104  if (!particlelistj) {
105  B2INFO("ParticleListj " << m_strParticleLists[jList] << " not found");
106  continue;
107  }
108  if (!particlelistj->getListSize()) continue;
109 
110  // if the event passed both the i and j list selection then increment
111  (*m_PassMatrix)(iList, jList) = (*m_PassMatrix)(iList, jList) + 1.;
112  if (iList != jList) unique = false;
113 
114  } // end inner loop over all particle lists
115 
116  if (unique)(*m_PassMatrix)(iList, m_nLists) = (*m_PassMatrix)(iList, m_nLists) + 1.;
117 
118  } // end outer loop over all particle lists
119 
120  // finally count the particles created in this event, and the number of events
121  // passing any of the list selections that we were interested in
122  m_nParticles += m_particles.getEntries();
123  if (pass) m_nPass++;
124 }
125 
126 // finish up the calculation and print a table to B2INFO
128 {
129  auto nEvents = (float)Environment::Instance().getNumberOfEvents();
130  B2INFO("ParticleStats Summary:");
131  std::ostringstream stream;
132 
133  nlohmann::json json;
134 
135  // divide every entry of the pass matrix by the number of events processed
136  // (entrywise) to get the fraction of events
137  for (unsigned iList = 0; iList < m_nLists; ++iList)
138  for (unsigned jList = 0; jList < m_nLists + 1; ++jList)
139  (*m_PassMatrix)(iList, jList) = (*m_PassMatrix)(iList, jList) / nEvents;
140 
141  for (unsigned iList = 0; iList < m_nLists; ++iList)
142  for (unsigned jList = 0; jList < m_nLists + 1; ++jList)
143  if (iList != jList && (*m_PassMatrix)(iList, iList) > 0.)
144  (*m_PassMatrix)(iList, jList) = (*m_PassMatrix)(iList, jList) / (*m_PassMatrix)(iList, iList) ;
145 
146  if (m_printPassMatrix && m_nLists > 1) {
147 
148  // format the pass matrix table
149  stream << "=======================================================================\n";
150  stream << " Pass matrix (for i, j: fraction passing selection i also passes selection j)\n\n";
151  stream << " ";
152 
153  // table headings
154  for (unsigned iList = 0; iList < m_nLists; ++iList)
155  stream << "|" << Form(" %5d", iList);
156  stream << "| Unique|\n";
157 
158  // table data
159  for (unsigned iList = 0; iList < m_nLists; ++iList) {
160  // first column is particle list name
161  stream << Form("%14s(%2d)", m_strParticleLists[iList].c_str(), iList) << "|";
162  // next N columns are particle list survival fractions (need to use tabs here)
163  for (unsigned jList = 0; jList < m_nLists + 1; ++jList) { // matrix
164  if (iList != jList) {
165  stream << Form(" %6.4f|", (*m_PassMatrix)(iList, jList));
166  std::string jName = (jList < m_nLists ? m_strParticleLists[jList].c_str() : "Unique");
167  json["Pass matrix"][m_strParticleLists[iList].c_str()][jName.c_str()] = (*m_PassMatrix)(iList, jList);
168  }
169  if (iList == jList) {
170  stream << Form(" %6.4f|", 1.0);
171  json["Pass matrix"][m_strParticleLists[iList].c_str()][m_strParticleLists[jList].c_str()] = 1.0;
172  }
173 
174  }
175  stream << "\n";
176  }
177  B2INFO(stream.str()); // print the pass matrix table
178 
179 
180  } // end if
181 
182  // clear the stream and format the multiplicity table
183  stream.str("");
184  stream << "\n======================================================================\n";
185  stream << " Average Candidate Multiplicity (ACM) and ACM for Passed Events (ACMPE) \n\n";
186 
187  // table headings
188  stream << " | All Particles | Particles | Anti-particles | Self-conjugates |\n";
189  stream << " | Retention| ACM| ACMPE| ACM| ACMPE| ACM| ACMPE| ACM| ACMPE|\n";
190 
191  // table data
192  for (unsigned iList = 0; iList < m_nLists; ++iList) {
193  // first column is particle list name
194  stream << Form("%14s(%2d)", m_strParticleLists[iList].c_str(), iList) << "|";
195  // second column is retention (no need to use tabs here because it can't be
196  // more than 1.{followed by 4 digits})
197  stream << Form(" %6.4f|", (*m_PassMatrix)(iList, iList));
198 
199  std::string pName = m_strParticleLists[iList].c_str();
200  float retRate = (*m_PassMatrix)(iList, iList);
201  json["Retention"][pName]["Retention"] = retRate;
202  std::string flavs[4] = {"All Particles", "Particles", "Anti Particles", "Self-conjugates"};
203  // now the ACM and ACMPE
204  for (int iFlav = 0; iFlav < 4; ++iFlav) {
205  stream << Form(" %8.4f|", (*m_MultiplicityMatrix)(iList, iFlav) / nEvents);
206  json["Retention"][pName][Form("%s ACM", flavs[iFlav].c_str())] = (*m_MultiplicityMatrix)(iList, iFlav) / nEvents;
207 
208  stream << Form(" %8.4f|", (*m_MultiplicityMatrix)(iList, iFlav) / nEvents / (*m_PassMatrix)(iList, iList));
209  json["Retention"][pName][Form("%s ACPME", flavs[iFlav].c_str())] = (*m_MultiplicityMatrix)(iList,
210  iFlav) / nEvents / (*m_PassMatrix)(iList,
211  iList);
212  }
213  stream << "\n";
214  }
215  B2INFO(stream.str()); // print the multiplicity table
216 
217  // now print some global information
218  stream.str("");
219  stream << "\n======================================================================\n";
220  stream << "Total Retention: " << m_nPass << " events passing / " << nEvents << " events processed = " << Form("%6.4f\n",
221  (float)m_nPass / (float)nEvents);
222  stream << "Total Number of Particles created in the DataStore: " << m_nParticles;
223  stream << "\n======================================================================\n";
224  json["Total retention"] = m_nPass / nEvents;
225  json["Events passing"] = m_nPass;
226  json["Events processed"] = nEvents;
227  json["Total particles number"] = m_nParticles;
228  B2INFO(stream.str());
229  if (m_outputFile != "") {
230  std::ofstream jsonFile(m_outputFile);
231  jsonFile << json.dump(2) << std::endl;
232  }
233 
234  delete m_PassMatrix;
235  delete m_MultiplicityMatrix;
236 }
bool init(const std::string &str)
Initialise the DecayDescriptor from given string.
int getNDaughters() const
return number of direct daughters.
unsigned int getNumberOfEvents() const
Return the number of events, from either input or EventInfoSetter, or -n command line override (if le...
Definition: Environment.cc:39
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:28
Base class for Modules.
Definition: Module.h:72
void setDescription(const std::string &description)
Sets the description of the module.
Definition: Module.cc:214
TMatrix * m_PassMatrix
Pass matrix for the particle lists.
TMatrix * m_MultiplicityMatrix
Particle multiplicities for the particle lists.
bool m_printPassMatrix
Shall we also calculate and print out the pass matrix?
virtual void initialize() override
Initialises the module.
virtual void event() override
Fill the particle stats matrices for each event.
std::string m_outputFile
Name of output file.
StoreArray< Particle > m_particles
StoreArray of Particles.
virtual void terminate() override
Print out the arrays as a table in B2INFO.
std::vector< std::string > m_strParticleLists
The particle lists to produce statistics about.
int m_nParticles
Count the total number of particles.
unsigned m_nLists
The number of particle lists.
int m_nPass
Number of events with Particle candidates.
DecayDescriptor m_decaydescriptor
Decay descriptor of the particle being selected.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
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.