ROOT Version: 6.12/06
Platform: Fedora 27
Compiler: gcc version 7.3.1 20180303 (Red Hat 7.3.1-5) (GCC)
I am trying to perform this rather simple task of looping over a TTree
(tree1) from a TFile
(dummy.root) and getting the desired data based on applied gates on this particular tree and on another one (tree2) that is stored in the file.
Although this is fairly simple to be performed in interactive mode by using
root [0] new TFile("dummy.root")
root [1] tree1->AddFriend("tree2")
root [2] tree1->Draw("x", "Run==1 && y<19 && tree2.Run==2", "histo")
it doesn’t seem to be so straightforward when done inside a macro, assigning the trees to new trees and trying to loop over the entries in the tree.
A sample code is the following
#include "TFile.h"
#include "TTree.h"
#include "TRandom.h"
#include "TH1.h"
#include <iostream>
using namespace std;
int Run, Event;
float x,y,z;
/**********************************************
* *
* Dummy function to create TTrees *
* *
**********************************************/
void CreateTTree() {
// (1) Create the file to store the TTrees
TFile *f = new TFile("dummy.root","RECREATE");
// (2) Create and fill the 1st TTree
TTree *tree1 = new TTree("tree1","tree1");
tree1->Branch("Run",&Run,"Run/I");
tree1->Branch("Event",&Event,"Event/I");
tree1->Branch("x",&x,"x/F");
tree1->Branch("y",&y,"y/F");
tree1->Branch("z",&z,"z/F");
TRandom r;
for (int i=0; i<10000; ++i) {
if (i < 5000) Run = 1;
else Run = 2;
Event = i;
x = r.Gaus(10,1);
y = r.Gaus(20,2);
z = r.Landau(2,1);
tree1->Fill();
}
//tree1->Print();
tree1->Write();
// (3) Create and fill the 2nd TTree
TTree *tree2 = new TTree("tree2","tree2");
tree2->Branch("Run",&Run,"Run/I");
tree2->Branch("Event",&Event,"Event/I");
tree2->Branch("x",&x,"x/F");
tree2->Branch("y",&y,"y/F");
tree2->Branch("z",&z,"z/F");
//TRandom r;
for (int i=0; i<2000; ++i) {
if (i < 1000) Run = 1;
else Run = 2;
Event = i;
x = r.Gaus(100,1);
y = r.Gaus(200,2);
z = r.Landau(20,1);
tree2->Fill();
}
//tree2->Print();
tree2->Write();
// (4) Release TFile from memory
delete f;
}
/**********************************************
* *
* Run this function to illustrate the issue *
* Load, compile and execute addFriend() *
* *
**********************************************/
void addFriend(){
CreateTTree();
TFile *fin = new TFile("dummy.root", "OPEN");
TTree *t1 = (TTree*) fin->Get("tree1");
TTree *t2 = (TTree*) fin->Get("tree2");
t1->AddFriend(t2);
//t1->Draw("x", "Run==1 && y<19 && t2.Run==2", "histo");//<------- It doesn't work when compiled and executed
//tree1->AddFriend("tree2"); //<------- It works in interactive mode
//tree1->Draw("x", "Run==1 && y<19 && tree2.Run==2", "histo");//<------- It works in interactive mode
t1->SetBranchAddress("Run", &Run);
t1->SetBranchAddress("Event", &Event);
t1->SetBranchAddress("x", &x);
t1->SetBranchAddress("y", &y);
t1->SetBranchAddress("z", &z);
TH1F *h_x_1 = new TH1F("h_x_1", "x variable from tree1; x; Counts", 100, 5, 15);
for (int i=0; i<t1->GetEntries(); ++i){
t1->GetEntry(i);
//if (Run==1 && t2.Run==2)//<------- It doesn't work when compiled and executed
if (Run==1)
h_x_1->Fill(x);
}
h_x_1->Draw("histo");
}
When trying to call t2.Run==2
for instance, I get an error
error: no member named ‘Run’ in ‘TTree’
which although I understand why I get it, I can’t seem to find a workaround it.
It goes without saying that I could always define new variables (i.e. x2, y2, z2, Run2, Event2
), separately loop over the second tree, somehow find a connection between the cuts in both trees and keep what is desired, which is what I was doing so far, but I believe it’s not the most convenient solution for many reasons (i.e. it takes a lot of time if the file is big).
Any idea how to properly use AddFriend
inside a macro when looping over the entries in one TTree
?
Thank you very much in advance!