pyROOT RDataFrame Reduce Vector branch TypeError

python Version: 3.8.6
ROOT Version: 6.22/02
Platform: linux (lxplus)
Compiler: cling

Hello People of the ROOT forums,

I want to use RDataFrames in python to compute the sum of vector branches in my TTrees.
For this, there is the possibility of using RDataFrame::Reduce, however i’m struggling to transfer code from root cpp to pyROOT.
The culprit seems to be templates used in cpp which arent easily transferable to python.
I attached a python script as a minimal example to this post as well as a cpp script to show the working functionality using root cpp.
As a TLDR:
In cpp root i can use:

    ROOT::RDataFrame df("Tree", "RDF.root");
    auto Node = df.Define("w", "x * y * rndPoisson");
    auto Sums = Node.Reduce< RVec<double> (const RVec<double> &, const RVec<double> &)>(VecSum, "w", RVec<double>(100, 0));
    cout << Sums.GetValue() << endl;

While in python all my attempts have resulted in Errors, here is my most recent try:

    Node = df.Define('w', 'x * y * rndPoisson')
    Sums = Node.Reduce['ROOT::VecOps::RVec<double> (const ROOT::VecOps::RVec<double> &, const ROOT::VecOps::RVec<double> &)'](r.VecSum, 'w', r.RVec['double'](100, 0)).GetValue()

StandAlone.cpp (405 Bytes) StandAlone.py (1.3 KB)

If anyone has an idea how to solve this problem i would be glad to hear it!
Cheers,
Sebastian

Error Message in python:

    Sums = Node.Reduce['ROOT::VecOps::RVec<double> (const ROOT::VecOps::RVec<double> &, const ROOT::VecOps::RVec<double> &)'](r.VecSum, 'w', r.RVec['double'](100, 0)).GetValue()
TypeError: Could not instantiate Reduce<ROOT::VecOps::RVec<double> (const ROOT::VecOps::RVec<double> &, const ROOT::VecOps::RVec<double> &)>:
  ROOT::RDF::RResultPtr<ROOT::VecOps::RVec<double> > ROOT::RDF::RInterface<ROOT::Detail::RDF::RLoopManager,void>::Reduce(RVec<double> f, basic_string_view<char,char_traits<char> > columnName = "") =>
    TypeError: takes at most 2 arguments (3 given)

Hi,
PyROOT sometimes chokes on template functions with function arguments but works when you pass functor classes instead of free functions. This should work:

    vecSumCode='''                                                                                                      
    using namespace ROOT::VecOps;                                                                                       
    struct SumHelper {                                                                                                  
        RVec<double> operator()(const RVec<double> &v1, const RVec<double> &v2) {                                       
            return v1 + v2;                                                                                             
        }                                                                                                               
    };                                                                                                                  
    '''    
    r.gInterpreter.Declare(vecSumCode)                                                                                  
    # build RDF                                                                                                         
    df = makeTree('Tree', 'RDF.root')                                                                                   
    # try to perform sum                                                                                                
    Node = df.Define('w', 'x * y * rndPoisson')                                                                         
    Sums = Node.Reduce(r.SumHelper(), 'w', r.RVec['double'](100)).GetValue()  

Cheers,
Enrico

Hi,
Indeed this works.
Thank you very much for the help and the explanation! :slight_smile:
Cheers,
Sebastian

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