Project

General

Profile

CAF ROOT Macros and PyROOT

There are two popular interfaces for ROOT libraries: the ROOT interpreter (CINT) and PyROOT (a set of python bindings for ROOT classes). Both of these are exceptionally easy to use. This page will document both. As one digs deeper into the CAF, they may be interested in the tree structure. The structure is currently documented in doxygen, but eventually there will be documentation on this wiki.

The ROOT interpreter can be used either interactively at the prompt or by writing macros. The prompt acts as an interactive environment where commands can be executed one at a time. A ROOT macro is essentially a script which executes a set of commands one after another.

A Note on Versions

The CAFMaker package underwent a restructuring in early April 2013. For releases prior to S13-04-09, StandardRecord and its members lived in the CAFMaker package. For releases S13-04-09 and later, those classes were moved to the StandardRecord package. If you are using a release with a date earlier than S13-04-09, please use this alternate version of the documentation. The primary difference is that the file libCAFMaker_dict.so has been replaced with libStandardRecord_dict.so

Getting Started

Before you start mucking around with CAF files, make sure that you have run the nova setup function, as described in Documentation FOR BEGINNERS. Running the setup function gives you access to the required dictionary libraries, ROOT, CAFE and PyROOT. Note that you must source the release under which the files were produced. For the MDC CAF production, this was S12-10-07, so for instance, you would type:

% setup_nova -r S12-10-07

Starting your ROOT macros

The following preamble will allow you to load CAF files without warnings and loop over trees. This should be placed inside your function, and you will not need any explicit #include statements.

gSystem->Load("libCintex.so");
Cintex::Enable();
gSystem->Load("$SRT_PUBLIC_CONTEXT/lib/Linux2.6-GCC-debug/libStandardRecord_dict.so");

Note that if you're making local changes to CAFMaker that you will need to load your version of libStandardRecord_dict.so and not
the version in $SRT_PUBLIC_CONTEXT:

gSystem->Load("$SRT_PRIVATE_CONTEXT/lib/Linux2.6-GCC-debug/libStandardRecord_dict.so")

Then you can load your file, as demonstrated with an mdc file :

TFile* file = new TFile("/nova/ana/caf/mdc/fd/mdc0/mdcCAF_fd_nhc_262_r159_0_mdc0_S12.06.17_20121023_162736_reco.root", "READ");
TTree* tree = (TTree*)file->Get("recTree");

Starting a ROOT interactive session manually

The first step is to enter the ROOT environment by entering the following command:

% root 

This should bring up the root prompt that looks like root [0]. The ROOT prompt interprets commands in C++ syntax. There is a magic incantation that must be executed prior to loading any ROOT trees, as follows:

root [0]  gSystem->Load("libCintex.so");
root [1]  Cintex::Enable();

Now you can load the CAF libraries:
root [2]  gSystem->Load("$SRT_PUBLIC_CONTEXT/lib/Linux2.6-GCC-debug/libStandardRecord_dict.so");

And then we can load a file. I have picked one of the MDC CAF files: /nova/ana/caf/mdc/fd/mdc0/mdcCAF_fd_nhc_262_r159_0_mdc0_S12.06.17_20121023_162736_reco.root.
We can load this file as a TFile and extract the CAF tree from it:
root [3] file = new TFile("/nova/ana/caf/mdc/fd/mdc0/mdcCAF_fd_nhc_262_r159_0_mdc0_S12.06.17_20121023_162736_reco.root", "READ");
root [4] tree = (TTree*)file->Get("recTree");

Easiest method: CAF Environment (CAFE)

The nova setup script creates an alias that loads the libraries automatically. You can use this to start an interactive session or run a macro without the steps above. On the command line, type:

% cafe 

Then you could immediately do these steps:
root [0] file = new TFile("/nova/ana/caf/mdc/fd/mdc0/mdcCAF_fd_nhc_262_r159_0_mdc0_S12.06.17_20121023_162736_reco.root", "READ");
root [1] tree = (TTree*)file->Get("recTree");

Alternatively, you can pass file paths as command line arguments:

% cafe /nova/ana/caf/mdc/fd/mdc0/mdcCAF_fd_nhc_262_r159_0_mdc0_S12.06.17_20121023_162736_reco.root

which produces the output:
root [0] 
Attaching file /nova/ana/caf/mdc/fd/mdc0/mdcCAF_fd_nhc_262_r159_0_mdc0_S12.06.17_20121023_162736_reco.root as _file0...

This indicates that we can access the tree using:

tree = (TTree*)_file0->Get("recTree")

Analysis Strategies

Histograms with TTree::Draw()

Now we can use the tree to make some histograms. Let's start with a simple one-dimensional dimensional histogram, for instance, the number of hits in each slice:

root [5] tree->Draw("rec.slc.nhit")

which should produce something like the following display:

We can also have make a two dimensional histogram using the colon syntax below. Also note that I am supplying "colz" as a display option, this makes a color plot and draws a z-axis.

root [6] tree->Draw("rec.slc.nhit:slc.nmiphit", "", "colz")

The 2D histogram should look like this:

Finally, we might want some cuts, for instance, we might want to have more than 20 contiguous planes. The second parameter in TTree::Draw() accepts cuts.

root [7] tree->Draw("rec.slc.nhit:slc.nmiphit", "slc.ncontplanes > 20", "colz")

which then produces the prettier histogram:

We can also do math in these strings, so we could do:

