I have a long list of systematics variables, each one corresponding to an input branch from the inFile.root
while looping, I need to save that in another .root file, and I need to save them in a format like
self.var[0] = entry.var
So, I start by creating the branch var[0] which works ok,
for i_ in vars :
self.i_ = array('f',[0])
self.tree.Branch("'"+i_+"'", self.i_, i_+'/F')
but filling it fails
for i_ in list :
j= '{0:s}.{1:s}'.format(entry,i_)
ii = i_+'[0]'
self.ii = float(j)
with an error like
self.ii = float(j)
ValueError: could not convert string to float: <ROOT.TTree object ("Events") at 0x75415b0>.MET_pt_jesAbsoluteUp
I understand what the message means, but how could I convert my var->entry.var and change the datatype here ? The plain float(var) seems to not be working…
I’m no Python expert, but it seems that you are trying to convert this text
<ROOT.TTree object ("Events") at 0x7525b70>.MET_pt_jesBBEC1_2016Down
to float, which cannot be done; as I understand, to do float(something), that something must be a “number” (in text form), i.e. it only accepts digits and possibly a decimal point. I suppose you are trying to copy the entries from a branch to another branch (in a new tree), and I don’t understand the way you are trying to do it, sorry, but probably there are easier ways; I’d search how to copy trees with PyROOT (which I don’t use, so I cannot tell), or maybe someone else has better advice.
I mean, what the best way would be to create and fill branches from a list of variables when each of the variables corresponds to a float in the input tree ?
for a number of technical and practical reasons I cannot use TNuple. In the end, the setattr seems to be working, and I do get the right values on screen on the fly, but when actually Filling the TTree, the tree is filled with not the expected value
for i_ in self.allsyst :
j = getattr(entry, "{0:s}".format(str(i_))) ## this reads the value from the input_tree
setattr(self,i_,j) ## this one set the self.Branch_var_i_ = value
print getattr(self,i_), 'var =', i_, 'value from tree:', j
116.465354919, var = MET_pt_jesEC2Up value from tree: 116.465354919
Of course, if I manually type something like self.MET_pt_jesEC2Up[0] = float(j) then the Tree is filled with the correct value, but I want to avoid having to write few 100’s of similar lines…
Actually this seems like a question for @etejedor (i.e. PyROOT syntax/magic). (In C++ you would call SetBranchAddress( branchname, address_of_float ) for each branch and/or use an std::vector and distribute its addresses to all the branches.
There is a “PyROOT” box at the end of the C++ docs. There you can find examples for several types of branches for both Branch and SetBranchAddress. There is actually one for branches of type float, which are written via an array.
would it be possible to tell me why the setattr although it seems to fill the tree.branch properly, in the end the tree is not filled ?
I mean I see in the documentation so it is still necessary to fill such object with the desired content before calling TTree::Fill but I cannot understand what step I am missing by using the setattr and then just self.tree.Fill
setattr just sets an attribute (on the Python side), but that will not be picked by tree.Fill afterwards. Instead of setattr, you need to do Branch before the loop (using some array variable), and once inside the loop you change the value you want to store at each iteration, then you call tree.Fill. The goal here is to create new branches in the output tree, and that can’t be done with setattr but with Branch, together with the setting of the right value and the call to Fill.
I believe the SetBranchAddress should not be necessary here, since you are reading the branches of the input tree via the getattr syntax of Python.
In your case with many branches, isn’t this what you would do?
# Create a list with all the arrays that will hold the branches to be written
list_of_arrays = []
for _ in self.allsyst:
list_of_arrays.append(array('f', [ 0 ]))
# Create the branches in the output tree
for i, v in enumerate(self.allsyst):
outputTree.Branch(v, list_of_arrays[i], '{0:s}/F'.format(v))
# Iterate over the input tree and fill branches
for event in inputTree:
for i, v in enumerate(self.allsyst):
list_of_arrays[i][0] = getattr(event, v)
outputTree.Fill()
thanks @etejedor, that indeed seems to work! One last question, how would it be possible to define and work with 2D array ie going from list_of_arrays.append(array('f', [ 0 ]))