Re: [ROOT] TTree::BuildIndex

From: Sue Kasahara (schubert@hep.umn.edu)
Date: Wed Mar 17 2004 - 02:52:35 MET


Hi Rene,
Thanks for your quick response, and sorry that I missed the documentation
about using TTree::BuildIndex with majorname only - I see that this does
work as you described.
I am making use of TTree::BuildIndex in a script that I've written
to facilitate use of TTree::AddFriend for cases in which the entries in the
friend trees need to be synchronized by "key value" and not tree index.
Our need to be able to make use of TTree::AddFriend in this way was first
described in:
http://root.cern.ch/root/roottalk/roottalk03/3814.html
and also summarized at the recent root workshop.
  Even though I've been able to write a script to provide the functionality
we want, I would like to make this process simpler for our users and am
hoping that ROOT will support the ability to use AddFriend with entries
synchronized by key value and not tree index.
  I'm attaching the scripts that I've written so that you can see better
what it is that we're after.  (demo script AddFriendByKey.C makes use
of AlignTreesByKey.C)
  Can you please tell me if this is something root will support, and if
so on what time scale?
Thanks,
-Sue

Rene Brun wrote:

> Hi Sue,
>
> see: http://root.cern.ch/root/htmldoc/TTree.html#TTree:BuildIndex
>
> I have implemented your suggestion with the return type.
> see the doc for specifying only majorname
>
> Rene
>
> On Sat,
> 13 Mar 2004, Sue Kasahara wrote:
>
> > Hi root team,
> > I'm wondering if the method:
> >   virtual void      BuildIndex(const char *majorname, const char *minorname);
> > can be modified in the following ways:
> > 1)To allow the user to specify only a majorname if desired.  Currently, doing this creates an invalid
> >     string "majorname +*1e-9".
> > 2)To return a value (-1?) indicating failure if the method failed to successfully build the user's index.
> > I'm using cvs root from Feb. 10, 2004.
> > Thanks,
> > -Sue
> >


{
// Macro to illustrate how to use AlignTreesByKey to facilitate
// the use of TTree::AddFriend with trees which have non-aligned
// entries.
// Usage:
// loon
// root [0] .L AlignTreesByKey.C
// root [1] .x AddFriendByKey.C
//

  TFile* mcfile = new TFile("ntupleMC.root","READ");
  TTree* mctree = (TTree*)(mcfile->Get("NtpMC"));

  TFile* srfile = new TFile("ntupleSR.root","READ");
  TTree* srtree = (TTree*)(srfile->Get("NtpSR"));

  // Create clone trees with aligned by timestamp.  The resulting
  // aligned trees are stored in the current gDirectory.
  // Creating a TFile automatically sets gDirectory to the new file
  TFile* newFile = new TFile("cloneTreeFile.root","RECREATE");
  AlignTreesByKey(mctree,srtree,"fHeader.fVldContext.fTimeStamp.fSec",
                                "fHeader.fVldContext.fTimeStamp.fNanoSec");

  // Aligned trees will work with TTree::AddFriend
  // These trees contain only the subset of entries that have matching
  // key values across the two trees.
  TTree* newmctree = (TTree*)(gDirectory->Get("NtpMC_clone"));
  TTree* newsrtree = (TTree*)(gDirectory->Get("NtpSR_clone"));
  newmctree -> AddFriend(newsrtree);
  newmctree -> Draw("evt.vtx.z:mc.vtxz","","box");
  
  // It's also possible to draw from full mc or sr tree:
  // mctree -> Draw("mc.vtxz");

}


#include <iostream>
#include "TTree.h"
#include "TFile.h"
#include "TMath.h"
#include "TBranchElement.h"

using namespace std;

