PyROOT SetBranchAddress error

I have been using PyROOT to interrogate root files for several years, successfully using the same workflow. When I installed 6.24, however, the process broke. I quickly found that AddressOf() needed to be replaced with addressof(), but then SetBranchAddress() started misbehaving.

I’m using ROOT 6.24/02,
Python 3.6.8

Here is a sample code, the point of which is to allow iteration over the data points in the TChain

import ROOT as rt

tchain = rt.TChain('Cluster')
tchain.SetMakeClass(1)
tchain.Add(datafile)
rt.gROOT.ProcessLine("struct cluster_volume_struct{Double_t cluster_volume;}")
data = rt.cluster_volume_struct()
tchain.SetBranchAddress('Cluster_volume', rt.addressof(data, 'cluster_volume'))

which (assuming datafile has been defined) generates this error:

  File "/home/tecampb2/Documents/analysis/root/lib/ROOT/pythonization/_ttree.py", line 156, in _SetBranchAddress
    res = self._OriginalSetBranchAddress(*args)
TypeError: Template method resolution failed:
  none of the 3 overloaded methods succeeded. Full details:
  int TChain::SetBranchAddress(const char* bname, void* add, TBranch** ptr = 0) =>
    TypeError: could not convert argument 2
  int TChain::SetBranchAddress(const char* bname, void* add, TBranch** ptr, TClass* realClass, EDataType datatype, bool isptr) =>
    TypeError: takes at least 6 arguments (2 given)
  int TChain::SetBranchAddress(const char* bname, void* add, TClass* realClass, EDataType datatype, bool isptr) =>
    TypeError: takes at least 5 arguments (2 given)
  Failed to instantiate "SetBranchAddress(std::string,int)"

Does anybody know how to fix this error?

I guess @etejedor can help.

Hello,

I believe in this case it should work if you just do tchain.SetBranchAddress('Cluster_volume', data), since it will use the address of data which coincides with that of its member cluster_volume.

Thank you, etejedor,
You are correct, for my oversimplified example, your suggestion works. In general, however, I’m interested in querying more than one branch of the TChain, in which case this method does not work. Apologies for providing an inadequate example. Normally, my struct would be more complex, and I’ll make multiple calls to SetBranchAddress, as in (following your suggestion):

rt.gROOT.ProcessLine("struct cluster_volume_struct{Double_t cluster_volume, utc; UInt_t cluster_size;}")
data = rt.cluster_volume_struct()   
tchain.SetBranchAddress('Frame_start_time', data)
tchain.SetBranchAddress('Cluster_size', data)
tchain.SetBranchAddress('Cluster_volume', data)

If I follow this (or any of several permutations) with the following, the best I can get is 1 nonzero field in my struct

for i in range(tchain.GetEntries()):
        tchain.GetEntry(i)
        print(data.cluster_volume, data.utc, data.cluster_size)

Hello,

In that case, we are missing a pythonization in SetBranchAddress (i.e. some extra behaviour in Python) that allows to pass e.g. addressof(data, 'cluster_size') as argument. We should add this but, in the meantime, you can do the same by creating a wrapping buffer for the address like so:

from libROOTPythonizations import CreateBufferFromAddress
buffer = CreateBufferFromAddress(addressof(data, 'cluster_size'))
tchain.SetBranchAddress('Cluster_size', buffer)

and similarly for the other members of the struct.

Thank you,
this has solved the problem.

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