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 theTTreeReader
variable. 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
MakeSelector
to create an “code skeleton” for you. TheTTreeReader
andTTReaderValue
declarations were “hidden” inAnalyze.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.TTreeReader
andTTReaderValue
are 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[]
!