TTree, TBranch and TBasket

Header Files

The following may be needed if not using CINT Shortcuts #include "TTree.h" #include "TBranch.h" #include "TBasket.h"


Acting together these, and closely related classes, provide the following services:-

Synchronised I/O

As explained in ROOT I/O. the basic method for reading and writing objects is to send objects Read and Write messages supplying the name of the object on disk. There are two drawbacks when using this method to write large numbers of events:- TTree and related classes provides a solution to these problems. TTree is the top level bank. It has a set of TBranch objects. Each TBranch looks after a single object. The user sets up a TTree, creating a TBranch for each object in the event. Then I/O commands sent to TTree results in all TBranch objects reading or writing the objects they manage. The following diagram shows the basic scheme:-

In this diagram there are 3 objects, ObjA, ObjB and ObjC, each managed by a TBranch BraA, BraB and BraC. The TBranch objects serialise the data into TBasket objects and it is these buffers that are written and read from disk. As the diagram shows, it is possible to distribute the event over multiple files, although the default is to write it all to one.

Assume, in what follows, MyObjA, MyObjB and MyObjC are pointers to objects of classes MyClassA, MyClassB and MyClassC respectively. To create the above tree:-

TFile *MyFile1 = new TFile("File1.root","NEW");

TTree *MyTree = new TTree("MyTree","An example of a ROOT tree");

Int_t split = 0;
Int_t bsize = 64000;

TBranch *MyBranchA = MyTree->Branch("MyObjA", "MyClassA", &MyObjA, bsize, split);
TBranch *MyBranchB = MyTree->Branch("MyObjB", "MyClassB", &MyObjB, bsize, split);
TBranch *MyBranchC = MyTree->Branch("MyObjC", "MyClassC", &MyObjC, bsize, split);

The sequence is:-
  1. A TFile object is created, which result in a new ROOT file being created.
  2. A TTree object is created.
  3. 2 integers are defined. split will be explained below, bsize is used to define the TBasket size in bytes.
  4. The TTree is asked to create 3 TBranch objects, passing a pointer to a pointer to the object that the TBranch must managed. TTree needs the address of the pointer so that it can update it if the event object moves in memory. This is about as close as ROOT gets to pointer management that FORTRAN memory managers such as ZEBRA used to support!
  5. Finally the last Tbranch is told to set its file to "File2.root", it will create this file automatically when it attempts to write.
To output a copy of all the event objects now requires just one command:-
If event objects are recreated in memory, it is essential to report this fact to the TTree, using the SetBranchAddress message. For example, suppose MyObjB is recreated, then, to update the TTree:-
MyTree->SetBranchAddress("MyObjB", &MyObjB);
or, alternatively, directly to the TBranch, with:-
At the end of the job, the all event objects should be deleted and then the TFile sends its Write message (which will write out TTree, TBranch etc. objects) and then closed:-
To read the tree back:-
TFile *MyFile1 = new TFile("File1.root","READ");

TTree *MyTree = (TTree *) MyFile->Get("MyTree");

MyClassA *MyObjA = new MyClassA;
MyClassB *MyObjB = new MyClassB;
MyClassC *MyObjC = new MyClassC;

MyTree->SetBranchAddress("MyObjA", &MyObjA);
MyTree->SetBranchAddress("MyObjB", &MyObjB);
MyTree->SetBranchAddress("MyObjC", &MyObjC);

  1. Creates a TFile object to open an existing file.
  2. Retrieves the TTree named "MyTree".
  3. Creates dummy event objects and attaches them to the 3 TBranches. This is necessary as the Tree will delete the current event objects each time it reads a new event.
  4. Sets the TBranch associated with MyObjC to use "File2.root" for its I/O.
To loop processing all events:- Int_t nevent = MyTree->GetEntries(); for (Int_t i=0;i<nevent;i++) { MyTree->GetEvent(i); \\ MyObjA, MyObjB and MyObjC pointers now point to event i }
  1. MyTtree is asked how many events it has, and this is stored in the integer nevent.
  2. Now there is a loop getting each event in turn. Note that the first event number is 0 not 1. Although this demonstrates sequential processing, it is also O.K. to ask GetEvent to jump directly to any event.

Partial I/O

Another powerful feature of TTrees is the possibility of partial input as shown by the diagram below:-

Here only ObjB is read back, by passing its TBranch the GetEvent message. Then depending on the values found in ObjB, other parts of the event can be read back in. Sending the TTree its GetEvent message will just input the rest. This allows a fast skim looking at summary data in one set of objects and then analysing in depth only those events that warrant it. As each object has its own buffer this means that I/O is minimised.

