I’ve created TTree with a branch that holds a generic TObject. To do this, I must declare the branch as unsplit (otherwise I can’t hold objects of different types in the branch).
However, it appears that declaring the branch as unsplit causes RDataFrame to crash when I try to interact with that branch with a lambda function (e.g. Foreach(...))
Hi,
I’m afraid you are hitting a known bug: TTreeReader, which RDataFrame uses to read ROOT data, does not support TBranchObjects, and your unsplit branch is indeed a TBranchObject. Relaxing this limitation is very high on my to-do list. In the meanwhile, a dirty workaround that might give you some mileage is to manually instantiate a TBranchElement instead of a TBranchObject:
Thanks, this does prevent the crash, but with some further playing, I see it isn’t letting me access the object as anything other than a TObject? I cannot cast it to its true type, and I note that the 'ClassName()` of the object is always ‘TObject’, unlike when I used a proper TObject branch when it would be whatever the actual type of the object is.
Is this something I just will have to live without until RDataFrame /TTreeReader can be fixed to truly support this branch type?
Let’s see until where we can push RDF+arbitrary TObject-inheriting things
The following code prints "RooFitResult" when asked the ClassName or the IsA()->GetName() of the TObjects, so I cannot reproduce the problems you mentioned.
#include <ROOT/RDataFrame.hxx>
#include <TTree.h>
#include <TObject.h>
#include <RooFitResult.h>
#include <TBranchElement.h>
#include <iostream>
int main()
{
// make a tree with a couple of branches - one branch will hold a generic TObject (must be unsplit because could be anything!)
auto t = new TTree("tree", "tree");
double d = 0;
TObject *o = 0;
t->Branch("d", &d);
TBranchElement* branch = new TBranchElement(t, "o", (TStreamerInfo*)TObject::Class()->GetStreamerInfo(), -1, (char*)&o, 32000, 0);
t->GetListOfBranches()->Add(branch);
t->SetBranchAddress("o", &o);
// fill it with some 'data'
o = new RooFitResult("myFit");
d = 5;
t->Fill();
o = new RooFitResult("anotherFit");
d = 2;
t->Fill();
t->Scan();
ROOT::RDataFrame(*t).Foreach([] (const TObject &obj) { std::cout << obj.IsA()->GetName() << std::endl; }, {"o"});
ROOT::RDataFrame(*t).Foreach([] (const TObject &obj) { std::cout << obj.ClassName() << std::endl; }, {"o"});
ROOT::RDataFrame(*t).Foreach([] (const TObject &obj) { std::cout << static_cast<const RooFitResult&>(obj).status() << std::endl; }, {"o"});
return 0;
}
prints
~ ./repro
RooFit v3.60 -- Developed by Wouter Verkerke and David Kirkby
Copyright (C) 2000-2013 NIKHEF, University of California & Stanford University
All rights reserved, please read http://roofit.sourceforge.net/license.txt
************************************
* Row * d.d * o *
************************************
* 0 * 5 * 0 *
* 1 * 2 * 0 *
************************************
RooFitResult
RooFitResult
RooFitResult
RooFitResult
-1717986919
-1717986919
I’d be interested to see what and where breaks exactly.
Oof, indeed it crashes already in TTree::Scan when the object type changes between events.
Well, that’s how far the hack goes I gues @pcanal might be able to suggest a more robust way to force the unsplit branch to a TBranchElement.
Meanwhile, I guess I really have to fix TTreeReader+TBranchObject…
Hi @will_cern,
any chance you can try out this patch and see if it fixes RDF/TTreeReader+TBranchObject for all cases you care about?
It works for me for the case with unsplit object with RooFitResult and TH1D inside (and ROOT tests are running, but I’m pretty confident it does not break any).