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 3.
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 2:
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 theTTreeReadervariable. 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 1.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. TheTTreeReaderandTTReaderValuedeclarations were “hidden” inAnalyze.h, so you could focus on the event loop.Listing 2 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.TTreeReaderandTTReaderValueare not normally used in Python/pyroot. I want the C++ code and the Python code (in Listing 3) 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[]!