Problem with VecOps::Map method on RVec of Lorentz Vectors

_ROOT Version: 6.22 to 6.24
_Platform: Centos7
_Compiler: gcc8

Dear all,

I would need to understand why a code like the one below does not work. The guilty seems to be the “Map” method (the code runs fine without that instruction). Am I doing anything wrong? Note that df.Report().Print() line is there just to trigger the event loop. Any other equivalent instruction triggering the loop leads to the same error.

Thanks in advance, Juan

###// Python script begins ##########
import ROOT
import array

#/ Create a trivial tree with just one entry with two muons
hfile = ROOT.TFile(“myfile.root”,“RECREATE”)
tree = ROOT.TTree(“events”,“My trivial tree”)
px = array.array(‘f’, [ 10., -10. ])
py = array.array(‘f’, [ 20., -20. ])
pz = array.array(‘f’, [ 30., -30. ])
mass = array.array(‘f’, [ 0.106, 0.106 ])
tree.Branch(‘Muon_px’, px, ‘Muon_px[2]/F’)
tree.Branch(‘Muon_py’, py, ‘Muon_py[2]/F’)
tree.Branch(‘Muon_pz’, pz, ‘Muon_pz[2]/F’)
tree.Branch(‘Muon_mass’, mass, ‘Muon_mass[2]/F’)

#/ Reopen file and use the tree that we have just created
df = ROOT.RDataFrame(“events”,“myfile.root”)

#/ Muon_px, Muon_py, Muon_pz, Muon_mass are already present in the tree, vectors of floats
df = df.Define(“Muon_p4”,“ROOT::VecOps::Construct<ROOT::Math::PxPyPzMVector>(Muon_px, Muon_py, Muon_pz, Muon_mass)”)

df = df.Define(“Muon_theta”,“ROOT::VecOps::Map(Muon_p4,[](ROOT::Math::PxPyPzMVector x){return x.Theta();})”)

###// Python script ends

The error starts with:

In module ‘std’ imported from input_line_1:1:
/cvmfs/…/lib/gcc/x86_64-pc-linux-gnu/8.3.0/…/…/…/…/include/c++/8.3.0/ext/alloc_traits.h:64:23: error: cannot form a reference to ‘void’
typedef value_type& reference;
…Preformatted text

1 Like

I can reproduce the error and I would have expected this to work, too. @eguiraud Can you help?

Hi @alcaraz ,
quickly trying to guess, I think our string-to-c++ conversion logic is confused by the expression that you pass to Define above (because it contains a return statement but not at the “right” place). Without going into the ugly details, does this work instead?

df.Define("Muon_theta", "return ROOT::VecOps::Map(Muon_p4,[](ROOT::Math::PxPyPzMVector x){return x.Theta();})")


Hello @eguiraud,
It seems to work. If I understand properly it seems to be a confusion with the return statement. Should the issue occur with any other object unless we precede it with “return” ?


It’s just that the C++ parsing we do there is a bit rough.
Basically if you pass "x + y" as expression we put a return in there for you and generate the lambda expression [] { return x + y; }, but if you already put a return like in e.g. df.Define("z", "return x + y") we of course don’t add another one.

In your case there is a return in the expression but it’s an inner scope, and our parsing logic does not detect that correctly.

This limitation is quite hard to fix properly (requires to properly parse C++ to figure out scopes and whatnot) and quite easy to work around by manually adding a return, so I’m afraid I don’t have a more elegant solution.


This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.