Rene Brun
Nick West wrote:
>
> Hi Rene,
>
> I have to say I am a fan of TClonesArray and your suggestion:-
>
> > We could may be add a few additional and specialized containers
> > "a la TClonesArray". I am thinking to one specially.
> > Suppose the frequent case where you have hits/tracks referencing each
> > other. Having pointers as data members of the tiny objects may
> > induce a big penalty in I/O (4 or 8 bytes required). In case
> > you always reference the same list, it may be more clever to store
> > only the index inside the list, typically saving a factor 4 or 8
> > in storage.
>
> is a good one but reminded me of some unfinished business. Earlier this year I
> reported a problem with pointers to objects held in TClonesArrays, but got
> side-track onto something else. I can still reproduce the problem in that, on
> output, all such objects get written twice, and when reinput, the pointer points
> to a copy of the object, NOT the one in the TClonesArray. I think the basic
> problem is that, in TClonesArray::Streamer, the way objects get written out is
> by:-
>
> fCont[i]->Streamer(b);
>
> rather than by writing a pointer, so the pointer address is never recorded and
> so, when the pointer gets streamed, there is no entry in the map, so it
> generates another copy. I have a trivial example that demonstrates this:-
>
> MyClass.cxx,MyClass.h Define MyClass which has a TClonesArray of MyTrack
> MyTrack has a pointer to another MyTrack
>
> test_write.cxx Creates a TTree with a MyClass branch
> Creates a MyClass, prints, fills tree once and
> writes tree out.
>
> rest_read.cxx Opens the file, reads the tree and the first event
> Prints it
>
> In test_write I store 2 MyTracks in the MyClass TClonesArray and point each to
> the other. MyClass::Print() asks each MyTrack to print itself:-
>
> > MyClass 0x1403f4f38 contains:
> >
> > MyTrack 0x14043ff08 fPx: 1 fPy: 2 fPz: 3
> > Related track: 0x14043ffc8
> >
> > MyTrack 0x14043ffc8 fPx: 4 fPy: 5 fPz: 6
> > Related track: 0x14043ff08
>
> as you see "Related track" of each points to the other. However, on input in
> test_read they don't:-
>
> > MyClass 0x1404818a8 contains:
> >
> > MyTrack 0x140480e88 fPx: 1 fPy: 2 fPz: 3
> > Related track: 0x140480ec8
> >
> > MyTrack 0x140480f48 fPx: 4 fPy: 5 fPz: 6
> > Related track: 0x140480f08
>
> If you, or anyone else, has time to look, here are the files I am using with
> Digital UNIX V4.0D (Rev. 878) and Root 2.00/12
>
> >>>>>MyClass_LinkDef.h
>
> #ifdef __CINT__
>
> #pragma link off all globals;
> #pragma link off all classes;
> #pragma link off all functions;
>
> #pragma link C++ class MyClass;
> #pragma link C++ class MyTrack;
>
> #endif
>
> >>>>>MyClass.h
>
> #ifndef MYCLASS
> #define MYCLASS
>
> // Trivial class with TClonesArray and pointer to object it holds.
>
> #include "Rtypes.h"
>
> #include "TClonesArray.h"
>
> class MyClass : public TObject {
>
> private:
> TClonesArray *fMyClonesArray; //This will hold MyTrack objects
>
> public:
> MyClass();
> ~MyClass() {;}
> void Build();
> void Print();
>
> ClassDef(MyClass,1) //Trivial class
> };
>
> class MyTrack : public TObject {
>
> private:
> MyTrack *fRelatedTrack;
> Float_t fPx;
> Float_t fPy;
> Float_t fPz;
>
> public:
> MyTrack();
> MyTrack( Float_t px, Float_t py, Float_t pz);
> ~MyTrack() {;}
> void AddRelatedTrack( MyTrack* t );
> void Print();
>
> ClassDef(MyTrack,1) //Trivial track class
> };
>
> #endif
>
> >>>>>MyClass.cxx
>
> #include "MyClass.h"
> #include <iostream.h>
>
> ClassImp(MyClass)
>
> static TClonesArray *gfMyClonesArray; //This is the permanent copy
>
> //______________________________________________________________________________
>
> MyClass::MyClass()
>
> {
>
> // Create permanent TClonesArray if required.
>
> if ( ! gfMyClonesArray )gfMyClonesArray = new TClonesArray("MyTrack", 2);
> fMyClonesArray = gfMyClonesArray;
>
> }
>
> //______________________________________________________________________________
>
> void MyClass::Build()
>
> {
>
> // Store two MyTracks.
>
> MyTrack *t1 = new( (*fMyClonesArray)[0] ) MyTrack(1.,2.,3.);
> MyTrack *t2 = new( (*fMyClonesArray)[2] ) MyTrack(4.,5.,6.);
> t1->AddRelatedTrack(t2);
> t2->AddRelatedTrack(t1);
>
> }
>
> //______________________________________________________________________________
>
> void MyClass::Print()
>
> {
>
> cout << "MyClass " << this << " contains:" << endl << endl;
> MyTrack *t = 0;
> for ( Int_t tk_num = 0; tk_num < fMyClonesArray->GetEntriesFast(); tk_num++) {
> if ( t = (MyTrack*) fMyClonesArray->At(tk_num) ) t->Print();
> }
>
> }
>
> ClassImp(MyTrack)
>
> //---------------------------------------------------------------
>
> MyTrack::MyTrack()
>
> {
> fRelatedTrack = 0;
> fPx = 0.;
> fPy = 0.;
> fPz = 0.;
> }
>
> //---------------------------------------------------------------
>
> MyTrack::MyTrack( Float_t px, Float_t py, Float_t pz )
>
> {
> fRelatedTrack = 0;
> fPx = px;
> fPy = py;
> fPz = pz;
>
> }
>
> void MyTrack::AddRelatedTrack( MyTrack* t )
>
> {
> fRelatedTrack = t;
> }
>
> //---------------------------------------------------------------
>
> void MyTrack::Print()
>
> {
> cout << "MyTrack " << this
> << " fPx: " << fPx << " fPy: " << fPy << " fPz: " << fPz << endl;
> cout << "Related track: " << fRelatedTrack << endl << endl;
>
> }
>
> >>>>>test_write.cxx
>
> #include "TROOT.h"
> #include "TFile.h"
> #include "TTree.h"
>
> #include "MyClass.h"
>
> // Initialize the ROOT system
> TROOT root("test_write","Test of TClonesArray I/O with pointers");
>
> int main(int argc, char **argv)
> {
>
> TFile *output_file = new TFile( "test.root", "RECREATE");
>
> MyClass *myclass = new MyClass;
>
> TTree *tree = new TTree("T","Test of TClonesArray I/O with ponters");
> Int_t split = 0;
> Int_t bsize = 1000;
> tree->Branch("myclass", "MyClass", &myclass, bsize, split);
>
> myclass->Build();
> myclass->Print();
>
> tree->Fill();
> output_file->Write();
> output_file->Close();
>
> return 0;
> }
>
> >>>>>test_read.cxx
>
> #include "TROOT.h"
> #include "TFile.h"
> #include "TTree.h"
>
> #include "MyClass.h"
>
> // Initialize the ROOT system
> TROOT root("test_read","Test of TClonesArray I/O with pointers");
>
> int main(int argc, char **argv)
> {
>
> TFile *input_file = new TFile( "test.root", "READ");
>
> MyClass *myclass = new MyClass;
>
> TTree *tree = (TTree*)input_file->Get("T");
> tree->SetBranchAddress("myclass", &myclass);
>
> tree->GetEvent( 0 );
>
> myclass->Print();
>
> input_file->Close();
>
> return 0;
> }