[ROOT] Making a TTree containing a subset of another TTree...

From: Steve Sekula (sekula@SLAC.stanford.edu)
Date: Tue Aug 13 2002 - 04:55:23 MEST


Hello,

The general question which I am hoping to address is as follows: given 
an TChain of files, chain, containing a TTree, oldtree, what is the 
"correct" way to obtain a new tree, newtree, which contains a subset of 
oldtree's events?

In my current analysis, I begin with one of the TFiles in the chain, 
"file.root", and generate a class based off the tree, oldtree, in that file:

 > TFile f("file.root")
 > oldtree->MakeClass("OldTree");

Inside of OldTree.h I define a new method, passAnalysis(), which returns 
a boolean. I then flesh out this method in OldTree.C, but the bottom 
line is that it examines the values of branches (and functions of those 
branches) in the structure of oldtree and decides whether or not to pass 
the event.

I then edit the Loop() function and add the following code, so that a 
new TTree is created from the old one, based on the results of the 
passAnalysis() method:

void OldTree::Loop()
{
   if (fChain == 0) return;

   TFile oFile("newfile.root","recreate"); // Added by Steve
   TTree* newtree; // Added by Steve

   Int_t nentries = Int_t(fChain->GetEntriesFast());

   Int_t nbytes = 0, nb = 0;
   for (Int_t jentry=0; jentry<nentries;jentry++) {
      Int_t ientry = LoadTree(jentry); //in case of a TChain, ientry is 
the entry number in the current file
      if (ientry < 0) break;
      nb = fChain->GetEntry(jentry);   nbytes += nb;

      if (jentry == 0) { // Copy the structure of the old tree, added by 
Steve
         newtree = (fChain->GetTree())->CloneTree(0);  // added by Steve
         fChain->CopyAddresses(newtree);               // added by Steve
      }

      Bool_t passes = passAnalysis();
      if (passes) newtree->Fill();
   }

   if (newtree) newtree->Write();
   oFile.Close()
}

I then start ROOT and run the code on a TChain of files with _identical_ 
structure to file.root:

 > .L OldTree.C;
 > TChain chain("oldtree");
 > chain.Add("*.root");
 > OldTree test(&chain);
 > test.Loop();

This then leads to the memory filling extremely rapidly on the host 
machine (about 5% per second) until I achieve a wonderful segementation 
violation (long before the completion of the for-loop). However, this 
method of copying only a subset of interesting events in the tree has 
worked in the past.

The first thing that occurred to me was that instead of the above one 
could use CopyTree and apply it with conditions supplied by TCut 
objects. However, our current analysis structure is based not just on 
the values of the branches in the TTree but also on complicated 
functions derived from those branches which are called by 
passAnalysis(); it's therefore not a simple matter of using TCut objects.

It seems like the above procedure - CloneTree(0), copy addresses, and 
Fill() - ought to work. But it seems to lead to a rapid fill of the 
system memory and the inevitable crash that results from such behaviour. 
We are in the process of finding a simple way to migrate to TCut 
objects, but since this above procedure carried us through ROOT version 
3.03.05 (we are now using 3.03.07) it seems it ought to still work.

So to retiterate my question: (apart from using CopyTree and TCut 
objects) what is the best/correct way to make a copy of the subset of 
events in one TTree into another TTree with identical structure?

Regards,
Steve Sekula



This archive was generated by hypermail 2b29 : Sat Jan 04 2003 - 23:51:04 MET