Why using a macro?
As real analyses don't fit into simple TTree::Draw() invocations, and as it is quite cumbersome to type the same lines again and again in the Root prompt, simply create macros for commonly used code. A macro is a file that is interpreted by ROOT.
Creating and Editing the Macro
Create a macro (e.g. AnalyzeTree.C) using your favorite text editor, e.g. with vi, emacs, wordpad, Eclipse, Visual Studio,... The macro should start with the proper #include statements and should contain the function declaration with the same name than the macro itself. As we know we're going to use TFile and TTree (at least), we can already include their headers TFile.h and TTree.h. Then come the function implementation.
Function Implementation
Lets start with something simple: calculate the sum of all event sizes. For this we need a new variable of type int. Create (declare) it at the beginning of the function, and don't forget to initialize it to 0. At the end, the code in AnalyzeTree.C should look like this:
#include "TFile.h"
#include "TTree.h"
void AnalyzeTree()
{
// Variables used to store the data
Int_t totalSize = 0; // Sum of data size (in bytes) of all events
...
Opening the File and Getting the Tree
The first thing to do is to open the file containing the tree, by calling TFile::Open(), passing the file name, and then, if the file is open (i.e. if the pointer to it is not NULL), create a TTreeReader using the tree name and the file. At the end, the code in AnalyzeTree.C should look like this:
...
// open the file
TFile *f = TFile::Open("http://root.cern/files/introtutorials/eventdata.root");
if (f == 0) {
// if we cannot open the file, print an error message and return immediatly
printf("Error: cannot open http://root.cern/files/introtutorials/eventdata.root!\n");
return;
}
// Create tyhe tree reader and its data containers
TTreeReader myReader("EventTree", f);
...
Getting the data out of the TTree
Fine, we have access to our tree. But now we need to get a handle on the data it stores, as shown below:
...
TTreeReaderValue<Int_t> eventSize(myReader, "fEventSize");
...
Loading TTree's Data
For the analysis example we need to access the events' size, which is accessible through the TTreeReaderValue eventSize. But the TTreeReader first needs to get told about which TTree entry to access. For that call TTreeReader::Next() in a loop. It will return false once it has reached the end of the TTree.
In the same loop, compute the total size of all events (simply add the current event size to the total size)
...
// Loop over all entries of the TTree or TChain.
while (myReader.Next()) {
// Get the data from the current TTree entry by getting
// the value from the connected reader (eventSize):
totalSize += *eventSize;
}
Accessing the Analysis Result
At the end of the loop, print the sum of all event sizes. This sum shows you the real power of a TTree: even though you can analyze large amounts of data (our example tree with 22MB is tiny!) ROOT needs just a few MB of your RAM, no matter how many events you analyze. Imagine what it would be like if you had to load all data into memory, e.g. using a simple vector
...
Int_t sizeInMB = totalSize/1024/1024;
printf("Total size of all events: %d MB\n", sizeInMB);
}
Running the Macro
To run this macro, simply type .x AnalyzeTree.C and ROOT will execute it. If it finds an error it might be wise to quit ROOT (.q) and try again!
If, for any reason, you don't manage to get it working, you can download a working macro file here: CountEvents.C
Here again, if you are using ROOT via ssh, you have to download the file with wget from your remote directory: wget http://root-mirror.github.io/training/intro/CountEvents.C