Re: [ROOT] TClonesArray gathering

From: Ben Kilminster (bjk@fnal.gov)
Date: Thu Mar 25 2004 - 01:50:27 MET


Hi,

Here is the code to gather TClonesArrays of objects and put them in a  
TTree.
There is a Parent class, a Daughter class, and a Thing class.
The Parent object creates some Daughter objects.  The Daughters decide  
they want some Things.   The Parent object then checks the Daughters,  
finds out what Things are wanted and makes an entry in the tree.   The  
following example doesn't crash, but it also doesn't store the  
TClonesArray into the TTree.   I tried to do this by adding the  
Daughters' Things one at a time to the tree, but I couldn't get the  
syntax correct (commented part).

{
// This macro requires Thing.hh, Thing.cc, Daughter.hh, Daughter.cc,  
Parent.hh, Parent.cc
gSystem->CompileMacro("Thing.cc");
gSystem->CompileMacro("Daughter.cc");
gSystem->CompileMacro("Parent.cc");
Parent P(1);
P->HasDaughters();
}

-----------------------------------------
//Thing.hh
class Thing : public TObject {
   public:
   Thing();
   ~Thing() {};
   int Value;
   int ThingID;
   ClassDef(Thing,1)
};
-----------------------------------------
//Thing.cc
#include "Thing.hh"
Thing::Thing() {
   ThingID = -999;
   Value = -999;
}
ClassImp(Thing)
-----------------------------------------
// Daughter.hh
#include "TClonesArray.h"
#include "Thing.hh"
class Daughter
{
public:
   int ID;
   int GotAThing;
   TClonesArray* CloneThing;    Thing*  MyThing;
   Daughter ();
   Daughter (int minutes_apart);
   void Reset();
   void Want(int cash);
};
-----------------------------------------
// Daughter.cc
Daughter::Daughter (){}
Daughter::Daughter (int minutes_apart)
{
	this->ID = minutes_apart;
     CloneThing = new TClonesArray("Thing");
}
void Daughter::Reset()
{
       CloneThing->Clear();
       GotAThing = 0;
}
void Daughter::Want(int cash)
{
     MyThing = new ((*CloneThing)[GotAThing]) Thing;
     MyThing->ThingID = this->ID;
     MyThing->Value = cash;
     GotAThing++;
}
-----------------------------------------
// Parent.hh
#include "Daughter.hh"
#include "TClonesArray.h"
#include "TFile.h"
#include "TTree.h"

class Parent {
public:
   Parent( );
   Parent(int tree);
   ~Parent( );
   void  HasDaughters();
private:
   TFile* newfile;
   TTree* MoneyTree;
   Daughter* Triplet[3];
   TClonesArray* CloneThing;
   Thing* MyThing;
   int numThings;
};
-----------------------------------------
// Parent.cc
#include "Parent.hh"
#include "TClonesArray.h"
#include "TFile.h"
#include "TRandom.h"

#include <assert.h>
#include <string>
#include <strstream>
#include <iostream>
#include <stdio.h>

using namespace std;