void AlignTreesByKey(TTree* tree1, TTree* tree2,  
                     const char* majorname, const char* minorname) {
  // This macro takes input trees "tree1" & "tree2", clones them (tree
  // branch structure only), and inserts entries in the two cloned trees such 
  // that entries are aligned by user-specified key value stored in both 
  // trees.  The user must specify the branch names "majorname"
  // & "minorname" a la TTree::BuildIndex, which will be used to form
  // the key value in form:
  // "majorname + minorname*1.e-9"
  // The majorname & minorname must correspond to branchnames
  // of branches existing on both trees storing basic data types. 
  // Set minorname to "0" to use majorname only. 
  //   The cloned trees are stored in gDirectory.  The user may set this
  // to a TFile by creating a TFile just before invoking the macro.
  // The cloned trees are owned by gDirectory, and will be deleted by
  // the TDirectory destructor.  The cloned trees have the same name
  // as the original trees with extension "_clone" tacked to the end.
  //   See AddFriendByKey.C for an example of how to use AlignTreesByKey.C
  // in an application in which the user wishes to use TTree::AddFriend
  // on two trees on which the entries don't have a 1:1 relationship by 
  // tree index.
  //   A key value on one tree (e.g. tree1) which does not have a matching 
  // entry by key valued on the other tree (e.g. tree2) is eliminated from 
  // the clone trees.
  //

  if ( !tree1 || !tree2 ) {
    cout << "Error: Received null tree pointer as argument." << endl;
    return;
  }
  if ( !gDirectory ) {
    cout << "Error: Null gDirectory on input." << endl;
    return;
  }

  // For each input tree, use BuildIndex to establish association between
  // tree index and key value. Key value is majorname + minorname*1.e-9
  TTree* tree[2] = {tree1,tree2}; // tree pointers
  Int_t nval[2] = {0};
  Int_t*    index[2] = {0};  // array of indices returned by BuildIndex
  Double_t* value[2] = {0};  // array of values returned by BuildIndex

  for ( int it = 0; it < 2; it++ ) {
    nval[it] = tree[it] -> BuildIndex(majorname,minorname);
    if ( nval[it] != tree[it] -> GetEntries() ) {
      cout << "Error: BuildIndex failure on TTree " 
           << tree[it] -> GetName() << endl;
      return;
    } 

    // The entries have been sorted by majorname + minorname*1e-9 in 
    // TTree data members fIndexValues and fIndex
    index[it] = tree[it] -> GetIndex();
    value[it] = tree[it] -> GetIndexValues();
  }

  // Determine key values in common across two trees
  
  Int_t* newindex[2] = {0};
  Int_t nmin = TMath::Min(nval[0],nval[1]);
  newindex[0] = new Int_t[nmin];
  newindex[1] = new Int_t[nmin];
  Int_t nmaster = 0;
  Int_t i1 = 0;
  for ( int i0 = 0; i0 < nval[0]; i0++ ) {
    while ( i1 < nval[1] && value[0][i0] > value[1][i1] ) {
      i1++;
    }
    if ( i1 < nval[1] && value[0][i0] == value[1][i1] ) {
      newindex[0][nmaster] = i0;
      newindex[1][nmaster] = i1;
      nmaster++; i1++;
    } 
  }

  // Retrieve main branch and other data from information stored in TTree.
  // There should only be one main branch in TTree's created with the
  // Persistency package.  Selected entries (those on master value list)
  // are transfered to clone tree.
  TTree* newtree[2] = {0};
  for ( int it = 0; it < 2; it++ ) {
    TObjArray* branchlist = tree[it] -> GetListOfBranches();
    Int_t nbranch = branchlist -> GetEntriesFast();
    if ( nbranch != 1 ) {
      cout << "Error: Unexpected number of main branches in tree " << endl;
      return;
    }
    TBranchElement* branch = dynamic_cast<TBranchElement*>(branchlist->At(0));
  
    // Create a new clone tree, the tree will be stored in the input directory
    // specified by the user
    std::string clonename = std::string(tree[it]->GetName()) + "_clone";
    newtree[it] = tree[it] -> CloneTree(0);
    newtree[it] -> SetName(clonename.c_str());
   
    for ( int imas = 0; imas < nmaster; imas++ ) {
      TObject* object = 0;
      branch -> SetAddress(&object);
      Int_t nbytes = tree[it] -> GetEntry(newindex[it][imas]);
      newtree[it] -> Fill();
      if ( object ) delete object; object = 0;
    }
  }

  delete [] newindex[0];
  delete [] newindex[1];

  return;

}



This archive was generated by hypermail 2b29 : Sun Jan 02 2005 - 05:50:06 MET