Hello,
I have an issue filling a tree branch with dynamic size array. Just to clarify, in each MadGraph event, there are different number of jets and leptons – so for example to keep jet’s pT in a branch, I need to fill it by arrays (which have different size for each event)!
Here is code which is close to what I want to do in my analysis.
import array
import ROOT as r
import numpy as np
r.gROOT.SetBatch(1)
treeBefUnf = r.TTree("treeBefUnf", "ensemble bin contents before unfolding")
binContBefUnf = array.array( 'd', 10*[ 0. ] )
arrtest = array.array( 'd')
treeBefUnf.Branch('mynum', binContBefUnf, 'mynum[%d]/D'%len(binContBefUnf))
treeBefUnf.Branch('myarrtest', arrtest, 'myarrtest[size]/D')
for i in range(100) :
arrtest = array.array( 'd')
for b in range(len(binContBefUnf)) :
binContBefUnf[b] = i*10+b
size = np.random.randint(0,5)
for j in range(size):
arrtest.append(j)
#arrtest[j] = j*10
print arrtest
treeBefUnf.Fill()
#treeBefUnf.Scan("mynum[0]:myarrtest[0]:myarrtest[1]")
treeBefUnf.Scan("myarrtest")
outFile = r.TFile.Open('example_tree.root', 'recreate')
outFile.cd()
treeBefUnf.Write()
outFile.Close()
arrtest is an array which is filled 100 times (100 events as an example) and for each event, it has different size (which is determined by a numpy random variable between 0-5). It seems the code does not work properly in filling the tree since I am getting this error:
"Error in TTreeFormula::Compile: Bad numerical expression : “myarrtest[1]”
Do you have a suggestion how to define a dynamic size array and then fill the branch with it?
You need to add a branch that contains the size you refer to here (and it needs to be a Int_t and/or int).
Independently of the problem you report, we strongly recommend create a file backup TTree rather than a memory backup TTree. To do so move the file opening before the TTree creation.
outFile = r.TFile.Open('example_tree.root', 'recreate')
treeBefUnf = r.TTree("treeBefUnf", "ensemble bin contents before unfolding")
Thanks a lot for the hints. So I just did what you suggested like having separate branch for size and putting the file creation at the beginning:
import array
import ROOT as r
import numpy as np
from ROOT import Int_t
r.gROOT.SetBatch(1)
outFile = r.TFile.Open('example_tree.root', 'recreate')
treeBefUnf = r.TTree("treeBefUnf", "ensemble bin contents before unfolding")
size = Int_t()
#size = int()
binContBefUnf = array.array( 'd', 10*[ 0. ] )
arrtest = array.array( 'd')
treeBefUnf.Branch('Size', size, 'Size/I')
treeBefUnf.Branch('mynum', binContBefUnf, 'mynum[%d]/D'%len(binContBefUnf))
treeBefUnf.Branch('myarrtest', arrtest, 'myarrtest[size]/D')
for i in range(100) :
arrtest = array.array('d')
for b in range(len(binContBefUnf)) :
binContBefUnf[b] = i*10+b
size = np.random.randint(0,5)
#arrtest = array.array( 'd', size*[0. ])
for j in range(size):
#arrtest[j] = j*10
arrtest.append(j*10)
print arrtest
print size
treeBefUnf.Fill()
#treeBefUnf.Scan("mynum[0]:myarrtest[0]:myarrtest[1]")
treeBefUnf.Scan("Size: myarrtest[0]")
outFile.cd()
treeBefUnf.Write()
outFile.Close()
those prints look fine but the tree is still recording 0 for the size variable and Error in <TTreeFormula::Compile>: Bad numerical expression : "myarrtest[0]" for myarrtest. I think the tree is just filled by the initial value of size which is zero and not considering other elements of arrtets. Do you have ideas or suggestions on how to correct this?
Thanks a lot @Wile_E_Coyote. As you mentioned that treeBefUnf.SetBranchAddress('myarrtest', arrtest) was the key point and it fixes all the issue. Just as reference, the final code is like below:
import array
import ROOT as r
import numpy as np
from ROOT import Int_t
r.gROOT.SetBatch(1)
outFile = r.TFile.Open('example_tree.root', 'recreate')
treeBefUnf = r.TTree("treeBefUnf", "ensemble bin contents before unfolding")
#size = Int_t()
size = array.array( 'l', [ 0 ] )
binContBefUnf = array.array( 'd', 10*[ 0. ] )
arrtest = array.array( 'd')
treeBefUnf.Branch('size', size, 'size/I')
treeBefUnf.Branch('mynum', binContBefUnf, 'mynum[%d]/D'%len(binContBefUnf))
treeBefUnf.Branch('myarrtest', arrtest, 'myarrtest[size]/D')
for i in range(100) :
arrtest = array.array( 'd')
for b in range(len(binContBefUnf)) :
binContBefUnf[b] = i*10+b
size[0] = np.random.randint(0,5)
for j in range(size[0]):
#arrtest[j] = j*10
arrtest.append(j*10)
print arrtest
print size
treeBefUnf.SetBranchAddress('myarrtest', arrtest) # "refresh" the address
treeBefUnf.Fill()
treeBefUnf.Scan("size: myarrtest[0]:myarrtest[1]:myarrtest[2]")
outFile.cd()
treeBefUnf.Write()
outFile.Close()