Read/write TLorentzVectors from a TTree

Hi PyRoot’ers,

I’m trying to read TLorentzVector objects from a TTree/TChain using PyRoot. However, it seems to crash hard on me.

[code]Traceback (most recent call last):
File “./read_4vecs.py”, line 27, in
readTree()
File “./read_4vecs.py”, line 23, in readTree
print t.my4vec.E()
AttributeError: ‘TChain’ object has no attribute ‘my4vec’

*** Break *** segmentation violation
Attaching to program: /proc/6285/exe, process 6285
[Thread debugging using libthread_db enabled]
0xb803d424 in __kernel_vsyscall ()
#1 0xb7f0f19b in waitpid () from /lib/i686/cmov/libc.so.6
#2 0xb7eabb0b in ?? () from /lib/i686/cmov/libc.so.6
#3 0xb7eabeb2 in system () from /lib/i686/cmov/libc.so.6
#4 0xb800d32d in system () from /lib/i686/cmov/libpthread.so.0
#5 0xb762621d in TUnixSystem::Exec(char const*) () from /usr/local/lib/root/libCore.so.5.22
#6 0xb762b5ec in TUnixSystem::StackTrace() () from /usr/local/lib/root/libCore.so.5.22
#7 0xb762c38d in TUnixSystem::DispatchSignals(ESignals) () from /usr/local/lib/root/libCore.so.5.22
#8 0xb762c48d in SigHandler(ESignals) () from /usr/local/lib/root/libCore.so.5.22
#9 0xb7622e82 in sighandler(int) () from /usr/local/lib/root/libCore.so.5.22
#10
#11 0x09cdd940 in ?? ()
#12 0xb61a7d73 in ROOT::delete_TChain(void*) () from /usr/local/lib/root/libTree.so.5.22
#13 0xb75e3992 in TClass::Destructor(void*, bool) () from /usr/local/lib/root/libCore.so.5.22
#14 0xb7b95548 in PyROOT::op_dealloc_nofree(PyROOT::ObjectProxy*) () from /usr/local/lib/root/libPyROOT.so
#15 0xb7b95592 in PyROOT::(anonymous namespace)::op_dealloc(PyROOT::ObjectProxy*) () from /usr/local/lib/root/libPyROOT.so
#16 0x0809eb9d in ?? ()
#17 0x08112eda in ?? ()
#18 0x080f1704 in ?? ()
#19 0x080f1711 in ?? ()
#20 0x08086411 in ?? ()
#21 0x0808807e in PyDict_SetItem ()
#22 0x08088272 in PyDict_SetItemString ()
#23 0x080dfb21 in PyImport_Cleanup ()
#24 0x080eabc2 in Py_Finalize ()
#25 0x08058d4f in Py_Main ()
#26 0x08058742 in main ()
A debugging session is active.

    Inferior 1 [process 6285] will be detached.

[/code]

I’m trying to read the TLorenzVector the same as I would a float but perhaps this is wrong?

# Create the TChain
  t = TChain("T")
  t.Add("test.root")
  t.Print()

  # Turn on a branch
  t.SetBranchStatus( '*', 0 )
  t.SetBranchStatus( 'my4vec', 1 )
  t.SetBranchStatus( 'tf', 1 )

  # Event loop
  nev = t.GetEntries()
  for n in xrange (t.GetEntries()):
    t.GetEntry(n)

    print t.tf
    print t.my4vec.E()

I’m attaching the full sample code that I used to write to and read from the sample root file. I’ve also written/read a simple ‘float’ that seems to work OK.

I fear I’m missing something simple. Any help is greatly appreciated. Thanks in advance.

Matt
write_4vecs.py (680 Bytes)
read_4vecs.py (460 Bytes)

Hi,

Try creating the branch a trailing dot: tree.Branch( "my4vec.", p4, "TLorentzVector") and make sure to enable all the subranches:t.SetBranchStatus( 'my4vec.*', 1 )

Cheers,
Philippe.

Hi Philippe,

This still does not work for the reading portion.

File "./read_4vecs.py", line 23, in readTree print t.my4vec.E() AttributeError: 'TChain' object has no attribute 'my4vec'

Does it work for you with my code snippets? Perhaps I have an old version (5.22)?

Matt

[quote]Does it work for you with my code snippets? Perhaps I have an old version (5.22)?[/quote]Unfortunately no. I.e. on top the fact that the re-enabling the branch was incorrect, they appear to be a mismatch in retrieving the branch; I will forward this report to Wim who makes have a better idea on what’s the issue here.

