Filling TTree in Python with PyROOT

Hello,

A caveat from the start: I am somewhat new at using ROOT and also somewhat new at using Python.

I’m trying to fill a TTree within Python using PyROOT. As a test, I wanted to see if I could fill a TTree with a single branch of TH1F histograms, but I haven’t gotten very far.

I get a segfault when trying to define the branch :

Python 2.2.3 (#1, Oct 15 2003, 23:33:35)
[GCC 3.3.1 20030930 (Red Hat Linux 3.3.1-6)] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.

from ROOT import *
H = TH1F()
tree = TTree(‘test’, ‘Test histogram tree’)
tree.Branch(‘hist_branch’, ‘TH1F’, H)

*** Break *** segmentation violation
Generating stack trace…
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
/usr/bin/addr2line: python: No such file or directory
0x007182d8 in G__CallFunc::Exec(void*) + 0x6e from /usr/local/cern/root/lib/libCint.so
0x00ecfe4f in TClass::BuildRealData(void*) + 0x2f7 from /usr/local/cern/root/lib/libCore.so
0x013da675 in TTree::BuildStreamerInfo(TClass*, void*) + 0x31 from /usr/local/cern/root/lib/libTree.so
0x013da213 in TTree::Bronch(char const*, char const*, void*, int, int) + 0x53d from /usr/local/cern/root/lib/libTree.so
0x013d901f in TTree::Branch(char const*, char const*, void*, int, int) + 0x41 from /usr/local/cern/root/lib/libTree.so
0x013f23ca in from /usr/local/cern/root/lib/libTree.so
0x00718380 in G__CallFunc::ExecInt(void*) + 0x66 from /usr/local/cern/root/lib/libCint.so
0x003c235a in PyROOT::MethodHolder::execute(void*, long&) + 0x6c from /usr/local/cern/root/lib/libPyROOT.so
0x003c260c in PyROOT::MethodHolder::operator()(_object*, _object*) + 0x15e from /usr/local/cern/root/lib/libPyROOT.so
0x003bfe61 in PyROOT::MethodDispatcher::operator()(_object*, _object*) + 0xcf from /usr/local/cern/root/lib/libPyROOT.so
0x003bfc7a in PyROOT::MethodDispatcher::invoke(_object*, _object*, _object*) + 0x2a from /usr/local/cern/root/lib/libPyROOT.so
0x080d1b4e in PyCFunction_Call + 0x18e from python
0x080b4137 in PyObject_Call + 0x37 from python
0x0807d540 in from python
0x0807b061 in from python
0x0807bd7e in PyEval_EvalCodeEx + 0x43e from python
0x08078977 in PyEval_EvalCode + 0x57 from python
0x08098ad9 in from python
0x080976a6 in PyRun_InteractiveOneFlags + 0x186 from python
0x08097446 in PyRun_InteractiveLoopFlags + 0x66 from python
0x08097347 in PyRun_AnyFileExFlags + 0x47 from python
0x08053aba in Py_Main + 0x49a from python
0x08053519 in main + 0x29 from python
0x00250770 in __libc_start_main + 0xf0 from /lib/tls/libc.so.6
0x08053461 in ldexp + 0x5d from python
Abort (core dumped)

What am I doing wrong? The TTree::Branch method above wants a pointer to the object being added to the tree. Is there a Python-y way of doing this?

Thank you very much for your help.

The TTree::Branch method above wants a pointer to the object being added

Well, there is the problem. The interface takes a void*, but actually wants a void**
(ie. the address of a pointer to an object, not the pointer to an object). The method
does the casting internally.

You didn’t tell me which version of ROOT you’re working with, but the following
works with HEAD:

from ROOT import *
from array import array

H = TH1F()
tree = TTree( ‘test’, ‘Test histogram tree’ )
holder = array( ‘i’, [ H.IsA().DynamicCast( H.IsA(), H ) ] )
tree.Branch( ‘hist_branch’, ‘TH1F’, holder )

etc. Make sure that “holder” doesn’t dissappear until you’re done filling the tree. The
DynamicCast() is necessary to turn the TObject* into a void*. The array is then
required to turn the void* into an void** passed as int*, which maps onto the void*
as best overload match.

I’ll think of some more general convenience functions to allow C++ style
reinterpret casting on the python side …

Cheers,
Wim

Wim,

Doh! I did forget to tell you which root version I’m using (4.00/08 on Fedora Core 1 with Python 2.2)

Your suggestion worked quite well! Thank you very much for your help.

Dear ROOT users,

With root v5-26b and python2 .4, I’m running the following example from above :

from ROOT import *
from array import array
H = TH1F()
tree = TTree( 'test', 'Test histogram tree' )
holder = array( 'i', [ H.IsA().DynamicCast( H.IsA(), H ) ] )
tree.Branch( 'hist_branch', 'TH1F', holder ) 

That fails with error :
[ul]
holder = array( ‘i’, [ H.IsA().DynamicCast( H.IsA(), H ) ] )
TypeError: void* TClass::DynamicCast(const TClass* base, void* obj, Bool_t up = kTRUE) => takes at least 2 arguments (1 given)
[/ul]
Am I doing something wrong or maybe there is a new way (that I did not found :blush:) to do it ?

Thanks !
Adrien.

Hi,

what’s new since that old post is that the original code:[code]>>> from ROOT import *

H = TH1F()
tree = TTree(‘test’, ‘Test histogram tree’)
tree.Branch(‘hist_branch’, ‘TH1F’, H)[/code]now simply works due to Branch() having been pythonized.

Cheers,
Wim

Thanks for that.
Many thanks also for pyroot, I don’t know if I would be as efficient writing code in c++.
Adrien.