Issue in calling a c++ template function with pyroot

Hi pyroot experts,
I’m trying to call this c++ template function* with pyroot:

ROOT.gInterpreter.Declare("""....""")
types = ['float','float','float','float','float']
ROOT.Histogram(*types)(d, histoname, rules, binsVec, args)

this trial is unsuccessful in giving the correct template types:

ROOT.Histogram(*types)(d, histoname, rules, binsVec, args)
TypeError: Template method resolution failed:
  void ::Histogram(ROOT::RDF::RInterface<ROOT::Detail::RDF::RNodeBase,void> d, string name, map<pair<string,bool>,vector<string> > variationRules, vector<vector<float> > bins, const vector<string>& columns) =>
    TypeError: could not convert argument 1
  Failed to instantiate "Histogram(std::string,std::string,std::string,std::string,std::string)"

can you spot what I am doing wrong?

Cheers,
Elisabetta

#include "/scratchnvme/emanca/wproperties-analysis/RDFprocessor/framework/interface/boostHistoHelper.hpp"
using RNode = ROOT::RDF::RNode;

template <typename... Ts>
void Histogram(RNode d, std::string name, std::map<std::pair<std::string, bool>, std::vector<std::string>> variationRules, std::vector<std::vector<float>> bins, const std::vector<std::string> & columns)
{
    auto vec = [](float value) {
        ROOT::VecOps::RVec<float> myvec;
        myvec.push_back(value);
        return myvec;
    };

    bool check = false;
    std::vector<std::string> new_cols;
    std::string s = "RVec";
    for(auto &col:columns){
        if(col.find(s) != std::string::npos){// if it's a vector
            bool found = false;
            for(auto &x:variationRules){
                if(x.first.first==col) found = true;
            }
            if(found) check = true;
            new_cols.emplace_back(col);
        }
        else{// if it's a scalar
            bool found = false;
            for(auto &x:variationRules){
                if(x.first.first==col) found = true;
            }
            if(found) check = false;
            else{
                d = d.Define(Form("vec_%s",col.c_str()),vec,{Form("%s",col.c_str())});
                new_cols.emplace_back(Form("vec_%s",col.c_str()));
            }
        }
    }
    for(auto &col:new_cols) std::cout<<col<<std::endl;
    
    boostHistoHelper helper(name, columns, variationRules, bins);
    auto h = d.Book<ROOT::VecOps::RVec<Ts>...>(std::move(helper), columns);
    return;
}

Please read tips for efficient and successful posting and posting code

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


Hi Elisabetta,

I believe the issue here is related to how function templates are instantiated in the new PyROOT (I assume you are using the new PyROOT? i.e. ROOT >= 6.22). Class templates in the new PyROOT can be instantiated with either parentheses or square brackets, but function templates (like in this case) need to be instantiated with square brackets.

So can you try with the following code (note that list unpacking won’t work with square brackets, so you need to specify the types within the brackets):

ROOT.Histogram['float','float','float','float','float'](d, histoname, rules, binsVec, args)

Hope this helps!

Enric

In case it can be useful for you, the backwards incompatible changes of the new PyROOT are documented here (the one we just discussed is one of them):

Hi Enric!
Thanks for your answer!
Yes I am using ROOT nightlies, so latest version.
I had already found that solution but was hoping to pass a list of types from outside.
Luckily @eguiraud found a workaround modifying the function to be a struct.

Cheers!
Elisabetta

Good to hear you guys solved it!

Cheers,
Enric

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