The mistery in TTree or TChain

Hi friends,
Unfortunately, I have difficulties reading my tree and branches. What I wanna do is basically to read “previously created root file” where there is one tree name and, let’s say 2 branches in it. After ı read this, ı want to be able to draw anything from these raw branches. Later, after processing these data, let’s say we multiply the branch contents with 2, I want to be able to create another tree and branch names to be filled and drawn.
Even though, it sounds simple, I found th examples in ROOT manuals not so useful for myself. They are either too advance, or there are so much unnecessary complications in the code, they can’t keep it simple for G.S. for a start.

For a start, ı want anybody to tell me why his simple code doesn’t want to work, then I will post other part of the codes one by one to build up a healthy and useful conversation to all of us.

1part: HOW TO READ ,let’s say 2 root files which were created in a same manner with same tree and branch names?

Part of the code: ignore the uncommented parts. Thanks in advance.

#include <fstream>
#include <iostream>
#include "TAttMarker.h"
#include "TLegend.h"
#include "TCanvas.h"
#include "TFile.h"
#include "TStyle.h"
#include "TF1.h"
#include "TChain.h"
#include "TTree.h"
#include "TH2F.h"
#include "TH1F.h"
#include "TRandom.h"
#include "TH1F.h"
#include "TApplication.h"
#include "TProfile.h"
#include <string>
#include "string.h"


using namespace std;
void testcode()

{

TCanvas*c1= new TCanvas("c1","Analysis",900,600);
c1->cd();
TChain *ch=new TChain("Analysed_Data");
ch->Add("~/Desktop/ilkeroutput/run07*.root");

if(!ch){    cout << "\nCould not open the file" <<endl;   exit(-1); }  
cout << " test 1 PASSED" << endl;
if (ch->IsZombie()) { cout << "Error opening file" << endl;  exit(-1);}
cout << " test 2 PASSED" << endl;
ch->SetBranchStatus("*", 0);
ch->SetBranchStatus("TrifoilE", 1);
ch->SetBranchStatus("Theta_p", 1);
ch->SetBranchStatus("T_initial_p", 1);
gStyle->SetPalette(51);
gDirectory->Delete("*");
c1->SetLogz();
ch->Draw("T_initial_p:Theta_p>>h1(180,0,180,1000,0,20000)","TrifoilE>15000","colz");

//gDirectory->Delete("*");
//gStyle->SetOptStat(0);
//gStyle->SetOptTitle(0);
//gStyle->SetPalette(1); //51
//int UD1Fmult, UD1Fnum;  float UD1Fenergy;  double UD1Ftime;
/*
TFile *f1 = TFile::Open("/home/ic00025/Desktop/ilkeroutput/run07284.root","READ"); 
TCanvas*c1= new TCanvas("c1","Analysis",900,600);
c1->cd();
TTree *t1 = (TTree *)f1->FindObjectAny("Analysed_Data");
if(!f1){    cout << "\nCould not open the file" <<endl;   exit(-1); }  
cout << " test 1 PASSED" << endl;
if (f1->IsZombie()) { cout << "Error opening file" << endl;  exit(-1);}
cout << " test 2 PASSED" << endl;
t1->SetBranchStatus("*", 0);
t1->SetBranchStatus("TrifoilE", 1);
t1->SetBranchStatus("Theta_p", 1);
//t1->Draw("Theta_p>>h1(180,0,180)","TrifoilE>15000","colz");
t1->Draw("Theta_p:Theta_p>>h1(180,0,180,180,0,180)","TrifoilE>15000","colz");
*/


}



ROOT Version: Not Provided
Platform: Not Provided
Compiler: Not Provided


Hi,

the easiest way to read ROOT datasets, analyse them and manipulate them is probably RDataFrame. Can you have a look to it and its tutorials?

Cheers,
D

I can have look at that, but ı rather continue my discussion instead of distracting it. I am not familiar with RDataFrame, so ı may waste more time than ı need.
Thanks.

I think RDataFrame is the way to go for your use case. I would not be too afraid of throwing away the code you have at the moment.

Cheers,
D

If you insist that much, that means you won’t mind sharing your little code to work on what ı want, will you?

ı want to read individual branches in one tree in one root file, then store it into an another new tree in a new root file.

What do u say? My code was enough for me to finish my ph.d at that time, tough.

Hi eveybody,
ı got one question because of my curiosity. What do “argc and argv stand for inside the main(int argc, char **argv)” in some codes?
ı guess arg is for argument, but what’s this c and v for?

