9 #include <analysis/modules/VariablesToNtuple/VariablesToNtupleModule.h>
12 #include <analysis/dataobjects/ParticleList.h>
13 #include <analysis/VariableManager/Manager.h>
14 #include <analysis/VariableManager/Utility.h>
17 #include <framework/logging/Logger.h>
18 #include <framework/pcore/ProcHandler.h>
19 #include <framework/core/ModuleParam.templateDetails.h>
22 #include <framework/utilities/MakeROOTCompatible.h>
23 #include <framework/utilities/RootFileCreationManager.h>
38 setDescription(
"Calculate variables specified by the user for a given ParticleList and save them into a TNtuple. The TNtuple is candidate-based, meaning that the variables of each candidate are saved separate rows.");
39 setPropertyFlags(c_ParallelProcessingCertified | c_TerminateInAllProcesses);
41 vector<string> emptylist;
42 addParam(
"particleList", m_particleList,
43 "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)",
45 addParam(
"variables", m_variables,
46 "List of variables (or collections) to save. Variables are taken from Variable::Manager, and are identical to those available to e.g. ParticleSelector.",
49 addParam(
"fileName", m_fileName,
"Name of ROOT file for output.",
string(
"VariablesToNtuple.root"));
50 addParam(
"treeName", m_treeName,
"Name of the NTuple in the saved file.",
string(
"ntuple"));
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 candidates and every 10th background candidate.",
58 void VariablesToNtupleModule::initialize()
60 m_eventMetaData.isRequired();
61 if (not m_particleList.empty())
66 if (m_fileName.empty()) {
67 B2FATAL(
"Output root file name is not set. Please set a valid root output file name (\"fileName\" module parameter).");
71 m_file = RootFileCreationManager::getInstance().getFile(m_fileName);
73 B2ERROR(
"Could not create file \"" << m_fileName <<
74 "\". Please set a valid root output file name (\"fileName\" module parameter).");
78 TDirectory::TContext directoryGuard(m_file.get());
81 if (m_file->Get(m_treeName.c_str())) {
82 B2FATAL(
"Tree with the name \"" << m_treeName
83 <<
"\" already exists in the file \"" << m_fileName <<
"\"\n"
84 <<
"\nYou probably want to either set the output fileName or the treeName to something else:\n\n"
85 <<
" from modularAnalysis import variablesToNtuple\n"
86 <<
" variablesToNtuple('pi+:all', ['p'], treename='pions', filename='variablesToNtuple.root')\n"
87 <<
" variablesToNtuple('gamma:all', ['p'], treename='photons', filename='variablesToNtuple.root') # two trees, same file\n"
89 <<
" from modularAnalysis import variablesToNtuple\n"
90 <<
" variablesToNtuple('pi+:all', ['p'], filename='pions.root')\n"
91 <<
" variablesToNtuple('gamma:all', ['p'], filename='photons.root') # two files\n"
97 m_tree.registerInDataStore(m_fileName + m_treeName, DataStore::c_DontWriteOut);
98 m_tree.construct(m_treeName.c_str(),
"");
99 m_tree->get().SetCacheSize(100000);
102 m_tree->get().Branch(
"__experiment__", &m_experiment,
"__experiment__/I");
103 m_tree->get().Branch(
"__run__", &m_run,
"__run__/I");
104 m_tree->get().Branch(
"__event__", &m_event,
"__event__/I");
105 m_tree->get().Branch(
"__production__", &m_production,
"__production__/I");
106 if (not m_particleList.empty()) {
107 m_tree->get().Branch(
"__candidate__", &m_candidate,
"__candidate__/I");
108 m_tree->get().Branch(
"__ncandidates__", &m_ncandidates,
"__ncandidates__/I");
110 for (
const auto& variable : m_variables)
111 if (Variable::isCounterVariable(variable)) {
112 B2WARNING(
"The counter '" << variable
113 <<
"' is handled automatically by VariablesToNtuple, you don't need to add it.");
117 m_variables = Variable::Manager::Instance().resolveCollections(m_variables);
118 m_branchAddresses.resize(m_variables.size() + 1);
119 m_tree->get().Branch(
"__weight__", &m_branchAddresses[0],
"__weight__/D");
120 size_t enumerate = 1;
121 for (
const string& varStr : m_variables) {
125 Variable::Manager::Instance().checkDeprecatedVariable(varStr);
127 m_tree->get().Branch(branchName.c_str(), &m_branchAddresses[enumerate], (branchName +
"/D").c_str());
132 B2ERROR(
"Variable '" << varStr <<
"' is not available in Variable::Manager!");
134 if (m_particleList.empty() && var->description.find(
"[Eventbased]") == string::npos) {
135 B2ERROR(
"Variable '" << varStr <<
"' is not an event-based variable, "
136 "but you are using VariablesToNtuple without a decay string, i.e. in the event-wise mode.\n"
137 "If you have created an event-based alias you can wrap your alias with `eventCached` to "
138 "declare it as event based, which avoids this error.\n\n"
139 "vm.addAlias('myAliasName', 'eventCached(myAlias)')");
142 m_functions.push_back(var->function);
146 m_tree->get().SetBasketSize(
"*", 1600);
148 m_sampling_name = std::get<0>(m_sampling);
149 m_sampling_rates = std::get<1>(m_sampling);
151 if (m_sampling_name !=
"") {
152 m_sampling_variable = Variable::Manager::Instance().getVariable(m_sampling_name);
153 if (m_sampling_variable ==
nullptr) {
154 B2FATAL(
"Couldn't find sample variable " << m_sampling_name <<
" via the Variable::Manager. Check the name!");
156 for (
const auto& pair : m_sampling_rates)
157 m_sampling_counts[pair.first] = 0;
159 m_sampling_variable =
nullptr;
164 float VariablesToNtupleModule::getInverseSamplingRateWeight(
const Particle* particle)
166 if (m_sampling_variable ==
nullptr)
169 long target = std::lround(m_sampling_variable->function(particle));
170 if (m_sampling_rates.find(target) != m_sampling_rates.end() and m_sampling_rates[target] > 0) {
171 m_sampling_counts[target]++;
172 if (m_sampling_counts[target] % m_sampling_rates[target] != 0)
175 m_sampling_counts[target] = 0;
176 return m_sampling_rates[target];
182 void VariablesToNtupleModule::event()
184 m_event = m_eventMetaData->getEvent();
185 m_run = m_eventMetaData->getRun();
186 m_experiment = m_eventMetaData->getExperiment();
187 m_production = m_eventMetaData->getProduction();
189 if (m_particleList.empty()) {
190 m_branchAddresses[0] = getInverseSamplingRateWeight(
nullptr);
191 if (m_branchAddresses[0] > 0) {
192 for (
unsigned int iVar = 0; iVar < m_variables.size(); iVar++) {
193 m_branchAddresses[iVar + 1] = m_functions[iVar](
nullptr);
195 m_tree->get().Fill();
200 m_ncandidates = particlelist->getListSize();
201 for (
unsigned int iPart = 0; iPart < m_ncandidates; iPart++) {
203 const Particle* particle = particlelist->getParticle(iPart);
204 m_branchAddresses[0] = getInverseSamplingRateWeight(particle);
205 if (m_branchAddresses[0] > 0) {
206 for (
unsigned int iVar = 0; iVar < m_variables.size(); iVar++) {
207 m_branchAddresses[iVar + 1] = m_functions[iVar](particle);
209 m_tree->get().Fill();
215 void VariablesToNtupleModule::terminate()
217 if (!ProcHandler::parallelProcessingUsed() or ProcHandler::isOutputProcess()) {
218 B2INFO(
"Writing NTuple " << m_treeName);
219 TDirectory::TContext directoryGuard(m_file.get());
220 m_tree->write(m_file.get());
222 const bool writeError = m_file->TestBit(TFile::kWriteError);
225 B2FATAL(
"A write error occurred while saving '" << m_fileName <<
"', please check if enough disk space is available.");
In the store you can park objects that have to be accessed by various modules.
Class to store reconstructed particles.
bool isRequired(const std::string &name="")
Ensure this array/object has been registered previously.
Type-safe access to single objects in the data store.
Module to calculate variables specified by the user for a given ParticleList and save them into a ROO...
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.
Abstract base class for different kinds of events.
A variable returning a floating-point value for a given Particle.