Reading values from TBranchElement

Hello, I am new to root and I have been trying to read the value from a TBranchElement object. I tried looking for a corresponding function online but the best I could find was GetValue(), which is only yielding the first value of a TBranchElement. Does anyone know how to obtain all values from a specific TBranchElement (to a specific entry)?

That’s rarely needed. Given that you’re new (welcome!) could you maybe tell us a bit more of the big picture: do you maybe have a couple of ROOT files, with TTrees, and you wonder how to read their data?

1 Like

Hello @Axel, thanks for your reply. In the attachment below I send you the root file I am trying to read. By visualising it with TBrowser, I recognise the “Delphes” tree, with several branches, which are actually TBranchElement objects. So far I have done:

tree = inFile.Get("Delphes")
for entry in tree:
    ePT = entry.GetBranch("Electron.PT")
    e1PT = ePT.GetValue(0,1))

This allows me to access the pT value for the leading electron, but by calling ePT.GetValue(1,1) I still obtain the same values. Is there perhaps an easier, more intuitive way of doing this?
ee_to_ll.root (951.0 KB)

The problem is with for entry in tree: :slight_smile: That’s not how you want to do analysis in Python. Please have a loot at RDataFrame: this gets rid of having to think about how to extract data, and you get scalabiity and speed for free.

We’re happy to help, e.g. for “how do I find the leading electron” - but let’s do that with RDataFrame! You could start with the tutorials at ROOT: Dataframe tutorials

1 Like

Dear @Axel, many thanks for the quick reply! I started working with RDataFrame and I imported the root file by simply doing.

df = ROOT.RDataFrame("Delphes", "ll_to_ee.root")

Now I understand that each of the branches corresponds to a column and each of the rows to an entry (i.e. event). I took a look at the tutorial you sent me, showing many examples of how to apply cuts and plotting histograms. However, I am still a bit puzzled on how to apply this to my case; I tried counting the number of events with exactly two electrons by doing:

print(dftest.Filter('Electron_size==2').Count())

which yields the output

<cppyy.gbl.ROOT.RDF.RResultPtr<ULong64_t> object at 0x600003d3fc60>

I also don’t know how to access the variables associated to different particles within a single event, e.g. the pT values for the leading and subleading electrons (i.e. what is the correct syntax in this case). Do I perhaps need to modify something in my file first?

Usually, the electrons are already sorted by pT - but you can assert that, e.g. through Filter("Electron_size >1 && Electron_pt[0] < Electron_pt[0]") which should not leave any events. Note that I didn’t check the branch name for electron pT, my example likely needs to be adjusted to the actual branch name.

Count() returns a RResultPtr, see ROOT: ROOT::RDF::RInterface< Proxied, DataSource > Class Template Reference

You can call GetValue() on that: print(dftest.Filter('Electron_size==2').Count().GetValue()) - this will trigger the event loop.

1 Like

Thanks for the reply @Axel that was very helpful! Now I wanted to add new branches to my root file (e.g. sum of leading and subleading lepton pT’s) by calling:

df_extended = df.Filter('Electron_size>1').Define('sumElectonPT', 'Electron.PT[0]+Electron.PT[1]')

but when displaying the list of columns of df extended with print(df.GetColumnNames())I did not find the newly defined column, is this perhaps to be expected?
Furthermore, I wanted to save this new file with:

df_extended.Snapshot("Delphes", "newFile.root")

but this yields the following error:

