Cloning tree and changing contents in the new tree

Hello,
I have a following problem - I would like to clone a tree and to modify the contents of the new tree a bit. However my approach seems not to work. Here is what I do (I am trying this in pyRoot but it shouldn’t matter) (simplified):

g=TFile(“myoutputfile.root”,“RECREATE”)
newtree=oldtree.CloneTree(0)
for i in range(oldtree.GetEntries()):
oldtree.GetEntry(i)
newtree.RunNumber=7
newtree.Fill()

newtree.Write()
g.Close()

The thing is that when I open the new file RunNumber variable is not 7 in every event but whatever it was in the oldtree! What am I doing wrong?

What I really need to do is a bit more complicated. My tree has a bunch of branches holding vector variables where a particular entry in the vector is a quantity of an object. e.g. el_Et[3] would be the Et of the third electron, el_phi[3] would be phi of the third electron etc. (The format of this tree is out of my control).
However vast majority of in this case electrons in a given event (that otherwise passes my cuts) is simply not interesting (low pt, bad quality etc) - so I would like to throw them away and keep only the interesting electrons.

My attempt goes like this (in analogy to the example above)


for i in range(oldtree.GetEntries()):
oldtree.GetEntry(i)
newtree.el_Et=[]
for el_i in range(oldtree.el_n):
if some criteria:
newtree.el_Et.append(oldtree.el_Et[el_i])

 newtree.Fill()

newtree.Write()

This also doesn’t work the same way as the simpler example didn’t - the values in the newtree are the same as the values in the oldtree…

Any hints on how to proceed?

Thanks,
Wojtek

Wojtek,

accesses such as “newtree.RunNumber=7” are to local variables (i.e. copies). In fact, it would even work if RunNumber dit not exist due to python simply creating the data members. Instead, you’ll have to go the normal way of SetBranchAddress() and Write() like in C++.

Cheers,
Wim

Hi,
Thanks for the answer
So I need to make an entirely new tree and declare branches with the same names and the same types…
Can you give me a hint on how to declare a branch which will hold vector or vector from python?
Thanks,
Wojtek

Wojtek,

no, I don’t think a new tree or branch declarations are necessary, just that the new tree needs to be given a real object via SetBranchAddress() so that you can modify the right variable (instead of a python copy). Something like:

v = ROOT.std.vector('float')() newtree.SetBranchAddress( 'name', v ) v.push_back(3.14) newtree.Fill()
Note that I have no experience with cloning TTrees, so I can’t be sure that this will work, but at least the variable setting bit of it should be correct (e.g. I don’t know whether the above will overwrite the existing vector on the branch in the tree, or just append an extra variable; I’m guessing the latter). Note also that you have to make sure that the lifetime of the tree and v are the same. That’s most easily accomplished with newtree.name = v and then you can actually write into the variable name on the tree. :slight_smile:

Cheers,
WIm

Hello again,
Ok I’ll try that - I am a bit worried about the blurb from the TTree::CloneTree documentation:

  • but the reverse is not mentioned… we’ll see
    I am still really confused about what newtree.RunNumber means though. oldtree.RunNumber or oldtree.el_Et[3] work fine for reading and I can also read from newtree e.g. newtree.RunNumber has the same value as in the oldtree before I change it’s value. But somehow it doesn’t get stored - so I am not sure what I am changing in the end…
    Thanks,
    Wojtek

ah -

so it should be fine…
trying now…
w

Another silly question -
How do I SetBranchAddress for an integer?
e.g.
i_RunNumber=0

newtree.SetBranchAddress(‘RunNumber’,i_RunNumber)
gives me TypeError: none of the 3 overloaded methods succeeded …

newtree.SetBranchAddress(‘RunNumber’,ROOT.AddresOf(i_RunNumber))
gives me ValueError: invalid argument for AddressOf()

thanks,
Wojtek

Wojtek,

since you can’t change python integers in place (well, one could, but python likes to cache its integers, meaning that the results would be … interesting), a C array of integers of length one is needed:import array i_RunNumber = array.array('i',[0])
Alternatively, you can set them up as data members of a C++ struct, generate a dictionary for that and pass AddressOf( mystruct, ‘i_RunNumber’ ) or something equivalent.

Cheers,
WIm