Belle II Software  release-06-00-14
PhaseSpaceAnalysisModule.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 <tracking/modules/spacePointCreator/PhaseSpaceAnalysisModule.h>
10 
11 #include <genfit/TrackCand.h>
12 #include <tracking/spacePointCreation/SpacePointTrackCand.h>
13 
14 #include <framework/datastore/StoreArray.h>
15 #include <framework/dataobjects/EventMetaData.h>
16 #include <framework/datastore/StoreObjPtr.h>
17 
18 #include <algorithm>
19 #include <numeric>
20 // #include <mdst/dataobjects/MCParticle.h> // already in header
21 
22 #include <TVector3.h> // COULDDO: B2Vector3.h
23 
24 using namespace std;
25 using namespace Belle2;
26 
27 REG_MODULE(PhaseSpaceAnalysis)
28 
30 {
31  setDescription("Module for analysing the phase space covered by TrackCands (resp. their related MCParticles)");
32 
33  std::vector<std::string> defaultNames = { std::string("") };
34  addParam("containerNames", m_PARAMcontainerNames, "Collection names of trackCands to be analized.", defaultNames);
35  addParam("trackCandTypes", m_PARAMtrackCandTypes, "Either 'GFTC' for genfit::TrackCand or 'SPTC' for SpacePointTrackCand." \
36  "If there are more 'containerNames' than 'trackCandTypes' the last type is assumed for all the names that cannot be matched"\
37  "one-to-one with a trackCandType. If there are as much names as types the i-th name is assumed to be of the i-th type");
38 
39  addParam("diffAnalysis", m_PARAMdiffAnalysis,
40  "Use the first container as reference and only collect data for those MCParticle that"\
41  " cannot be found in the other containers.", false);
42 
43  std::vector<std::string> defaultRootFName = { "PhaseSpaceAnalysis", "RECREATE" };
44  addParam("rootFileName", m_PARAMrootFileName, "Name of the output root file without '.root' file ending + write mode"\
45  " ('UPDATE' or 'RECREATE')", defaultRootFName);
46 
47  // initialize pointers to nullptr (cppcheck)
48  m_rootFilePtr = nullptr;
49  initializeCounters(0);
50 }
51 
52 // ===================================================== INITIALIZE ===============================================================
53 void PhaseSpaceAnalysisModule::initialize()
54 {
55  B2INFO("PhaseSpaceAnalysis ------------------------ initialize --------------------------");
56 
57  StoreArray<MCParticle> mcParticles;
58  mcParticles.isRequired();
59 
60  size_t nNames = m_PARAMcontainerNames.size();
61  size_t nTypes = m_PARAMtrackCandTypes.size();
62 
63  if (nTypes > nNames) { B2FATAL("Passed " << nTypes << " trackCandTypese but only " << nNames << " containerNames!"); }
64 
65  for (size_t iName = 0; iName < nNames; ++iName) {
66  size_t iType = iName < nTypes ? iName : nTypes - 1; // only acces values that are possible
67  string tcType = m_PARAMtrackCandTypes.at(iType);
68  if (tcType.compare(string("GFTC")) != 0 && tcType.compare(string("SPTC")) != 0) {
69  B2FATAL("Found id " << tcType << " in 'trackCandTypes' but only 'GFTC' and 'SPTC' are allowed!");
70  }
71 
72  string contName = m_PARAMcontainerNames.at(iName);
73  if (tcType.compare(string("GFTC")) == 0) {
74  StoreArray<genfit::TrackCand> trackCands(contName);
75  trackCands.isRequired();
76  m_tcStoreArrays.push_back(make_pair(trackCands, c_gftc));
77  } else {
78  StoreArray<SpacePointTrackCand> trackCands(contName);
79  trackCands.isRequired();
80  m_tcStoreArrays.push_back(make_pair(trackCands, c_sptc));
81  }
82  if (m_PARAMrootFileName.size() != 2 || (m_PARAMrootFileName[1] != "UPDATE" && m_PARAMrootFileName[1] != "RECREATE")) {
83  string output;
84  for (string id : m_PARAMrootFileName) {
85  output += "'" + id + "' ";
86  }
87  B2FATAL("PhaseSpaceAnalysis::initialize() : rootFileName is set wrong: entries are: " << output);
88  }
89 
90  m_treeNames.push_back(contName);
91  if (m_PARAMdiffAnalysis && iName != 0) m_treeNames.push_back(contName + "_diff");
92  }
93 
94  initializeRootFile(m_PARAMrootFileName[0] + string(".root"), m_PARAMrootFileName[1], m_treeNames);
95  initializeCounters(m_treeNames.size());
96 }
97 
98 
99 // ============================================================= EVENT ============================================================
100 void PhaseSpaceAnalysisModule::event()
101 {
102  // print out the number of the event in debug output
103  StoreObjPtr<EventMetaData> eventMetaDataPtr("EventMetaData", DataStore::c_Event);
104  const int eventCounter = eventMetaDataPtr->getEvent();
105  string arrayNames;
106  for (string name : m_PARAMcontainerNames) {
107  arrayNames += " " + name;
108  }
109  B2DEBUG(10, "PhaseSpaceAnalysis::event(). Processing event " << eventCounter << " for StoreArray names :" << arrayNames);
110 
111  StoreArray<MCParticle> mcParticles;
112  const int nMCParticles = mcParticles.getEntries();
113  B2DEBUG(25, "Found " << nMCParticles << " MCParticles for this event");
114 
115  vector<vector<int> > mcPartIds; // collect all mcParticle Ids of all trackCands
116 
117  for (pair<boost::any, e_trackCandType> storeArray : m_tcStoreArrays) {
118  // COULDDO: wrap this in try-catch, but since it is known what has to be casted, nothing should really happen
119  if (storeArray.second == c_gftc) {
120  mcPartIds.push_back(getMCParticleIDs(boost::any_cast<StoreArray<genfit::TrackCand> >(storeArray.first)));
121  } else if (storeArray.second == c_sptc) {
122  mcPartIds.push_back(getMCParticleIDs(boost::any_cast<StoreArray<SpacePointTrackCand> >(storeArray.first)));
123  }
124  B2DEBUG(25, mcPartIds.back().size() << " MCParticles of this event were set for this container");
125  }
126 
127  if (m_PARAMdiffAnalysis) { mcPartIds = getDiffIds(mcPartIds); }
128  // TODO: get the referee Status of a SPTC into the getValuesForRoot stuff
129 
130  // now loop over all MCParticle IDs
131  for (size_t iTree = 0; iTree < mcPartIds.size(); ++iTree) {
132  B2DEBUG(25, "Now collecting values for vector of MCParticle Ids " << iTree);
133  m_mcPartCtr[iTree]++; // increase counter
134 
135  m_rootVariables = RootVariables(); // clear root variables for each run
136  for (int id : mcPartIds[iTree]) {
137  if (id < 0) {
138  B2WARNING("Found a negative id in mcParticleId: " << id << \
139  ". It seems that it has not been set properly, I will skip this MC Particle");
140  m_skippedTCsCtr++;
141  continue;
142  }
143  MCParticle* mcParticle = mcParticles[id];
144  if (mcParticle == nullptr) { // safety measure
145  m_noMcPartCtr++;
146  continue;
147  }
148  getValuesForRoot(mcParticle, m_rootVariables);
149  }
150  m_treePtrs[iTree]->Fill(); // write values to TTree
151  }
152 }
153 
154 // ================================================================= TERMINATE ====================================================
155 // TODO: update to new version and new counters
156 void PhaseSpaceAnalysisModule::terminate()
157 {
158  stringstream furtherInfo;
159  if (m_skippedTCsCtr || m_noMcPartCtr) {
160  furtherInfo << " There were " << m_skippedTCsCtr << " negative mcParticle IDs and " << m_noMcPartCtr <<
161  " nullptr pointers to MCParticles";
162  }
163  unsigned int nMCParts = accumulate(m_mcPartCtr.begin(), m_mcPartCtr.end(), 0);
164  B2INFO("PhaseSpaceAnalysis::terminate(): Collected mcParticle info in " << m_PARAMcontainerNames.size() << " containers."\
165  " Collected information from " << nMCParts << " MCParticles and wrote them into " << m_treeNames.size() << " different trees."\
166  << furtherInfo.str());
167 
168  if (LogSystem::Instance().isLevelEnabled(LogConfig::c_Debug, 1, PACKAGENAME())) {
169  stringstream output;
170  output << "tree-wise summary (no of mcParticles):";
171  for (unsigned int ctr : m_mcPartCtr) output << " " << ctr;
172  B2DEBUG(1, output.str());
173  }
174 
175  // do ROOT stuff
176  if (m_rootFilePtr != nullptr) {
177  m_rootFilePtr->cd(); //important! without this the famework root I/O could mix with the root I/O of this module
178  for (TTree* tree : m_treePtrs) { tree->Write(); }
179  m_rootFilePtr->Close();
180  }
181 }
182 
183 // ================================== initialize root ===============================
184 void PhaseSpaceAnalysisModule::initializeRootFile(std::string fileName, std::string writeOption, std::vector<std::string> treeNames)
185 {
186  B2DEBUG(10, "initializing root file. fileName: " << fileName << ", writeOption: " << writeOption);
187  m_rootFilePtr = new TFile(fileName.c_str(), writeOption.c_str());
188 
189  for (size_t i = 0; i < treeNames.size(); ++i) {
190  TTree* tree = new TTree(treeNames[i].c_str(), "data of mc particles");
191  tree->Branch("momentum_X", &m_rootVariables.MomX);
192  tree->Branch("momentum_Y", &m_rootVariables.MomY);
193  tree->Branch("momentum_Z", &m_rootVariables.MomZ);
194 
195  tree->Branch("eta", &m_rootVariables.Eta);
196  tree->Branch("p_T", &m_rootVariables.pT);
197 
198  tree->Branch("vertex_X", &m_rootVariables.VertX);
199  tree->Branch("vertex_Y", &m_rootVariables.VertY);
200  tree->Branch("vertex_Z", &m_rootVariables.VertZ);
201 
202  tree->Branch("energy", &m_rootVariables.Energy);
203  tree->Branch("mass", &m_rootVariables.Mass);
204 
205  tree->Branch("charge", &m_rootVariables.Charge);
206  tree->Branch("pdg_code", &m_rootVariables.PDG);
207 
208  m_treePtrs.push_back(tree);
209  }
210 }
211 
212 // =============================== collect values for root ====================================
213 void PhaseSpaceAnalysisModule::getValuesForRoot(Belle2::MCParticle* mcParticle, RootVariables& rootVariables)
214 {
215  B2DEBUG(100, "Collecting values for MCParticle " << mcParticle->getArrayIndex());
216  // collect all the momentum
217  const TVector3 momentum = mcParticle->getMomentum();
218  rootVariables.MomX.push_back(momentum.X());
219  rootVariables.MomY.push_back(momentum.Y());
220  rootVariables.MomZ.push_back(momentum.Z());
221 
222  rootVariables.pT.push_back(momentum.Pt());
223  rootVariables.Eta.push_back(momentum.Eta());
224 
225  B2DEBUG(499, "TVector3 momentum: (" << momentum.X() << "," << momentum.Y() << "," << momentum.Z() << \
226  "). This leads to p_T = " << momentum.Pt() << " and eta = " << momentum.Eta());
227 
228  const TVector3 vertex = mcParticle->getVertex();
229  rootVariables.VertX.push_back(vertex.Y());
230  rootVariables.VertY.push_back(vertex.Y());
231  rootVariables.VertZ.push_back(vertex.Z());
232 
233  B2DEBUG(499, "TVector3 vertex: (" << vertex.X() << "," << vertex.Y() << "," << vertex.Z() << ")");
234 
235  rootVariables.Charge.push_back(mcParticle->getCharge());
236  rootVariables.Energy.push_back(mcParticle->getEnergy());
237  rootVariables.PDG.push_back(mcParticle->getPDG());
238  rootVariables.Mass.push_back(mcParticle->getMass());
239 
240  B2DEBUG(499, "Charge " << mcParticle->getCharge() << ", PDG code" << mcParticle->getPDG() << ", Energy " << \
241  mcParticle->getEnergy() << ", Mass " << mcParticle->getMass());
242 }
243 
244 // ==================================================== GET MCPARTICLE IDS ========================================================
245 template<typename TrackCandType>
246 std::vector<int> PhaseSpaceAnalysisModule::getMCParticleIDs(Belle2::StoreArray<TrackCandType> trackCands)
247 {
248  const int nTrackCands = trackCands.getEntries();
249  B2DEBUG(25, "In StoreArray " << trackCands.getName() << ": " << nTrackCands << " track candidates for this event");
250  std::vector<int> mcPartIds;
251  for (int i = 0; i < nTrackCands; ++i) mcPartIds.push_back(trackCands[i]->getMcTrackId());
252  // COULDDO: more debug output
253  return mcPartIds;
254 }
255 
256 // ================================================== GET DIFF IDS ================================================================
257 // TODO: test
258 std::vector<std::vector<int> > PhaseSpaceAnalysisModule::getDiffIds(const std::vector<std::vector<int> >& allIDs)
259 {
260  if (allIDs.size() < 2) { // do nothing if there are less than two entries
261  B2DEBUG(50, "There are no more than 1 vectors passed to getDiffIds. No comparison possible. Returning passed vector");
262  return allIDs;
263  }
264 
265 // // COULDDO: remove (left here for checking if working properly, simply prints out all the entries in the vector of vectors)
266 // if(LogSystem::Instance().isLevelEnabled(LogConfig::c_Debug, 1999, PACKAGENAME())) { // very verbose dev output
267 // stringstream output;
268 // output << "content of allIDs: " << endl;
269 // for(vector<int> vec: allIDs) {
270 // output << "vector: ";
271 // for(int i : vec) output << i << " ";
272 // output << endl;
273 // }
274 // B2DEBUG(1999, output.str())
275 // }
276 
277  vector<vector<int> > diffIds;
278  vector<int> referenceIds = allIDs.at(0); // the first vector is the reference
279  diffIds.push_back(referenceIds);
280 
281  // loop over other vectors and look for missing IDs
282  for (size_t iVec = 1; iVec < allIDs.size(); ++iVec) {
283  vector<int> compareIds = allIDs[iVec];
284  diffIds.push_back(compareIds);
285  vector<int> notFoundIds;
286  for (int id : referenceIds) {
287  if (find(compareIds.begin(), compareIds.end(), id) == compareIds.end()) { // not found
288  notFoundIds.push_back(id);
289  }
290  }
291  diffIds.push_back(notFoundIds); // push_back empty vectors too! otherwise the filling of the TTrees will be wrong!
292  }
293 
294  return diffIds;
295 }
296 
297 // ================================================== GET REFEREE STATUSES ========================================================
298 // std::vector<unsigned short int>
299 // PhaseSpaceAnalysisModule::getRefereeStatuses(Belle2::StoreArray<Belle2::SpacePointTrackCand> trackCands)
300 // {
301 // std::vector<unsigned short int> statuses;
302 // for(int i = 0; i < trackCands.getEntries(); ++i) { statuses.push_back(trackCands[i]->getRefereeStatus()); }
303 // return statuses;
304 // }
A Class to store the Monte Carlo particle information.
Definition: MCParticle.h:32
float getEnergy() const
Return particle energy in GeV.
Definition: MCParticle.h:147
float getMass() const
Return the particle mass in GeV.
Definition: MCParticle.h:135
int getArrayIndex() const
Get 0-based index of the particle in the corresponding MCParticle list.
Definition: MCParticle.h:244
TVector3 getVertex() const
Return production vertex position, shorthand for getProductionVertex().
Definition: MCParticle.h:183
TVector3 getMomentum() const
Return momentum.
Definition: MCParticle.h:198
float getCharge() const
Return the particle charge defined in TDatabasePDG.
Definition: MCParticle.cc:34
int getPDG() const
Return PDG code of particle.
Definition: MCParticle.h:112
Base class for Modules.
Definition: Module.h:72
Module for analysing the phase space of genfit::TrackCand(s) and SpacePointTrackCand(s) NOTE: this is...
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.
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
#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.
helper class to have all RootVariables assembled in one container
std::vector< double > VertZ
z position of vertex
std::vector< int > PDG
mc particle pdg code
std::vector< double > VertY
y position of vertex
std::vector< double > VertX
x position of vertex
std::vector< double > Charge
mc particle charge
std::vector< double > pT
transverse momentum.
std::vector< double > Energy
mc particle energy