Problemas reading an external class

Dear all,

I am trying to read a custom-defined class that is stored in a root file:
(making the ls of the root file):
TDirectoryFile* eventInfo eventInfo
KEY: TH1F histNVerteces;1 NumberOfVerteces
KEY: TH1F histNGoodVerteces;1 NumberOfGoodVerteces
KEY: TObjString runLuminosityReport;1 Collectable string class
KEY: TObjString runSummaryReport;1 Collectable string class
KEY: cutFlow current_EPSfilteredDATAProof_cutFlow;1

I want to read that last object a cutFlow object. For that I use in my python script

gROOT.ProcessLine('.L Loader.C++')

being Loader.C:

#include <map>
#include <string>
#include <vector>
#include "cutFlow.cxx"
#ifdef __CINT__
#pragma link C++ class cutFlow+;
#pragma link C++ class map<string,int>+;
#pragma link C++ class map<TString,Bool_t>+;
#pragma link C++ class map<Int_t,TString>+;
#pragma link C++ class map<string,float>+;

#else
template class std::map<std::string, int>;
template class std::map<string,float>;
#endif

and the cutFlow.cxx has the code that implements the class which is the same as the one who wrote that class in the root file. Surprisingly enough it seemed to work at first try:

It is giving me two notes:

but it is not giving further error. Later in the code I try to read the object in the root file and then I am lost. I tried several thing but all of the give me errors. What I do is the simplest thing:

File["DATA_EFT"]="/afs/cern.ch/user/f/fullana/scratch0/D3PD_CALJET_ANALYSIS/current_EPSfilteredDATAProof.root"
DataEFT_File=TFile(File["DATA_EFT"])
DataEFT_File.ls();
DataEFT_File.cd("eventInfo");
DataEFT_File.ls();
theCutFlow=DataEFT_File.Get("current_EPSfilteredDATAProof_cutFlow");
print theCutFlow.internal_print();

it gives me the error:

[quote] print theCutFlow.internal_print();
AttributeError: ‘TObject’ object has no attribute ‘internal_print’
[/quote]

And the internal_print is one of the methods defined in CutFlow. I am rather new in Python so there may be something silly missing

Hi,

are there any base classes between cutFlow and TObject? If yes, they should be generated as well for the auto-downcast to work.

Cheers,
Wim

Thanks for the quick answer Wim. cutFlow inherits from TNamed:

#include <string>
#include <vector>
#include <iostream>

using namespace std;

class cutFlow : public TNamed
{
 public :
  cutFlow(Bool_t  t = true , const char* an = "dummyName");
  virtual ~cutFlow();
  
  void addEntry(const char* cutName, int runNumber, int incNumber);
  
  void print(){ std::cout << this->internal_print() << std::endl;};
  
  std::string getSummary(){return this->internal_print();};
  
  map<string, map<int, int> > getMap(){return m_cutsMap;};
  
  Long64_t Merge(TCollection* );
  
 private:
  
  /*   struct stringcomp { */
  /*     bool operator() (const char* lhs, const char* rhs) const */
  /*     {return lhs[0]<rhs[0];} */
  /*   }; */
  /*   struct intcomp { */
  /*     bool operator() (const int lhs, const int rhs) const */
  /*     {return lhs<rhs;} */
  /*   }; */
  
  //  std::stringstream internal_print();
  
  Bool_t m_isData;
  
  std::string internal_print();
  
  map<string, map< int, int > > m_cutsMap;  // cut name : runNumber : value
  
  ClassDef(cutFlow,1);
};

#endif

but I did not get exactly by you mean by "generated " should I include it also in the Loader.C?

Hi,