Cheers,
Philippe.

Ps. I also mistyped the branch creation I gave you I meant:

Hi,

in the original script, I only noticed that:tree.Branch( "my4vec", p4, "TLorentzVector")should’ve been:tree.Branch( "my4vec", "TLorentzVector", p4 )Other than that, it simply works for me … (Linux, SVN trunk as well as v5-22-00-patches).

Cheers,
Wim

Hi Wim,

It also works for me if I do not have the trailing dot in the branchname. I.e. PyROOT does not yet support that common case (having the trailing dot).

Cheers,
Philippe.

Hi guys,

Thanks much for the pointers. The write/read works for me now with those two examples!

However, I had actually only included the write script to demonstrate another read issue I was having. Unfortunately I introduced that bug you caught with the branch syntax in the write script I included.

The original problem stemmed from trying to read a TLorentzVector from a different file which had been created from some C++ code from a colleague. Would there be any reason that a TTree with TLorentzVector’s created from some other process would be unreadable from my PyRoot script?

Matt

[quote]The original problem stemmed from trying to read a TLorentzVector from a different file which had been created from some C++ code from a colleague. Would there be any reason that a TTree with TLorentzVector’s created from some other process would be unreadable from my PyRoot script? [/quote] A priori no. How does it fail?

Cheers,
Philippe.

Matt,

I wouldn’t see any difference (unless there is some difference in naming, but TTree::Print() should make that show up).

Philippe,

not sure what the ‘.’ thing does, but all PyROOT does is lookup of the branch (or leaf, or leaf of branch) with the name used as “data member.” So, this works again:getattr(t,'my4vec.').E()where getattr() is needed b/c ‘my4vec.’ can not be used as a data member name b/c of the ‘.’ (syntax error, otherwise).

Cheers,
WIm

Hi Wim

[quote]not sure what the ‘.’ thing does[/quote]With the trailing dot, the sub-branch names are like “my4vec.fP”, “my4vec.fP.fX”, etc. Without the trailing dot the sub branch names are like “fP”, “fP.fX”.
If you tree contains more than one branch with the same data type, you need the trailing dot to avoid possible ambiguity.

[quote]where getattr() is needed b/c ‘my4vec.’ can not be used as a data member name b/c of the ‘.’ (syntax error, otherwise). [/quote]For (and only for) the top level member, I think you should automate this (i.e. search for both the member name and the member with a trailing dot) as this is a very common case (and actually the recommended way of naming branches).

Cheers,
Philippe.

Philippe,

[quote]I think you should automate this (i.e. search for both the member name and the member with a trailing dot)[/quote]now in trunk.

Cheers,
Wim

Hi guys,

I’m attaching a small version of the original root file with which we were having problems. The file contains a TTree object (“emc”) with one branch (“candP4”). In CINT, I can do this…

root [0] TFile f("small.root") root [1] emc->Draw("candP4.E()")

…and it draws. However, I seem unable to do this in PyRoot without a segfault on the order of…

[code] *** Break *** illegal instruction
Attaching to program: /proc/7957/exe, process 7957
[Thread debugging using libthread_db enabled]
[New Thread 0xb4d6bb70 (LWP 7964)]
0xb7fe1424 in __kernel_vsyscall ()
Thread 2 (Thread 0xb4d6bb70 (LWP 7964)):
#0 0xb7fe1424 in __kernel_vsyscall ()
#1 0xb7faf285 in sem_wait@@GLIBC_2.1 () from /lib/i686/cmov/libpthread.so.0
#2 0x080f2808 in PyThread_acquire_lock ()
#3 0x080c7043 in PyEval_AcquireThread ()
#4 0x080f720f in ?? ()
#5 0xb7fa9585 in start_thread () from /lib/i686/cmov/libpthread.so.0
#6 0xb7efb18e in clone () from /lib/i686/cmov/libc.so.6

