Belle II Software  release-06-00-14
arichToNtupleModule.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 <arich/modules/arichToNtuple/arichToNtupleModule.h>
10 
11 #include <arich/dataobjects/ARICHLikelihood.h>
12 #include <arich/dataobjects/ARICHAeroHit.h>
13 #include <arich/dataobjects/ARICHTrack.h>
14 #include <arich/dataobjects/ARICHPhoton.h>
15 #include <arich/dataobjects/ARICHHit.h>
16 #include <mdst/dataobjects/Track.h>
17 #include <tracking/dataobjects/ExtHit.h>
18 
19 // analysis
20 #include <analysis/dataobjects/ParticleList.h>
21 #include <analysis/VariableManager/Manager.h>
22 #include <analysis/VariableManager/Utility.h>
23 
24 // framework
25 #include <framework/logging/Logger.h>
26 #include <framework/pcore/ProcHandler.h>
27 #include <framework/core/ModuleParam.templateDetails.h>
28 
29 #include <framework/datastore/DataStore.h>
30 #include <framework/datastore/StoreArray.h>
31 
32 // framework - root utilities
33 #include <framework/utilities/MakeROOTCompatible.h>
34 #include <framework/utilities/RootFileCreationManager.h>
35 
36 #include <cmath>
37 
38 using namespace std;
39 using namespace Belle2;
40 
41 // Register module in the framework
42 REG_MODULE(arichToNtuple)
43 
44 
46  Module(), m_tree("", DataStore::c_Persistent)
47 {
48  //Set module properties
49  setDescription("Local arich extension of VariblesToNtuple module to append detailed arich information to reconstructed candidates in the analysis output Ntuple. The TNtuple is candidate-based, meaning that the variables of each candidate are saved separate rows.");
50  setPropertyFlags(c_ParallelProcessingCertified | c_TerminateInAllProcesses);
51 
52  vector<string> emptylist;
53  addParam("particleList", m_particleList,
54  "Name of particle list with reconstructed particles. If no list is provided the variables are saved once per event (only possible for event-type variables)",
55  std::string(""));
56  addParam("arichSelector", m_arichSelector,
57  "Decay string with selected particles to which arich info should be appened", std::string(""));
58  addParam("variables", m_variables,
59  "List of variables (or collections) to save. Variables are taken from Variable::Manager, and are identical to those available to e.g. ParticleSelector.",
60  emptylist);
61  addParam("arichVariables", m_arichVariables,
62  "List of aliases for particles to which arich info will be appended (used for tree branch names)",
63  emptylist);
64 
65  addParam("fileName", m_fileName, "Name of ROOT file for output.", string("arichToNtuple.root"));
66  addParam("treeName", m_treeName, "Name of the NTuple in the saved file.", string("ntuple"));
67 
68  std::tuple<std::string, std::map<int, unsigned int>> default_sampling{"", {}};
69  addParam("sampling", m_sampling,
70  "Tuple of variable name and a map of integer values and inverse sampling rate. E.g. (signal, {1: 0, 0:10}) selects all signal candidates and every 10th background candidate.",
71  default_sampling);
72 }
73 
74 void arichToNtupleModule::initialize()
75 {
76  m_eventMetaData.isRequired();
77 
78  StoreArray<Track> tracks;
79  tracks.isRequired();
80  StoreArray<ExtHit> extHits;
81  extHits.isRequired();
82  StoreArray<ARICHTrack> arichTracks;
83  arichTracks.isRequired();
84 
85 
86  if (not m_particleList.empty())
87  StoreObjPtr<ParticleList>().isRequired(m_particleList);
88 
89  m_decaydescriptor.init(m_arichSelector);
90 
91  // Initializing the output root file
92  if (m_fileName.empty()) {
93  B2FATAL("Output root file name is not set. Please set a vaild root output file name (\"fileName\" module parameter).");
94  }
95  // See if there is already a file in which case add a new tree to it ...
96  // otherwise create a new file (all handled by framework)
97  m_file = RootFileCreationManager::getInstance().getFile(m_fileName);
98  if (!m_file) {
99  B2ERROR("Could not create file \"" << m_fileName <<
100  "\". Please set a vaild root output file name (\"fileName\" module parameter).");
101  return;
102  }
103 
104  TDirectory::TContext directoryGuard(m_file.get());
105 
106  // check if TTree with that name already exists
107  if (m_file->Get(m_treeName.c_str())) {
108  B2FATAL("Tree with the name \"" << m_treeName
109  << "\" already exists in the file \"" << m_fileName << "\"\n"
110  << "\nYou probably want to either set the output fileName or the treeName to something else:\n\n"
111  << " from modularAnalysis import arichToNtuple\n"
112  << " arichToNtuple('pi+:all', ['p'], treename='pions', filename='arichToNtuple.root')\n"
113  << " arichToNtuple('gamma:all', ['p'], treename='photons', filename='arichToNtuple.root') # two trees, same file\n"
114  << "\n == Or ==\n"
115  << " from modularAnalysis import arichToNtuple\n"
116  << " arichToNtuple('pi+:all', ['p'], filename='pions.root')\n"
117  << " arichToNtuple('gamma:all', ['p'], filename='photons.root') # two files\n"
118  );
119  return;
120  }
121 
122  // set up tree and register it in the datastore
123  m_tree.registerInDataStore(m_fileName + m_treeName, DataStore::c_DontWriteOut);
124  m_tree.construct(m_treeName.c_str(), "");
125  m_tree->get().SetCacheSize(100000);
126 
127  // declare counter branches - pass through variable list, remove counters added by user
128  m_tree->get().Branch("__experiment__", &m_experiment, "__experiment__/I");
129  m_tree->get().Branch("__run__", &m_run, "__run__/I");
130  m_tree->get().Branch("__event__", &m_event, "__event__/I");
131  if (not m_particleList.empty()) {
132  m_tree->get().Branch("__candidate__", &m_candidate, "__candidate__/I");
133  m_tree->get().Branch("__ncandidates__", &m_ncandidates, "__ncandidates__/I");
134  }
135  for (const auto& variable : m_variables)
136  if (Variable::isCounterVariable(variable)) {
137  B2WARNING("The counter '" << variable
138  << "' is handled automatically by arichToNtuple, you don't need to add it.");
139  }
140 
141  // declare branches and get the variable strings
142  m_variables = Variable::Manager::Instance().resolveCollections(m_variables);
143  m_branchAddresses.resize(m_variables.size() + 1);
144  m_tree->get().Branch("__weight__", &m_branchAddresses[0], "__weight__/D");
145  size_t enumerate = 1;
146  for (const string& varStr : m_variables) {
147 
148  string branchName = makeROOTCompatible(varStr);
149  m_tree->get().Branch(branchName.c_str(), &m_branchAddresses[enumerate], (branchName + "/D").c_str());
150 
151  // also collection function pointers
152  const Variable::Manager::Var* var = Variable::Manager::Instance().getVariable(varStr);
153  if (!var) {
154  B2ERROR("Variable '" << varStr << "' is not available in Variable::Manager!");
155  } else {
156  m_functions.push_back(var->function);
157  }
158  enumerate++;
159  }
160 
161  // add arich related branches
162  for (const string& varStr : m_arichVariables) {
163  string branchName = makeROOTCompatible(varStr);
164  addARICHBranches(branchName);
165  }
166 
167  m_tree->get().SetBasketSize("*", 1600);
168 
169  m_sampling_name = std::get<0>(m_sampling);
170  m_sampling_rates = std::get<1>(m_sampling);
171 
172  if (m_sampling_name != "") {
173  m_sampling_variable = Variable::Manager::Instance().getVariable(m_sampling_name);
174  if (m_sampling_variable == nullptr) {
175  B2FATAL("Couldn't find sample variable " << m_sampling_name << " via the Variable::Manager. Check the name!");
176  }
177  for (const auto& pair : m_sampling_rates)
178  m_sampling_counts[pair.first] = 0;
179  } else {
180  m_sampling_variable = nullptr;
181  }
182 }
183 
184 
185 float arichToNtupleModule::getInverseSamplingRateWeight(const Particle* particle)
186 {
187  if (m_sampling_variable == nullptr)
188  return 1.0;
189 
190  long target = std::lround(m_sampling_variable->function(particle));
191  if (m_sampling_rates.find(target) != m_sampling_rates.end() and m_sampling_rates[target] > 0) {
192  m_sampling_counts[target]++;
193  if (m_sampling_counts[target] % m_sampling_rates[target] != 0)
194  return 0;
195  else {
196  m_sampling_counts[target] = 0;
197  return m_sampling_rates[target];
198  }
199  }
200  return 1.0;
201 }
202 
203 void arichToNtupleModule::event()
204 {
205  m_event = m_eventMetaData->getEvent();
206  m_run = m_eventMetaData->getRun();
207  m_experiment = m_eventMetaData->getExperiment();
208 
209  if (m_particleList.empty()) {
210  m_branchAddresses[0] = getInverseSamplingRateWeight(nullptr);
211  if (m_branchAddresses[0] > 0) {
212  for (unsigned int iVar = 0; iVar < m_variables.size(); iVar++) {
213  m_branchAddresses[iVar + 1] = m_functions[iVar](nullptr);
214  }
215  for (auto& arich : m_arich) arich->clear();
216  m_tree->get().Fill();
217  }
218 
219  } else {
220  StoreObjPtr<ParticleList> particlelist(m_particleList);
221  m_ncandidates = particlelist->getListSize();
222 
223  for (unsigned int iPart = 0; iPart < m_ncandidates; iPart++) {
224  m_candidate = iPart;
225  const Particle* particle = particlelist->getParticle(iPart);
226  m_branchAddresses[0] = getInverseSamplingRateWeight(particle);
227  if (m_branchAddresses[0] > 0) {
228  for (unsigned int iVar = 0; iVar < m_variables.size(); iVar++) {
229  m_branchAddresses[iVar + 1] = m_functions[iVar](particle);
230  }
231  for (auto& arich : m_arich) arich->clear();
232  fillARICHTree(particle);
233  m_tree->get().Fill();
234  }
235  }
236  }
237 }
238 
239 void arichToNtupleModule::terminate()
240 {
241  if (!ProcHandler::parallelProcessingUsed() or ProcHandler::isOutputProcess()) {
242  B2INFO("Writing NTuple " << m_treeName);
243  TDirectory::TContext directoryGuard(m_file.get());
244  m_tree->write(m_file.get());
245 
246  const bool writeError = m_file->TestBit(TFile::kWriteError);
247  m_file.reset();
248  if (writeError) {
249  B2FATAL("A write error occured while saving '" << m_fileName << "', please check if enough disk space is available.");
250  }
251  }
252 }
253 
254 void arichToNtupleModule::addARICHBranches(const std::string& name)
255 {
256 
257  ARICH::ARICHTree* tree = new ARICH::ARICHTree();
258  m_arich.push_back(tree);
259  m_tree->get().Branch((name + "_detPhot").c_str(), &tree->detPhot, "detPhot/I");
260  m_tree->get().Branch((name + "_expPhot").c_str(), &tree->expPhot, "e/F:mu:pi:K:p:d");
261  m_tree->get().Branch((name + "_logL").c_str(), &tree->logL, "e/F:mu:pi:K:p:d");
262  m_tree->get().Branch((name + "_recHit").c_str(), &tree->recHit, "PDG/I:x/F:y:z:p:theta:phi");
263  m_tree->get().Branch((name + "_mcHit").c_str(), &tree->mcHit, "PDG/I:x/F:y:z:p:theta:phi");
264  m_tree->get().Branch((name + "_winHit").c_str(), &tree->winHit, "x/F:y");
265  m_tree->get().Branch((name + "_photons").c_str(), "std::vector<Belle2::ARICHPhoton>", &tree->photons);
266 
267 }
268 
269 void arichToNtupleModule::fillARICHTree(const Particle* particle)
270 {
271 
272  std::vector<const Particle*> selParticles = m_decaydescriptor.getSelectionParticles(particle);
273  int iTree = 0;
274  for (auto p : selParticles) {
275  const Track* track = p->getTrack();
276  if (!track) continue;
277  for (const ExtHit& hit : track->getRelationsTo<ExtHit>()) {
278  const ARICHTrack* atrk = hit.getRelated<ARICHTrack>();
279  if (!atrk) continue;
280 
281  if (atrk->hitsWindow()) {
282  TVector2 winHit = atrk->windowHitPosition();
283  m_arich[iTree]->winHit[0] = winHit.X();
284  m_arich[iTree]->winHit[1] = winHit.Y();
285  }
286 
287  m_arich[iTree]->photons = atrk->getPhotons();
288 
289  TVector3 recPos = atrk->getPosition();
290  m_arich[iTree]->recHit.x = recPos.X();
291  m_arich[iTree]->recHit.y = recPos.Y();
292  m_arich[iTree]->recHit.z = recPos.Z();
293 
294  TVector3 recMom = atrk->getDirection() * atrk->getMomentum();
295  m_arich[iTree]->recHit.p = recMom.Mag();
296  m_arich[iTree]->recHit.theta = recMom.Theta();
297  m_arich[iTree]->recHit.phi = recMom.Phi();
298 
299  const ARICHLikelihood* lkh = NULL;
300  lkh = track->getRelated<ARICHLikelihood>();
301  if (lkh) {
302  m_arich[iTree]->logL.e = lkh->getLogL(Const::electron);
303  m_arich[iTree]->logL.mu = lkh->getLogL(Const::muon);
304  m_arich[iTree]->logL.pi = lkh->getLogL(Const::pion);
305  m_arich[iTree]->logL.K = lkh->getLogL(Const::kaon);
306  m_arich[iTree]->logL.p = lkh->getLogL(Const::proton);
307  m_arich[iTree]->logL.d = lkh->getLogL(Const::deuteron);
308 
309  m_arich[iTree]->expPhot.e = lkh->getExpPhot(Const::electron);
310  m_arich[iTree]->expPhot.mu = lkh->getExpPhot(Const::muon);
311  m_arich[iTree]->expPhot.pi = lkh->getExpPhot(Const::pion);
312  m_arich[iTree]->expPhot.K = lkh->getExpPhot(Const::kaon);
313  m_arich[iTree]->expPhot.p = lkh->getExpPhot(Const::proton);
314  m_arich[iTree]->expPhot.d = lkh->getExpPhot(Const::deuteron);
315 
316  m_arich[iTree]->detPhot = lkh->getDetPhot();
317  }
318 
319  const ARICHAeroHit* aeroHit = atrk->getRelated<ARICHAeroHit>();
320  if (aeroHit) {
321  TVector3 truePos = aeroHit->getPosition();
322  m_arich[iTree]->mcHit.x = truePos.X();
323  m_arich[iTree]->mcHit.y = truePos.Y();
324  m_arich[iTree]->mcHit.z = truePos.Z();
325 
326  TVector3 trueMom = aeroHit->getMomentum();
327  m_arich[iTree]->mcHit.p = trueMom.Mag();
328  m_arich[iTree]->mcHit.theta = trueMom.Theta();
329  m_arich[iTree]->mcHit.phi = trueMom.Phi();
330  m_arich[iTree]->mcHit.PDG = aeroHit->getPDG();
331 
332  }
333  }
334  iTree++;
335  }
336 }
Datastore class that holds information on track parameters at the entrance in aerogel.
Definition: ARICHAeroHit.h:27
TVector3 getMomentum() const
Get track momentum (at entrance in 1. aerogel plane)
Definition: ARICHAeroHit.h:71
int getPDG() const
Get particle PDG identity number.
Definition: ARICHAeroHit.h:65
TVector3 getPosition() const
Get track position (at entrance in 1. aerogel plane)
Definition: ARICHAeroHit.h:68
This is a class to store ARICH likelihoods in the datastore.
float getDetPhot() const
Return number of detected photons for a given particle.
float getLogL(const Const::ChargedStable &part) const
Return log likelihood for a given particle.
float getExpPhot(const Const::ChargedStable &part) const
Return number of expected photons for a given particle.
Datastore class that holds position and momentum information of tracks that hit ARICH.
Definition: ARICHTrack.h:32
const std::vector< ARICHPhoton > & getPhotons() const
Returns vector of ARICHPhoton's associated with track.
Definition: ARICHTrack.h:189
bool hitsWindow() const
Returns true if track hits HAPD window.
Definition: ARICHTrack.h:151
TVector3 getPosition() const
returns track position vector
Definition: ARICHTrack.h:133
TVector2 windowHitPosition() const
Get HAPD window hit position.
Definition: ARICHTrack.h:157
TVector3 getDirection() const
returns track direction vector
Definition: ARICHTrack.h:139
double getMomentum() const
returns track momentum
Definition: ARICHTrack.h:145
In the store you can park objects that have to be accessed by various modules.
Definition: DataStore.h:51
Store one Ext hit as a ROOT object.
Definition: ExtHit.h:30
Base class for Modules.
Definition: Module.h:72
Class to store reconstructed particles.
Definition: Particle.h:74
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
Class that bundles various TrackFitResults.
Definition: Track.h:25
This module extends existing variablesToNtuple to append detailed arich information to candidates in ...
std::string makeROOTCompatible(std::string str)
Remove special characters that ROOT dislikes in branch names, e.g.
#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.
Structure of a flat ntuple.
A variable returning a floating-point value for a given Particle.
Definition: Manager.h:133