Thanks.

argc: arguments count (number of arguments passed to the program)
argv: the C-array of arguments.

Here is my temporary solution to read branches from a tree or chain. I draw 4 histograms in kind of 4 different ways.
As far as how I fell, I HAVE TO create something which is, for instance, a histogram to store the content of, for example, a branch from a TREE of CHAIN. Can anyone approve this theory of mine? That’s important for me.
I will try to post the root file I was reading later, but it might be too big for here. For now, you can just imagine a root file with 3 branches which have random numbers in it.
Here is the new working code:
Note: One thing I notice, you should define the branch type correctly, otherwise it doesn’t work, surely.

#include <iostream>
#include <sstream>      // std::istringstream
//#include <string>       // std::string
#include <stdio.h>
#include "TDirectory.h"
#include "TROOT.h"
//#include "TLine.h"
//#include "TLegend.h"
#include "TCanvas.h"
#include "TAxis.h"
//#include "TPaveText.h"
#include "TStyle.h"
#include "TAttLine.h"
#include "TH2F.h"
#include "TH1F.h"
#include "TChain.h"
//#include "TPad.h"
#include "TFile.h"
// STL
//#include<vector>
// ROOT
#include"TString.h"
/* itoa example */
#include <stdio.h>
#include <stdlib.h>
using namespace std;
void test3()

{



TCanvas *c1 = new TCanvas("c1", "c1",1,549,1200,800);
//gStyle->SetPalette(1);
//gStyle->SetOptStat("i");
c1->Divide(2,2);
c1->cd(1); 


/*  To download the ROOT file, go to "https://drive.google.com/file/d/1uOL59JhEYAFUEwtwrycO5WcCN7Km9cZ7/view?usp=sharing"    */

TChain *ch=new TChain("Analysed_Data");
ch->Add("~/Desktop/ilkeroutput/run07284.root", -1); //run07*.root

if(!ch){    cout << "\nCould not open the file" <<endl;   exit(-1); }  
cout << " test 1 PASSED" << endl;
if (ch->IsZombie()) { cout << "Error opening file" << endl;  exit(-1);}
cout << " test 2 PASSED" << endl;
ch->SetBranchStatus("*", 0);
ch->SetBranchStatus("TrifoilE", 1);
ch->SetBranchStatus("Theta_p", 1);
ch->SetBranchStatus("T_initial_p", 1);
gStyle->SetPalette(51);
gDirectory->Delete("*");
c1->SetLogz();
ch->Draw("Theta_p>>h1(180,0,180)","","colz"); //TrifoilE>15000
TH1F* h1 = (TH1F*)gDirectory->FindObjectAny("h1");  
h1->SetLineWidth(1);  
h1->SetLineColor(kBlack);
h1->Draw();    
cout << " test 3 PASSED" << endl;
/*
cout<< ch->GetEntries()   << endl; 
cout<< ch->GetNbranches() << endl; 
cout<< ch->GetNtrees() << endl; 
cout<< ch->GetTree()   << endl;
cout<< ch->GetNtrees() << endl;
cout<< ch->GetNtrees() << endl;
cout<< ch->GetNtrees() << endl;
*/
c1->cd(2); 

/////////// That's where I write existing histogram in to another new root file.

TH1F *h2 = (TH1F*)h1->Clone();
h2->SetName("h2");
h2->SetLineWidth(1);  
h2->SetLineColor(kRed);
h2->Draw("histo"); 



TDirectory* original1 = gDirectory;
TFile* myHistoFile1 = new TFile("~/Desktop/YeniRootAnalizKodları/test.root","RECREATE");  //Create  a file to save the pad and histograms on it instead of saving only pad which won't give you the histograms in it as well.
//Go to newly created root file as a directory to process on it.
if(!myHistoFile1){    cout << "\nCould not open the file" <<endl;   exit(-1); }  
cout << " test 4 PASSED" << endl;

h2->SetDirectory(myHistoFile1);
/////// Write the histograms in our rootfile //////////
h2->Write();
// To get out of the first HistoFile90.root file to draw second pad and its histograms. 
h2->SetDirectory(original1);
//////We need to close this root file to create a new root file
myHistoFile1->Close();
///////We need to delete after we close the file otherwise we'll loose everything
delete myHistoFile1;

cout << " test 5 PASSED" << endl;
/////////////  This is where I read the existing root file and branches, then I store the branch contents into individual histogram

unsigned int TrifoilE;
Float_t Theta_p;
Float_t T_initial_p;

TH1F *h3= new TH1F("h3","h3",180,0,180);
TH1F *h4= new TH1F("h4","h4",180,0,180);
/*
TH1F *h3 = (TH1F*)h1->Clone();
TH1F *h4 = (TH1F*)h1->Clone();
TH1F *h5 = (TH1F*)h1->Clone();
h3->SetName("h3");
h4->SetName("h4");
h5->SetName("h5");
*/
TFile *myfile = TFile::Open("/home/ic00025/Desktop/ilkeroutput/run07284.root","READ"); 
if(!myfile){    cout << "\nCould not open the file" <<endl;   exit(-1); }  
cout << " test 6 PASSED" << endl;
TTree *tree= (TTree*)myfile->Get("Analysed_Data");
tree->Branch("TrifoilE",&TrifoilE, "TrifoilE/i"); 
tree->Branch("Theta_p",&Theta_p, "Theta_p/f"); 
tree->Branch("T_initial_p",&T_initial_p, "T_initial_p/f"); 
tree->SetBranchAddress("TrifoilE", &TrifoilE);
tree->SetBranchAddress("Theta_p", &Theta_p);
tree->SetBranchAddress("T_initial_p", &T_initial_p);

int Nentries = tree->GetEntries();
for (int i=0; i<  Nentries; i++)
{
tree->GetEntry(i);
h3->Fill(Theta_p);
h4->Fill(T_initial_p);
}

c1->cd(3); 
h3->Draw();
//c1->cd(4); 
//h4->Draw();
myfile->Close();
cout << " test 7 PASSED" << endl;

////////////////// This is where I read the histogram that I created and stored in a root file previously. Then, I change the content of this specific histogram which actually refers to one specific branch content. 

double ObservedValue;
double ExpectedValue;
int ScalingFactorProton=10;
for (int bin=1; bin< h3->GetNbinsX() ; bin++ ){ 
//when I loop over among all bins like above, no need for angle to bin number conversion by using FindBin(angle)
//Selection of only existing bins with data inside.
//loop over only in the middle data points where the content is not zero
//Decide the angle range the most  important to our case as below.
//FinalAdding10and12->GetBinCenter(36)= 175.5 , Thus, ...
	if (h3->GetBinContent(bin)!=0 && h3->GetBinCenter(bin) <181 ){  //to eliminate empty bins
		 ObservedValue= h3->GetBinContent(bin);
		 ExpectedValue = ObservedValue* ScalingFactorProton ;
                 h4->SetBinContent(bin,ExpectedValue);
                 //h4->Fill(bin);
	}
}
//Make sure you delete and close the files 
//delete h3;
myfile->Close();
delete myfile;
c1->cd(4); 
h4->Draw();
}

