Accessing TBranch Value

Unfortunately I cannot access my files. I can still see them just fine in TBrowser, but not using the TTreeReader.
I have already embeded the “file_info” into the root file. I just want to read it out into a variable.

Can this be achieved using RDataFrame?

Hi,

what’s the issue?


Yes, for example you can get all the contents of a TTree branch in a std::vector with RDataFrame’s Take (haven’t tested the code, might contain typos):

std::vector<double> values = ROOT::RDataFrame("my_tree", "my_file.root").Take<double>("my_double_branch")->GetValue();

Cheers,
Enrico

My TFile has TTree called “file_info” which has a branch “RUNID” for an example.
From the TBrowser, I can see that RUNID has a value of 4232, which is what was appropriate.
From other methods it reads either 0, 1, 4 or 90000

The branch is NOT a vector. It is a single value.

I appreciate your help, but I come from a software development badkground, and I feel that I cannot progress without an accurate documentation on the object “tree”, “branches”, and believe me I read them both, and none of the getters can actually return the value that I have embeded from

TTree* file_info = new TTree(“file_info”,“file_info”);
file_info->Branch( keywords[i].c_str() , &headerlist[i] ,“Value/F” );

For example, when I use the print function of the tree I get this:

->Print()
******************************************************************************
*Tree    :file_info : file_info                                              *
*Entries :        1 : Total =           10125 bytes  File  Size =       2357 *
*        :          : Tree compression factor =   1.00                       *
******************************************************************************
*Br    0 :RUNID     : Value/F                                                *
*Entries :        1 : Total  Size=        566 bytes  File Size  =         81 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   1.00     *
*............................................................................*

In first approximation, and especially for your current usecase, you can think of a TTree as a table.
Branches are columns of the table, entries are rows.

When creating/writing a TTree, every call to TTree::Branch will create a new column, and every call to TTree::Fill will add a new row. The values that are used to fill each column for each row are read from the addresses that are associated to the columns by the TTree::Branch call.

For example:

float value = 0.f;
tree->Branch("value", &value);
tree->Fill();
value = 8.f;
tree->Fill();

creates a column with name "value" which will have two rows, one with value 0 and one with value 8.

That’s why RDataFrame’s Take returns a vector: typically you have more than one value per branch. If you have only one value, you can retrieve it as the first and only element of the vector.

As to why the values that you read back are wrong, I don’t know, there is a problem somewhere in your code. Maybe it’s the extra "Value/F" argument to TTree::Branch that makes it trickier to retrieve the correct values later.

Here is a working snippet that creates a TTree called "file_info" in a file "f.root", writes one entry of branch "RUNID" and then reads it back with raw TTree, TTreeReader and RDataFrame.

#include <TTree.h>
#include <TFile.h>
#include <TTreeReader.h>
#include <TTreeReaderValue.h>
#include <ROOT/RDataFrame.hxx>
#include <vector>
#include <cassert>

void write_tree()
{
   TFile f("f.root", "recreate");
   TTree t("file_info", "file_info");
   float value = 42.f;
   t.Branch("RUNID", &value);
   t.Fill();
   f.Write();
   f.Close();
}

float read_value_with_tree()
{
   TFile f("f.root");
   TTree *t = nullptr;
   f.GetObject("file_info", t);
   float value;
   t->SetBranchAddress("RUNID", &value);
   t->GetEntry(0);
   return value;
}

float read_value_with_treereader()
{
   TFile f("f.root");
   TTreeReader r("file_info", &f);
   TTreeReaderValue<float> v(r, "RUNID");
   r.SetEntry(0); // should check ret value to be sure reading succeded
   return *v;
}

float read_value_with_rdf()
{
   ROOT::RDataFrame df("file_info", "f.root");
   const std::vector<float> all_v = df.Take<float>("RUNID").GetValue();
   return all_v[0];
}

int main()
{
   write_tree();
   assert(read_value_with_tree() == 42.f);
   assert(read_value_with_treereader() == 42.f);
   assert(read_value_with_rdf() == 42.f);
   return 0;
}
1 Like

Okay, Excellent. This is the solution that I was looking for. I guess the point I was missing all this time is that the tree pointer address.
Thank you Enrico!

As a note, I don’t suggest using TTree directly to read ROOT data, it’s a low-level API, gives very few (type) safety guarantees, performs very few sanity checks and it’s also trickier to get good performance out of it. None of this might matter for this specific application of yours, but habits do matter :smile:

Given a branch created with file_info->Branch("RUNID", &some_float_var ,“Value/F” ); I can read it with

TFile f("f.root");
TTreeReader r("file_info", &f);
TTreeReaderValue<float> v(r, "RUNID.Value");
r.SetEntry(0);
std::cout << *v << std::endl;

I will also try and test the TTreeReader. For my specific application, I am basically handling everything in RAM and I have written a few upper level safety mechanisms such that if returning value isn’t very nice, I exit(0) or return from the function on the spot with an error message.

In the analysis that I am dealing with, the input file is rather large and read/write is only done in the beginning and and the end, and I hard-mallocate/free.

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