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