Belle II Software  release-05-02-19
VariablesToEventBasedTreeModule.cc
1 /**************************************************************************
2 * BASF2 (Belle Analysis Framework 2) *
3 * Copyright(C) 2013 - Belle II Collaboration *
4 * *
5 * Author: The Belle II Collaboration *
6 * Contributors: Thomas Keck *
7 * *
8 * This software is provided "as is" without any warranty. *
9 **************************************************************************/
10 
11 #include <analysis/modules/VariablesToEventBasedTree/VariablesToEventBasedTreeModule.h>
12 
13 #include <analysis/dataobjects/ParticleList.h>
14 #include <analysis/VariableManager/Manager.h>
15 #include <analysis/VariableManager/Utility.h>
16 #include <framework/logging/Logger.h>
17 #include <framework/pcore/ProcHandler.h>
18 #include <framework/utilities/MakeROOTCompatible.h>
19 #include <framework/utilities/RootFileCreationManager.h>
20 #include <framework/core/ModuleParam.templateDetails.h>
21 
22 #include <cmath>
23 
24 using namespace std;
25 using namespace Belle2;
26 
27 // Register module in the framework
28 REG_MODULE(VariablesToEventBasedTree)
29 
30 
32  Module(), m_tree("", DataStore::c_Persistent)
33 {
34  //Set module properties
35  setDescription("Calculate variables specified by the user for a given ParticleList and save them into a TTree. The Tree is event-based, meaning that the variables of each candidate for each event are saved in an array of a branch of the Tree.");
36  setPropertyFlags(c_ParallelProcessingCertified | c_TerminateInAllProcesses);
37 
38  vector<string> emptylist;
39  addParam("particleList", m_particleList,
40  "Name of particle list with reconstructed particles. An empty ParticleList is not supported. Use the VariablesToNtupleModule for this use-case",
41  std::string(""));
42  addParam("variables", m_variables,
43  "List of variables (or collections) to save for each candidate. Variables are taken from Variable::Manager, and are identical to those available to e.g. ParticleSelector.",
44  emptylist);
45 
46  addParam("event_variables", m_event_variables,
47  "List of variables (or collections) to save for each event. Variables are taken from Variable::Manager, and are identical to those available to e.g. ParticleSelector. Only event-based variables are allowed here.",
48  emptylist);
49 
50  addParam("fileName", m_fileName, "Name of ROOT file for output.", string("VariablesToEventBasedTree.root"));
51  addParam("treeName", m_treeName, "Name of the NTuple in the saved file.", string("tree"));
52  addParam("maxCandidates", m_maxCandidates, "The maximum number of candidates in the ParticleList per entry of the Tree.", 100u);
53 
54  std::tuple<std::string, std::map<int, unsigned int>> default_sampling{"", {}};
55  addParam("sampling", m_sampling,
56  "Tuple of variable name and a map of integer values and inverse sampling rate. E.g. (signal, {1: 0, 0:10}) selects all signal events and every 10th background event. Variable must be event-based.",
57  default_sampling);
58 }
59 
60 void VariablesToEventBasedTreeModule::initialize()
61 {
62  m_eventMetaData.isRequired();
63  StoreObjPtr<ParticleList>().isRequired(m_particleList);
64 
65  // See if there is already a file in which case add a new tree to it ...
66  // otherwise create a new file (all handled by framework)
67  m_file = RootFileCreationManager::getInstance().getFile(m_fileName);
68  if (!m_file) {
69  B2ERROR("Could not create file \"" << m_fileName <<
70  "\". Please set a vaild root output file name (\"fileName\" module parameter).");
71  return;
72  }
73 
74  m_file->cd();
75 
76  // check if TTree with that name already exists
77  if (m_file->Get(m_treeName.c_str())) {
78  B2FATAL("Tree with the name " << m_treeName << " already exists in the file " << m_fileName);
79  return;
80  }
81 
82  m_variables = Variable::Manager::Instance().resolveCollections(m_variables);
83  m_event_variables = Variable::Manager::Instance().resolveCollections(m_event_variables);
84 
85  m_tree.registerInDataStore(m_fileName + m_treeName, DataStore::c_DontWriteOut);
86  m_tree.construct(m_treeName.c_str(), "");
87 
88  m_values.resize(m_variables.size());
89  m_event_values.resize(m_event_variables.size());
90 
91  m_tree->get().Branch("__event__", &m_event, "__event__/I");
92  m_tree->get().Branch("__run__", &m_run, "__run__/I");
93  m_tree->get().Branch("__experiment__", &m_experiment, "__experiment__/I");
94  m_tree->get().Branch("__ncandidates__", &m_ncandidates, "__ncandidates__/I");
95  m_tree->get().Branch("__weight__", &m_weight, "__weight__/F");
96 
97  for (unsigned int i = 0; i < m_event_variables.size(); ++i) {
98  auto varStr = m_event_variables[i];
99 
100  if (Variable::isCounterVariable(varStr)) {
101  B2WARNING("The counter '" << varStr
102  << "' is handled automatically by VariablesToEventBasedTree, you don't need to add it.");
103  continue;
104  }
105 
106  m_tree->get().Branch(makeROOTCompatible(varStr).c_str(), &m_event_values[i], (makeROOTCompatible(varStr) + "/D").c_str());
107 
108  //also collection function pointers
109  const Variable::Manager::Var* var = Variable::Manager::Instance().getVariable(varStr);
110  if (!var) {
111  B2ERROR("Variable '" << varStr << "' is not available in Variable::Manager!");
112  } else {
113  m_event_functions.push_back(var->function);
114  }
115  }
116 
117  for (unsigned int i = 0; i < m_variables.size(); ++i) {
118  auto varStr = m_variables[i];
119  m_values[i].resize(m_maxCandidates);
120  m_tree->get().Branch(makeROOTCompatible(varStr).c_str(), &m_values[i][0],
121  (makeROOTCompatible(varStr) + "[__ncandidates__]/D").c_str());
122 
123  //also collection function pointers
124  const Variable::Manager::Var* var = Variable::Manager::Instance().getVariable(varStr);
125  if (!var) {
126  B2ERROR("Variable '" << varStr << "' is not available in Variable::Manager!");
127  } else {
128  m_functions.push_back(var->function);
129  }
130  }
131 
132  m_sampling_name = std::get<0>(m_sampling);
133  m_sampling_rates = std::get<1>(m_sampling);
134 
135  if (m_sampling_name != "") {
136  m_sampling_variable = Variable::Manager::Instance().getVariable(m_sampling_name);
137  if (m_sampling_variable == nullptr) {
138  B2FATAL("Couldn't find sample variable " << m_sampling_name << " via the Variable::Manager. Check the name!");
139  }
140  for (const auto& pair : m_sampling_rates)
141  m_sampling_counts[pair.first] = 0;
142  } else {
143  m_sampling_variable = nullptr;
144  }
145 
146 }
147 
148 
149 float VariablesToEventBasedTreeModule::getInverseSamplingRateWeight()
150 {
151 
152  if (m_sampling_variable == nullptr)
153  return 1.0;
154 
155  long target = std::lround(m_sampling_variable->function(nullptr));
156  if (m_sampling_rates.find(target) != m_sampling_rates.end() and m_sampling_rates[target] > 0) {
157  m_sampling_counts[target]++;
158  if (m_sampling_counts[target] % m_sampling_rates[target] != 0)
159  return 0;
160  else {
161  m_sampling_counts[target] = 0;
162  return m_sampling_rates[target];
163  }
164  }
165 
166  return 1.0;
167 }
168 
169 void VariablesToEventBasedTreeModule::event()
170 {
171  // get counter numbers
172  m_event = m_eventMetaData->getEvent();
173  m_run = m_eventMetaData->getRun();
174  m_experiment = m_eventMetaData->getExperiment();
175 
176  StoreObjPtr<ParticleList> particlelist(m_particleList);
177  m_ncandidates = particlelist->getListSize();
178  m_weight = getInverseSamplingRateWeight();
179  if (m_weight > 0) {
180  for (unsigned int iVar = 0; iVar < m_event_functions.size(); iVar++) {
181  m_event_values[iVar] = m_event_functions[iVar](nullptr);
182  }
183  for (unsigned int iPart = 0; iPart < m_ncandidates; iPart++) {
184 
185  if (iPart >= m_maxCandidates) {
186  B2WARNING("Maximum number of candidates exceeded in VariablesToEventBasedTree module. I will skip additional candidates");
187  break;
188  }
189 
190  const Particle* particle = particlelist->getParticle(iPart);
191  for (unsigned int iVar = 0; iVar < m_functions.size(); iVar++) {
192  m_values[iVar][iPart] = m_functions[iVar](particle);
193  }
194  }
195  m_tree->get().Fill();
196  }
197 }
198 
199 void VariablesToEventBasedTreeModule::terminate()
200 {
201  if (!ProcHandler::parallelProcessingUsed() or ProcHandler::isOutputProcess()) {
202  B2INFO("Writing TTree " << m_treeName);
203  TDirectory::TContext directoryGuard(m_file.get());
204  m_tree->write(m_file.get());
205 
206  const bool writeError = m_file->TestBit(TFile::kWriteError);
207  if (writeError) {
208  B2FATAL("A write error occured while saving '" << m_fileName << "', please check if enough disk space is available.");
209  }
210  }
211 }
Belle2::Variable::Manager::Var
A variable returning a floating-point value for a given Particle.
Definition: Manager.h:137
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::VariablesToEventBasedTreeModule
Module to calculate variables specified by the user for a given ParticleList and save them into a TTr...
Definition: VariablesToEventBasedTreeModule.h:42
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2::makeROOTCompatible
std::string makeROOTCompatible(std::string str)
Remove special characters that ROOT dislikes in branch names, e.g.
Definition: MakeROOTCompatible.cc:74
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::Particle
Class to store reconstructed particles.
Definition: Particle.h:77
Belle2::DataStore
In the store you can park objects that have to be accessed by various modules.
Definition: DataStore.h:53