Loosing pointers to branches

Hi,

I have currently a problem with my self-defined tree class that I use to “cache” trees. I.e. I read in the branches with something like that:

cache={}
branches=tree.GetListOfBranches()
for n in xrange(len(branches)):
cache[branches[n].GetName()]=branches[n]

This is all built in a new style class to emulate the behaviour a tree, i.e. when I access t.Elec_N it actually gets the branch, then it gets the entry if not already done and returns the value.

So after some usage of an instance of the class, I suddenly loose all the pointers, i.e. cache suddenly contains only “None”.

I am trying to find out at what stage this happens, but I randomly access a lot of branches of the tree, so it is very cumbersome to track down the exact moment when it happpens. I think the pointers are deleted by the Garbage Collection, is there a way to prevent this from happening?

Thanks,
Duc

Duc,

could you print the type of the object that has gone, after it has gone? If the type of it is PyROOT_NoneType, then it means that the underlying C++ object has been deleted, and the python object has been set to a psuedo-None to prevent segfaults. One way that this can happen, is if the tree disappears, taking the branches with it. This scheme is independent of python ref-counting.

Cheers,
Wim

Hi Wim,

so the type is indeed <type ‘PyROOT_NoneType’>. But I checked, the original tree is “saved” inside the object. Right after loading the tree from a file I execute tree.SetDirectory(gDirectory).

This is what it looks like before:

t.tree._AODtree.GetListOfBranches()[0]
<ROOT.TBranch object (“HTall”) at 0x2b13cb90>
t.tree._branches[“HTall”]
<ROOT.TBranch object (“HTall”) at 0x2b13cb90>

and this afterwards, the tree is still there! And it has branches:

t.tree._branches[“HTall”]
None
t.tree._AODtree.GetListOfBranches()[0]
<ROOT.TBranch object (“HTall”) at 0x3bda0780>

The branch adress has changed, how can this happen?

Cheers
Duc

Looking at the TTree source, it’s not clear to me what would cause a branch to be cycled (other than the obvious ones of copying and deleting). Is the tree a transient one with branches created on the fly (e.g. as is done in ATLAS’ ARA)?

Cheers,
Wim

[quote]But I checked, the original tree is “saved” inside the object. Right after loading the tree from a file I execute tree.SetDirectory(gDirectory). [/quote]I am not sure what you mean by “saved”, but please remember that most of the content of the TTree is stored (unless it is a “memory” TTree) in the file itself and disassociating a TTree from its file (by calling SetDirectory) is almost always a bad thing to do (except just after the TTree is created and no data has been stored in it yet).

If you really need to insure that the TTree is kept independent of its underlying tree and you really have enough RAM to hold it, you can call TTree::LoadBaskets and/or use CloneTree to copy the TTree in memory.

If the TTree is actually a TChain, the address of the branches will change every time a new file is loaded.

Cheers,
Philippe.

PS. In order to write a framework caching the branches address of a TChain you need to make sure to check and/or be notified (see “SetNotify” and be called back via “Notify”) each time the chain move to a new file.

Hi,

thanks for the input, so the current problem occurs on standard root trees so far (but since it is a python class, it could also be used on a ARA tree).

By saved I mean that I remember the pointer of the tree and it is not lost or deleted.

I have to set the tree to a new directory since I open multiple files and I loose the tree if I change to a new file.

Actually I use TChains, but right now with only one file. Can it be that the branch pointers change also if I reach the end of the one and only file? This would explain the behaviour, since I loop over the tree once to get the events I want to select and when I try to run over it again I loose the pointers. I will try the Notify function to check if this is the case.

Cheers
Duc[/quote]

Hi again,
so I traced back the moment where I loose the pointers. Somewhere in between I call tree.GetEntries(“eventWeight<0”) and right after that call my pointers are all set to None!

I don’t if that helps to understand what is going on…

Btw. I tried the Notify function and I use a class derived from TObject which refreshes the branch list when it is called. The function is not called at all and I still loose the pointers.

Cheers
Duc

[quote]Btw. I tried the Notify function and I use a class derived from TObject which refreshes the branch list when it is called. The function is not called at all and I still loose the pointers[/quote]Did you register your object with the chain?

Philippe.

Hi,

yes I call chain.SetNotify(notifierobject). Where notifierobject has a member called “tree”, which is the tree that should refresh its branches and a member function “Notify(self)”, which calls “tree._getBranches()” to refresh the branches. That is all, right?

Cheers
Duc

Is the class a python class?

Philippe.

Hi,

yes it is, but it is derived from TObject, is that sufficient?

Cheers
Duc

Hi,

Probably not (Wim should confirm). In order for the C++ code (like TChain) to ‘use’ overloaded function (your Notify function), it needs to be informed of their existence (This must be done by properly setting pointers in the virtual function table).
The easiest way is to write this class (or a wrapper for it) in C++ and compiling the code via ACLiC [gROOT.ProcessLine(".L MyScript.C+")]

Cheers,
Philippe.

Hi,

yes, virtual methods don’t work across the language barrier. There have been several prototypes to work around the problem, but nothing coherent yet.

Philippe, can Notify be setup via ROOT’s signal/slot? That works with through TPyDispatcher class.

Cheers,
Wim

Hi Wim

Unfortunately no.

Another way to ‘implement’ this is to monitor the value of GetTreeNumber, whenever it changes, the TBranch object are changed.

Cheers,
Philippe.