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