Walkthrough: Using a C++ TTreeReader to analyze a Tree
(10 minutes)
Why TTreeReader?
If you look through the ROOT TTree
examples,
you’ll see that using
TTreeReader is
the preferred method for reading n-tuples and TTrees.
I’ve prepared an example to get you started. In your UNIX window, copy
AnalyzeReader.C from my home directory:1
> cp ~seligman/root-class/AnalyzeReader.C
Take a look:
> less AnalyzeReader.C
Here’s an abbreviated version of that file, without some of the comments: 2
void AnalyzeReader() {
  //******** Definition section *********
  //******** Initialization section *********
  // Open the file containing the tree.
  TFile* myFile = TFile::Open("experiment.root");
  // Create a TTreeReader for the TTree "tree1" in 'myFile'.
  TTreeReader myReader("tree1", myFile);
  // Tell the TTreeReader which branches (or columns) we'll read.
  TTreeReaderValue<Float_t> ebeam(myReader, "ebeam");
  // Loop over all the entries of the TTree.
  while (myReader.Next()) {
    
    //******** Loop section *********
  }
  //******** Wrap-up section *********
}
Compare this with the Python code in Listing 39.
While you look through the code, it helps to understand the typical steps needed for an analysis task:
- Definition – define the variables we’re going to use. 
- Initialization - open files, create histograms, etc. 
- Loop - for each event in the n-tuple or Tree, perform some tasks: calculate values, apply cuts, fill histograms, etc. 
- Wrap-up - display results, save histograms, etc. 
For this macro, the Definition and Initialization parts aren’t really distinct, the way they are in a TSelector macro.
A closer look (optional)
Let’s take a more abstract view of the key statements in Listing 42:
TFile* file = TFile::Open(NameOfFile);
This opens a ROOT file (in read-only mode by default).
- file= A variable that contains the pointer to a ROOT file.
- NameOfFile= A C-style string constant containing the name of the ROOT file.
TTreeReader myReader(NtupleName, file);
- myReader= The name of the- TTreeReadervariable. This will be used to fetch the contents of an n-tuple from the file.
- NtupleName= A C-style text string with the name of the n-tuple within the file.
TTreeReaderValue<TYPE> branchVariable(myReader, BranchName);
- TYPE= This is the C++ type of the variable stored in the branch (or column) in the n-tuple; e.g.,- int,- float,- double, etc.
- branchVariable= A variable that acts like a pointer to the value of the given branch.
- BranchName= A C-style text string that contains the name of the branch in the n-tuple.
In a typical analysis task, you’ll have one TTreeReaderValue<T>
definition for every branch you want to access.
How do you know the names and types of the branches? What I usually do
is load the file in interactive ROOT and use the TTree::Print()
method:3
> root experiment.root
[] tree1->Print()
When I type those commands, what I see is this:
******************************************************************************
*Tree    :tree1     : Reconstruction ntuple                                  *
*Entries :   100000 : Total =         2810761 bytes  File  Size =    2171135 *
*        :          : Tree compression factor =   1.30                       *
******************************************************************************
*Br    0 :event     : event/I                                                *
*Entries :   100000 : Total  Size=     401519 bytes  File Size  =     134514 *
*Baskets :       12 : Basket Size=      32000 bytes  Compression=   2.85     *
*............................................................................*
*Br    1 :ebeam     : ebeam/F                                                *
*Entries :   100000 : Total  Size=     401519 bytes  File Size  =     260330 *
*Baskets :       12 : Basket Size=      32000 bytes  Compression=   1.47     *
*............................................................................*
*Br    2 :px        : px/F                                                   *
*Entries :   100000 : Total  Size=     401465 bytes  File Size  =     359238 *
*Baskets :       12 : Basket Size=      32000 bytes  Compression=   1.07     *
*............................................................................*
*Br    3 :py        : py/F                                                   *
*Entries :   100000 : Total  Size=     401465 bytes  File Size  =     359138 *
*Baskets :       12 : Basket Size=      32000 bytes  Compression=   1.07     *
*............................................................................*
*Br    4 :pz        : pz/F                                                   *
*Entries :   100000 : Total  Size=     401465 bytes  File Size  =     292046 *
*Baskets :       12 : Basket Size=      32000 bytes  Compression=   1.31     *
*............................................................................*
*Br    5 :zv        : zv/F                                                   *
*Entries :   100000 : Total  Size=     401465 bytes  File Size  =     349087 *
*Baskets :       12 : Basket Size=      32000 bytes  Compression=   1.10     *
*............................................................................*
*Br    6 :chi2      : chi2/F                                                 *
*Entries :   100000 : Total  Size=     401501 bytes  File Size  =     321049 *
*Baskets :       12 : Basket Size=      32000 bytes  Compression=   1.20     *
*............................................................................*
Most of what you see is not relevant to this tutorial; for example, you’re not going to care about “Baskets” unless you want to optimize ROOT I/O for gigabyte-size files. What’s important here are the names of the branches; e.g.;
*Br    6 :chi2      : chi2/F
tells you that the sixth branch’s name is chi2. More important, it
also tells you the type of the variable: chi2/F means that type of
chi2 is float. So if you wanted to access the value of chi2,
you’d include a statement like:
TTreeReaderValue<Float_t> chi2(myReader, "chi2");
You can find the correspondence between the C++ types and those one-letter abbreviations on the TTree documentation page.
- 1
- If you’re not at Nevis, you can download it. 
- 2
- If you’re working through all the sections in this tutorial, Your first reaction on looking at this code is that it doesn’t look much like - Analyze.C, the code that we saw in Listing 41.- It’s actually the same code, but it’s arranged differently. In that walkthrough, I have you use - MakeSelectorto create an “code skeleton” for you. The- TTreeReaderand- TTReaderValuedeclarations were “hidden” in- Analyze.h, so you could focus on the event loop.- Listing 42 is simpler, but I chose not to introduce a newcomer C++-based analysis with this code because: - It uses a template (as in - TTreeReaderValue<double>). For students who are relatively new to C++, this can be confusing.
- TTreeReaderand- TTReaderValueare not normally used in Python/pyroot. I want the C++ code and the Python code (in Listing 39) to resemble each other.
 
- 3
- Don’t forget that I use the different prompts to indicate whether you’re running in UNIX or ROOT. Don’t actually type the - >or- []!