no, that should be fine: TNamed already has a dictionary (although I’m missing an #include “TNamed.h” in your posted header file of cutFlow).

Other silly question: did you load loader.C+ in your python file (I don’t see it in the code snippet)? In effect, is ROOT.cutFlow there?

Cheers,
Wim

Thanks again Wim,

Yes you are right, I missed that part, here it is complete

#ifndef __cutFlow__h__
#define __cutFlow__h__

#include "TString.h"
#include "TNamed.h"
#include "TCollection.h"
#include <map>
#include <string>
#include <vector>
#include <iostream>

using namespace std;

class cutFlow : public TNamed
{
 public :
  cutFlow(Bool_t  t = true , const char* an = "dummyName");
  virtual ~cutFlow();
  
  void addEntry(const char* cutName, int runNumber, int incNumber);
  
  void print(){ std::cout << this->internal_print() << std::endl;};
  
  std::string getSummary(){return this->internal_print();};
  
  map<string, map<int, int> > getMap(){return m_cutsMap;};
  
  Long64_t Merge(TCollection* );
  
 private:
  
  /*   struct stringcomp { */
  /*     bool operator() (const char* lhs, const char* rhs) const */
  /*     {return lhs[0]<rhs[0];} */
  /*   }; */
  /*   struct intcomp { */
  /*     bool operator() (const int lhs, const int rhs) const */
  /*     {return lhs<rhs;} */
  /*   }; */
  
  //  std::stringstream internal_print();
  
  Bool_t m_isData;
  
  std::string internal_print();
  
  map<string, map< int, int > > m_cutsMap;  // cut name : runNumber : value
  
  ClassDef(cutFlow,1);
};

#endif

…hum let me write down my python script:

import sys, time
from ROOT import gROOT, TCanvas, TF1, TFile, TKey, TIter, TStyle, TH1F, TCanvas, TLatex, TLegend, TF1, TGraphAsymmErrors, TMath, TPad, TH2D
from math import *
from array import array
from decimal import *
import PyCintex; PyCintex.Cintex.Enable()


gROOT.Reset()


gROOT.ProcessLine('.L Loader.C++')

from ROOT import cutFlow

# Defining the droot file where the cut flow information can be found
File={}
File["DATA_EFT"]="/afs/cern.ch/user/f/fullana/scratch0/D3PD_CALJET_ANALYSIS/current_EPSfilteredDATAProof.root"

DataEFT_File=TFile(File["DATA_EFT"])
DataEFT_File.ls();
DataEFT_File.cd("eventInfo");
DataEFT_File.ls();

# theCutFlowTrial=cutFlow();
theCutFlow=DataEFT_File.Get("current_EPSfilteredDATAProof_cutFlow");
print type(theCutFlow);
theCutFlow.internal_print();
#theCutFlow.Print();
# theCutFlowTrial.internal_print();

I am really not sure if this is the proper way to do it… well I am sure it is not, otherwise it will work :slight_smile:

Sorry to reply myself but as I am having a quiet night shift I can work on this…

So the cutFlow class works fine in the python script. I can create one, access the method in the class and everything seems to work fine. However, if I open a root file that contains an object of that class:

and I get that object doing:

theCutFlow=DataEFT_File.Get("current_EPSfilteredDATAProof_cutFlow");

python does not recognize it as a cutFlow object but as a TObject (if I do a print type(theCutFlow); I get [quote]<class ‘ROOT.TObject’>[/quote] and of course python is not allowing me to access the methods of the cutFlow class in that object

Hi,

not too happy about the Cintex.Enable(), b/c that means that the map dictionary for the cutFlow datamember can now come from two sources. Other than that, no idea. Was the cutFlow written with the same dictionary as it is being read? Is it possible for me to have access to a sample file that causes problems, so that I could reproduce the issue?

Cheers,
Wim

Yes of course Wim. I can not give you my the one I am using because it contains ATLAS data but I’ve just created another one that does not have any events but has the cutFlow object (full of zeros I suppose) that should work fine for this purpose.
RunProofReadingDATALocal.root (667 KB)

Hi,

back to this one (I’ve been traveling) …

A bundle of problems, but the main ones seem to be that the object is in a subdirectory called eventInfo, so it should be Get(“eventInfo/current_EPSfilteredDATAProof_cutFlow”) or as per the sample file it should be Get(“eventInfo/RunProofReadingDATALocal_cutFlow”), at which point it at least finds it.

However, after that it still crashes as it appears that the class with which it was written is not the one for which I’m generating a CINT dictionary using loader.C?

Cheers,
Wim

Hi Wim,

thanks a lot for the answer.

About the first issue, yes you are right but I do first DataEFT_File.cd("eventInfo");. I know it is not very elegant, but I writing it in “developer mode”, checking each step.

About the second issue. let me explain, the code to generate the class, cutFlow.cxx and cutFlow.h are exactly the same in the “python area” than in the “proof area”, I removed a couple of lines that contained includes of not needed headers. The file to create the dictionary are quite different (see below the one of the “proof area”. The reason is because in the “proof area” I am creating the dictionaries for the cutFlow class and some more that I don’t need in my python script. So I remove those files to write the Loader.C. I don’t know if this is the correct way to do it.

#ifdef __CINT__


#pragma link off all globals;
#pragma link off all classes;
#pragma link off all functions;
#pragma link C++ nestedclasses;

// #pragma link C++ class JetID+;
// #pragma link C++ class JESUncertaintyProvider+;
// #pragma link C++ class EMJESFixer+;


#pragma link C++ class xsJet+;
#pragma link C++ class cutFlow+;
#pragma link C++ class xsEvent+;
#pragma link C++ class xsLuminosity+;
#pragma link C++ class xsAnalysis+;



#pragma link C++ class qcd_v1+;

// EFT #ifdef athenaR15
// EFT #pragma link C++ class SelectorP298+;
// EFT #endif
// EFT #ifdef athenaR16
// EFT #pragma link C++ class SelectorP350+;
// EFT #endif

#pragma link C++ class Directory+;

#pragma link C++ class xsObservable+;
#pragma link C++ class xsInclusiveJets+;

//#pragma link C++ class TTree+;
//#pragma link C++ class TLorentzVector+;

#pragma link C++ class map<string,int>+;
#pragma link C++ class map<TString,Bool_t>+;
#pragma link C++ class map<Int_t,TString>+;
#pragma link C++ class map<string,float>+;
//#pragma link C++ class map<Int_t, map<Int_t,Int_t> >+;
//#pragma link C++ class map<UInt_t, map<UInt_t,UInt_t> >+;


#pragma extra_include "vector";
#include <vector>
#pragma extra_include "map";
#include <map>




#endif

Hi,

okay, but then in my case I still do find the object (i.e., I get a cutFlow, not a TObject pointing to zero). Have you checked with ls() on the file that the name is spelled correctly? The name in the file that you gave me is different from the one in the script that you posted.

(Btw., note that internal_print() is a private method, so you won’t be able to call it anyway.)

Cheers,
Wim

Hi Wim, thanks again.

yes of course, the root file I sent you it is a special one I did to avoid breaking ATLAs rules.

Yes you are right of course, I use Print() now but as you said the pointer is empty so still does not work.

I missed that one, how do you get the cutFlow instead of the Tobject pointing to zero that I am getting? and once you have the cutFlow, can you access the cutFlow methods?