Issue in tree branch filling with dynamic size array in python

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?

Thanks in advance!

Cheers,
Meisam

ROOT Version: 6.18/04

Hi,
@pcanal can maybe help you on this problem,

Cheers, Lorenzo

Hi,
Thanks @moneta. I am looking forward to see what @pcanal and others thinking on this.

Cheers,
Meisam

treeBefUnf.Branch('myarrtest', arrtest, 'myarrtest[size]/D')

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")

Hi @pcanal,

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?

Best regards,
Meisam

Size” != “size

Hi @Wile_E_Cyotoe,

Thanks for your reply (thought the first and third params are just names)! I just edited the size branch definition by:

treeBefUnf.Branch('size', size, 'size/I')

but still tree fills with nothing basically

************************************
*    Row   *      Size *  myarrtes *
************************************
*        0 *           *           *
*        1 *           *           *
*        2 *           *           *

Names are “case sensitive” (you still use “Size”).

Sorry @Wile_E_Cyotoe, forgot to edit the scan part. So just fixing with:

treeBefUnf.Scan("size: myarrtest[0]")

now it turns back to the same issue – zero for size branch and None for myarrtest:

************************************
*    Row   *      size *  myarrtes *
************************************
*        0 *         0 *           *
*        1 *         0 *           *
*        2 *         0 *           *
  1. You need: size = array.array( 'l', [ 0 ] ) # basic Int_t type (array of length 1)
  2. You need: arrtest = array.array( 'd', MAX_ARRTEST_ELEMENTS * [ 0. ])
  3. Afterwards, you must NOT modify the “arrest” addresses (i.e., NO “arrtest = ...” and NO “arrtest.append(...)”)

See also the PyROOT examples in the TTree class description.

Actually, you could use “arrtest = array.array( 'd' )” and “arrtest.append(...)”, but then you need:

treeBefUnf.SetBranchAddress('myarrtest', arrest) # "refresh" the address
treeBefUnf.Fill()

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()

Thanks to all again for the support!

Best regards,
Meisam

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