Hi Christian, When a branch references the same class, one can add a "." (dot) character at the end of the branch name. When splitting the object, the generated branches will be labelled branch.subbranch. This information is added in 2.24. In your example, replace the two statements: FooTable* table1 = new FooTable("Table1", 10); FooTable* table2 = new FooTable("Table2", 20); by FooTable* table1 = new FooTable("Table1.", 10); FooTable* table2 = new FooTable("Table2.", 20); The result of tree.Print will give: ****************************************************************************** *Tree :Tree : A Foo Tree * *Entries : 1 : Total Size = 0 bytes File Size = 0 * * : : Tree compression factor = 1.00 * ****************************************************************************** *Branch :Table1. : Table1. * *Entries : 1 : BranchObject (see below) * *............................................................................* *Branch :Table1.fArray_ : Table1.fArray_/I * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fArray.fData : fData[Table1.fArray_]/F * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fArray.fUniqueID : fUniqueID[Table1.fArray_]/i * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fArray.fBits : fBits[Table1.fArray_]/i * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fName[16] : fName[16] * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fUser : fUser * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fIndex : fIndex * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fUniqueID : fUniqueID * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table1.fBits : fBits * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table2. : Table2. * *Entries : 1 : BranchObject (see below) * *............................................................................* *Branch :Table2.fArray_ : Table2.fArray_/I * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table2.fArray.fData : fData[Table2.fArray_]/F * *Entries : 1 : Total Size = 0 bytes File Size = 0 * *Baskets : 0 : Basket Size = 32000 bytes Compression= 1.00 * *............................................................................* *Branch :Table2.fArray.fUniqueID : fUniqueID[Table2.fArray_]/i * Rene Brun Christian Holm Christensen wrote: > > Hi ROOT'ers, > > I have a few questions to the routines that generate names for > TBranch'es, and how to Scan/Draw/Query a TTree. > > Suppose you have the simple classes FooTable, and FooData: > > class FooData : public TObject { > private: > Float_t fData; > public: > FooData(void) : fData(0) {} > FooData(Float_t data) : fData(data) {} > > Float_t GetData(void) const { return fData; } > void SetData(Float_t data) { fData = data; } > > ClassDef(FooData,1) // > }; > > class FooTable : public TObject { > private: > TClonesArray* fArray; > Char_t fName[16]; > Int_t fUser; > Int_t fIndex; > public: > FooTable(void) : fUser(-1), fIndex(0) { > strcpy(fName, "Table"); > fArray = new TClonesArray("FooData"); } > FooTable(const Char_t* name, Int_t user) : fUser(user), fIndex(0) { > strncpy(fName,name,15); > fArray = new TClonesArray("FooData"); } > > void Add(Float_t x) { new((*fArray)[fIndex++]) FooData(x); } > FooData* At(Int_t i) { return (FooData*)fArray->At(i); } > void SetUser(Int_t user) { fUser = user; } > Int_t GetUser(void) const { return fUser; } > Char_t* GetName(void) const { return fName; } > > ClassDef(FooTable,1) // > }; > > Now I want to make one TTree with two TBranch'es, both containing > FooTable objects: > > ClassImp(FooTable); > ClassImp(FooData); > TROOT fooRoot("FooRoot", "FooRoot"); > > int main(int argc, char** argv) { > TFile* file = new TFile("File.root", "RECREATE"); > FooTable* table1 = new FooTable("Table1", 10); > FooTable* table2 = new FooTable("Table2", 20); > > TTree* tree = new TTree("Tree", "A Foo Tree"); > TBranch* branch1 = tree->Branch(table1->GetName(), "FooTable", &table1); > TBranch* branch2 = tree->Branch(table2->GetName(), "FooTable", &table2); > > for (Int_t i = 0; i < 10; i++) { > table1->Add((Float_t)i / 10 + i); > table2->Add(i * 10 + i); > } > > tree->Fill(); > tree->Print(); > tree->Write(); > file->Close(); > return 0; > } > > Now, when I look at the outout from TTree::Print(), I see the > following TBranch names: > > Table1 > fArray_ > fArray.fData > fArray.fUniqueID > fArray.fBits > fUser > fName[16] > fIndex > fUniqueID > fBits > Table2 > fArray_ > fArray.fData > fArray.fUniqueID > fArray.fBits > fUser > fName[16] > fIndex > fUniqueID > fBits > > That is Table1::fArray::fData and Table2::fArray::fData _both_ have > the _same_ name: fArray::fData. This means, when I try to > Scan/Draw/Query the TTree for these members, I allways get the first > occurence, that is Table1.fArray: > > root [0] gSystem->Load("libFoo.so"); > root [1] TFile* file = new TFile("File.root", "READ"); > root [2] TTree* tree = (TTree*)file->Get("Tree"); > root [3] tree->Scan("fArray.fData[1]", "fUser==10") > ************************ > * Row * fArray.fD * > ************************ > * 0 * 1.1 * > ************************ > ==> 1 selected entry > root [4] tree->Scan("fArray.fData[1]", "fUser==20") > ************************ > * Row * fArray.fD * > ************************ > ************************ > ==> 0 selected entries > > The last line fails misarably, because the first entry of fUser is 10 > - it never sees the second entry where fUser == 20. Now, if I get the > branches specifically, then everything is fine: > > root [5] FooTable* table1 = new FooTable > root [6] FooTable* table2 = new FooTable > root [7] TBranch* branch1 = tree->GetBranch("Table1") > root [8] TBranch* branch2 = tree->GetBranch("Table2") > root [9] branch1->SetAddress(&table1) > root [10] branch2->SetAddress(&table2) > root [11] tree->GetEntry() > (Int_t)273 > root [11] table1->GetUser() > (Int_t)10 > root [12] table2->GetUser() > (Int_t)20 > root [13] table1->At(1)->GetData() > (Float_t)1.10000002384185791e+00 > root [14] table2->At(1)->GetData() > (Float_t)1.10000000000000000e+01 > > Now, I really want to use the Scan/Draw/Query functionallity of TTree, > so looking into the code of that class, I figured out I could set > names of my TBranches to end in a '.': > > FooTable* table1 = new FooTable("Table1.", 10); > FooTable* table2 = new FooTable("Table2.", 20); > > TTree* tree = new TTree("Tree", "A Foo Tree"); > TBranch* branch1 = tree->Branch(table1->GetName(), "FooTable", &table1); > TBranch* branch2 = tree->Branch(table2->GetName(), "FooTable", &table2); > > Doing that, I get the list of TBranch names: > > Table1 > Table1.fArray_ > Table1.fArray.fData > Table1.fArray.fUniqueID > Table1.fArray.fBits > Table1.fUser > Table1.fName[16] > Table1.fIndex > Table1.fUniqueID > Table1.fBits > Table2 > Table2.fArray_ > Table2.fArray.fData > Table2.fArray.fUniqueID > Table2.fArray.fBits > Table2.fUser > Table2.fName[16] > Table2.fIndex > Table2.fUniqueID > Table2.fBits > > And now it's possible to uniquely identify my entries: > > root [0] gSystem->Load("libFoo.so"); > root [1] TFile* file = new TFile("File.root", "READ"); > root [2] TTree* tree = (TTree*)file->Get("Tree"); > root [3] tree->Scan("Table1.fArray.fData[1]") > ************************ > * Row * Table1.fA * > ************************ > * 0 * 1.1 * > ************************ > root [4] tree->Scan("Table2.fArray.fData[1]") > ************************ > * Row * Table2.fA * > ************************ > * 0 * 11 * > ************************ > > However, when I get my TBranch'es > > root [5] FooTable* table1 = new FooTable > root [6] FooTable* table2 = new FooTable > root [7] TBranch* branch1 = tree->GetBranch("Table1.") > root [8] TBranch* branch2 = tree->GetBranch("Table2.") > root [9] branch1->SetAddress(&table1) > root [10] branch2->SetAddress(&table2) > root [11] tree->GetEntry() > (Int_t)228 > root [12] table1->GetUser() > (Int_t)10 > root [13] table2->GetUser() > (Int_t)20 > root [14] table1->At(1)->GetData() > Error: illegal pointer to class object At(1) 0x0 441 FILE:/tmp/fileYb8Tcw_cint LINE:1 > *** Interpreter error recovered *** > root [15] table2->At(1)->GetData() > Error: illegal pointer to class object At(1) 0x0 441 FILE:/tmp/fileSyRJwq_cint LINE:1 > *** Interpreter error recovered *** > > it fails misarbly, because the fArray member of the objects table1 and > table2 wasn't read in when TTree::GetEntry() was performed. The remedy > is to get the TBranch'es Table1.fArray, and Table2.fArray, and then > set address of those TBracnh'es to the FooTable::fArray's addresses. > > And now for the question: is this right? Am I missing something here? > If not - is this really what is intended? It seems, that _either_ you > can Scan/Draw/Query your TTree, _or_ you can get the TBranches by > hand, you can't have it both ways in an easy way. (I really don't want > to set the addresses of several Sub-TBranch'es. No more then the > Top-TBranch'es addresses should be set by the user.) Further, you have > to decide at creation time which sort of TTree you want to create: > _either_ one for queries, _or_ one for branch analysis. I, for one can > imagine several instances where you'd like to do both. > > I've attched the full source code for this example for your pleasure > and reference. > > Thanks for all your help and patience, > > Christian ----------------------------------------------------------- > Holm Christensen Phone: (+45) 35 35 96 91 > Sankt Hansgade 23, 1. th. Office: (+45) 353 25 305 > DK-2200 Copenhagen N Web: www.nbi.dk/~cholm > Denmark Email: cholm@nbi.dk > > > > > > -------------------------------------------------------------------------------- > > Name: Foo.hh > Foo.hh Type: Plain Text (Text/Plain) > Encoding: 7bit > Description: Declaration file for classes FooTable and FooData > > Name: Foo.cc > Foo.cc Type: Plain Text (Text/Plain) > Encoding: 7bit > Description: Implementation file for classes FooTable and FooData > > Name: FooLinkDef.hh > FooLinkDef.hh Type: Plain Text (Text/Plain) > Encoding: 7bit > Description: Link specification file for classes FooTable and FooData > > Name: FooMain.cc > FooMain.cc Type: Plain Text (Text/Plain) > Encoding: 7bit > Description: Test program - writes file File.root > > Name: Makefile > Makefile Type: Plain Text (Text/Plain) > Encoding: 7bit > Description: GNU Makefile for Linux
This archive was generated by hypermail 2b29 : Tue Jan 02 2001 - 11:50:24 MET