class EntryOne : public TObject { public: Int_t val; ClassDef(EntryOne, 1) }; class EntryTwo : public TObject { public: TRefArray entriesOne; Int_t ev; ClassDef(EntryTwo, 1) }; // creates few root files with tree carrying 'raw' EntryOne objs: // // ones =====> ones_1 ~~~~> Int_t val // "====> ones_2 ~~~~> Int_t val // // Each time runs in separate session. void writeOnes(int n) { TProcessID::GetPID()->Print(); TFile out_f(Form("tmp%d.root", n), "recreate"); TTree tr("ones", ""); EntryOne eOne1, eOne2; TRef ref = &eOne1; ref = &eOne2; tr.Branch("ones_1", &eOne1); tr.Branch("ones_2", &eOne2); for (int ev=0; ev < 10; ++ev) { eOne1.val = n * 2 + ev % 2; eOne2.val = -eOne1.val; tr.Fill(); } tr.Write(); gROOT->CloseFiles(); gSystem->Exit(0); } // construct pre-analysis tree on base of 'raw' files and save it in separate file. // New tree comprises own branch for serializing EntryTwo objs and branches from old tree as a friend: // // twos ===> twos // | `~~~~> Int_t ev // | `~~~~> TRefArray entriesOne // | // `----> ones_1 <**** entriesOne[0] // `----> ones_2 <**** entriesOne[1] // // Also runs in separate session void writeTwos() { TFile out_f("tmp.root", "recreate"); TTree tr("twos", ""); EntryTwo eTwo; tr.Branch("twos", &eTwo); TChain *ones = new TChain("ones"); ones->Add("tmp[0-9].root"); tr.AddFriend(ones); EntryOne *eOne1 = 0, *eOne2 = 0; ones->SetBranchAddress("ones_1", &eOne1); ones->SetBranchAddress("ones_2", &eOne2); for (int ev=0; ev < ones->GetEntries(); ++ev) { eTwo.ev = ev; ones->GetEntry(ev); if (ones->GetTree()->GetReadEntry() == 0) { eTwo.entriesOne.Clear(); eTwo.entriesOne.Add(eOne1); // eTwo.entriesOne.AddAt(eOne1, 0); eTwo.entriesOne.Add(eOne2); } tr.Fill(); } out_f.cd(); tr.Write(); gROOT->CloseFiles(); gSystem->Exit(0); } void readTwos() { TTree *twos = (TTree*) TFile::Open("tmp.root")->Get("twos"); TChain *ones = new TChain("ones"); ones->Add("tmp[0-9].root"); EntryTwo *two = 0; twos->SetBranchAddress("twos", &two); for (int ev=0; ev < twos->GetEntries(); ++ev) { twos->GetEntry(ev); cout << "two.ev: " << two->ev << '\t'; TObject *one = two->entriesOne.At(0); if (one) cout << "two.entriesOne[0].val: " << ((EntryOne*)one)->val << '\t'; else cout << "Not derefed. uid=" << two->entriesOne.GetUID(0) << '\t'; one = two->entriesOne.At(1); if (one) cout << "two.entriesOne[1].val: " << ((EntryOne*)one)->val << endl; else cout << "Not derefed. uid=" << two->entriesOne.GetUID(1) << endl; } gSystem->Exit(0); } void test(int mode=0, int f_idx=0) { switch (mode) { case 0: for (int n=0; n<3; ++n) { gSystem->Exec(Form("root -l -b 'test.C(1, %d)'", n)); } gSystem->Exec("root -l -b 'test.C(2)'"); gSystem->Exec("root -l -b 'test.C(3)'"); break; case 1: writeOnes(f_idx); break; case 2: writeTwos(); break; case 3: readTwos(); } gSystem->Exit(0); }