PyROOT: unexpected change of TTree when combining c_types, AddFriend and SetBranchAddress

Dear experts,

With ROOT version 6.22/06 on MacOS, as well as 6.22 versions on CentOS7, we are experiencing some unexpected behaviour when we loop over a TTree to compute a simple sum. To invoke this unexpected behaviour, three ingredients are required:

  • We create a new TTree in a function that we directly add as a friend, using TTree::AddFriend;
  • We call SetBranchAddress for one of the branches of the original tree, giving it a c_types.c_double() as a container;

What we see is that the original tree changes each time we call this function, which should leave the original tree intact. It is as if the original branch value is overwritten by the friend tree’s value. If we do not call AddFriend, this behaviour is not seen. If we use a array('d', [0.]) as a container for the branch values instead of the c_double, the behaviour is also not seen.

We added a call to ResetBranchAddresses to be sure, but this does not fix the behaviour. What is going wrong when using the c_doubles paired with AddFriend? Is this intended behaviour, and should we always just use the array containers for SetBranchAddress?

Included is a minimal example that reproduces the problem. The expected output is a set of identical numbers. With my ROOT version I see “((6716.289999781176, 6716.289999781176, None), (5035.0, 5035.0, None))”. When the type is changed to array in lines 44/43, the problem is fixed. Also when commenting out line 60. There is an explicit tree.Show call to illustrate that the values of the original tree seemingly change.

Many thanks.

Minimal example

Hello,

Thank you for the report, I will have a look and get back to you.

Cheers,
Enric

Hello @LaurentDufour,

I’d like to ask one clarification, this behaviour you see with 6.22/06 is different from what you saw in older versions of ROOT? If I try 6.20/06, I still get the same behaviour when using c_types.c_double.

In any case, if you want to read a branch of type double, I would use the array option (numpy array also works). You can find some documentation for that here:

(look for the PyROOT box)

What I believe is going on is that the pythonization of SetBranchAddress can handle the array but not the ctypes type. Such pythonization retrieves the pointer to the data buffer from the Python object (e.g. the array) and passes it on to ROOT in C++, so that the data that is read later is stored at that location in memory.

Hi @etejedor,

Many thanks for looking in to this. Indeed, also under ROOT 6.20 I see this behaviour. It’s interesting that the behaviour with the ctypes type becomes hard to understand, but with all the C++ <-> python magic going on behind the scenes it’s not entirely unexpected. We have switched to array and everything works as expected again.

Because this behaviour is hard to debug, do you think it’s worthwhile to protect, or warn the user from using the wrong types with SetBranchAddress? I have to admit that I’m not sure how easy that would be to implement, but probably already a word of caution in the documentation is enough.

Thanks again.

Hi,

Thanks for your feedback, I agree that a ctypes c_double would make sense in this context (and it’s even more intuitive than an array of one position), it’s just that it’s not currently supported. I do think though that the documentation cited above is clear about the Python type to be used to read branches of basic types.

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