Tree question

Hi,
I’m new to root and I was reading the documentation on trees (12Trees.pdf) where it discusses “Example 4: A Tree with an Event Class”. So in the routine tree4w(), where it creates two branches:

[code] //create a Tree file tree4.root
TFile f(“tree4.root”,“RECREATE”);

// Create a ROOT Tree
TTree t4(“t4”,“A Tree with Events”);

// Create a pointer to an Event object
Event *event = new Event();

// Create two branches, split one.
t4.Branch(“event_split”, &event,16000,99);
t4.Branch(“event_not_split”, &event,16000,0);

[/code]
And fills the appropriate Event class where fNtrack is a data member in class Event:

[code]class Event : public TObject {

private:
char fType[20]; //event type
char *fEventName; //run+event number in character format
Int_t fNtrack; //Number of tracks
Int_t fNseg; //Number of track segments
Int_t fNvertex;
UInt_t fFlag;
Double32_t fTemperature;
Int_t fMeasures[10];
Double32_t fMatrix[4][4];
Double32_t *fClosestDistance; //[fNvertex][0,0,6]
EventHeader fEvtHdr;
TClonesArray *fTracks; //->array with all tracks
TRefArray *fHighPt; //array of High Pt tracks only
TRefArray *fMuons; //array of Muon tracks only
TRef fLastTrack; //reference pointer to last track
TRef fWebHistogram; //EXEC:GetWebHistogram reference to an histogram in a TWebFile
TH1F *fH; //->
TBits fTriggerBits; //Bits triggered by this event.
Bool_t fIsValid; //

static TClonesArray *fgTracks;
static TH1F *fgHist
…[/code]

So after filling the tree, it attempts to read the same tree just created (in routine tree4r()):

[code] //note that we use “new” to create the TFile and TTree objects !
//because we want to keep these objects alive when we leave this function.
TFile *f = new TFile(“tree4.root”);
TTree t4 = (TTree)f->Get(“t4”);

// create a pointer to an event object. This will be used
// to read the branch values.
Event *event = new Event();

// get two branches and set the branch address
TBranch *bntrack = t4->GetBranch(“fNtrack”);
TBranch *branch = t4->GetBranch(“event_split”);
branch->SetAddress(&event);

Int_t nevent = (Int_t)t4->GetEntries();
Int_t nselected = 0;
Int_t nb = 0;
for (Int_t i=0;i<nevent;i++) {
//read branch "fNtrack"only
bntrack->GetEntry(i);

//reject events with more than 587 tracks          
if (event->GetNtrack() > 587)continue;

//read complete accepted event in memory 
nb += t4->GetEntry(i);                  
nselected++;

//print the first accepted event
if (nselected == 1) t4->Show();[/code]

So here is where I’m getting confused, why is it identifying “fNtrack” to be a branch when the only two branches in this tree is “event_split” and “event_not_split” (which is never filled). I don’t understand what TBranch *bntrack is here if fNtrack is not a branch but a leaf of branch event_split. I can see that event is set to the beginning of branch “event_split” via branch->SetAddress(&event).

So in the for loop what is bntrack->GetEntry(i) doing? And how is that impacting the next line (where GetNtrack() is just returning the value of fNtrack):
if (event->GetNtrack() > 587)continue;

I ask this because I didn’t understand why a leaf “fNtrack” was being set as the pointer to Tbranch pointer nbtrack and hence wondered what would differ in the printout (t4>Show()) if I commented out
TBranch *bntrack = t4->GetBranch(“fNtrack”);

and commented out this code inside the for loop:
//read branch "fNtrack"only
bntrack->GetEntry(i);

As it seems when I did that it behaved as if the following condition wasn’t there:
//reject events with more than 587 tracks
if (event->GetNtrack() > 587)continue;

and prints out the very first event of t4 as the result of the code that follows that line.

[quote](which is never filled).
[/quote]Why is it never filled?

[quote]So here is where I’m getting confused, why is it identifying “fNtrack” to be a branch when the only two branches in this tree is “event_split” and “event_not_split” [/quote]When a branch is split, it contains sub-branches. If you create the split with a trailing dot:t4.Branch("event_split.", &event,16000,99);the name of the sub-branch will be “event_split.fNtrack” (rather than fNtrack).

[quote]So in the for loop what is bntrack->GetEntry(i) doing? [/quote]It reads the data for just the subbranch (and its won subbranches if any).

[quote] And how is that impacting the next line (where GetNtrack() is just returning the value of fNtrack):
if (event->GetNtrack() > 587)continue;[/quote]It actually set the value of event->fNtrack thus make the line of code you mention ‘valid’.

Cheers,
Philippe.

[quote=“pcanal”][quote](which is never filled).
[/quote]Why is it never filled? [/quote]

I have no idea why branch event_not_split is never filled (I didn’t write this sample code but was in the document). Only something I observed when actually running the example code given and viewing the output via StartViewer(); event_not_split was an empty branch…

Thanks for the explanation on accessing data members without having to load the whole object.

BTW is event->Clear(); really necessary at the bottom of the for-loop, since at the top of the for-loop it does this:
bntrack->GetEntry(i);
which should just over ride that data member in the event object (and if it gets past the condition also loads the whole object via t4->GetEntry(i))?

Jade

[quote]I have no idea why branch event_not_split is never filled (I didn’t write this sample code but was in the document) … and viewing the output via StartViewer();[/quote]Ah … the TTreeViewer can not show the content of unsplit branches … It is likely to have been properly filled. For example you can try explore it with the TBrowser instead.

[quote]BTW is event->Clear(); really necessary at the bottom of the for-loop, since at the top of the for-loop it does this:[/quote]It is not strictly necessary but if you are partially reading the object (in particular if you are conditionally partially reading it), it make it clear what was set or not set by the reading.

Cheers,
Philippe.