TTree, TBranch and TBasket
The following may be needed if not using
Acting together these, and closely related
provide the following services:-
- Synchronised I/O, allowing a group of
to collectively represent an event, providing random and sequential access to
the group in a single operation.
- Partial I/O, allowing selected parts of an event to be input and
- Automated Event Processing, for example generating histograms of event data
from a single command.
As explained in
the basic method for reading and writing objects is to send objects Read and
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:-
- First, typically an event will not be a single object but a collection of
them. Then reading and writing has to ensure that they all operated on
together. Of course this can be solved by creating a new class whose
are the objects of the event, but that means that an entire event has to be
read to access any part of it.
- Second, each copy of the event on file has to have its own unique key
which is rather wasteful.
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
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:-
To output a copy of all the event objects now requires just one command:-
object is created, which result in a new ROOT file being created.
- A TTree object is created.
- 2 integers are defined. split will be explained
below, bsize is used to define the TBasket size in
- 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!
- Finally the last Tbranch is told to set its file to "File2.root", it will
create this file automatically when it attempts to write.
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:-
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;
To loop processing all events:-
Int_t nevent = MyTree->GetEntries();
for (Int_t i=0;iGetEvent(i);
\\ MyObjA, MyObjB and MyObjC pointers now point to event i
- Creates a TFile object to open an existing file.
- Retrieves the TTree named "MyTree".
- 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.
- Sets the TBranch associated with MyObjC to use "File2.root" for its I/O.
Another powerful feature of TTrees is the possibility of partial input as
shown by the diagram below:-
- MyTtree is asked how many events it has, and this is stored in the integer
- 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.
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
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
that is to say an array
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
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,
Effectively this means that the first 3 are character strings and the last two
- 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
can be exploited: CINT will be able to find hsqrt and then, to change its
If writing code,
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.
- 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"
- 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.
- Int_t nevents
This is the number of events to process. By default all are.
- 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
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.
- First comes the TClonesArray pointer name.
- Next comes the member selection operator . (dot)
- Finally comes the member name of the class held in the array.
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
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
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