ROOT Version: 6.24/06
I’m trying to use a custom class with a Fill method with an rdataframe but I can’t see to manage to make it work.
As a test case I adapted the code from example df001_introduction.C
I added a new class, called notTH1, for which I’m trying to use its fill method.
// ## Preparation
// A simple helper function to fill a test tree: this makes the example
// stand-alone.
void fill_tree(const char *treeName, const char *fileName)
{
ROOT::RDataFrame d(10);
int i(0);
d.Define("b1", [&i]() { return (double)i; })
.Define("b2",
[&i]() {
auto j = i * i;
++i;
return j;
})
.Snapshot(treeName, fileName);
}
class notTH1 : public TObject
{
public:
TH1D hist;
notTH1()
{
this->hist = TH1D("h", "h", 12, -1, 11);
}
notTH1(const notTH1 & obj)
{
this->hist = TH1D(obj.hist);
}
Long64_t Merge(TCollection * list)
{
TList hist_list;
for (const auto&& item : *list)
{
notTH1* temp = (notTH1*) item;
hist_list.Add( &(temp->hist) );
}
return this->hist.Merge(&hist_list);
}
void Fill(const double & Value)
{
this->hist.Fill(Value);
}
};
int dataframe_fill()
{
// We prepare an input tree to run on
auto fileName = "test_myfill.root";
auto treeName = "myTree";
fill_tree(treeName, fileName);
// We read the tree from the file and create a RDataFrame, a class that
// allows us to interact with the data contained in the tree.
// We select a default column, a *branch* to adopt ROOT jargon, which will
// be looked at if none is specified by the user when dealing with filters
// and actions.
ROOT::RDataFrame d(treeName, fileName, {"b1"});
// ## Operations on the dataframe
// ### `Foreach` action
// The most generic action of all: an operation is applied to all entries.
// In this case we fill a histogram. In some sense this is a violation of a
// purely functional paradigm - C++ allows to do that.
notTH1 h1;
d.Filter([](int b2) { return b2 % 2 == 0; }, {"b2"}).Foreach([&h1](double b1) { h1.Fill(b1); });
std::cout << "Filled h1 with " << h1.hist.GetEntries() << " entries" << std::endl;
// ### `Fill` action
notTH1 h2;
d.Filter([](int b2) { return b2 % 2 == 0; }, {"b2"}).Fill<double>(h2, {"b2"});
std::cout << "Filled h2 with " << h2.hist.GetEntries() << " entries" << std::endl;
TCanvas* c1 = new TCanvas();
h1.hist.DrawClone();
TCanvas* c2 = new TCanvas();
h2.hist.DrawClone();
return 0;
}
The process works well using the Foreach
method but fails with Fill
.
I get many errors but here the ones where I believe the problem is:
In module 'std' imported from input_line_1:1:
/usr/include/c++/9/bits/allocator.h:118:24: error: 'const_pointer' declared as a pointer to a reference of type 'notTH1 &'
typedef const _Tp* const_pointer;
^
In module 'std' imported from input_line_1:1:
/usr/include/c++/9/bits/shared_ptr.h:255:9: error: type '__shared_ptr<notTH1 &>' is not a direct or virtual base of 'std::shared_ptr<notTH1 &>'
: __shared_ptr<_Tp>(std::move(__r)) { }
^~~~~~~~~~~~~~~~~
/home/home/opt/root/include/ROOT/RDF/RInterface.hxx:1504:16: note: in instantiation of member function 'std::shared_ptr<notTH1 &>::shared_ptr' requested here
auto h = std::make_shared<T>(std::forward<T>(model));
^
/home/home/data/dataframe_fill.cpp:88:57: note: in instantiation of function template specialization 'ROOT::RDF::RInterface<ROOT::Detail::RDF::RFilter<(lambda at /home/home/data/dataframe_fill.cpp:88:13), ROOT::Detail::RDF::RLoopManager>, void>::Fill<double, notTH1 &>' requested here
d.Filter([](int b2) { return b2 % 2 == 0; }, {"b2"}).Fill<double>(h2, {"b2"});
^
Can someone help in understanding what I’m doing wrong?