Making use of histograms as input of Define variables in Root Data Frame

Hello,

I am trying to use histograms as input of “Define” in Root Data Frame, but it does not look like trivial. I want to do something as simple as:

.Define(“weights”,“compute_weights(mu_pt,mu_eta,histo2D)”)

compute_weights is a C++ function where I will read the muon eta and pt values (potentially more than one per event, but it’s irrelevant here) and a 2D histogram. How can I do this?

Thanks, Guillelmo

Hi @ceballos ,
and welcome to the ROOT forum.
is histo2D a variable defined outside of RDF? If so, you need a lambda that captures it (or equivalentely a functor class that has it as a data member):

TH2D histo2D;
df.Define("weights", [&histo2D] (const ROOT::RVecF &pt, const ROOT::RVecF &eta) {
   return compute_weights(pt, eta, histo2D);
},
 {"mu_pt", "mu_eta"});

or

struct WeightsComputer {
   TH2D *fHist2D;
   WeightsComputer(TH2D *h) : fHist2D(h) {}

   ROOT::RVecF operator()(const ROOT::RVecF &pt, const ROOT::RVecF &eta) {
      return compute_weights(pt, eta, fHist2D);
  }
};

df.Define("weights", WeightsComputer(&histo2D), {"mu_pt", "mu_eta"});

I didn’t
I hope this helps!
Enrico

Hello,

yes, histo2D indeed a variable member outside RDF. I’ve tried to use the struct, and I think it’s “almost” working. I am trying to use pyroot. I have a C++ external struct as you write, but then the Define doesn’t work well.

I am not allowed to write:
df.Define(“weights”, ROOT.WeightsComputer(&histo2D), {“mu_pt”, “mu_eta”})

I tried (without &)
df.Define(“weights”, ROOT.WeightsComputer(histo2D), {“mu_pt”, “mu_eta”})

But then, it says:
Error sample: Template method resolution failed:
TypeError: takes at most 2 arguments (3 given)
Failed to instantiate “Define(std::string,WeightsComputer&,set)”
Failed to instantiate “Define(std::string,WeightsComputer*,set)”
Failed to instantiate “Define(std::string,WeightsComputer,set)”

Thanks! Guillelmo

Not sure what the problem is, maybe the curly braces instead of the parens for the last argument of Define. This works (at least with the master branch):

In [4]: ROOT.gInterpreter.Declare("""
   ...: // dummy implementation
   ...: ROOT::RVecF compute_weights(const ROOT::RVecF &, const ROOT::RVecF &, TH2D &h) {
   ...:    return {};
   ...: }
   ...:
   ...: struct WeightsComputer {
   ...:    TH2D *fHist2D;
   ...:    WeightsComputer(TH2D *h) : fHist2D(h) {}
   ...:
   ...:    ROOT::RVecF operator()(const ROOT::RVecF &pt, const ROOT::RVecF &eta) {
   ...:       return compute_weights(pt, eta, *fHist2D);
   ...:   }
   ...: };
   ...: """)
Out[4]: True

In [5]: df = ROOT.RDataFrame(10).Define("mu_pt", "ROOT::RVecF{}").Define("mu_eta", "mu_pt")

In [9]: h = ROOT.TH2D()

In [10]: df.Define("weights", ROOT.WeightsComputer(h), ("mu_pt", "mu_eta"))
Out[10]: <cppyy.gbl.ROOT.RDF.RInterface<ROOT::Detail::RDF::RLoopManager,void> object at 0x55bc07a443f0>

Cheers,
Enrico

Hi Enrico,

thanks a lot for your help! It works now. It seems the issue was that I was using {“pt”, “eta”} in Define, while it should be (“pt”, “eta”). After making this change, I am able to get the proper information from the histogram in the function.

Thanks again, Guillelmo

1 Like

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