Sum for each RVec column, returning an RVec

Dear experts,

I have written a custom action which attempts to compute out of a RVec column a
RVec sum .
Here the code :

using namespace ROOT::VecOps;
template<typename T , int N  >
class SUMRVEC : public ROOT::Detail::RDF::RActionImpl<SUMRVEC<T,N>> {
    public  : 
    const int NBSLOTS = N;
    using Result_t = T;    
    std::shared_ptr<Result_t> fResultSum;
    std::vector< Result_t > fSumsPerSlot;
    SUMRVEC(){
    std::cout<<"Constructor"<<std::endl;
    const auto nSlots = ROOT::IsImplicitMTEnabled() ?  ROOT::GetImplicitMTPoolSize() : 1;
    for (auto slot : ROOT::TSeqU(0,nSlots)){
        T slotSum; 
        slotSum.resize(N);
        for( int j = 0; j < N; ++j){
            slotSum[j] = 0; 
        }
        fSumsPerSlot.push_back( slotSum);
    }
    T myVec(N);
    fResultSum = std::make_shared<T>( myVec);
  }
  SUMRVEC( SUMRVEC &&)= default;  
  SUMRVEC( const SUMRVEC &) = delete;  
  void Exec(unsigned int slot, const T &vs)
                    
   
{
        std::cout<<"EXEC"<<std::endl;
        for( auto  slot : ROOT::TSeqU(0, fSumsPerSlot.size())){                
            for( int i = 0 ; i < vs.size(); ++i){
             fSumsPerSlot[slot][i] += vs.at(i);
            }
        }        
   }
  void Initialize() {
      std::cout<<"Initialize"<<std::endl;
      (*fResultSum).resize(N);
      for( int i = 0; i < N; ++i){
          (*fResultSum)[i] = 0.;
      }
  }
  void Finalize(){
        for( auto  slot : ROOT::TSeqU(0, fSumsPerSlot.size())){                
            for(int i = 0; i< N; ++i){
                (*fResultSum)[i] += fSumsPerSlot[slot][i];
            }                  
        }       
   }
    std::shared_ptr<T> GetResultPtr() const { 
         std::cout<<"ResultPtr"<<std::endl;
        return  fResultSum;
    }
    void InitTask(TTreeReader *, unsigned int) {}
    std::string GetActionName(){
        return "SUMRVEC";
    }   
};

and a tester for 100-vector lenght column .

I wonder if you have any suggestions on how to make it working in a MT environment and if in my implementation i am skipping some details.

Thanks in advance

Renato

Proto.C (2.9 KB)


Please read tips for efficient and successful posting and posting code

ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided


Perhaps @eguiraud has some useful tips.

Hi, all
Basically i am using the class in a real case :

What i do is

            ROOT::RDataFrame  dfDecay(*_tupleShared.GetTuple());

            RNode last_node      = dfDecay.Define("1>0","CRAPDEFINE");

            using BSWeightSumColumn =  decltype(dfDecay.Book< RVec<double>>( std::move( test), {"RndPoisson"}));

            map< TString , map< TriggerSlot_weightConfig , BSWeightSumColumn  > > _sumWBSWeights;         


                        SumVecCol<RVec<double>, WeightDefRX::nBS> sumWBSFULL; 
                        _sumWBSWeights[_weightOption][_slot]       =  nodes_cuts[FullSelectionDT].Define("weightBSFull" , weightBS_FULL.Data())
                                                                                                 .Book< RVec<double>>( std::move( sumWBSFULL), {"weightBSFull"});

having the class for the custom action defined as :


