Processing individual trees of chain breaks friend behaviour

Hello,

I have a need to process a tchain by individually processing each of the trees myself (I want to do it this way because I will be producing an output file for each individual tree in the chain). But when I try to process the trees individually, the indexed friend tree I have attached to my tree does not work as expected. I’ve prepared a minimal code example that I believe demonstrates my problem.

Create a simple proxy (called it friendProxy.C):

double friendProxy() {
   Int_t fVar = friendTree.friendVar;
   Int_t mVar = mainVar;
   Info("friendProxy","mVar=%d, fVar=%d",mVar,fVar);
   return fVar;
}

Now run this:

{
   TFile f1("mainTree.root","RECREATE");
   TTree *t = new TTree("mainTree","mainTree");
   Int_t mVar(0);
   t->Branch("mainVar",&mVar);

   for(int i=0;i<10;i++) {
      mVar = i/2;
      t->Fill();
   }
   t->Write();
   f1.Close();

   TFile f2("friendTree.root","RECREATE");

   TTree *ft = new TTree("friendTree","friendTree");
   Int_t fVar(0);
   ft->Branch("mainVar",&mVar);
   ft->Branch("friendVar",&fVar);

   for(int i=0;i<5;i++) {
      mVar = i;fVar = mVar*2;
      ft->Fill();
   }
   ft->BuildIndex("mainVar");
   ft->Write();
   f2.Close();

   TChain *c = new TChain("mainTree");
   c->Add("mainTree.root");c->Add("mainTree.root"); //added twice to demonstrate

   TChain *fc = new TChain("friendTree");
   fc->Add("friendTree.root");
   fc->BuildIndex("mainVar"); //why do we need to rebuild the index!?
   c->AddFriend(fc);


   c->MakeProxy("genProxy","friendProxy.C");

   TSelector* selector = TSelector::GetSelector("genProxy.h++");

   cout << "Process whole chain" << endl;
   c->Process(selector);

   cout << "Process first tree" << endl;
   c->LoadTree(0);
   c->GetTree()->Process(selector);
   cout << "Process second tree" << endl;
   c->LoadTree(10);
   c->GetTree()->Process(selector);

}

The processing from the whole chain gives the expected results…

Process whole chain
Info in <genProxy::friendProxy>: mVar=0, fVar=0
Info in <genProxy::friendProxy>: mVar=0, fVar=0
Info in <genProxy::friendProxy>: mVar=1, fVar=2
Info in <genProxy::friendProxy>: mVar=1, fVar=2
Info in <genProxy::friendProxy>: mVar=2, fVar=4
.....
Info in <genProxy::friendProxy>: mVar=3, fVar=6
Info in <genProxy::friendProxy>: mVar=3, fVar=6
Info in <genProxy::friendProxy>: mVar=4, fVar=8
Info in <genProxy::friendProxy>: mVar=4, fVar=8

But the processing of the first tree alone gives incorrect results:

Info in <genProxy::friendProxy>: mVar=0, fVar=0
Info in <genProxy::friendProxy>: mVar=0, fVar=0
Info in <genProxy::friendProxy>: mVar=1, fVar=0
Info in <genProxy::friendProxy>: mVar=1, fVar=0
Info in <genProxy::friendProxy>: mVar=2, fVar=0
Info in <genProxy::friendProxy>: mVar=2, fVar=0
Info in <genProxy::friendProxy>: mVar=3, fVar=0
Info in <genProxy::friendProxy>: mVar=3, fVar=0
Info in <genProxy::friendProxy>: mVar=4, fVar=0
Info in <genProxy::friendProxy>: mVar=4, fVar=0

And then the processing of the second tree actually causes a crash for me!!??

Can someone please explain how to correctly load up each individual tree for processing?

Thanks,
Will

As a follow up to this issue. I have found that I can process the events of a single tree by specifying the start and number of events to process, e.g.:

chain->Process(selector,"",10,0);

to process the first tree. However, this workaround does not suffice for my needs, since my set up requires the “Begin” method of the generated selector to receive the TTree to be processed, and processing the chain appears to always leave the chain’s current tree as the last tree of the chain. Yes, I might be able to workaround by having the tree number passed via the option string, so that I can correctly load the right tree in the Begin method (since begin appears to receive the chain as its argument when processing as a chain), but that’s a bit of a hack, and I would rather learn how to correctly loop over the trees in a chain and process them individually without breaking the tfriend connection!

Thanks

Hi,

[quote]But the processing of the first tree alone gives incorrect results:[/quote]How do you actually do that? In particular, the likely cause is that the way you are doing it prevents/avoids the proper setting of the friendship (Since the friendship is added at the TChain level (c->AddFriend(fc);), the setting is done via the TChain functions).

Cheers,
Philippe.

I was running on the first tree by getting the pointer to the current tree and processing it (see the run code in my post above)…

c->LoadTree(0);
   c->GetTree()->Process(selector);

the chain © has already had its friend chain added to it. Does this mean that the loaded tree does not have a friend tree associated to it? How would one do that?

Hi,

Yes, this should have been sufficient (assuming that the chain and its friends have have the same decomposition in term of TTree length).

Can you provide a complete running example reproducing the issue?

Thanks,
Philippe.

Complete code is given in the first post of this thread.

Note that this isn’t a scenario where the friend tree has the same number of entries as the main tree - the point is that the friend tree is indexed and should be hooked up to the main tree to load the correct friend entry by looking at the corresponding branch value in the main tree.

Hi,

For technical reasons (including to avoid some infinite recursion) the friendship propagated from a TChain to its underlying TTree is only really active when calling TChain::LoadTree for each entry (i.e. TChain::LoadTree does move the cursor for those friend tree but TTree::LoadTree does not).

But much importantly there is a real semantic issue in your case, which means that even if the above technical restriction was lifted, it would still not work correctly.

The issue in your case is that the main tree/chain and the friends are uneven. Namely, in your example, the main tree (chain) contains 10 entries (20 entries) while the friend tree (chain) contains 5 entries (10 entries).

This means that there is not obviously correlation between the underlying TTree and the friends. For example, if the first LoadTree(0) seems ‘clear’ and would attach the first tree/file of the main chain to the first tree/file of the friend chain, what should LoadTree(10) do? There is only 10 entries in the friend chain, so which file should it attach it too? In you case, it is the friend tree starting at entry 5 … but how would LoadTree ‘guess’ that?

This is the same reason/problem that required the creating of the index for the whole friend chain:fc->BuildIndex("mainVar"); //why do we need to rebuild the index!?. When friending TChains but not creating an overall index, the assumption are:

  • the trees in both the main and friend chain have the same number of entries
  • the index value increase from TTree to TTree.

The best means to achieve your goals is to either creating multiple ‘main’ chain with the subset of files that you want to process or to explicitly (if you need just one TTree) read the main TTree from the file and associate to it the friend chain:cout << "Process first tree" << endl; TFile *file = new TFile::Open(c->GetListOfFiles()->At(0)->GetTitle()); TTree *tree; file->GetObject("mainTree",tree); tree->AddFriend(fc); tree->Process(selector); delete file; // deletes both the TFile and the TTree

Cheers,
Philippe.