The scope of gInterpreter working in pyroot environment with RDataframe

Hi,

I have been facing problem reading object declared via ROOT.gInterpreter.Declare in RDataframe. What i wanted to achieved is to pass a std::map consists of string and TH2D histogram into RDataframe via a c++ function through df.Define, where std::map object is defined and declared together custom c++ function:

ROOT.gInterpreter.Declare(
'''
static std::map<const std::string,TH2D*> SFmap;

void loadSF2D( const char *filename )
{
  
    TFile f = TFile( filename , "READ" );

    SFmap.insert(std::make_pair( "sf"       , (TH2D*) f.Get("sf") ));
    SFmap.insert(std::make_pair( "sf_sys"   , (TH2D*) f.Get("sf_sys") ));
    std::cout<<"loaded 2D map : "<<filename<<std::endl;
    std::cout<<"Load::SFmap[sf]->GetNbinsX() : "<< SFmap["sf"]->GetNbinsX() <<std::endl;

    f.Close();
}

float evalFlip( const double pt , const double eta )
{
    std::cout<<"Accessing TH2D "<< SFmap["sf"]->GetNbinsX() <<std::endl;
    some calculation
    return somecalculation;
}
'''
)

In the main pyroot script i did

loadSF2D("sf_file.root")
df.Define( 'sf' , 'evalFlip( lep1_pt , lep1_eta  )' ).Sum('sf').GetValue()

The cout under loadSF2D works as expected, printing the correct number of bins in x axis; meanwhile the cout under evalFlip does not work and return segfault… How should i declare my SFmap so that it is accessible by evalFlip function? I am not sure how the scope works under gInterpreter environment though.

Looking forward to hear from you.
Cheers,
Siewyan

_ROOT Version: 6.22
Platform: Not Provided
Compiler: Not Provided


I think this has little to do with gInterpreter.Declare or RDataframe; the histograms are deleted when the files is closed and goes out of scope, see https://root.cern/root/htmldoc/guides/users-guide/ROOTUsersGuide.html#ownership-by-current-directory-gdirectory .
The simplest solution is to use TFile::Open instead, and not close the file (at least as long as you need the histograms - if you need to control closing the files and deleting the TFile, you need some longer-lived object to do keep track of them), or call SetDirectory(0) on the histograms.

1 Like

Hi,
indeed as @pieterdavid says you don’t need RDF to reproduce the problem:

import ROOT                                                                                                                                                                   
                                                                                                                                                                              
f = ROOT.TFile("f.root", "recreate")                                                                                                                                          
h1 = ROOT.TH2D("sf", "sf", 100, 0, 1, 100, 0, 1)                                                                                                                              
h2 = ROOT.TH2D("sf_sys", "sf_sys", 100, 0, 1, 100, 0, 1)                                                                                                                      
h1.Write()                                                                                                                                                                    
h2.Write()                                                                                                                                                                    
f.Close()                                                                                                               
                                                                                                                                                                              
ROOT.gInterpreter.Declare(                                                                                                                                                    
'''                                                                                                                                                                           
static std::map<const std::string,TH2D*> SFmap;                                                                                                                               
                                                                                                                                                                              
void loadSF2D( const char *filename )                                                                                                                                         
{                                                                                                                                                                             
                                                                                                                                                                              
    TFile f = TFile( filename , "READ" );                                                                                                                                     
                                                                                                                                                                              
    SFmap.insert(std::make_pair( "sf"       , (TH2D*) f.Get("sf") ));                                                                                                         
    SFmap.insert(std::make_pair( "sf_sys"   , (TH2D*) f.Get("sf_sys") ));                                                                                                     
    std::cout<<"loaded 2D map : "<<filename<<std::endl;                                                                                                                       
    std::cout<<"Load::SFmap[sf]->GetNbinsX() : "<< SFmap["sf"]->GetNbinsX() <<std::endl;                                                                                      
                                                                                                                                                                              
    f.Close();                                                                                                                                                                
}                                                                                                                                                                             
                                                                                                                                                                              
void evalFlip( const double pt , const double eta )                                                                                                                          
{                                                                                                                                                                             
    std::cout<<"Accessing TH2D "<< SFmap["sf"]->GetNbinsX() <<std::endl;                                                                                                      
}                                                                                                                                                                             
'''                                                                                                                                                                           
)                                                                                                                                                                             
                                                                                                                                                                              
ROOT.loadSF2D("f.root")                                                                                                                                                       
ROOT.evalFlip(0,0) 
1 Like

Some more possible solutions:

  • call TH1::AddDirectory(false) to turn off file ownership of ROOT histograms globally
  • put a f.Get("sf")->Clone() of those histograms in the map rather than the original histograms. the copy will be owned by ROOT’s runtime
  • make it a std::map<string, TH2D> (i.e. values instead of pointers) and copy the histograms you read from file into the histograms owned by the map
1 Like

Thanks you very much @pieterdavid and @eguiraud for untangle the problem, and yes, by taking your advise, it is working fine now and it is running with my Rdataframe.

Thanks!!!
Cheers,
Siewyan

For someone out there looking for similar issue, the working code is:

import ROOT                                                                                                                                                                   
                                                                                                                                                                              
f = ROOT.TFile("f.root", "recreate")                                                                                                                                          
h1 = ROOT.TH2D("sf", "sf", 100, 0, 1, 100, 0, 1)                                                                                                                              
h2 = ROOT.TH2D("sf_sys", "sf_sys", 100, 0, 1, 100, 0, 1)                                                                                                                      
h1.Write()                                                                                                                                                                    
h2.Write()                                                                                                                                                                    
f.Close()                                                                                                               
                                                                                                                                                                              
ROOT.gInterpreter.Declare(                                                                                                                                                    
'''                                                                                                                                                                           
static std::map<const std::string,TH2D*> SFmap;                                                                                                                               
                                                                                                                                                                              
void loadSF2D( const char *filename )                                                                                                                                         
{                                                                                                                                                                             
                                                                                                                                                                              
    TFile f = TFile( filename , "READ" );          

    TH2D *h_sf       = (TH2D*) f.Get("sf")->Clone();
    TH2D *h_sf_sys   = (TH2D*) f.Get("sf_sys")->Clone();                                

    h_sf->SetDirectory(0) ; h_sf_sys->SetDirectory(0);
                                                                                                                                                                              
    SFmap.insert(std::make_pair( "sf"       , h_sf ));                                                                                                         
    SFmap.insert(std::make_pair( "sf_sys"   , h_sf_sys ));                                                                                                     
    std::cout<<"loaded 2D map : "<<filename<<std::endl;                                                                                                                       
    std::cout<<"Load::SFmap[sf]->GetNbinsX() : "<< SFmap["sf"]->GetNbinsX() <<std::endl;                                                                                      
                                                                                                                                                                              
    f.Close();                                                                                                                                                                
}                                                                                                                                                                             
                                                                                                                                                                              
void evalFlip( const double pt , const double eta )                                                                                                                          
{                                                                                                                                                                             
    std::cout<<"Accessing TH2D "<< SFmap["sf"]->GetNbinsX() <<std::endl;                                                                                                      
}                                                                                                                                                                             
'''                                                                                                                                                                           
)                                                                                                                                                                             
                                                                                                                                                                              
ROOT.loadSF2D("f.root")                                                                                                                                                       
ROOT.evalFlip(0,0) 
1 Like

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