So I was trying to write a function that can take a vector of expressions which are then used to create a new branch on a given tree where these expressions are evaluated.
For this I first build a vector of TTreeFormula
, from which I extract the names of the branches needed to evaluate all formulas (not taking care of making them unique yet, will add this in the future).
I then create the new branches (using a second character vector which contains the names of the new branches), disable all branches except the newly created and the needed ones.
Finally, I loop over all entries of the tree and fill the new branches. Here is the code of the function:
#include "cppitertools/zip.hpp"
void AddBranches(std::vector<const char *> names, std::vector<const char *> expressions, TTree *tree)
{
auto n_expressions = expressions.size();
std::vector<TTreeFormula *> formulas;
std::vector<TBranch *> branches;
std::vector<Double_t> variables;
// Define formulas and new branches
for (auto expression : iter::zip(names, expressions)) {
formulas.push_back(new TTreeFormula(std::get<0>(expression), std::get<1>(expression), tree));
variables.push_back(Double_t(0.));
branches.push_back(tree->Branch(std::get<0>(expression), &variables.back()));
}
// Activate only needed branches
tree->SetBranchStatus("*", kFALSE);
for (auto branch : branches) {
tree->SetBranchStatus(branch->GetName(), kTRUE);
}
for (auto formula : formulas) {
for (Int_t i = 0; i < formula->GetNcodes(); i++) {
auto branch_name = formula->GetLeaf(i)->GetName();
tree->SetBranchStatus(branch_name, kTRUE);
variables.push_back(Double_t(0.));
tree->SetBranchAddress(branch_name, &variables.back());
}
}
std::cout << "Setup of new branches done" << std::endl;
// Calculate content of new branches
Long64_t nentries = tree->GetEntries();
for (Long64_t i = 0; i < nentries; i++) {
if (i % 100000 == 0) {
std::cout << i << "/" << nentries << std::endl;
}
if (tree->GetEntry(i)) {
for (auto j = 0; j < n_expressions; j++) {
variables[j] = formulas[j]->EvalInstance();
branches[j]->Fill();
}
}
}
// re-activate all branches
tree->SetBranchStatus("*", kTRUE);
}
The cppitertools
can be found here.
This seems to work fine when running it manually in a ROOT session with a given tree (a few GB large) and expressions. However, it quickly fails when trying to run it with root script.cxx++
with the following error, which I don’t understand at all:
===========================================================
#6 0x00007fa77db9ee11 in TList::FindObject (this=<optimized out>, obj=0x558a06492e50) at /cern/root-git2/core/cont/src/TList.cxx:525
#7 0x00007fa77dba1abf in TMap::GetValue (this=0x558a05d8a850, key=key
entry=0x558a06492e50) at /cern/root-git2/core/cont/src/TMap.cxx:249
#8 0x00007fa77b5c895f in TFile::GetCacheRead (this=this
entry=0x558a05d899f0, tree=0x558a06492e50) at /cern/root-git2/io/io/src/TFile.cxx:1210
#9 0x00007fa76ff8952e in TBranch::GetBasket (this=0x558a06cfcb10, basketnumber=0) at /cern/root-git2/tree/tree/src/TBranch.cxx:1141
#10 0x00007fa76ff89ad3 in TBranch::GetEntry (this=0x558a06cfcb10, entry=0, getall=<optimized out>) at /cern/root-git2/tree/tree/src/TBranch.cxx:1275
#11 0x00007fa76ffe2e37 in TTree::<lambda()>::operator() (__closure=<synthetischer Zeiger>) at /cern/root-git2/tree/tree/src/TTree.cxx:5334
#12 TTree::GetEntry (this=0x558a06492e50, entry=0, getall=0) at /cern/root-git2/tree/tree/src/TTree.cxx:5403
#13 0x00007fa76dae57f9 in AddBranches(std::vector<char const*, std::allocator<char const*> >, std::vector<char const*, std::allocator<char const*> >, TTree*) () from /home/andreas/cernbox/work/drell-yan/scripts/reduce_alt_cxx.so
#14 0x00007fa76dae68a0 in reduce_alt(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) () from /home/andreas/cernbox/work/drell-yan/scripts/reduce_alt_cxx.so
#15 0x00007fa77e341156 in ?? ()
#16 0x00007ffd0cfa3978 in ?? ()
#17 0x00007ffd0cfa3940 in ?? ()
#18 0x0000000000000015 in ?? ()
#19 0x00007fa778df8c7d in std::_Function_handler<unsigned long (), llvm::orc::LazyEmittingLayer<llvm::orc::IRCompileLayer<cling::IncrementalJIT::RemovableObjectLinkingLayer> >::EmissionDeferredSet::find(llvm::StringRef, bool, llvm::orc::IRCompileLayer<cling::IncrementalJIT::RemovableObjectLinkingLayer>&)::{lambda()#1}>::_M_invoke(std::_Any_data const&) () from /cern/root-6.09.02/lib/libCling.so
#20 0x00007fa778da60e7 in cling::Interpreter::RunFunction(clang::FunctionDecl const*, cling::Value*) [clone .part.275] () from /cern/root-6.09.02/lib/libCling.so
#21 0x00007fa778da8fad in cling::Interpreter::EvaluateInternal(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, cling::CompilationOptions, cling::Value*, cling::Transaction**, unsigned long) () from /cern/root-6.09.02/lib/libCling.so
#22 0x00007fa778da91d6 in cling::Interpreter::process(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, cling::Value*, cling::Transaction**) () from /cern/root-6.09.02/lib/libCling.so
#23 0x00007fa778e35f12 in cling::MetaProcessor::process(char const*, cling::Interpreter::CompilationResult&, cling::Value*) () from /cern/root-6.09.02/lib/libCling.so
#24 0x00007fa778d30086 in HandleInterpreterException (metaProcessor=<optimized out>, input_line=<optimized out>, compRes=
0x7ffd0cfa3dd4: cling::Interpreter::kSuccess, result=result
entry=0x7ffd0cfa3de0) at /cern/root-git2/core/metacling/src/TCling.cxx:1886
===========================================================
It succeeds if I limit the size of the tree to have only a few (less than 3000) entries.