Hi,
there are several ways, in ROOT, to access the content of a TTree and fill an histogram.
This answer goes over the most common ways to do it and shows some example code. TTree::SetBranchAddress, that you are using in your snippet, is the lower-level, hands-on-the-internals way, mostly meant for expert users nowadays.

If you have access to ROOT v6.14, I agree with @Danilo that RDataFrame is the simplest way to produce a histogram from a TTree (at the time of the answer I linked, it was still called TDataFrame). Here’s an example snippet:

// rdf.C

void rdf()
{
   ROOT::RDataFrame df("Analysed_Data", "run07*.root"); // build the dataframe
   ROOT::RDF::TH1DModel hm("h1", "h1", 180, 0 180); // build a histogram model
   auto h1 = df.Histo1D(hm, "Theta_p"); // ask the dataframe for a histogram of Theta_p with binning like the model's
   h1->Draw("colz") // draw the histogram
}

Hope this clarifies things.
If you have more specific questions feel free to post them here or in a new thread.

As far as how I fell, I HAVE TO create something which is, for instance, a histogram to store the content of, for example, a branch from a TREE of CHAIN. Can anyone approve this theory of mine?

No, that’s not correct. You can do whatever you want with the values you read from a TTree, you can sum them together, forget about them, use them to fill a histogram…your choice.

One thing I notice, you should define the branch type correctly, otherwise it doesn’t work

Of course :slight_smile: TTree::Draw and, for most common operations, RDataFrame offer interfaces that do not require that you specify the type of a branch to do things with it, but in the general case you will have to put the branch value in a variable (e.g. when using TTree::SetBranchAddress and that variable must be of the correct type). Higher-level interfaces (e.g. RDataFrame and TTreeReader will complain if there is a type mismatch).

