Good afternoon,
I am a novice user of TSelector and TProof and thus my questions are probably very trivial.
I try to migrate a sequential ROOT macro, which works fine, in a derived TSelector class to take advantage of my 8 cores machine.
I wrote the macro analyse_multipleruns_proof.C which loads the trees from three independent root files, launches PROOF and the analysis:
#include <iostream.h>
void analyse_multipleruns_proof() {
TChain* c= new TChain("DosimConvtree") ;
c->Add("../root/Converter_Dosimeter_NoPhantom_neutron_norminc_PhysList_I_2MEvts/converter_dosimeter_neutron_144keV_norminc.root") ;
c->Add("../root/Converter_Dosimeter_NoPhantom_neutron_norminc_PhysList_I_2MEvts/converter_dosimeter_neutron_5MeV_norminc.root") ;
c->Add("../root/Converter_Dosimeter_NoPhantom_neutron_norminc_PhysList_I_2MEvts/converter_dosimeter_neutron_14p8MeV_norminc.root") ;
// cout <<"Number of trees: " << c->GetNtrees() << endl ;
//cout << "Get Tree Number : " << c->GetTreeNumber() << endl ;
//gROOT->Time() ;
TProof* p=TProof::Open("") ;
p->Exec("gSystem->Load(\"$DIRDOSIMG4/RootObject/libDosimConvEvent.so\")") ;
p->Exec("gSystem->Load(\"$DIRDOSIMG4/RootObject/libDosimConvCalorimeterHitData.so\")") ;
c->SetProof() ;
c->Process("MySelector.C+") ;
}
Question 1 : Is the Loading of the .so libraries correctly performed in PROOF ? If no, what is the method to proceed ?
The MySelector.h which was first generated using MakeSelector and then modified:
//////////////////////////////////////////////////////////
// This class has been automatically generated on
// Wed Oct 8 10:10:02 2014 by ROOT version 5.34/18
// from TTree DosimConvtree/
// found on file: ../root/Converter_Dosimeter_NoPhantom_neutron_norminc_PhysList_I_2MEvts/converter_dosimeter_neutron_144keV_norminc.root
//////////////////////////////////////////////////////////
// This class is modified mostly in the Init part for branches
// and pointer initialization
#ifndef MySelector_h
#define MySelector_h
#include <TROOT.h>
#include <TChain.h>
#include <TTree.h>
#include <TFile.h>
#include <TSelector.h>
#include <TH1D.h>
#include <TH2D.h>
#include <TObject.h>
#include <iostream>
// Header file for the classes stored in the TTree if any.
#include "/projet/simu-dosim/geant4/RootObject/DosimConvEvent.h"
#include "/projet/simu-dosim/geant4/RootObject/DosimConvCryst.h"
// My personnal add
#include <TClonesArray.h>
// Fixed size dimensions of array or collections stored in the TTree if any.
const Int_t kMaxfCrystals = 1;
//const Int_t kMaxfCrystals = 1;
class MySelector : public TSelector {
public :
TChain* fChain; //!pointer to the analyzed TTree or TChain
// Declaration of leaf types
//DosimConvEvent *DosimEventBranch;
DosimConvEvent* fdosimevt ;
//DosimConvEvent *ConvEventBranch;
DosimConvEvent* fconvevt ;
// TClonesArray
TClonesArray* fcrystalsconv ;
TClonesArray* fcrystalsdosim ;
// List of branches
TBranch* fbranchconv; //!
TBranch* fbranchdosim; //!
// Number of root files (and thus histograms) to read
Int_t fnfile ;
// Index for following reading file process
Int_t findex ;
// Number of events in a Tree for each run
Int_t* fnevent ;
// Table of histograms
TH1D** fhconv ;
TH1D** fhdosim ;
TH1D** fhtot ;
TH2D** fh2D ;
// Initial energy table
Double_t* fetotinit ;
//Tables for efficiency assessment
Int_t* fnexit ;
Int_t* fnexitconv ;
Int_t* fnexitdosim ;
Double_t* fzerorate ;
Double_t* fzerorateconv ;
Double_t* fzeroratedosim ;
MySelector(TTree * /*tree*/ =0) : fChain(0), fdosimevt(0), fconvevt(0), fcrystalsconv(0), fcrystalsdosim(0), fbranchconv(0), fbranchdosim(0), fnfile(0), findex(-1), fnevent(0), fhconv(0), fhdosim(0), fhtot(0), fh2D(0), fetotinit(0), fnexit(0), fnexitconv(0), fnexitdosim(0), fzerorate(0), fzerorateconv(0), fzeroratedosim(0) { }
virtual ~MySelector() ;
virtual Int_t Version() const { return 2; }
virtual void Begin(TTree *tree);
virtual void SlaveBegin(TTree *tree);
virtual void Init(TTree *tree);
virtual Bool_t Notify();
virtual Bool_t Process(Long64_t entry);
virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; }
virtual void SetOption(const char *option) { fOption = option; }
virtual void SetObject(TObject *obj) { fObject = obj; }
virtual void SetInputList(TList *input) { fInput = input; }
virtual TList *GetOutputList() const { return fOutput; }
virtual void SlaveTerminate();
virtual void Terminate();
ClassDef(MySelector,0);
};
#endif
#ifdef MySelector_cxx
void MySelector::Init(TTree *tree)
{
// The Init() function is called when the selector needs to initialize
// a new tree or chain. Typically here the branch addresses and branch
// pointers of the tree will be set.
// It is normally not necessary to make changes to the generated
// code, but the routine can be extended by the user if needed.
// Init() will be called many times when running on PROOF
// (once per file to be processed).
// Set branch addresses and branch pointers
if (!tree) return;
fChain = tree;
fChain->SetMakeClass(1);
findex++ ;
if (findex < 0) return ;
fnevent[findex]= fChain->GetEntries() ;
fconvevt= new DosimConvEvent(kMaxfCrystals) ;
fdosimevt= new DosimConvEvent(kMaxfCrystals) ;
fcrystalsconv= fconvevt->GetCrystals() ;
fcrystalsdosim= fdosimevt->GetCrystals() ;
fbranchconv= fChain->GetBranch("ConvEventBranch") ;
fbranchdosim= fChain->GetBranch("DosimEventBranch") ;
fbranchconv->SetAddress(&fconvevt) ;
fbranchdosim->SetAddress(&fdosimevt) ;
}
Bool_t MySelector::Notify()
{
// The Notify() function is called when a new file is opened. This
// can be either for a new TTree in a TChain or when when a new TTree
// is started when using PROOF. It is normally not necessary to make changes
// to the generated code, but the routine can be extended by the
// user if needed. The return value is currently not used.
cout << "**********************************************" << endl ;
cout << "Reading file: " << fChain->GetFile()->GetName() << endl ;
cout << "File index: " << findex << endl ;
cout <<"Number of Events " << fnevent[findex] << endl ;
return kTRUE;
}
#endif // #ifdef MySelector_cxx
The MySelector.C file was generated the same way and then modified:
#define MySelector_cxx
// The class definition in MySelector.h has been generated automatically
// by the ROOT utility TTree::MakeSelector(). This class is derived
// from the ROOT class TSelector. For more information on the TSelector
// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.
// The following methods are defined in this file:
// Begin(): called every time a loop on the tree starts,
// a convenient place to create your histograms.
// SlaveBegin(): called after Begin(), when on PROOF called only on the
// slave servers.
// Process(): called for each event, in this function you decide what
// to read and fill your histograms.
// SlaveTerminate: called at the end of the loop on the tree, when on PROOF
// called only on the slave servers.
// Terminate(): called at the end of the loop on the tree,
// a convenient place to draw/fit your histograms.
//
// To use this file, try the following session on your Tree T:
//
// Root > T->Process("MySelector.C")
// Root > T->Process("MySelector.C","some options")
// Root > T->Process("MySelector.C+")
//
#include "MySelector.h"
#include <TStyle.h>
#include <TROOT.h>
#include <TH1D.h>
#include <TH2D.h>
#include <TCanvas.h>
#include <TChain.h>
#include <TTree.h>
#include <TPaveText.h>
#include <TPaveStats.h>
MySelector::~MySelector() {
if(fnexit) delete [] fnexit ;
if(fnexitconv) delete [] fnexitconv ;
if(fnexitdosim) delete [] fnexitdosim ;
if(fzerorate) delete [] fzerorate ;
if(fzerorateconv) delete [] fzerorateconv ;
if(fzeroratedosim) delete [] fzeroratedosim ;
if(fetotinit) delete [] fetotinit ;
}
void MySelector::Begin(TTree * /*tree*/)
{
// The Begin() function is called at the start of the query.
// When running with PROOF Begin() is only called on the client.
// The tree argument is deprecated (on PROOF 0 is passed).
TString option = GetOption();
}
void MySelector::SlaveBegin(TTree * /*tree*/)
{
// The SlaveBegin() function is called after the Begin() function.
// When running with PROOF SlaveBegin() is called on each slave server.
// The tree argument is deprecated (on PROOF 0 is passed).
TString option = GetOption();
//Int_t ifile=0 ;
// Search the number of files in fChain
//TObjArray *fileElements=fChain->GetListOfFiles();
//TIter next(fileElements);
//TChainElement *chEl=0;
// while (( chEl=(TChainElement*)next() )) {
// // TFile f(chEl->GetTitle());
// // ... do something with f ...
// cout << "ROOT files to be read " << chEl->GetTitle << endl ;
// ifile++ ;
// }
// Get Number of Root files in TChain c
fnfile= fChain->GetNtrees() ;
const Int_t nfile= static_cast<const Int_t>(fnfile) ;
if((nfile >3) || (nfile ==0) ) {
cout << "Number of files to be read is < 3 or =0 : " << nfile << endl;
Abort("Number of files to be read is < 3 or =0") ;
}
//Efficiency counters
fnexit = new Int_t[nfile] ;
fnexitconv= new Int_t[nfile] ;
fnexitdosim= new Int_t[nfile] ;
for(Int_t in=0;in<nfile;in++) {
fnexit[in]=0 ;
fnexitconv[in]=0 ;
fnexitdosim[in]=0 ;
}
fzerorate = new Double_t[nfile] ;
fzerorateconv = new Double_t[nfile] ;
fzeroratedosim = new Double_t[nfile] ;
for(Int_t iz=0;iz<nfile;iz++) {
fzerorate[iz]=0. ;
fzerorateconv[iz]=0. ;
fzeroratedosim[iz]=0. ;
}
fnevent = new Int_t[nfile] ;
// Histograms parameters
char* titlehisto[nfile]={"n 144keV","n 5MeV", "n 14.8MeV" } ;
// Init initial energy table
fetotinit= new Double_t[nfile] ;
fetotinit[0]=0.144 ;
fetotinit[1]=5.0 ;
fetotinit[2]=14.8 ;
Double_t convmin[nfile] ;
Int_t convbin[nfile] ;
for(Int_t iconv=0;iconv<nfile;iconv++) {
convmin[iconv]=1e-3 ;
convbin[iconv]=1000 ;
}
Double_t convmax[nfile]={0.15, 6.0, 16.0} ;
Double_t dosimmin[nfile] ;
Int_t dosimbin[nfile] ;
for(Int_t idosim=0;idosim<nfile;idosim++) {
dosimmin[idosim]=1.0e-3 ;
dosimbin[idosim]=1000 ;
}
Double_t dosimmax[nfile]={0.15, 6.0, 16.0} ;
Double_t etotmin[nfile] ;
Int_t etotbin[nfile] ;
for(Int_t ietot=0;ietot<nfile;ietot++) {
etotmin[ietot]=1.0e-3 ;
etotbin[ietot]=1000 ;
}
Double_t etotmax[nfile]={0.15, 6.0, 16.0} ;
Double_t rxmin=1.0e-3 ;
char name1[40], name2[40], name3[40], name4[40] ;
fhconv = new TH1D*[nfile] ; // Histogram table for Energy in Converter
fhdosim= new TH1D*[nfile] ; // Histogram table for Energy in Dosimeter
fhtot=new TH1D*[nfile] ; // Histogram for Total Energy (Converter+Dosimeter)
fh2D= new TH2D*[nfile] ; // Histogram table for Energy 2D
for(Int_t iii=0;iii<nfile;iii++) { // Begin Init histo table
sprintf(name1,"Conv%d",iii+1) ;
sprintf(name2,"Dosim%d",iii+1) ;
sprintf(name3,"Conv+Dosim%d",iii+1);
sprintf(name4,"Bidim%d",iii+1);
fhconv[iii]= new TH1D(name1,titlehisto[iii],convbin[iii], convmin[iii], convmax[iii]) ;
fhconv[iii]->SetFillColor(0) ;
fhconv[iii]->SetLineColor(1) ;
fhconv[iii]->GetXaxis()->SetTitle("E_{Conv}(MeV)") ;
fhconv[iii]->GetXaxis()->SetTitleOffset(1.3) ;
fhconv[iii]->GetXaxis()->SetRangeUser(rxmin,convmax[iii]) ;
fhconv[iii]->GetYaxis()->SetTitle("Counts") ;
fhconv[iii]->GetYaxis()->SetTitleOffset(1.4) ;
fhconv[iii]->GetYaxis()->SetRangeUser(0.1,1000000) ;
fhdosim[iii]= new TH1D(name2,titlehisto[iii],dosimbin[iii], dosimmin[iii], dosimmax[iii]) ;
fhdosim[iii]->SetFillColor(0) ;
fhdosim[iii]->SetLineColor(1) ;
fhdosim[iii]->GetXaxis()->SetTitle("E_{Dosim}(MeV)") ;
fhdosim[iii]->GetXaxis()->SetTitleOffset(1.3) ;
fhdosim[iii]->GetXaxis()->SetRangeUser(rxmin,dosimmax[iii]) ;
fhdosim[iii]->GetYaxis()->SetTitle("Counts") ;
fhdosim[iii]->GetYaxis()->SetTitleOffset(1.4) ;
fhdosim[iii]->GetYaxis()->SetRangeUser(0.1,1000000) ;
fhtot[iii]= new TH1D(name3,titlehisto[iii],etotbin[iii], etotmin[iii], etotmax[iii]) ;
fhtot[iii]->SetFillColor(0) ;
fhtot[iii]->SetLineColor(1) ;
fhtot[iii]->GetXaxis()->SetTitle("E_{Dosim}(MeV)") ;
fhtot[iii]->GetXaxis()->SetTitleOffset(1.3) ;
fhtot[iii]->GetXaxis()->SetRangeUser(rxmin,etotmax[iii]) ;
fhtot[iii]->GetYaxis()->SetTitle("Counts") ;
fhtot[iii]->GetYaxis()->SetTitleOffset(1.4) ;
fhtot[iii]->GetYaxis()->SetRangeUser(0.1,1000000) ;
fh2D[iii]= new TH2D(name4,titlehisto[iii] ,convbin[iii],convmin[iii],convmax[iii],dosimbin[iii],dosimmin[iii],dosimmax[iii] ) ;
fh2D[iii]->SetFillColor(0) ;
fh2D[iii]->GetXaxis()->SetTitle("E_{Conv}(MeV)") ;
fh2D[iii]->GetXaxis()->SetLabelSize(0.037) ;
fh2D[iii]->GetYaxis()->SetTitle("E_{Dosim}(MeV)") ;
fh2D[iii]->GetYaxis()->SetTitleOffset(1.26) ;
fh2D[iii]->GetYaxis()->SetLabelSize(0.037) ;
// Adding histograms in the output list
GetOutputList()->Add(fhconv[iii]) ;
GetOutputList()->Add(fhdosim[iii]) ;
GetOutputList()->Add(fhtot[iii]) ;
GetOutputList()->Add(fh2D[iii]) ;
}
}
Bool_t MySelector::Process(Long64_t entry)
{
// The Process() function is called for each entry in the tree (or possibly
// keyed object in the case of PROOF) to be processed. The entry argument
// specifies which entry in the currently loaded tree is to be processed.
// It can be passed to either MySelector::GetEntry() or TBranch::GetEntry()
// to read either all or the required parts of the data. When processing
// keyed objects with PROOF, the object is already loaded and is available
// via the fObject pointer.
//
// This function should contain the "body" of the analysis. It can contain
// simple or elaborate selection criteria, run algorithms on the data
// of the event and typically fill histograms.
//
// The processing can be stopped by calling Abort().
//
// Use fStatus to set the return value of TTree::Process().
//
// The return value is currently not used.
Double_t etotconv, etotdosim, etot ;
Int_t nb;
nb = MySelector::GetEntry(entry) ;
if(findex < 0) {
cout << "FATAL ERROR on findex, findex == " << findex << endl ;
Abort("FATAL ERROR on findex") ;
}
etotconv=fconvevt->GetEtot() ;
fhconv[findex]->Fill(etotconv) ;
etotdosim=fdosimevt->GetEtot() ;
fhdosim[findex]->Fill(etotdosim) ;
fh2D[findex]->Fill(etotconv,etotdosim) ;
etot=etotconv+etotdosim ;
fhtot[findex]->Fill(etot) ;
if(etotconv<(0.001*fetotinit[findex])) fnexitconv[findex]++ ;
if(etotdosim<(0.001*fetotinit[findex])) fnexitdosim[findex]++ ;
if(etot<(0.001*fetotinit[findex])) fnexit[findex]++ ;
return kTRUE;
}
void MySelector::SlaveTerminate()
{
// The SlaveTerminate() function is called after all entries or objects
// have been processed. When running with PROOF SlaveTerminate() is called
// on each slave server.
}
void MySelector::Terminate()
{
// The Terminate() function is the last function to be called during
// a query. It always runs on the client, it can be used to present
// the results graphically or save the results to file.
TCanvas* c1= new TCanvas("c1", "Energy Converter", 700, 700) ;
c1->SetFillColor(0) ;
c1->Divide(2,2) ;
TCanvas* c2= new TCanvas("c2", "Energy Dosimeter", 700, 700) ;
c2->SetFillColor(0) ;
c2->Divide(2,2) ;
TCanvas* c3= new TCanvas("c3", "Sum of energy in Converter and energy in Dosimeter", 700, 700) ;
c3->SetFillColor(0) ;
c3->Divide(2,2) ;
TCanvas* c4= new TCanvas("c4", "Energy in Dosimeter vs energy in Converter", 1300, 1000) ;
c4->SetFillColor(0) ;
c4->Divide(2,2) ;
//NEED TO MAKE A LOOP ON ALL FILES
for(Int_t ifile=0;ifile<fnfile;ifile++) {
// Calculated zero rates
fzerorateconv[ifile]= ((Double_t)(fnexitconv[ifile])/(Double_t)(fnevent[ifile]))*100. ;
fzeroratedosim[ifile]= ((Double_t)(fnexitdosim[ifile])/(Double_t)(fnevent[ifile]))*100. ;
fzerorate[ifile]= ((Double_t)(fnexit[ifile])/(Double_t)(fnevent[ifile]))*100. ;
char bufferconv[250] ;
sprintf(bufferconv,"NI percent: %.1f ",fzerorateconv[ifile]) ;
char bufferdosim[250] ;
sprintf(bufferdosim,"NI percent: %.1f ",fzeroratedosim[ifile]) ;
char buffer[250] ;
sprintf(buffer,"NI percent: %.1f ",fzerorate[ifile]) ;
cout << "********************" << endl ;
cout << "File index: " << ifile << endl ;
cout << "Converter " << bufferconv << endl ;
cout << "Dosimeter " << bufferdosim << endl ;
cout << "Total " << bufferdosim << endl ;
c1->cd(ifile+1) ;
(c1->cd(ifile+1))->SetFrameFillColor(0) ;
//cout << "OK" << endl ;
gPad->SetLogy() ;
gPad->SetLogx() ;
fhconv[ifile]->Draw() ;
//TPaveText* ptzc= new TPaveText(etotmax[ifile]/8.,5e4,3.*etotmax[ifile]/4.,5e5,"t") ;
TPaveText* ptzc= new TPaveText(1e-5, 1e3, 3e-4, 2e5,"t") ;
ptzc->SetFillColor(0) ;
ptzc->AddText(bufferconv) ;
ptzc->SetTextSize(0.05) ;
//ptzc->Draw("SAME") ;
c2->cd(ifile+1) ;
(c2->cd(ifile+1))->SetFrameFillColor(0) ;
gPad->SetLogy() ;
gPad->SetLogx() ;
fhdosim[ifile]->Draw() ;
//TPaveText* ptzd= new TPaveText(etotmax[ifile]/8.,5e4,3.*etotmax[ifile]/4.,5e5,"t") ;
TPaveText* ptzd= new TPaveText(1e-5, 1e3, 3e-4, 2e5,"t") ;
ptzd->SetFillColor(0) ;
ptzd->AddText(bufferdosim) ;
ptzd->SetTextSize(0.05) ;
//ptzd->Draw("SAME") ;
c3->cd(ifile+1) ;
(c3->cd(ifile+1))->SetFrameFillColor(0) ;
gPad->SetLogy() ;
gPad->SetLogx() ;
fhtot[ifile]->Draw() ;
//TPaveText* ptz= new TPaveText(etotmax[ifile]/8.,5e4,3.*etotmax[ifile]/4.,5e5,"t") ;
TPaveText* ptz= new TPaveText(1e-5, 1e3, 3e-4, 2e5,"t") ;
ptz->SetFillColor(0) ;
ptz->AddText(buffer) ;
ptz->SetTextSize(0.05) ;
//ptz->Draw("SAME") ;
c4->cd(ifile+1) ;
(c4->cd(ifile+1))->SetFrameFillColor(0) ;
gPad->SetLogz() ;
//if(ifile>1) {
fh2D[ifile]->Draw("COLZ") ;
//}
//else {
//h2D->Draw("COL") ;
//}
c4->cd(ifile+1)->Update() ;
TPaveStats *st= (TPaveStats*)fh2D[ifile]->FindObject("stats") ;
st->SetX1NDC(0.52) ;
st->SetX2NDC(0.78) ;
st->SetY1NDC(0.62) ;
st->SetY2NDC(0.88) ;
fh2D[ifile]->Draw("COLZ") ;
} // end loop on ifile
c1->cd(4) ;
TPaveText* pt1= new TPaveText(0.05,0.05,0.95,0.95) ;
pt1->SetFillColor(0) ;
pt1->AddText("Converter 19x9x1 mm^{3}: G4_POLYETHYLENE") ;
pt1->AddText("Dosimeter 19x9x1 mm^{3} : Allyl Diglycol Carbonate") ;
pt1->AddText("Geant4 9.6p03") ;
pt1->AddText("Hadrons: FTFP_BERT_HP, Elastic_HP + Thermal, G4NDL4.2") ;
pt1->AddText("Elecmg: Penelope G4EMLOW6.32") ;
pt1->AddText("Radioactive Decay Physics") ;
pt1->SetLabel("Neutron,90^{o} on Converter center") ;
// pt1->SetLabel("#gamma,Random Emission") ;
//TText* txt1=pt1->AddText("Germanium: R=44m L=70mm") ;
//TText* txt0=pt1->AddText("BGO: R_{min}=44mm,R_{max}=53mm, L=300mm") ;
//txt1->SetTextSize(0.05) ;
//txt0->SetTextSize(0.05) ;
//pt1->SetTextSize(0.7) ;
pt1->Draw();
c2->cd(4) ;
pt1->Draw() ;
c3->cd(4) ;
pt1->Draw() ;
c4->cd(4) ;
pt1->Draw() ;
}
My goal is to read each tree of the three root files and fill several histogram tables. Each histogram of a histogram table must contains data from one root file.
When I compile I launch the analyse_multipleruns_proof.C macro I have the following message:
Question 2: I need to access in the SlaveBegin() function the number of trees (thus of files) contained in the TChain to define my tables. But the fChain variable is seen as a TTree and not a TChain. How can I do then ?
Question 3: The compiler seems to refuse the way titlehisto, convmax, dosimmax and etotmax are initialized. Is it related to the problem seen in question 2 ?
Question 4: I would like to print out the root file name in Notify(), but as in question 2, fChain is viewed as a TTree and not a TChain. How can I do then ?
Many thanks for your help !