Belle II Software  release-06-01-15
VariablesToEventBasedTreeModule.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/VariablesToEventBasedTree/VariablesToEventBasedTreeModule.h>
10 
11 #include <analysis/dataobjects/ParticleList.h>
12 #include <analysis/VariableManager/Manager.h>
13 #include <analysis/VariableManager/Utility.h>
14 #include <framework/logging/Logger.h>
15 #include <framework/pcore/ProcHandler.h>
16 #include <framework/utilities/MakeROOTCompatible.h>
17 #include <framework/utilities/RootFileCreationManager.h>
18 #include <framework/core/ModuleParam.templateDetails.h>
19 
20 #include <cmath>
21 
22 using namespace std;
23 using namespace Belle2;
24 
25 // Register module in the framework
26 REG_MODULE(VariablesToEventBasedTree)
27 
28 
30  Module(), m_tree("", DataStore::c_Persistent)
31 {
32  //Set module properties
33  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.");
34  setPropertyFlags(c_ParallelProcessingCertified | c_TerminateInAllProcesses);
35 
36  vector<string> emptylist;
37  addParam("particleList", m_particleList,
38  "Name of particle list with reconstructed particles. An empty ParticleList is not supported. Use the VariablesToNtupleModule for this use-case",
39  std::string(""));
40  addParam("variables", m_variables,
41  "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.",
42  emptylist);
43 
44  addParam("event_variables", m_event_variables,
45  "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.",
46  emptylist);
47 
48  addParam("fileName", m_fileName, "Name of ROOT file for output.", string("VariablesToEventBasedTree.root"));
49  addParam("treeName", m_treeName, "Name of the NTuple in the saved file.", string("tree"));
50  addParam("maxCandidates", m_maxCandidates, "The maximum number of candidates in the ParticleList per entry of the Tree.", 100u);
51 
52  std::tuple<std::string, std::map<int, unsigned int>> default_sampling{"", {}};
53  addParam("sampling", m_sampling,
54  "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.",
55  default_sampling);
56 }
57 
58 void VariablesToEventBasedTreeModule::initialize()
59 {
60  m_eventMetaData.isRequired();
61  StoreObjPtr<ParticleList>().isRequired(m_particleList);
62 
63  // See if there is already a file in which case add a new tree to it ...
64  // otherwise create a new file (all handled by framework)
65  m_file = RootFileCreationManager::getInstance().getFile(m_fileName);
66  if (!m_file) {
67  B2ERROR("Could not create file \"" << m_fileName <<
68  "\". Please set a valid root output file name (\"fileName\" module parameter).");
69  return;
70  }
71 
72  m_file->cd();
73 
74  // check if TTree with that name already exists
75  if (m_file->Get(m_treeName.c_str())) {
76  B2FATAL("Tree with the name " << m_treeName << " already exists in the file " << m_fileName);
77  return;
78  }
79 
80  m_variables = Variable::Manager::Instance().resolveCollections(m_variables);
81  m_event_variables = Variable::Manager::Instance().resolveCollections(m_event_variables);
82 
83  m_tree.registerInDataStore(m_fileName + m_treeName, DataStore::c_DontWriteOut);
84  m_tree.construct(m_treeName.c_str(), "");
85 
86  m_values.resize(m_variables.size());
87  m_event_values.resize(m_event_variables.size());
88 
89  m_tree->get().Branch("__event__", &m_event, "__event__/I");
90  m_tree->get().Branch("__run__", &m_run, "__run__/I");
91  m_tree->get().Branch("__experiment__", &m_experiment, "__experiment__/I");
92  m_tree->get().Branch("__production__", &m_production, "__production__/I");
93  m_tree->get().Branch("__ncandidates__", &m_ncandidates, "__ncandidates__/I");
94  m_tree->get().Branch("__weight__", &m_weight, "__weight__/F");
95 
96  for (unsigned int i = 0; i < m_event_variables.size(); ++i) {
97  auto varStr = m_event_variables[i];
98 
99  if (Variable::isCounterVariable(varStr)) {
100  B2WARNING("The counter '" << varStr
101  << "' is handled automatically by VariablesToEventBasedTree, you don't need to add it.");
102  continue;
103  }
104 
105  m_tree->get().Branch(makeROOTCompatible(varStr).c_str(), &m_event_values[i], (makeROOTCompatible(varStr) + "/D").c_str());
106 
107  //also collection function pointers
108  const Variable::Manager::Var* var = Variable::Manager::Instance().getVariable(varStr);
109  if (!var) {
110  B2ERROR("Variable '" << varStr << "' is not available in Variable::Manager!");
111  } else {
112  m_event_functions.push_back(var->function);
113  }
114  }
115 
116  for (unsigned int i = 0; i < m_variables.size(); ++i) {
117  auto varStr = m_variables[i];
118  m_values[i].resize(m_maxCandidates);
119  m_tree->get().Branch(makeROOTCompatible(varStr).c_str(), &m_values[i][0],
120  (makeROOTCompatible(varStr) + "[__ncandidates__]/D").c_str());
121 
122  //also collection function pointers
123  const Variable::Manager::Var* var = Variable::Manager::Instance().getVariable(varStr);
124  if (!var) {
125  B2ERROR("Variable '" << varStr << "' is not available in Variable::Manager!");
126  } else {
127  m_functions.push_back(var->function);
128  }
129  }
130 
131  m_sampling_name = std::get<0>(m_sampling);
132  m_sampling_rates = std::get<1>(m_sampling);
133 
134  if (m_sampling_name != "") {
135  m_sampling_variable = Variable::Manager::Instance().getVariable(m_sampling_name);
136  if (m_sampling_variable == nullptr) {
137  B2FATAL("Couldn't find sample variable " << m_sampling_name << " via the Variable::Manager. Check the name!");
138  }
139  for (const auto& pair : m_sampling_rates)
140  m_sampling_counts[pair.first] = 0;
141  } else {
142  m_sampling_variable = nullptr;
143  }
144 
145 }
146 
147 
148 float VariablesToEventBasedTreeModule::getInverseSamplingRateWeight()
149 {
150 
151  if (m_sampling_variable == nullptr)
152  return 1.0;
153 
154  long target = std::lround(m_sampling_variable->function(nullptr));
155  if (m_sampling_rates.find(target) != m_sampling_rates.end() and m_sampling_rates[target] > 0) {
156  m_sampling_counts[target]++;
157  if (m_sampling_counts[target] % m_sampling_rates[target] != 0)
158  return 0;
159  else {
160  m_sampling_counts[target] = 0;
161  return m_sampling_rates[target];
162  }
163  }
164 
165  return 1.0;
166 }
167 
168 void VariablesToEventBasedTreeModule::event()
169 {
170  // get counter numbers
171  m_event = m_eventMetaData->getEvent();
172  m_run = m_eventMetaData->getRun();
173  m_experiment = m_eventMetaData->getExperiment();
174  m_production = m_eventMetaData->getProduction();
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 occurred while saving '" << m_fileName << "', please check if enough disk space is available.");
209  }
210  }
211 }
In the store you can park objects that have to be accessed by various modules.
Definition: DataStore.h:51
Base class for Modules.
Definition: Module.h:72
Class to store reconstructed particles.
Definition: Particle.h:74
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
Module to calculate variables specified by the user for a given ParticleList and save them into a TTr...
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.
A variable returning a floating-point value for a given Particle.
Definition: Manager.h:133