The granularity of partial event processing can be dramatically increased by by setting:-

Int_t split = 1;
before creating TBranch objects by sending the TTree the Branch message. Then each object is broken down into its individual data members and each given its own TBranch and TBasket. If an event object contains a pointer to a TClonesArray, that is to say an array container holding objects of a single class, then each of its data members is also broken out and given its own TBranch and TBasket. So with the split option active it is possible just to look at fragments of an object and this can lead to very efficient event processing, as described in the next section.

Automated Event Processing

TTrees have a very powerful function: Draw which corresponds closely to the PAW command NTUPLE/PLOT. Using the split feature described above it is is possible to produce 1D, 2D and 3D histograms of expressions involving the values associated with an event's TBranch objects as shown in this diagram:-

MyClassB has 3 data members fX, fY and fZ, and MyTree is asked to produce a a scatter plot of fY against fX for all events for which fZ < 0 with the statement:-

Note that only those TBranch objects that hold the members being plotted are read. This is rather similar to PAW's column-wise n-tuples.

The Draw message is a very flexible function having 5 arguments, with all but the first taking defaults. The formal arguments are:-

  void Draw(const Text_t *varexp,      
            const Text_t *selection, 
            Option_t *option,
            Int_t nevents, 
            Int_t firstevent) 
Effectively this means that the first 3 are character strings and the last two integers.
  1. const Text_t *varexp
    This takes the form e1, e1:e2 or e1:e2:e3 corresponding to 1D, 2D and 3D plots. e1, e2, and e3 are expressions involving an object's variables. As with PAW a wide range of formulae are permitted, for example:-
    "sqrt(fX**2 + fY**) * cos(fZ)"
    Unlike PAW, spaces are allowed to improve readability.
    By default the temporary histogram created is called htemp. If the expression ends >>hnew a new histogram called hnew is created and kept. For example:-
    will save the histogram as "hsqrt". The histogram can subsequently be manipulated in its own right. Assuming this is being done interactively, one of the CINT Shortcuts can be exploited: CINT will be able to find hsqrt and then, to change its fill colour:-
    If writing code, global ROOT object gROOT can be asked to go and find any object given its name, so to get a pointer to hsqrt:-
    TH2F *hsqrt = (TH2F*) gROOT->FindObject("hsqrt");

    By default, the specified histogram is reset. To continue to append data to an existing histogram, use "+" in front of the histogram name e.g.:-
    will not reset hsqrt, but will continue filling it.

  2. const Text_t *selection
    Specifies a weight function. If omitted a weight of 1. is used. Normally this is a logical expression yielding either true (1.) or false (0.):-
    "fZ < 0"
    but it could be a weighting factor, for example:-
    " 1. / fZ"

  3. Option_t *option
    This is an option string that it passed to the histogram, for example:-
    for a lego plot. The complete list of options can be found in ROOT description of the TH1::Draw function. By default a null option string is passed.

  4. Int_t nevents
    This is the number of events to process. By default all are.

  5. Int_t firstevent
    This is the first event number to process. By default this is 0 (events count from 0 not 1).

In the above example MyCLassB had data members fX, fY and fZ. If instead it had a pointer to TClonesArray called fMyClonesArray that held objects having these data members then, for example, to access fX, the variable name would be:-

  1. First comes the TClonesArray pointer name.
  2. Next comes the member selection operator . (dot)
  3. Finally comes the member name of the class held in the array.
The plot would now access every object in the array for all selected events. If an object has more than one TClonesArray pointer then Draw can take expressions that can have data drawn from them all, although it does not form multiple combinations; it simply takes the first member of each and then the second and so on. It quits as soon as any array in exhausted. So if a particular object has two arrays, one with 5 elements and an other with 8, expressions that combine them will yield 5 values.

The expressions to be plotted don't all have to come from within a single event object. In our example, expressions involving data from MyClassA, MyClassB and MyClassC can mixed. The same words of caution apply if dealing with TClonesArray pointers.

Example Use in MINFast

The loopmacro shows an example of the event TTree being asked to plot:-
Note the data member syntax, m_flsdigits is the TClonesArray pointer and the class held in the array is REROOT_FLSDigit whose data members include m_TPos and m_ICell.

For more information see:-

Go Back to the The ROOT Crib Top Page

If you have any comments about this page please send them to Nick West