Filling different trees in a loop in pyroot

I have a rootfile with one tree having a lot of events.

I want to have these events classified in different trees defined as bins of certain variables

What I do is making a new rootfile and define the empty trees with empty leaves. Now in the loop of the original events, I want to be able to fill the events in the leaves of the new trees, based on which bins they belong.

My question is, how do you fill leaves of existing trees in pyroot, and is there a more efficient way to do this?

Hello,

The most efficient way to do this would be to use RDataFrame:

With RDataFrame, the loop would happen in C++, and therefore the performance would be better than to have it in Python.

As for what you want to do, the way to proceed would be to create an RDataFrame from your initial tree stored in your ROOT file. From that tree, you can define new columns (branches) based on the information contained in the initial tree. Finally, you can Snapshot (store in a file) the derived trees.

In particular, this RDataFrame tutorial:

might be useful.

Please let us know if you need further assistance to develop this code with RDataFrame.

@eguiraud

Hi, thank you very much for the info!

I will definitely consider using RDataFrame in the future, but I was wondering how you can fill events in an existing tree, I was trying something like this:

#first make a new one

subtree = ROOT.TTree(“subtree”,“subtree”)
subtree.Branch(“var1” ,get_var1)
subtree.Branch(“var2” ,get_var2)
subtree.Write()

#later in an event loop

subtree = ROOT.gDirectory.Get(“subtree”)
get_var1 = var1_value_for_event_i
get_var2 = var2_value_for_event_i
subtree.Fill()

but this gives the following error:
Error in TBranchElement::Fill: attempt to fill branch var1 while addresss is not set
Error in TBranchElement::Fill: attempt to fill branch var2 while addresss is not set

Hello,

When you do:

 subtree.Branch(“var1” ,get_var1)

you are creating a new branch whose address will be taken from get_var1. If later you do:

get_var1 = var1_value_for_event_i

You are binding get_var1 to a new object, and the previous one (the one you associated with var1 in Branch) will be garbage collected. What you need to do is modify the original get_var1 object instead of reassigning the variable to a new object. So it should be something like:

Here’s some documentation about using Branch from Python (how to use it with different types of branches):

Hi, thanks a lot!

The problem is that I have a lot of these trees and I define them the same way, so get_var1 is just an example, but I don’t know how to specifically fill the var1 of a specific tree among all the others.

So if I know how to fill a existing branch of any existing tree from scratch, and put this in the loop, it would solve my problem I think :slight_smile: in the documentation they start by defining a new branch before filling it

but I don’t know how to specifically fill the var1 of a specific tree among all the others.

If you defined var1 as the Branch of a tree mytree, and then you call mytree.Fill, a new entry for var1 in mytree will be filled.

So if I know how to fill a existing branch of any existing tree from scratch, and put this in the loop, it would solve my problem I think :slight_smile: in the documentation they start by defining a new branch before filling it

Just to be sure, you don’t mean updating the values of an existing branch of a tree, right? You want to fill up new trees, whose branches you create with Branch.

Hi @etejedor, I’m sorry to be not very clear here.

Basically, in need 3k trees that are constructed from 1 tree, but just classified based on their values of certain variables, i.e if combining all the 3k trees I would get back the same original tree.

Now I define these 3k trees as following:

outfile =  ROOT.TFile("rootfile",'recreate')
for i in range(0,len(bins)-1):
             subtree = ROOT.TTree("name_with_bin_info","name_with_bin_info")
             subtree.Branch("var1" ,get_var1)
             subtree.Branch("var2" ,get_var2)
             subtree.Write()

So after having these trees, in an event loop I want to fill them:

for iev in chain:
      (decision to which bin the event belongs):
      fill to the corresponding tree

But in this case, I don’t have the variable pointing to corresponding tree, so I have to somehow open the tree from scratch, get address of var1 and var2, then add the event with the values of var1 and var2. And this is the part I’m missing

I see, so you need to make sure the trees you create are stored in a Python list, so you keep all their references and they are not garbage collected as the first loop runs, plus the same for the vars1 and vars2 - everything needs to be stored and survive the first loop:

outfile =  ROOT.TFile("rootfile",'recreate')
trees = []
vars1 = []
vars2 = []
for i in range(0,len(bins)-1):
             trees.append(ROOT.TTree("name_with_bin_info","name_with_bin_info"))
             vars1.append(get_var1_for_this_subtree)
             vars2.append(get_var2_for_this_subtree)
             trees[-1].Branch("var1" , vars1[-1])
             trees[-1].Branch("var2" , vars2[-1])
             trees[-1].Write()

Then in the second loop you don’t have to open any tree from scratch, since you have all of them stored in trees, and the same goes for var1 and var2.

for iev in chain:
      (decision to which bin the event belongs):
      assign value to the right var1 and var2 in vars1 and vars2
      fill the corresponding tree from trees
1 Like

Hi @etejedor, thank you very much, I think I’m almost there, just one last question:

For this part, how do I generate different variables without initialising 3k vars per variable?

vars1.append(get_var1_for_this_subtree)
vars2.append(get_var2_for_this_subtree)

My real struggle is really inside the eventloop to be honest, because there you need to fill the right var to the right tree

I think I solved the problem :slight_smile: Can’t thank you enough @etejedor !!!

Hello,

Good to hear!

That’s right, actually you don’t strictly need as many vars1 and vars2 as trees, you could just have one of each (the same for all the trees), as long as you change its value inside the event loop and fill one tree per iteration.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.