Home | News | Documentation | Download

TTree Vector Branch to TH2D

Hi there,

I have an possible issue with projecting vector branches out of a pair of TTrees. I assign a TTreeIndex to both TTrees and “friend them”:

# Assign common TTree Index
truth_index = TTreeIndex(truth_tree, "eventNumber", "0")
reco_index  = TTreeIndex(reco_tree,  "eventNumber", "0")

reco_tree.SetTreeIndex(reco_index)
truth_tree.SetTreeIndex(truth_index)

# "Combine TTress" by using Add Friend
truth_tree.AddFriend(reco_tree,reco_tree.GetName())

I have been using the Project function to generate TH2D histogram but notice that the behaviour is odd when projecting out a vector branch (perhaps this is expected?). For example, consider a branch of a TTree which is of varying length for each individual event in the TTree. I do:

hist2 = TH2D("hist2d","",len(bins)-1,bins)
truth_tree.Project(hist2.GetName(), truth_tree.GetName()+".<branch1>:" + reco_tree.GetName() + ".<branch1>")

For some - but not all - branches, this wrongly fills the TH2D, placing events in cells which should be empty. Specifically, if this branch corresponds to el_pt to which the cut “>25 GeV” has been previously applied to both truth and reco TTrees, then all cells below 25 GeV in the TH2D should be empty. This is not the case, as the bottom row is filled?

Example code below for pre-loaded TTrees:

# Assign common TTree Index
truth_index = TTreeIndex(truth_tree, "eventNumber", "0")
reco_index  = TTreeIndex(reco_tree,  "eventNumber", "0")

reco_tree.SetTreeIndex(reco_index)
truth_tree.SetTreeIndex(truth_index)

# "Combine TTress" by using Add Friend
truth_tree.AddFriend(reco_tree,reco_tree.GetName())

import numpy as np 
binX = np.linspace(0,100e3,21)
binY = binX
hist2d=TH2D("_unnormalised","",len(binX)-1,binX,len(binY)-1,binY)


varexp = truth_tree.GetName()+".el_pt:"+reco_tree.GetName()+".el_pt"
truth_tree.Project(hist2d.GetName(),varexp )#,selection,"",num_events_used,first_event)

hy=hist2d.ProjectionY()
h1d =TH1D("h1d","",len(binX)-1,binX)
reco_tree.Project(h1d.GetName(),"el_pt")

print(h1d.GetBinContent(1))
print(hy.GetBinContent(1))

returns:

0.0
9.0

i.e. different values. The first is expected…

Tested on ROOT versions 6.08.06 locally, and on 6.22.08 on lxplus

Thanks,
Ethan

Hi Ethan,

I’m not completely sure what the projection should do. The entry-by-entry lengths of the vector branches may not necessarily be the same. The 2D histogram, however, needs pairs of two values for every fill. Perhaps I’m missing something?

Cheers,
Jakob

Hi Jakob,

Thank you for the response. My hope here was that using Projection in this way should create a 2D histogram of matched events, for which there should then exist two values (one truth and one reco in the parlance of the example above). This mostly works as far as I can see, in that 2D histogram is generated as expected - the only confusion is the unexpected behaviour in the first bin; these entries should be zero. Perhaps a plot of the 2D hist would help, you can see the non-zero (though small) bin content in the first row (the row corresponding to 0 - 5 GeV on the y-axis). This row should be completely blank as the sample contains no events < 25 GeV.

Thanks for the additional information! Just for me to understand: the el_pt branch is an std::vector<float>? And for the matching events of the reco and the truth tree, does truth.el_pt and reco.el_pt contain the same number of elements?

Well for each event the el_pt branch is of type <class 'ROOT.vector<float>'>. truth.el_pt and reco.el_pt do not contain the same number of elements and for each event the lengths of the corresponding vectors may be different.

Try:

varexp = "Alt$(" + truth_tree.GetName() + ".el_pt, 0) : Alt$(" + reco_tree.GetName() + ".el_pt, 0)"

and / or:

varexp = "Alt$(" + truth_tree.GetName() + ".el_pt, -1) : Alt$(" + reco_tree.GetName() + ".el_pt, -1)"