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
This archive was generated by hypermail 2b29 : Tue Jan 02 2001 - 11:50:24 MET