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); MyBranchC->SetFile("File2.root");The sequence is:-
MyTree->Fill();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:-
MyBranchB->SetAddress(&MyObjB);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:-
MyFile1->Write(); MyFile1->Close();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); MyTree->GetBranch("MyObjC")->SetFile("File2.root");This:-
Int_t nevent = MyTree->GetEntries(); for (Int_t i=0;iGetEvent(i); \\ MyObjA, MyObjB and MyObjC pointers now point to event i }
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.
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:-
MyTree->Draw("fY:fX","fZ<0.");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.
"sqrt(fX**2 + fY**) * cos(fZ)"Unlike PAW, spaces are allowed to improve readability.
"sqrt(fX)>>hsqrt"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:-
hsqrt->SetFillColor(45);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");
"sqrt(fX)>>+hsqrt"will not reset hsqrt, but will continue filling it.
"fZ < 0"but it could be a weighting factor, for example:-
" 1. / fZ"
"LEGO"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.
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:-
fMyClonesArray.fXi.e.:-
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.
GEVT->Draw("m_flsdigits.m_TPos:m_flsdigits.m_ICell");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:-