Parent::Parent(int tree) {
// Open a file, and a tree
     newfile = new TFile("MoneyTree.root","RECREATE","Simple ROOT  
Ntuple");
     MoneyTree = new TTree("T","MoneyTree");
// Add a branch for things
     CloneThing = new TClonesArray("Thing");
     MoneyTree->Branch("CloneThing",&CloneThing,32000,2);
     MoneyTree->Branch("numThings",&numThings,"numThings/I");
// Verify what we have constructed...
     newfile->ls();
     TObjArray * br = MoneyTree->GetListOfBranches();
     TIter i(br);
     cout << "-----------------------------------------------------" <<  
endl;
     cout << "Branches:" << endl;
     while( TBranch * b = (TBranch*)i()){
       cout << b->GetName() << " : " << b->GetTitle() << endl;
     }
     cout << "-----------------------------------------------------" <<  
endl;
}

Parent::Parent( )
{}
Parent::~Parent( )
{}

void Parent::HasDaughters()
{
   CloneThing->Clear();
   // make daughters
   *Triplet = new Daughter[3];
   Triplet[0] = new Daughter(0);
   Triplet[1] = new Daughter(35);
   Triplet[2] = new Daughter(56);

   // Daughters want things
   Triplet[0]->Reset();
   Triplet[1]->Reset();
   Triplet[2]->Reset();
   Triplet[0]->Want(100);
   Triplet[0]->Want(150);
   Triplet[2]->Want(100);

   // Parent checks what daughters want, puts entry in money tree
   numThings = 0;
   for(int nd=0; nd <3; nd++) {
     int wantCash =  Triplet[nd]->GotAThing;
     printf("Daughter %d wants %d things\n",nd, wantCash);fflush(stdout);
     // Tried to add the whole clone array: runs, but doesn't store  
Things
     if (wantCash > 0) {
       CloneThing =  (TClonesArray*) Triplet[nd]->CloneThing->Clone();
       numThings += wantCash;
     }

//     // Also tried to add one at a time, can't get syntax right
//     for (int i = 0; i < wantCash; i++) {
//       MyThing = new  
((*CloneThing)[numThings])Triplet[nd]->CloneThing->At(i);
//       numThings++;
//     }

   }
   MoneyTree->Fill();

   // The above steps may repeat, then the file closes
   MoneyTree->GetCurrentFile()->Write();
   MoneyTree->GetCurrentFile()->Close();
}
-----------------------------------------







On Mar 12, 2004, at 2:25 AM, Rene Brun wrote:

> Hi Ben,
>
> It is not obvious to follow your explanations without looking at a  
> concrete
> piece of code ::)
> I have the feeling that you do not fill the TClonesArray correctly.  
> You must
> call the constructor of the class in the TClonesArray (as shown in
> $ROOTSYS/test/Event.cxx).
> Could you send the shortest possible file reproducing the problem?
>
> Rene brun
>
>
>
> Ben Kilminster wrote:
>>
>> I am trying to figure out how to fill a Tree in one object with a
>> TClonesArray from another object.
>> My code is crashing when I try to do the copying.
>>
>> In my main class, I define a tree with a branch, with a TClonesArray  
>> of
>> objects in it:
>>
>> class MainSim
>> {
>>    TTree* SimTree;
>>    TClonesArray* CloneXftpixel;
>>    xft2Lpixel* xftpixelB;
>> ...
>> }
>>
>> MainSim::MainSim()
>> {
>>      CloneXftpixel = new TClonesArray("xft2Lpixel");
>>      SimTree = new TTree("T","SimTree");
>>      SimTree->Branch("xft2Lpixel",&CloneXftpixel,32000,2);
>>      ...
>> }
>>
>> I then fill the TClonesArray in another class, like :
>>
>> class FinderChip
>> {    TClonesArray* CloneXftpixel;
>>       xft2Lpixel*  xft2pixelF;
>>       int iPixel;
>> ...
>> }
>>
>> FinderChip::FillBlock()
>> {
>>         iPixel++;
>>         xft2pixelF = new ((*CloneXftpixel)[iPixel]) xft2Lpixel;
>>         xft2pixelF->Chip =  this->COT_chip;
>>                         ...
>> }
>>
>> Now, I want to fill the SimTree with the array of xft2Lpixels from the
>> FinderChip object.
>> But I have many FinderChip objects, with any number of xft2pixelF
>> objects,  so I have to gather them by checking the iPixel counter for
>> each FinderChip :
>>
>> MainSim::FillTree()
>> {
>>         CloneXftpixel->Clear()
>>
>>      for(int nbrd=0; nbrd<8; nbrd++) {
>>        for (int nchp=0;nchp<8;nchp++) {
>>          int nPix =
>> XFTSystem->finderCrate[crate]->FinderBoard2_4Elements[nbrd]-
>>> finderChipElements[nchp]->iPixel;
>>         if (nPix > 0)
>>          CloneXftpixel =
>> (TClonesArray*)XFTSystem->finderCrate[crate]-
>>> FinderBoard2_4Elements[nbrd]->finderChipElements[nchp]- 
>>> >CloneXftpixel-
>>> Clone();
>>                 }
>>         }
>>
>>         SimTree->Fill()
>>
>> This compiles and runs, but crashes filling the CloneXftpixel in the
>> FillTree() method.
>>
>> Instead of the if (nPix>0), I also tried to do this with a loop as in
>> the At() statement :
>>          for (int i=0; i < nPix; nPix++) {
>>            xftpixelB =
>> (xft2Lpixel*)XFTSystem->finderCrate[crate]-
>>> FinderBoard2_4Elements[nbrd]->finderChipElements[nchp]- 
>>> >CloneXftpixel-
>>> At(i);
>>           }
>>
>> but this crashed in the same place.
>>
>> What is the correct way to do this ?
>>
>> Cheers,
>> Ben



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