template<typename T , int N  >
class SumVecCol : public ROOT::Detail::RDF::RActionImpl<SumVecCol<T,N>> {

When i try to compile i get this :



uilding CXX object CMakeFiles/efficiencyCreateFast.out.dir/targets/efficiencyCreateFast.cpp.o
FAILED: CMakeFiles/efficiencyCreateFast.out.dir/targets/efficiencyCreateFast.cpp.o 
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/bin/g++   -I/cvmfs/sft.cern.ch/lcg/releases/yamlcpp/0.6.2-fd0ec/x86_64-centos7-gcc8-opt/include -I../../pyloops -I../../roofit/src -I../../roofit/inc -I../../velo/src -I../../velo/inc -I../../kernel/src -I../../kernel/inc -I../../tuples/src -I../../tuples/inc -I../../optimization/src -I../../optimization/inc -I../../efficiencies/src -I../../efficiencies/inc -I../../fitter/src -I../../fitter/inc -I../../toys/src -I../../toys/inc -isystem /cvmfs/sft.cern.ch/lcg/releases/vdt/0.4.3-992df/x86_64-centos7-gcc8-opt/include -fPIC -DDROP_CGAL -Wno-return-type -Wno-deprecated-declarations -Wimplicit-fallthrough  -std=c++17 -pipe -fsigned-char -pthread -O2 -g -DNDEBUG   -std=gnu++17 -MD -MT CMakeFiles/efficiencyCreateFast.out.dir/targets/efficiencyCreateFast.cpp.o -MF CMakeFiles/efficiencyCreateFast.out.dir/targets/efficiencyCreateFast.cpp.o.d -o CMakeFiles/efficiencyCreateFast.out.dir/targets/efficiencyCreateFast.cpp.o -c ../../targets/efficiencyCreateFast.cpp
In file included from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/unique_ptr.h:37,
                 from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/locale_conv.h:41,
                 from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/locale:43,
                 from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/iomanip:43,
                 from ../../kernel/inc/MessageSvc.hpp:5,
                 from ../../kernel/inc/EnumeratorSvc.hpp:4,
                 from ../../kernel/inc/IOSvc.hpp:4,
                 from ../../efficiencies/inc/CounterHelpers.hpp:4,
                 from ../../targets/efficiencyCreateFast.cpp:6:
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/tuple: In instantiation of ‘std::pair<_T1, _T2>::pair(std::tuple<_Args1 ...>&, std::tuple<_Args2 ...>&, std::_Index_tuple<_Indexes1 ...>, std::_Index_tuple<_Indexes2 ...>) [with _Args1 = {const TString&}; long unsigned int ..._Indexes1 = {0}; _Args2 = {}; long unsigned int ..._Indexes2 = {}; _T1 = const TString; _T2 = ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void>]’:
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/tuple:1657:63:   required from ‘std::pair<_T1, _T2>::pair(std::piecewise_construct_t, std::tuple<_Args1 ...>, std::tuple<_Args2 ...>) [with _Args1 = {const TString&}; _Args2 = {}; _T1 = const TString; _T2 = ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void>]’
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/ext/new_allocator.h:136:4:   required from ‘void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> >; _Args = {const std::piecewise_construct_t&, std::tuple<const TString&>, std::tuple<>}; _Tp = std::_Rb_tree_node<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >]’
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/alloc_traits.h:475:4:   required from ‘static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> >; _Args = {const std::piecewise_construct_t&, std::tuple<const TString&>, std::tuple<>}; _Tp = std::_Rb_tree_node<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::_Rb_tree_node<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > > >]’
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/stl_tree.h:637:32:   required from ‘void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_construct_node(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const TString&>, std::tuple<>}; _Key = TString; _Val = std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> >; _KeyOfValue = std::_Select1st<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; _Compare = std::less<TString>; _Alloc = std::allocator<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >*]’
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/stl_tree.h:654:4:   required from ‘std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const TString&>, std::tuple<>}; _Key = TString; _Val = std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> >; _KeyOfValue = std::_Select1st<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; _Compare = std::less<TString>; _Alloc = std::allocator<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >*]’
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/stl_tree.h:2414:13:   required from ‘std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_hint_unique(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator, _Args&& ...) [with _Args = {const std::piecewise_construct_t&, std::tuple<const TString&>, std::tuple<>}; _Key = TString; _Val = std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> >; _KeyOfValue = std::_Select1st<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; _Compare = std::less<TString>; _Alloc = std::allocator<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::const_iterator = std::_Rb_tree_const_iterator<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >]’
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/stl_map.h:499:8:   required from ‘std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const key_type&) [with _Key = TString; _Tp = ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void>; _Compare = std::less<TString>; _Alloc = std::allocator<std::pair<const TString, ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void> > >; std::map<_Key, _Tp, _Compare, _Alloc>::mapped_type = ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void>; std::map<_Key, _Tp, _Compare, _Alloc>::key_type = TString]’
../../targets/efficiencyCreateFast.cpp:1188:97:   required from here
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/tuple:1668:70: error: no matching function for call to ‘ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase, void>::RInterface()’
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
                                                                      ^
