Hello ROOT forum,
I am having issues with generating dictionaries. Here’s a standalone, simplified reproducer MG_reproducer.C
. It looks for all udcs / anti quarks in an event and creates a vector of their 4-vectors, and saves that information at another .root file.
It has three helper functions: findPIDIndex
, which looks up a particle’s index from Particle.PID, get4Vector
, which creates a 4-vector, and get4VectorIndex
, which creates 4-vectors from indices of particles in the Particle class.
#include <ROOT/RDataFrame.hxx>
#include <ROOT/RVec.hxx>
#include <TLorentzVector.h>
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
std::vector<int> findPIDIndex(const ROOT::VecOps::RVec<int>& pid, const std::vector<int>& myIDs) {
std::vector<int> ret;
ret.reserve(pid.size()); // Reserve memory upfront for ret
for (int i = 0; i < pid.size(); ++i) {
for (int j = 0; j < myIDs.size(); ++j) {
if (pid[i] == myIDs[j]) {
ret.emplace_back(i);
}
}
}
return ret;
}
/*
Given a particle's parameters, output its 4-vector.
mode = 'xyze': register inputs as x, y, z and E
mode = 'pepm': register inputs as PT, eta, phi and mass
Default mode is 'xyze'.
*/
TLorentzVector get4Vec(
const double input1,
const double input2,
const double input3,
const double input4,
const std::string& mode)
{
TLorentzVector ret;
if (mode == "xyze") {
ret.SetPxPyPzE(input1, input2, input3, input4);
} else if (mode == "pepm") {
ret.SetPtEtaPhiM(input1, input2, input3, input4);
} else {
throw std::runtime_error("get4Vec: cannot recognise input string");
}
return ret;
}
/*
Given four input vectors, take the 4-vector from some given indices. return a vector of vectors ...! this preserves the order in indices.
*/
ROOT::VecOps::RVec<TLorentzVector> get4VecIndex(
const std::vector<int>& indices,
const ROOT::VecOps::RVec<Float_t>& inputVec1,
const ROOT::VecOps::RVec<Float_t>& inputVec2,
const ROOT::VecOps::RVec<Float_t>& inputVec3,
const ROOT::VecOps::RVec<Float_t>& inputVec4,
const std::string& mode)
{
ROOT::VecOps::RVec<TLorentzVector> retVector;
TLorentzVector ret_i;
for (int i = 0; i < indices.size(); ++i) {
ret_i = get4Vec(
inputVec1[ indices[i] ],
inputVec2[ indices[i] ],
inputVec3[ indices[i] ],
inputVec4[ indices[i] ],
mode);
retVector.emplace_back(ret_i);
}
return retVector;
}
int MG_reproducer() {
ROOT::EnableImplicitMT(); // Tell ROOT you want to go parallel
/* my file set-up */
std::string name_of_folder = "MG_0704";
std::string path = "/isilon/data/users/jhuan166/MG5_aMC_v3_5_0/" + name_of_folder + "/Events/run_01";
std::string f_in = "tag_1_delphes_events";
std::string full_path = path + "/" + f_in + ".root";
ROOT::RDataFrame df("Delphes", full_path); // Interface to TTree and TChain
/* obtain the tag udcs and their anti */
auto d1 = df.Define("Gen_qqx_indices", "return findPIDIndex(Particle.PID, {1, 2, 3, 4, -1, -2, -3, -4});"); // udcs and their anti
/* obtain a vector of 4-vecs. There would be two of them. */
d1 = d1.Define("Gen_qqx_4vecs", "return get4VecIndex(Gen_qqx_indices, Particle.Px, Particle.Py, Particle.Pz, Particle.E, \"xyze\");");
std::string f_out = "tag_1_delphes_events_tagged";
std::string full_path_out = path + "/" + f_out + ".root";
d1.Snapshot("Delphes", full_path_out, {"Gen_qqx_indices", "Gen_qqx_4vecs"});
return 0;
}
The error I get is
Error in <TTree::Branch>: The class requested (vector<TLorentzVector,ROOT::Detail::VecOps::RAdoptAllocator<TLorentzVector> >) for the branch "Gen_qqx_4vecs" is an instance of an stl collection and does not have a compiled CollectionProxy. Please generate the dictionary for this collection (vector<TLorentzVector,ROOT::Detail::VecOps::RAdoptAllocator<TLorentzVector> >) to avoid to write corrupted data.
RDataFrame::Run: event loop was interrupted
This error is repeated many times until it says
Error in <TRint::HandleTermInput()>: std::logic_error caught: Trying to insert a null branch address.
I get this error even after I tried compiling it in root, using .L MG_reproducer.C+
. It compiles successfully. I am using this technique from this tutorial by Enrico Guiraud. I also get similar errors if I use a std::vector<TLorentzVector
instead of a ROOT::VecOps::RVec<TLorentzVector>
.
Many thanks!