Error in <TTreeReaderArrayBase::CreateContentProxy()>: The branch Particle contains data of type GenParticle. It cannot be accessed by a TTreeReaderArray<TRef>
Error in <TTreeReaderArrayBase::CreateContentProxy()>: The branch Weight contains data of type Weight. It cannot be accessed by a TTreeReaderArray<float>
Error in <TTree::Bronch>: TClonesArray with no dictionary defined in branch: EFlowNeutralHadron
RDataFrame::Run: event loop was interrupted
Error in <TTreeReaderArrayBase::CreateContentProxy()>: The branch Particle contains data of type GenParticle. It cannot be accessed by a TTreeReaderArray<TRef>
Error in <TTreeReaderArrayBase::CreateContentProxy()>: The branch Weight contains data of type Weight. It cannot be accessed by a TTreeReaderArray<float>
Error in <TTree::Bronch>: TClonesArray with no dictionary defined in branch: EFlowNeutralHadron
RDataFrame::Run: event loop was interrupted
Traceback (most recent call last):
  File "/Users/yannickburkard/Documents/masterthesis/framework/PyRoot_analysis/root_to_histogram_RDataFrame.py", line 36, in <module>
    df_extended.Snapshot("Delphes", "newFile.root")
TypeError: Template method resolution failed:
  none of the 3 overloaded methods succeeded. Full details:
  ROOT::RDF::RResultPtr<ROOT::RDF::RInterface<ROOT::Detail::RDF::RLoopManager,void> > ROOT::RDF::RInterface<ROOT::Detail::RDF::RJittedFilter,void>::Snapshot(basic_string_view<char,char_traits<char> > treename, basic_string_view<char,char_traits<char> > filename, initializer_list<string> columnList, const ROOT::RDF::RSnapshotOptions& options = ROOT::RDF::RSnapshotOptions()) =>
    TypeError: takes at least 3 arguments (2 given)
  ROOT::RDF::RResultPtr<ROOT::RDF::RInterface<ROOT::Detail::RDF::RLoopManager,void> > ROOT::RDF::RInterface<ROOT::Detail::RDF::RJittedFilter,void>::Snapshot(basic_string_view<char,char_traits<char> > treename, basic_string_view<char,char_traits<char> > filename, const vector<string>& columnList, const ROOT::RDF::RSnapshotOptions& options = ROOT::RDF::RSnapshotOptions()) =>
    TypeError: takes at least 3 arguments (2 given)
  ROOT::RDF::RResultPtr<ROOT::RDF::RInterface<ROOT::Detail::RDF::RLoopManager,void> > ROOT::RDF::RInterface<ROOT::Detail::RDF::RJittedFilter,void>::Snapshot(basic_string_view<char,char_traits<char> > treename, basic_string_view<char,char_traits<char> > filename, basic_string_view<char,char_traits<char> > columnNameRegexp = "", const ROOT::RDF::RSnapshotOptions& options = ROOT::RDF::RSnapshotOptions()) =>
    logic_error: Trying to insert a null branch address.
  ROOT::RDF::RResultPtr<ROOT::RDF::RInterface<ROOT::Detail::RDF::RLoopManager,void> > ROOT::RDF::RInterface<ROOT::Detail::RDF::RJittedFilter,void>::Snapshot(basic_string_view<char,char_traits<char> > treename, basic_string_view<char,char_traits<char> > filename, basic_string_view<char,char_traits<char> > columnNameRegexp = "", const ROOT::RDF::RSnapshotOptions& options = ROOT::RDF::RSnapshotOptions()) =>
    logic_error: Trying to insert a null branch address.

My understanding is that some branches cannot be saved, so my way around this was to save only specific branches; but I wanted to know if there is another way around this, e.g. by “skipping” the branches which cannot be saved but still keeping the rest.

@eguiraud would this need to be print(df_extended.GetColumnNames()) or are the columns centrally managed in the LoopManager?

TTreeReader (used by RDataFrame) has problems with Delphes files, indeed. Selecting the branches to write, or not even writing the original branches but just writing out the new branches and adding them as a friend to the original tree, might be a reasonable workaround.

2 Likes

Yes, that’s correct

1 Like

Ah yes, of course it works with df_extended; I was mistyping the name of the DataFrame object! Thanks a lot for your help @Axel, it has been very useful to get me started with ROOT.

Hi Yannick,

Wow, to get you started with ROOT? Super cool, congrats for making that much progress so quickly! This is also really encouraging to us, to see you being able to get things done and move from old-ROOT to new-ROOT so smoothly.

Don’t hesitate to ask questions here, on your further path with ROOT!

Axel

1 Like

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