Cheers,
Enrico

1 Like

you delete everything … by the following

gDirectory->Delete("*");

1 Like

I think this delete part should’ve been in the very begining as for a precaution if you had declared anything with the same name previously. For some reason, it didn’t cause a problem at that time, but it should probably be in the begining.

That little code you posted looks useful, so I will try to use after cheking which root version I am using.

To Enrico, I think the way how you access the content is firstly reading a tree, secondly creating an histogram to store, then using this histogram to do any calculation with it. At least, that’s what I see in your micro code.

Therefore, will that be the same if I created an histogram per branch to draw. Then, do anything by playing with those histogram only.

I also wanna know what the real difference is (or maybe I should say what they area actually doing) between
" tree->Branch(“TrifoilE”, &TrifoilE, “TrifoilE/i”);" and
" tree->SetBranchAddress(“TrifoilE”, &TrifoilE);" ? I feel like we don’t really need them if we directly create and draw an histogram and do the rest with that histogram.
(like this: ch-> Draw(“Theta_p”, “h1(180,0,180)”,“”,“”); )
Cheers.
ilker.

/* To download the ROOT file, go to “https://drive.google.com/file/d/1uOL59JhEYAFUEwtwrycO5WcCN7Km9cZ7/view?usp=sharing” */

Hi Ilker,
the TTree contains values, numbers: N values per branch.
If you want, you can read those values one by one and do things with them, for example fill a histogram (or whatever else).

As per TTree::Branch vs TTree::SetBranchAddress, see the doc: the former creates a new branch in a TTree that you can later fill, the latter takes an existing branch and sets it up so that it puts its values in the variable you pass when you load a TTree entry.

But you don’t have to care about these low-level details yourself if you use one of the higher-level interfaces to access ROOT data, like RDataFrame or TTree::Draw. The latter is limited to producing histograms and graphs of the data, while the former is more general purpose and lets you freely specify what you want to do with the data.

I hope this clarifies things a bit: I’m not so sure what the question is anymore :slight_smile:
Cheers,
Enrico

ı see now that it was useless to use the Branch() in the beginning when we read existing root file because we are not creating a new branch at all, but just reading it. However, we can use `SetBranchAddress() when we want to create a new branch probably with a new name in another brand new root file to be stored. Al-right! Sometimes it’s not that clear when you directly check a function from root website, at least for me. That was my question, and you answered clearly. Thanks.

Unfortunately, I have NOT been introduced RDataFrame during my ph.d at that time, so ı did everything, maybe, in the hard way for myself. Probably, it didn’t exist in 2011. No idea.

I wanted to share the reason why I was asking all this. When you do your ph.d back in those days, if you don’t have a programming background at that time, you do most of the things by copying and pasting and changing things. However, you don’t fully understand everything at all. After couple of years, you will do more.

Anyways, when we do real experiments, mostly we are giving a pile of RAW data stored in a root file in a very simple look in a very complicated way. It’s like what we all have are only : “multiplicity, strip number, raw energy, and time from the RAW DATA”. Then, we access other informations like angle or calibrated energy in our detectors with huge codes.
These long codes, as far as I know and notice, start with reading the TREE with raw data and doing things with branch contents.

In conclusion, everything, or the story, starts with my simple questions like how to read that TREE and branch :slight_smile:

Have a nice day, folks.

1 Like

root [3] gROOT->GetVersion()
(const char *) “6.12/04”

That’s what ı am using currently, so will RDataFrame work with that version?

Hi,
RDataFrame is available since ROOT v6.14.
v6.12 only contains a beta version called ROOT::Experimental::TDataFrame.

(The upgrade from v6.12 to v6.14 should be fairly painless though.)

Cheers,
Enrico

I always use this method:
////////////////////////////////////////
download source from : "Release 61404 - ROOT "
mkdir root_source
mkdir root_build
mkdir root_install
cd root_build
cmake /home/ic00025/root_source -DCMAKE_INSTALL_PREFIX=/home/ic00025/root_install -Dminuit2=ON
make -j4
make install → copy only the relevant file to the final directory
source /bin/thisroot.sh

Trying now.
DONE.
root [0] gROOT->GetVersion()
(const char *) “6.14/04”
root [1]

What’s the header part before void rdf() to run this code?