Reading a branch with two intances

Hi all!

I have a root file with a tree “E” that contains a branch “trks.E”. This branch seems to have two instances. In particular, when I do a E->Scan(“trks.E”) in interactive mode, the output is:

***********************************
*    Row   * Instance *    trks.E *
***********************************
*        0 *        0 * 0.9389798 *
*        0 *        1 *         0 *
*        1 *        0 * 538.21652 *
*        1 *        1 * 119.74052 *
*        2 *        0 * 2.9860539 *
*        2 *        1 * 8.1507497 *
...

Then, I want to read this using C++. I have the code:

    oldfileAux.GetObject("E", oldtreeAux);
    oldfileAux.GetObject("T", oldtreeAuxT);
    oldtreeAux->SetBranchAddress("trks.E", &gE);
    const auto nentriesAux = oldtreeAux->GetEntries();

    for (int i=0; i<=nentriesAux;i++)
    {
        oldtreeAux->GetEntry(i);
        cout << gE << endl;
    }

The output depends on the root version. If I run this in local, with root version 6.27, I obtain

0
119.741
8.15075
3.3521
8.83862

but if I run the same script in a cluster, with root version 6.22, I obtain:

1.01856e-312

1.01856e-312

1.01856e-312

1.01856e-312

1.01856e-312

1.01856e-312

1.01856e-312

1.01856e-312

1.01856e-312

The point is that I need to run the script in the cluster, since the files are huge, and I don’t have control over the root version installed there.

So, how can access the different instances?

Thanks!

Hi @Miguel,

maybe our IO expert @pcanal has the answer on the fly…
Anyway, it would be easier for me to help you if you could provide a small size snapshot of your data, so I can reproduce your situation!

Cheers,
Monica

It seems like you’re encountering differences in behavior between different versions of ROOT when accessing the trks.E branch of your TTree. This could be due to changes in ROOT’s behavior or bug fixes between versions.

To ensure your code behaves consistently across different versions of ROOT, you can modify your loop to explicitly access each instance of the trks.E branch using the SetBranchAddress method along with the SetBranchAddressIndex method. Here’s how you can modify your code:

oldfileAux.GetObject("E", oldtreeAux);
oldfileAux.GetObject("T", oldtreeAuxT);

// Define variables to store the values of trks.E instances
Double_t gE_0, gE_1; // Change the data type according to the actual data type of trks.E

// Set branch addresses for each instance of trks.E
oldtreeAux->SetBranchAddress("trks.E", &gE_0);
oldtreeAux->SetBranchAddress("trks.E", &gE_1);

const auto nentriesAux = oldtreeAux->GetEntries();

for (int i = 0; i < nentriesAux; i++)
{
    oldtreeAux->GetEntry(i);
    cout << "Instance 0: " << gE_0 << endl;
    cout << "Instance 1: " << gE_1 << endl;
}

In this modified code, I’ve defined separate variables (gE_0 and gE_1) to store the values of each instance of the trks.E branch. Then, I’ve set the branch addresses for each instance separately using SetBranchAddress. Finally, within the loop, I’m accessing and printing the values of each instance separately.

This approach should ensure consistent behavior across different versions of ROOT and allow you to access each instance of the trks.E branch correctly. Make sure to adjust the data type of gE_0 and gE_1 according to the actual data type of the trks.E branch in your ROOT file.

I might be missing something. The 2nd lines seems to be to be completely replacing the first one (i.e. the result of the program ought to be strictly the same whether the 1st line is executed or not.

This branch seems to have two instances.
oldtreeAux->SetBranchAddress("trks.E", &gE);

If E is a double and gE is declared as double gE (or if the type of E and gE don’t match - but in this case you should get a warning) then this will result in memory over-write as the TTree will execute the moral equivalent of:

double *start = &gE;
start[0] = first_value;
start[1] = second_value;

In this scenario the last line will over-write whatever stack memory is around gE.

The typical way to deal with this is:

double gE[ max_number_element_in_tracks_E_that_could_possibly_be_seen ]; // 2 in the small snapshot you shown
...
oldtreeAux->SetBranchAddress("trks.E", &(gE[0]);

A better alternative is to use a tool (we recommend RDataFrame) that does not require you to specify the type or length of the data.