root [7] tree->Draw("rec.slc.nmiphit / slc.nhit", "slc.ncontplanes > 20")

to produce a 1D histogram of the fraction of hits that are MIP-like.

ROOT macros and looping over trees

If you'd rather not type your commands every time you want a plot, you can chain commands together in a ROOT macro. If you're not using the "cafe" environment,

Now you are free to do all of your favorite things, for instance, load a file:

TFile* file = new TFile("/nova/ana/caf/mdc/fd/mdc0/mdcCAF_fd_nhc_260_r184_0_mdc0_S12.06.17_20121023_162750_reco.root", "read");  

Get out the record tree:
 TTree *tree  = (TTree*)file->Get("recTree");

Draw a histogram:
  tree->Draw("rec.slc.nhit");

For more examples of how to exploit TTree::Draw(), look in the histograms section. Don't forget to include the proper libraries i.e. TFile.h, TTree.h etc, at
the beggining of your script.

We can also loop over trees entry-by-entry to do more complicated stuff, but ROOT does this in a somewhat counterintuitive way. To begin this process, we must create a StandardRecord object and set the branch address using our tree:

  caf::StandardRecord* rec = 0; 
  tree->SetBranchAddress("rec", &rec);

This means that the object rec is now tied to that branch. Note that we could have called SetBranchAddress() for a branch deeper in the tree, giving a performance boost upon looping.

Then, we loop over the tree. Each time we call tree->GetEntry(i), the data in the tree is copied to rec.

  for(int i = 0; i< tree->GetEntries(); ++i)
  {
    tree->GetEntry(i);
    cout << rec->slc.nhit << endl;    
  }

Rather than simply cout << ... you could have done fancier things, for instance, make calculations and fill histograms.

Looping efficiently

When looping over large CAF files with lots of information, time to process can become unbearable. In order to speed up the loop one can turn off all branches and only switch on the branches that one uses. This can have a significant impact on the time to loop.

  // Initialise CAF                                                             
  caf::StandardRecord* rec;
  tree->SetBranchAddress("rec", &rec);
  // Turn off ALL branches                                                      
  tree->SetBranchStatus("*", 0);

  // Turn on branches as we use them                                            
  // slice branch (slc)                                                         
  tree->SetBranchStatus("slc.nhit", 1);      // turned  on
  tree->SetBranchStatus("slc.nmiphit",1);    // turned on 
  tree->SetBranchStatus("slc.calE", 1);      // turned on
  tree->SetBranchStatus("slc.firstplane",0); // turned off - might use later
  tree->SetBranchStatus("slc.lastplane",0);  // turned off - might use later

In the example, ALL branches are turned off and we then turn on branches one-by-one as we need them.
There is also experimental code in CAFAna called FileReducer.cxx/.h that can be run to reduce the size of CAF files to only save variables one thinks one might use. Very much experimental at this point. Limited documentation as to how to use.

PyROOT

PyROOT is a module of Python bindings for ROOT functions that provide a stable more interface than macros. In addition to living All of the lines below can also be issued to the python interpreter. All pyROOT scripts should start with:

from ROOT import *

In Python, the preamble uses slightly different operators (everything is a ".") but the content is the same.

gSystem.Load("libCintex.so")
Cintex.Enable()
gSystem.Load("$SRT_PUBLIC_CONTEXT/lib/Linux2.6-GCC-debug/libStandardRecord_dict.so")
gInterpreter.AddIncludePath("$SRT_PUBLIC_CONTEXT")

Everything is a pointer in Python, so the new operation is implicit and we just call the constructor, in this case for a TFile.

file = TFile("/nova/data/mc/S13-06-18/genie/fd/fd_r0000001_s01_S13-06-18_v1_genie_3000_fhc_fluxswap_20121129_181947.sim.caf.root", "READ")

We can then access the tree of StandardRecord objects.

tree = file.Get("recTree")

Once we have our tree, it's easy to call the Draw() method to make some histograms, the argument syntax is identical to above.

tree.Draw("slc.nhit")

If we'd rather loop over the tree and do more complicated things, the syntax is far easier than in pyROOT than ROOT. TTree objects are iterable in Python, so we can ignore all the $SetBranchAddress()@ hoopla and simply write a for loop:

for entry in tree:
   # Access the nhit member
   nhit = entry.rec.slc.nhit
   # ... do more things if you'd like.  

   # If you don't like typing entry.rec every time, give it a variable name, or do this for any branch
   rec = entry.rec
   nhit = rec.slc.nhit
   print nhit

Looping efficiently

To improve processing time, you can turn off branches just as you would in a ROOT macro. All you have to do is change the arrows to dots in the snippet from the ROOT macro section.

  tree.SetBranchStatus("*", 0)

  // Turn on branches as we use them                                            
  // slice branch (slc)                                                         
  tree.SetBranchStatus("slc.nhit", 1)      // turned  on
  tree.SetBranchStatus("slc.nmiphit",1)    // turned on 
  tree.SetBranchStatus("slc.calE", 1)      // turned on
  tree.SetBranchStatus("slc.firstplane",0) // turned off - might use later
  tree.SetBranchStatus("slc.lastplane",0)  // turned off - might use later

More pyROOT guidance

Anything that can be done in a ROOT macro can also be done in pyROOT. It takes a little bit of getting used to, but becomes second nature after a while. This section has served as an introduction, but there are better tutorials out there, like this one.