In file included from /cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDataFrame.hxx:20,
                 from ../../efficiencies/inc/CounterHelpers.hpp:9,
                 from ../../targets/efficiencyCreateFast.cpp:6:
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDF/RInterface.hxx:2481:4: note: candidate: ‘ROOT::RDF::RInterface<T, V>::RInterface(const std::shared_ptr<_Tp>&, ROOT::RDF::RInterface<T, V>::RLoopManager&, const ROOT::Internal::RDF::RBookedCustomColumns&, ROOT::RDF::RDataSource*) [with Proxied = ROOT::Detail::RDF::RNodeBase; DataSource = void; ROOT::RDF::RInterface<T, V>::RLoopManager = ROOT::Detail::RDF::RLoopManager]’
    RInterface(const std::shared_ptr<Proxied> &proxied, RLoopManager &lm,
    ^~~~~~~~~~
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDF/RInterface.hxx:2481:4: note:   candidate expects 4 arguments, 0 provided
In file included from /cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDataFrame.hxx:20,
                 from ../../efficiencies/inc/CounterHelpers.hpp:9,
                 from ../../targets/efficiencyCreateFast.cpp:6:
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDF/RInterface.hxx:126:4: note: candidate: ‘template<class T, typename std::enable_if<std::is_same<T, ROOT::Detail::RDF::RLoopManager>::value, int>::type <anonymous> > ROOT::RDF::RInterface<T, V>::RInterface(const std::shared_ptr<_Tp>&)’
    RInterface(const std::shared_ptr<Proxied> &proxied)
    ^~~~~~~~~~
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDF/RInterface.hxx:126:4: note:   template argument deduction/substitution failed:
In file included from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/unique_ptr.h:37,
                 from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/bits/locale_conv.h:41,
                 from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/locale:43,
                 from /cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/iomanip:43,
                 from ../../kernel/inc/MessageSvc.hpp:5,
                 from ../../kernel/inc/EnumeratorSvc.hpp:4,
                 from ../../kernel/inc/IOSvc.hpp:4,
                 from ../../efficiencies/inc/CounterHelpers.hpp:4,
                 from ../../targets/efficiencyCreateFast.cpp:6:
/cvmfs/sft.cern.ch/lcg/releases/gcc/8.3.0-cebb0/x86_64-centos7/include/c++/8.3.0/tuple:1668:70: note:   candidate expects 1 argument, 0 provided
         second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
                                                                      ^
In file included from /cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDataFrame.hxx:20,
                 from ../../efficiencies/inc/CounterHelpers.hpp:9,
                 from ../../targets/efficiencyCreateFast.cpp:6:
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDF/RInterface.hxx:121:4: note: candidate: ‘ROOT::RDF::RInterface<T, V>::RInterface(ROOT::RDF::RInterface<T, V>&&) [with Proxied = ROOT::Detail::RDF::RNodeBase; DataSource = void]’
    RInterface(RInterface &&) = default;
    ^~~~~~~~~~
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDF/RInterface.hxx:121:4: note:   candidate expects 1 argument, 0 provided
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include/ROOT/RDF/RInterface.hxx:117:4: note: candidate: ‘ROOT::RDF::RInterface<T, V>::RInterface(const ROOT::RDF::RInterface<T, V>&) [with Proxied = ROOT::Detail::RDF::RNodeBase; DataSource = void]’
    RInterface(const RInterface &) = default;
    ^~~~~~~~~~
/cvmfs/sft.cern.ch/lcg/views/LCG_96b/x86_64-centos7-gcc8-opt/include

If i comment out the map-value assignment it works.
I wonder how i can cast the Book<> operation with my custom Action implementation in the map.

Thanks.

in practice the problem is how to add to a map< TString, XXX>
where XXX is the output of a Book call.
What are the specifics the Functor for the Book needs to have?

I got it compiling, however i don’t understand one thing about caching Filter() nodes.
Here the snippet

map<  TString , ROOT::RDF::RResultPtr<RVec<double> > > _sumWBSWeights;         
map<TString, ROOT::RDF::RNode>  nodes_cuts; 
for( config:  list_of_configurations ){ 
    TString cutString = TString(config.Cut().GetTitle());
    if( nodes_cuts.find(cutString) == nodes_cuts.end()){ 
        //given the large amount of filters, i optimize caching it. 
         nodes_cuts.insert( pair<TString, RNode>( cutString, df.Filter( cutString)); 
    } 
    TString weightConfig = config.GetWeight(); //this is different to each loop 
    /* 
     // THIS DOESN'T WORK
    _sumWBSWeights[weightConfig] = nodes_cuts[cutString].Book< ....>( ) ; 
    */
    _sumWBSWeights[weightConfig] = nodes_cuts.find( cutString)->second.Book< >(); //this works;
} 

Do you know why ? I am not so sure to understand why map[] vs find(XX)->second would allow me to book inside a map a Node .

(BTW: any tips on improving the syntax and ensuring MT is working fine on the custom class is more than welcome)

Here the updated script.
Unfortunately i tested enabling/disabling MT and i get different results.
Do you have any help on making it MT-safe ?
Proto.C (3.1 KB)

Hi, Here my final implementation ( which i think is working)

using namespace ROOT::VecOps;
template<typename T , int N  >
class SumVecCol : public ROOT::Detail::RDF::RActionImpl<SumVecCol<T,N>> {
    public  : 
    const int NBSLOTS = N;
    using Result_t = T;   
    bool m_debug  = true;
    TString m_name; 
    std::shared_ptr<Result_t> fResultSum;
    std::vector< Result_t > fSumsPerSlot;

    SumVecCol(TString _name){
        m_name = _name;
        if(m_debug){ 
            std::cout<< "Create with name "<< _name<<std::endl;
        }
        const auto nSlots = ROOT::IsImplicitMTEnabled() ?  ROOT::GetImplicitMTPoolSize() : 1;
        std::cout<<"# Create Custom Action SumVecCol(Init) : use nSLOTS "<< nSlots << " , " << m_name<< std::endl;
        for (auto slot : ROOT::TSeqU(nSlots)){
            T slotSum; 
            slotSum.resize(N);
            for( int j = 0; j < N; ++j){
                slotSum[j] = 0; 
            }
            fSumsPerSlot.push_back( slotSum);
            (void)slot;
        }
        std::cout<<"- SumVecSlots size() = "<< fSumsPerSlot.size() << "   with name " << m_name<< std::endl;
        for( int i = 0; i < nSlots ; ++i){
            std::cout<<" - SumVecSlots["<<i<<"] size = "<< fSumsPerSlot[i].size() << std::endl;
        }
        //Initialize for safety the final results to start from 0. the weight counting 
        T myVec(N); 
        for( int i = 0; i < N; ++i){
            myVec[i] = 0.;
        }
        fResultSum = std::make_shared<T>( myVec ); //should be enough to avoid going out of scope?
        std::cout<<"- SumResults size() = "<< (*fResultSum).size()<< std::endl;
        
    }
    SumVecCol( SumVecCol &&)= default;  
    SumVecCol( const SumVecCol &) = delete;  
    void Exec(unsigned int slot, const T &vs){     
        // if(m_debug){ 
        //     std::cout<< "Exec slot "<< slot<<std::endl;
        // }         
        // for( int i = 0 ; i < vs.size(); ++i){
        fSumsPerSlot[slot] += vs; //should be using RVec<double> sum operation?
        // }            
    }
    void Initialize() {
        //No init! Maybe share_ptr making has to go in constructor?
    }
    void Finalize(){
        std::cout<<"# Booked Custom Action SumVecCol(Finalize)" << std::endl;
        for( auto & m : fSumsPerSlot){
            std::cout<<"Result+=SlotResult"<<std::endl;
            *fResultSum += m;
        }      
    }
    std::shared_ptr<T> GetResultPtr() const { 
        //  std::cout<<"ResultPtr"<<std::endl;
        return  fResultSum;
    }
    void InitTask(TTreeReader *, unsigned int) {}

    std::string GetActionName(){
        return "SUMRVEC";
    }   
};

The thing i was fighting agains was the fact that the shared_ptr initialization must go in the creator and not in the Initialize(), which i left empty now.
I wonder if this information is correct , what i noticed is that when i plug the RReultPtr from my Booked action in a container, then I trigger the event loop and I try to access the GetValue() it segfault, as if the shared_ptr for results disappers.
Moving the initialziations inside the creator, fixed the problem.
Concering MT functionality , i was doing a bad loop in the Exec. Now it should work.
The full updated script with this class in attachment.
@eguiraud do you think something like this can be useful to be implemented in ROOT?

something like

auto vec100Sum = df.SumVec< RVec<double>, 100 >( "vec-colum") 

I.e in the case where the user knows in advance the length of the vec-column to use, and want to gather a summation over each entry rather thatn a sum of sum.
Proto.C (3.9 KB)

Yes that’s correct. I made a note to improve the documentation of Book to specify that GetResultPtr can be called before Initialize. Initialize is called at the beginning of the event loop, GetResultPtr is called while still building the computation graph, to create the RResultPtr for that action.

It didn’t disappear, it was never there: the RResultPtr was constructed from a null shared_ptr (the one returned by SumVecCol::GetResultPtr before Initialize was executed).

I this can be done with Reduce:

RVec<double> VecSum(const RVec<double> &v1, const RVec<double> &v2) {
  return v1 + v2;
}
...
df.Reduce(VecSum, {"vec-column"}, RVec<double>(100, 0));

Sorry for not thinking about it before!

Cheers,
Enrico

1 Like

This is a very elegant trick!!!
Anyway, it was helpful for me to try implementing this Sum as custom action.
I guess the Reduce is extensively tested to work in MT environment, right?

Just a question, is the Reduce operation, something “booked” and one can still trigger several calculations of Reducing oprations?
I.e is Reduce returning a RResultPtr<RVec<double>> ?

Yes it’s a normal RDF action, see the docs. If the reduce function is thread-safe everything’s fine, as usual.

1 Like

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