Problem with creating a Tree from another+histogram

  • Thread starter Thread starter ChrisVer
  • Start date Start date
  • Tags Tags
    Tree
AI Thread Summary
The discussion focuses on integrating histogram weights into a ROOT tree structure for data analysis. The initial code attempts to associate histogram values as weights based on the variable x from a tree, using a loop to find the appropriate bin. Suggestions include using the FindBin method for efficiency and clarity. The conversation shifts to creating a new tree to store these weights, with emphasis on using friend trees to avoid overwriting existing data, which can be risky and space-consuming. The importance of defining branches correctly and the potential issues with data types when filling the tree are highlighted. The final code example demonstrates the process of reading from an input tree, calculating weights based on a histogram, and filling a new tree with these weights, while addressing a specific issue regarding data type mismatches that can lead to incorrect results.
ChrisVer
Science Advisor
Messages
3,372
Reaction score
465
Suppose I have a histogram : h(x)
and I want to take the different values h(x_i) as weights which I can pass in a tree...

The code I wrote so far, which (theoriticially) would do this job for me looks like this:
C:
TFile* fin = new TFile("file_contains_tree_and_histo.root");

TH1F* h_x = (TH1F*) fin->Get("histo_X");
TTree* myTree = (TTree*) fin->Get("Tree");
Float_t x, w;
float binwidth= h->GetXaxis()->GetBinWidth(1);

myTree->SetBranchAddress("variable_x", &x)
Long64_t N_entries = myTree->GetEntries();
for( int iEntry=0; iEntry<N_entries ; iEntry++){
    myTree->GetEntry(iEntry);  //Get entry i from the existing tree
    int j=0;
    while(j<100){
         if(x> j *binwidth && x<(j+1)*binwidth){
              //checks if value x is in the range of bin j+1, 
              //if yes then the weight is the value of the histogram
             //at that value or bin.
              w= h->GetBinContent(j+1);
              break; //leave while
         }
         j++;
    }
    // Here I need help to pass w in a new tree
}

my problem then is that I am not sure if my logic is plausible, I can't think of any other way to do what I am trying to.
So for example if the histo's binwidth is 50 ~\text{GeV} and the value x of the iEntry is x_{i} and lies between 250 &lt; x_i &lt; 300, then the value of iEntry-th value of the weight should be the value of the histogram h(x) at the bin# 6.
Then again I am not sure how I can pass/Fill a new tree with the w's... (afterwards I'll try to make the tree friends, and so it will be equivalent to adding safely a new Branch)
 
Technology news on Phys.org
Where is the point of the while loop? x/binwidth, rounded down, will do the job for equal bin sizes starting at zero.
Even better, you can use ROOT to directly get the right bin:
TAxis *xaxis = h->GetXaxis();
Int_t binx = xaxis->FindBin(x);
Should also work in one line:
h->GetXaxis()->FindBin(x);

is h=h_x? More descriptive variable names would help.

You have to define a branch and add it to the tree, afterwards you can use Fill() in the loop as usual.
Example code
 
  • Like
Likes ChrisVer and Silicon Waffle
mfb said:
is h=h_x? More descriptive variable names would help.
yes sorry... The point to what I'm trying to do is associate an extra variable I was able to determine from a histogram (QCD fake factors) to trees I obtained from running the derivations on some QCD datasets. The variable x for example is the pT, since my fake factors are given from a histogram h_FakeFactor(pT).
So the while etc I used because I wanted to tell "if the QCD object has pT=100GeV, go and take the fake factor from the histogram FF= h_FakeFactor(pT=100GeV)".
I didn't know/thought of the FindBin method, thanks.
So I guess it should be something like this:
C:
w= h -> GetBinContent(   h->GetXaxis()->FindBin(x)   )
mfb said:
You have to define a branch and add it to the tree, afterwards you can use Fill() in the loop as usual.
That's what I am trying to understand too. So for example I should have defined a new tree:
C:
TTree*  tree_friend = new TTree("T_output","weight");
TBranch* branch_weight = tree_friend->Branch("weight", &w , "w/F");

and in the end of the for loop do:
C:
branch_weight->Fill();
?
 
Last edited:
You can make a new tree, but then you should clone the old one to keep all the other branches in. It is easier to update the existing one, see the example I linked to.
The downside of the update method: it appears as two trees in a TBrowser afterwards, for reasons I don't understand.
 
  • Like
Likes ChrisVer
mfb said:
It is easier to update the existing one, see the example I linked to.

Yes I've seen that example of "immediately adding branches to a tree". However after some small discussion I was informed that it's quiet risky to try and overwrite my existing trees from the derivation and it can be very heavy for the available space [I think?]... So I think the safest way would be to proceed with friend trees [that's why I'm trying to build a separate 2nd tree]...Afterwards the treatment of the two trees will be identical and I'll be able to call from my original tree [the one I'm working with] the variable that I created in the other.

mfb said:
but then you should clone the old one to keep all the other branches in
I didn't understand this one?
 
Ah, friend trees. Then you do not have to clone anything. Just create a new tree with a single branch then. Cloning would create a new tree that has all the old stuff plus your new variable. More handy than friend trees, but if you process TB of data a friend tree is probably better.
 
I am not sure, but there seems to be a problem when I try to use the TTree::Fill() method.
C:
Double_t weight, pT;
Int_t ID;

//DEFINE THE INPUT STUFF
TFile* f_input = new TFile("sum.root");
TTree*  myTree=(TTree*) f_input->Get("T");
myTree->SetBranchAddress(  "pt",&pT);
myTree->SetBranchAddress( "ID", &ID );

TH1* h_Weights_vs_pT = (TH1*) f_input->Get("h_FakeFactor");

//MAKE THE TREE TO FILL
TFile* f_output = new TFile("weightOut.root","recreate");
TTree* myTree_friend = new TTree("weight","weight");
TBranch* myBranch = myTree_friend->Branch("weight",&weight,"weight/F");

//MAKE A HISTOGRAM TO FILL TO COMPARE
TH1F* h_test = new TH1F("h2","h2",100,0.,0.4);

for(Int_t iEntry=0; iEntry< myTree->GetEntries() ; iEntry++){
    myTree->GetEntry(iEntry);
    if(ID==0)  weight= h_Weights_vs_pT ->GetBinContent( h_Weights_vs_pT ->GetXaxis()->FindBin(pT) );
    else weight=0.0;
    h_test->Fill(FF);
    myTree_friend->Fill();
  }

h_test->Write();
f_output->Write();
f_output->Close();

The result I get is shown in the pdfs : 1 the histogram's fill h_test which looks reasonable but the tree's in 2 is very off (even checking the mean ~e+35)...
 

Attachments

What is FF?

You define weight as double but fill it as float. That does not work. It is one of the rare cases where the difference really matters.
 
  • Like
Likes ChrisVer

Similar threads

Replies
7
Views
4K
Replies
3
Views
3K
Replies
3
Views
2K
4
Replies
175
Views
25K
Replies
43
Views
12K
Replies
7
Views
5K
Back
Top