Belle II Software prerelease-11-00-00a
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// analysis
12#include <analysis/dataobjects/ParticleList.h>
13#include <analysis/dataobjects/StringWrapper.h>
14#include <analysis/VariableManager/Utility.h>
15
16// framework
17#include <framework/datastore/DataStore.h>
18#include <framework/logging/Logger.h>
19#include <framework/pcore/ProcHandler.h>
20#include <framework/utilities/MakeROOTCompatible.h>
21#include <framework/utilities/RootFileCreationManager.h>
22#include <framework/core/ModuleParam.templateDetails.h>
23#include <framework/core/Environment.h>
24#include <framework/io/RootIOUtilities.h>
25
26#include <cmath>
27
28using namespace std;
29using namespace Belle2;
30
31// Register module in the framework
32REG_MODULE(VariablesToEventBasedTree);
33
34
36 Module(), m_tree("", DataStore::c_Persistent)
37{
38 //Set module properties
39 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.");
41
42 vector<string> emptylist;
43 addParam("particleList", m_particleList,
44 "Name of particle list with reconstructed particles. An empty ParticleList is not supported. Use the VariablesToNtupleModule for this use-case",
45 std::string(""));
46 addParam("variables", m_variables,
47 "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.",
48 emptylist);
49
50 addParam("event_variables", m_event_variables,
51 "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.",
52 emptylist);
53
54 addParam("fileName", m_fileName, "Name of ROOT file for output. Can be overridden using the -o argument of basf2.",
55 string("VariablesToEventBasedTree.root"));
56 addParam("treeName", m_treeName, "Name of the NTuple in the saved file.", string("ntuple"));
57 addParam("maxCandidates", m_maxCandidates, "The maximum number of candidates in the ParticleList per entry of the Tree.", 100u);
58
59 std::tuple<std::string, std::map<int, unsigned int>> default_sampling{"", {}};
60 addParam("sampling", m_sampling,
61 "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.",
62 default_sampling);
63
64 addParam("fileNameSuffix", m_fileNameSuffix, "The suffix of the output ROOT file to be appended before ``.root``.",
65 string(""));
66 addParam("ignoreCommandLineOverride", m_ignoreCommandLineOverride,
67 "Ignore override of file name via command line argument -o. Useful if you have multiple output modules in one path.", false);
68
69 addParam("storeEventType", m_storeEventType,
70 "If true, the branch __eventType__ is added. The eventType information is available from MC16 on.", true);
71}
72
74{
75 m_eventMetaData.isRequired();
77
78 // override the output file name with what's been provided with the -o option
80 const std::string& outputFileArgument = Environment::Instance().getOutputFileOverride();
81 if (!outputFileArgument.empty())
82 m_fileName = outputFileArgument;
83 }
84
85 if (!m_fileNameSuffix.empty())
86 m_fileName = m_fileName.insert(m_fileName.rfind(".root"), m_fileNameSuffix);
87
88 // See if there is already a file in which case add a new tree to it ...
89 // otherwise create a new file (all handled by framework)
91 if (!m_file) {
92 B2ERROR("Could not create file \"" << m_fileName <<
93 "\". Please set a valid root output file name (\"fileName\" module parameter).");
94 return;
95 }
96
97 m_file->cd();
98
99 // check if TTree with that name already exists or if the name is reserved
101 B2FATAL("Tree with the name \"" << m_treeName
102 << "\" already exists in the file \"" << m_fileName << "\"\n"
103 << "or is reserved for basf2 TTrees.\n");
104 return;
105 }
106
108 // remove duplicates from list of variables but keep the previous order
109 unordered_set<string> seen;
110 auto newEnd = remove_if(m_variables.begin(), m_variables.end(), [&seen](const string & varStr) {
111 if (seen.find(varStr) != std::end(seen)) return true;
112 seen.insert(varStr);
113 return false;
114 });
115 m_variables.erase(newEnd, m_variables.end());
116
118 // remove duplicates from list of variables but keep the previous order
119 unordered_set<string> seenEventVariables;
120 auto eventVariablesEnd = remove_if(m_event_variables.begin(),
121 m_event_variables.end(), [&seenEventVariables](const string & varStr) {
122 if (seenEventVariables.find(varStr) != std::end(seenEventVariables)) return true;
123 seenEventVariables.insert(varStr);
124 return false;
125 });
126 m_event_variables.erase(eventVariablesEnd, m_event_variables.end());
127
129 m_tree.construct(m_treeName.c_str(), "");
130
131 m_valuesDouble.resize(m_variables.size());
132 m_valuesInt.resize(m_variables.size());
135
136 m_tree->get().Branch("__event__", &m_event, "__event__/i");
137 m_tree->get().Branch("__run__", &m_run, "__run__/I");
138 m_tree->get().Branch("__experiment__", &m_experiment, "__experiment__/I");
139 m_tree->get().Branch("__production__", &m_production, "__production__/I");
140 m_tree->get().Branch("__ncandidates__", &m_ncandidates, "__ncandidates__/I");
141 m_tree->get().Branch("__weight__", &m_weight, "__weight__/F");
142
143 if (m_stringWrapper.isOptional("MCDecayString"))
144 m_tree->get().Branch("__MCDecayString__", &m_MCDecayString);
145
146 if (m_storeEventType) {
147 m_tree->get().Branch("__eventType__", &m_eventType);
148 if (not m_eventExtraInfo.isOptional())
149 B2INFO("EventExtraInfo is not registered. __eventType__ will be empty. The eventType is available from MC16 on.");
150 }
151
152
153 for (unsigned int i = 0; i < m_event_variables.size(); ++i) {
154 auto varStr = m_event_variables[i];
155
156 if (Variable::isCounterVariable(varStr)) {
157 B2WARNING("The counter '" << varStr
158 << "' is handled automatically by VariablesToEventBasedTree, you don't need to add it.");
159 continue;
160 }
161
162 //also collection function pointers
164 if (!var) {
165 B2ERROR("Variable '" << varStr << "' is not available in Variable::Manager!");
166 } else {
167 if (var->variabletype == Variable::Manager::VariableDataType::c_double) {
168 m_tree->get().Branch(MakeROOTCompatible::makeROOTCompatible(varStr).c_str(), &m_event_valuesDouble[i],
169 (MakeROOTCompatible::makeROOTCompatible(varStr) + "/D").c_str());
170 } else if (var->variabletype == Variable::Manager::VariableDataType::c_int) {
171 m_tree->get().Branch(MakeROOTCompatible::makeROOTCompatible(varStr).c_str(), &m_event_valuesInt[i],
172 (MakeROOTCompatible::makeROOTCompatible(varStr) + "/I").c_str());
173 } else if (var->variabletype == Variable::Manager::VariableDataType::c_bool) {
174 m_tree->get().Branch(MakeROOTCompatible::makeROOTCompatible(varStr).c_str(), &m_event_valuesInt[i],
175 (MakeROOTCompatible::makeROOTCompatible(varStr) + "/O").c_str());
176 }
177 m_event_functions.push_back(var->function);
178 }
179 }
180
181 for (unsigned int i = 0; i < m_variables.size(); ++i) {
182 auto varStr = m_variables[i];
184 m_valuesInt[i].resize(m_maxCandidates);
185
186 //also collection function pointers
188 if (!var) {
189 B2ERROR("Variable '" << varStr << "' is not available in Variable::Manager!");
190 } else {
191 if (var->variabletype == Variable::Manager::VariableDataType::c_double) {
192 m_tree->get().Branch(MakeROOTCompatible::makeROOTCompatible(varStr).c_str(), &m_valuesDouble[i][0],
193 (MakeROOTCompatible::makeROOTCompatible(varStr) + "[__ncandidates__]/D").c_str());
194 } else if (var->variabletype == Variable::Manager::VariableDataType::c_int) {
195 m_tree->get().Branch(MakeROOTCompatible::makeROOTCompatible(varStr).c_str(), &m_valuesInt[i][0],
196 (MakeROOTCompatible::makeROOTCompatible(varStr) + "[__ncandidates__]/I").c_str());
197 } else if (var->variabletype == Variable::Manager::VariableDataType::c_bool) {
198 m_tree->get().Branch(MakeROOTCompatible::makeROOTCompatible(varStr).c_str(), &m_valuesInt[i][0],
199 (MakeROOTCompatible::makeROOTCompatible(varStr) + "[__ncandidates__]/O").c_str());
200 }
201 m_functions.push_back(var->function);
202 }
203 }
204
205 m_sampling_name = std::get<0>(m_sampling);
206 m_sampling_rates = std::get<1>(m_sampling);
207
208 if (m_sampling_name != "") {
210 if (m_sampling_variable == nullptr) {
211 B2FATAL("Couldn't find sample variable " << m_sampling_name << " via the Variable::Manager. Check the name!");
212 }
213 for (const auto& pair : m_sampling_rates)
214 m_sampling_counts[pair.first] = 0;
215 } else {
216 m_sampling_variable = nullptr;
217 }
218
219}
220
221
223{
224
225 if (m_sampling_variable == nullptr)
226 return 1.0;
227
228 long target = 0;
229 if (m_sampling_variable->variabletype == Variable::Manager::VariableDataType::c_double) {
230 target = std::lround(std::get<double>(m_sampling_variable->function(nullptr)));
231 } else if (m_sampling_variable->variabletype == Variable::Manager::VariableDataType::c_int) {
232 target = std::lround(std::get<int>(m_sampling_variable->function(nullptr)));
233 } else if (m_sampling_variable->variabletype == Variable::Manager::VariableDataType::c_bool) {
234 target = std::lround(std::get<bool>(m_sampling_variable->function(nullptr)));
235 }
236
237 if (m_sampling_rates.find(target) != m_sampling_rates.end() and m_sampling_rates[target] > 0) {
238 m_sampling_counts[target]++;
239 if (m_sampling_counts[target] % m_sampling_rates[target] != 0)
240 return 0;
241 else {
242 m_sampling_counts[target] = 0;
243 return m_sampling_rates[target];
244 }
245 }
246
247 return 1.0;
248}
249
251{
252 // get counter numbers
253 m_event = m_eventMetaData->getEvent();
254 m_run = m_eventMetaData->getRun();
255 m_experiment = m_eventMetaData->getExperiment();
256 m_production = m_eventMetaData->getProduction();
257
258 if (m_stringWrapper.isValid())
259 m_MCDecayString = m_stringWrapper->getString();
260 else
261 m_MCDecayString = "";
262
263 if (m_storeEventType and m_eventExtraInfo.isValid())
264 m_eventType = m_eventExtraInfo->getEventType();
265 else
266 m_eventType = "";
267
269 m_ncandidates = particlelist->getListSize();
271 if (m_weight > 0) {
272 for (unsigned int iVar = 0; iVar < m_event_functions.size(); iVar++) {
273 if (std::holds_alternative<double>(m_event_functions[iVar](nullptr))) {
274 m_event_valuesDouble[iVar] = std::get<double>(m_event_functions[iVar](nullptr));
275 } else if (std::holds_alternative<int>(m_event_functions[iVar](nullptr))) {
276 m_event_valuesInt[iVar] = std::get<int>(m_event_functions[iVar](nullptr));
277 } else if (std::holds_alternative<bool>(m_event_functions[iVar](nullptr))) {
278 m_event_valuesInt[iVar] = std::get<bool>(m_event_functions[iVar](nullptr));
279 }
280 }
281 for (unsigned int iPart = 0; iPart < m_ncandidates; iPart++) {
282
283 if (iPart >= m_maxCandidates) {
284 B2WARNING("Maximum number of candidates exceeded in VariablesToEventBasedTree module. I will skip additional candidates");
286 break;
287 }
288
289 const Particle* particle = particlelist->getParticle(iPart);
290 for (unsigned int iVar = 0; iVar < m_functions.size(); iVar++) {
291 if (std::holds_alternative<double>(m_functions[iVar](particle))) {
292 m_valuesDouble[iVar][iPart] = std::get<double>(m_functions[iVar](particle));
293 } else if (std::holds_alternative<int>(m_functions[iVar](particle))) {
294 m_valuesInt[iVar][iPart] = std::get<int>(m_functions[iVar](particle));
295 } else if (std::holds_alternative<bool>(m_functions[iVar](particle))) {
296 m_valuesInt[iVar][iPart] = std::get<bool>(m_functions[iVar](particle));
297 }
298 }
299 }
300 m_tree->get().Fill();
301 }
302}
303
305{
307 B2INFO("Writing TTree " << m_treeName);
308 TDirectory::TContext directoryGuard(m_file.get());
309 m_tree->write(m_file.get());
310
311 const bool writeError = m_file->TestBit(TFile::kWriteError);
312 m_file.reset();
313 if (writeError) {
314 B2FATAL("A write error occurred while saving '" << m_fileName << "', please check if enough disk space is available.");
315 }
316 }
317}
In the store you can park objects that have to be accessed by various modules.
Definition DataStore.h:51
@ c_DontWriteOut
Object/array should be NOT saved by output modules.
Definition DataStore.h:71
const std::string & getOutputFileOverride() const
Return overridden output file name, or "" if none was set.
static Environment & Instance()
Static method to get a reference to the Environment instance.
static std::string makeROOTCompatible(std::string str)
Remove special characters that ROOT dislikes in branch names, e.g.
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition Module.cc:208
Module()
Constructor.
Definition Module.cc:30
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition Module.h:80
@ c_TerminateInAllProcesses
When using parallel processing, call this module's terminate() function in all processes().
Definition Module.h:83
Class to store reconstructed particles.
Definition Particle.h:76
static bool isOutputProcess()
Return true if the process is an output process.
static bool parallelProcessingUsed()
Returns true if multiple processes have been spawned, false in single-core mode.
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:96
std::vector< std::string > resolveCollections(const std::vector< std::string > &variables)
Resolve Collection Returns variable names corresponding to the given collection or if it is not a col...
Definition Manager.cc:180
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition Manager.cc:58
static Manager & Instance()
get singleton instance.
Definition Manager.cc:26
std::vector< std::string > m_variables
List of variables to save.
unsigned int m_maxCandidates
maximum number of candidates which is written out
std::vector< std::string > m_event_variables
List of event variables to save.
virtual void initialize() override
Initialises the module.
std::map< int, unsigned int > m_sampling_rates
Inverse sampling rates.
std::vector< int > m_event_valuesInt
Values of type int corresponding to given event variables.
virtual void event() override
Method called for each event.
unsigned int m_ncandidates
number of candidates in this event
virtual void terminate() override
Write TTree to file, and close file if necessary.
StoreObjPtr< EventMetaData > m_eventMetaData
event metadata (get event number etc)
std::map< int, unsigned long int > m_sampling_counts
Current number of samples with this value.
std::string m_fileName
Name of ROOT file for output.
std::tuple< std::string, std::map< int, unsigned int > > m_sampling
Tuple of variable name and a map of integer values and inverse sampling rate.
std::vector< std::vector< double > > m_valuesDouble
Values of type double corresponding to given variables.
float getInverseSamplingRateWeight()
Calculate inverse sampling rate weight.
int m_production
production ID (to distinguish MC samples)
StoreObjPtr< StringWrapper > m_stringWrapper
string wrapper storing the MCDecayString
bool m_storeEventType
If true, the branch eventType is added.
std::vector< Variable::Manager::FunctionPtr > m_functions
List of function pointers corresponding to given variables.
std::string m_particleList
Name of particle list with reconstructed particles.
bool m_ignoreCommandLineOverride
if true, ignore override of filename
StoreObjPtr< RootMergeable< TTree > > m_tree
The ROOT TNtuple for output.
std::shared_ptr< TFile > m_file
ROOT file for output.
std::string m_sampling_name
Variable name of sampling variable.
StoreObjPtr< EventExtraInfo > m_eventExtraInfo
pointer to EventExtraInfo
std::vector< std::vector< int > > m_valuesInt
Values of type int corresponding to given variables.
std::vector< double > m_event_valuesDouble
Values of type double corresponding to given event variables.
const Variable::Manager::Var * m_sampling_variable
Variable Pointer to target variable.
std::vector< Variable::Manager::FunctionPtr > m_event_functions
List of function pointers corresponding to given event variables.
std::string m_fileNameSuffix
Suffix to be appended to the output file name.
std::string m_MCDecayString
MC decay string to be filled.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
std::shared_ptr< TFile > getFile(std::string, bool ignoreErrors=false)
Get a file with a specific name, if is does not exist it will be created.
static RootFileCreationManager & getInstance()
Interface for the FileManager.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
bool isReservedTreeName(const std::string &name)
Check whether a tree name is a reserved basf2 tree name as defined in RootIOUtilities::c_treeNames.
Abstract base class for different kinds of events.
STL namespace.
A variable returning a floating-point value for a given Particle.
Definition Manager.h:146