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; }
This archive was generated by hypermail 2b29 : Tue Jan 04 2000 - 00:34:41 MET