Thread 1 (Thread 0xb7e2bb10 (LWP 7957)):
#0 0xb7fe1424 in __kernel_vsyscall ()
#1 0xb7ec507b in waitpid () from /lib/i686/cmov/libc.so.6
#2 0xb7e658cb in ?? () from /lib/i686/cmov/libc.so.6
#3 0xb7e65c72 in system () from /lib/i686/cmov/libc.so.6
#4 0xb7fb137d in system () from /lib/i686/cmov/libpthread.so.0
#5 0xb75b121d in TUnixSystem::Exec(char const*) () from /usr/local/lib/root/libCore.so.5.22
#6 0xb75b65ec in TUnixSystem::StackTrace() () from /usr/local/lib/root/libCore.so.5.22
#7 0xb75b738d in TUnixSystem::DispatchSignals(ESignals) () from /usr/local/lib/root/libCore.so.5.22
#8 0xb75b748d in SigHandler(ESignals) () from /usr/local/lib/root/libCore.so.5.22
#9 0xb75ade82 in sighandler(int) () from /usr/local/lib/root/libCore.so.5.22
#10
#11 0x08ffe61d in ?? ()
Cannot access memory at address 0xc8b58efb
A debugging session is active.

    Inferior 1 [process 7957] will be detached.

Quit anyway? (y or n) [answered Y; input not from terminal]
Detaching from program: /proc/7957/exe, process 7957
[/code]

This file was originally created using someone else’s C++ code, so could there be an issue with the way this was written to file?

Matt
small.root (8.45 KB)

Hi Matt,

This seems to work with the trunk:[code] python
Python 2.6 (r26:66714, Jun 8 2009, 16:07:29)
[GCC 4.4.0 20090506 (Red Hat 4.4.0-4)] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.

from ROOT import *
f = TFile(“small.root”)
emc.Draw(“candP4.E()”)
TCanvas::MakeDefCanvas: created default TCanvas with name c1

[/code]

Cheers,
Philippe.

Hi Philippe,

I should have been more specific. It does not work in any sort of XXXBranchYYY/event loop syntax I try out.

#!/usr/bin/env python

from ROOT import *
import sys

def readTree():
  f = TFile("small.root")
  t = f.Get("emc")
  t.Print()

  # Turn on a branch
  t.SetBranchStatus( '*', 0 )
  t.SetBranchStatus( 'candP4', 1 )

  # Event loop
  nev = t.GetEntries()
  for n in xrange (nev):
    t.GetEntry(n)

    print t.candP4.E()

#### Run read function
if __name__ == '__main__':
     readTree()

This seg faults for me.

Matt

Hi,

at issue is that t.GetLeaf( ‘candP4’ )->GetValuePointer() is expected (by PyROOT) to return a TLorentzVector*, but it is in fact a TLorentzVector**. The dereferencing subsequently goes wrong and a crash results.

Adding:t._l = TLorentzVector() t.SetBranchAddress( 'candP4', t._l )solves this, b/c the branch address will be used, rather than the leaf value pointer.

Not quite sure what is going on here: for builtin types, GetValuePointer() does yield a type*?

Cheers,
Wim

Hi Wim,

Using that syntax, how do access that branch in the event loop?

Matt

Matt,

once the SetBranchAddress is done, t.candP4.E() will follow a different route internally (that is, t.GetBranch( ‘candP4’ ).GetAddress() will succeed and return that TLorentzVector, filled with the proper values), so the loop should succeed as written.

I’m not sure I understand the difference (hopefully Philippe can clarify), but in the earlier test.root that you sent, the my4vec was a branch (and GetAddress() on the branch returns a value); whereas in small.root, candP4 is a leaf and GetAddress() on the result of GetBranch(‘candP4’) (which itself does return a valid TBranch) is zero.

Cheers,
Wim

Hi Wim,

This does not seem to work for me. Could I troube you to verify that it works for you?

Matt

[quote]for builtin types, GetValuePointer() does yield a type*? [/quote]Yes, especially if they are not part of an object (i.e. the leaf is not a TLeafElement).

Cheers,
Philippe.

Matt,

[quote=“mattbellis”]This does not seem to work for me. Could I troube you to verify that it works for you?[/quote]yes, it does. That’s why I posted it. :slight_smile: To be specific:[code]#!/usr/bin/env python

from ROOT import *
import sys

def readTree():
f = TFile(“small.root”)
t = f.Get(“emc”)
t.Print()

Turn on a branch

t.SetBranchStatus( ‘*’, 0 )
t.SetBranchStatus( ‘candP4’, 1 )
t._l = TLorentzVector()
t.SetBranchAddress( ‘candP4’, t._l )

Event loop

nev = t.GetEntries()
for n in xrange (nev):
t.GetEntry(n)

print t.candP4.E()

Run read function

if name == ‘main’:
readTree()[/code]works for me.

Cheers,
Wim