tree.GetEntry(x) triggers a Traceback in PyRoot

Hello, when I was a summer student I wrote a C++ code using ROOT that is still used in my university.

Now I want to “translate” this code to Python, I have solved several problems but this one has proven the hardest.

The code is supposed to go through the entries of a tree and get jet, met and lepton data to analyze.

In each iteration of the for-loop I used tree->GetEntry(ientry); to automatically fill several TClonesArrays, and this works with C++.

I thought I could translate this command as tree.GetEntry(ientry) since I have tested that this works for all the other ROOT methods, but the terminal gives me this message:

Traceback (most recent call last):
File “aprendiendo.py”, line 163, in
tree.GetEntry(ientry)
SystemError: int TTree::GetEntry(Long64_t entry = 0, int getall = 0) =>
problem in C++; program state has been reset

I have been toying around with it but all the other ways I can come up to fill the TClonesArrays in each iteration are too complex, so I want to find a way to make this method work, or something very similar to it.

Here are the important sections of both of my codes.
Thanks

C++ code that works

#include "Analysis_Libraries.hh"
#include "nero_07.hh"

#define minintu nero_07

minintu *d;   

int main(int argc, char* argv[])
{ 

  TFile* file = TFile::Open("/Users/Fer/Documents/traajo/samples/NeroNtuples_9.root");

  TTree *tree=(TTree*)file->Get("nero/events");

  int nentries = tree->GetEntries();

  TClonesArray *leptondata = new TClonesArray::TClonesArray ( "TLorentzVector", nentries);

  tree->SetBranchAddress("lepP4", &leptondata);

  TClonesArray *metdata = new TClonesArray::TClonesArray ( "TLorentzVector", nentries);

  tree->SetBranchAddress("metP4", &metdata);

  TClonesArray *jetdata = new TClonesArray::TClonesArray ( "TLorentzVector", nentries);

  tree->SetBranchAddress("jetP4", &jetdata);


  for(int ientry = 0; ientry < nentries-1; ientry++) 
  {
    //Reset the data
    leptondata->Clear();
    metdata->Clear();
    jetdata->Clear();

    //This line stores the proper data in the TClonesArrays
    tree->GetEntry(ientry);

        //Store all the data of the electron in this lorentz vector
        TLorentzVector * lorentz_leptondata = (TLorentzVector *)leptondata->At(i);

        //Get the transverse momentum of that lorentz vector
        mass=lorentz_leptondata.Pt();

    TLorentzVector * lorentz_metdata = (TLorentzVector *) metdata->At(0);

    //Get the invariant transverse energy of that lorentz vector
    mass=mass + lorentz_metdata.Et();

        TLorentzVector * lorentz_jetdata = (TLorentzVector *)jetdata->At(i);

        //Get the transverse energy of that lorentz vector
        mass=mass+orentz_jetdata.Et();

  }//This closes the main for loop


  // cleanup
  delete file; // automatically deletes "tree" too
  delete lepPdgId;
  delete leptondata;
  delete metdata;
  delete jetdata;
  return 0; 
}

PyRoot code that will eventually work

# -*- coding: cp1252 -*-
import sys
import ROOT
from ROOT import TLatex,TPad,TList,TH1,TH1F,TH2F,TH1D,TH2D,TFile,TTree,TCanvas,TLegend,SetOwnership,gDirectory,TObject,gStyle,gROOT,TLorentzVector,TGraph,TMultiGraph,TColor,TAttMarker,TLine,TDatime,TGaxis,TF1,THStack,TAxis,TStyle,TPaveText,TAttFill,TCutG

import numpy as np
ROOT.gROOT.SetBatch()

file = TFile("/Users/Fer/Documents/traajo/samples/NeroNtuples_9.root")

tree=file.Get("nero/events")

nentries = tree.GetEntries()

leptondata = TClonesArray( "TLorentzVector", nentries)

tree.SetBranchAddress("lepP4", leptondata)

metdata = TClonesArray("TLorentzVector", nentries)

tree.SetBranchAddress("metP4", metdata)

jetdata = TClonesArray("TLorentzVector", nentries)

tree.SetBranchAddress("jetP4", jetdata)

for ientry in xrange(0,nentries-1):

  #Reset the data
  leptondata=TClonesArray( "TLorentzVector", nentries)
  metdata=TClonesArray( "TLorentzVector", nentries)
  jetdata=TClonesArray( "TLorentzVector", nentries)

  #This line stores the proper data in the TClonesArrays
  tree->GetEntry(ientry);

  #Store all the data of the electron in this lorentz vector
  lorentz_leptondata = leptondata.At(i)

  #Get the transverse momentum of that lorentz vector
  mass=lorentz_leptondata.Pt()

  lorentz_metdata = metdata.At(0)

  #Get the invariant transverse energy of that lorentz vector
  mass=mass + lorentz_metdata.Et()

  lorentz_jetdata = jetdata.At(i)

  #Get the transverse energy of that lorentz vector
  mass=mass+orentz_jetdata.Et();


#cleanup
del file
del leptondata
del metdata
del jetdata

In C++:

    //Reset the data
    leptondata->Clear();
    metdata->Clear();
    jetdata->Clear();

yet in Python:

  #Reset the data
  leptondata=TClonesArray( "TLorentzVector", nentries)
  metdata=TClonesArray( "TLorentzVector", nentries)
  jetdata=TClonesArray( "TLorentzVector", nentries)

and you’re surprised that the behavior differs, why?

To be specific, that “problem in C++; program state has been reset” means you got a segfault on the C++ side. The reason is that by overwriting the XYZdata references, the old values are garbage collected even as you had passed pointers to them to C++. Then the GetEntry touches that deleted memory.

Just call Clear() on the clones arrays in Python like you do in C++ …

Thanks, to be honest I don’t know much python.

I used

	leptondata.Clear()
	metdata.Clear()
	jetdata.Clear()

but I got the same problem, then I checked the documentation for the clones arrays and found void TClonesArray::Clear ( Option_t * option = "" ).
So decided to use

	leptondata.Clear( option = "C")	
	metdata.Clear(option = "C")	
	jetdata.Clear(option = "C")

but I get “keyword arguments are not yet supported”, currently readding what does that mean

I have no idea what option “C” does for Clear() and I don’t see why it’s needed if the default as used in C++ is the empty string, but if you want to call with “C”, the syntax is:

leptondata.Clear("C")
# etc.

By setting ‘option = “C”’ you are not passing a positional function argument, but a keyword dictionary. The latter are not supported in PyROOT (but are in general Python).