Method to read a chain of trees with TSelector and TProof

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 ? #-o

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 !

Hi,

You have to use TProof::Load to load libraries or code in PROOF (both on the worker processes and the local ROOT session). Make sure that the env DIRDOSIMG4 is defined in the worker processes. You can use TProof::AddEnvVar to define envs in the worker processes. If you have many thinks to load, a better option could an empty PAR file which only loads things in its SETUP.C macro; see root.cern.ch/drupal/content/prep … l-software .

(Your compilation fails. I suggest you give a try with TSelector::GetSelector first, to check that your selector compiles: root [] TSelector *s = TSelector::GetSelector("MySelector.C+") )

The tree to be processed is only available during Process. The Init(Tree *) function of your selector is called for each new open file. I know that in the local processing case the tree is also available at Begin, but this is not possible in PROOF.
Also, the idea of knowing the number number of files (not of trees: it is the same tree stored in many files) is sort of against the concept of PROOF. One of the assumptions of PROOF is that the number of files and the order in which the events are processed does not matter.
You would like to keep the results of each file separated, right? Sort of different analysis in one?
Perhaps you should have your histogram tables as lists and add a new entry in Init, when a new file is open.

It refuses because nfile is only defined at compile time. If you know it is 3, you just set it to 3. But the need to set by hand the number of files shows that probably the problem is ill formulated.
Note that you have also an error from a missing cast in init: TChain is more that TTree, you cannot just set the two pointers equal. But, again, why do you need to work with a TChain here? Just for the number of files?

With the TTree this works and is commonly used:

  Info("Notify","processing file: %s",tree->GetCurrentFile()->GetName()); 

Again, I think you need to rethink the formulation of your problem so that you do not need to access the TChain object from inside your analysis flow.

Hope it helps.

G.Ganis

Dear Ganis,

thanks a lot for your reply.

Concerning question 1, I successfully created a PAR archive containing my classes and the created libraries, together with the BUILD.SH and the SETUP.C files. I made some modifications in the MySelector.C file et MySelector.h to read only one .root file, thus the tables size is 1.

The analysis_multiple_runs.C macro used to launch PROOF is currently the following:

#include <iostream.h>

void analyse_multipleruns_proof() {

  TChain* c= new TChain("DosimConvtree") ;
 
  //gSystem->Load("$DIRDOSIMG4/RootObject/libDosimConvEvent.so") ;
  //gSystem->Load("$DIRDOSIMG4/RootObject/libDosimConvCalorimeterHitData.so") ;
  
  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() ;


  //TFile* f= TFile::Open("../root/Converter_Dosimeter_NoPhantom_neutron_norminc_PhysList_I_2MEvts/converter_dosimeter_neutron_144keV_norminc.root") ;
  
  // f->MakeProject("packages/dosimconvevent","*","par") ;

   TProof* p=TProof::Open("") ;

   //p->Exec("gSystem->Load(\"$DIRDOSIMG4/RootObject/libDosimConvEvent.so\")") ;
   //p->Exec("gSystem->Load(\"$DIRDOSIMG4/RootObject/libDosimConvCalorimeterHitData.so\")") ;

  p->UploadPackage("packages/dosimconvevent.par");
  //p->Exec(".! tar -zxvf packages/dosimconvevent.par", kTRUE) ;
  p->EnablePackage("dosimconvevent");
  Printf("Enabled packages...\n");
  p->ShowEnabledPackages() ;
  //p->Load("packages/dosimconvevent/libDosimConvEvent.so") ;
  //p->Load("packages/dosimconvevent/libDosimConvCalorimeterHitData.so") ;
  c->SetProof() ;
  c->Process("MySelector.C+") ;



}

When launching it, the compilation seems fine and the two needed libraries are created

The MySelector.h is now:

//////////////////////////////////////////////////////////
// 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 "DosimConvEvent.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 :
   TTree*          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

and MySelector.C is:

#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>
#include "DosimConvEvent.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();

   // Info("Slave Begin","Begin MySelector::SlaveBegin(TTree * /*tree*/)") << endl ;

   //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
	      // if(fChain) {
	      //fnfile= fChain->GetNtrees() ;
    
	      //}  

   // 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") ;

   //}

   //const Int_t nfile= static_cast<const Int_t>(fnfile) ;
   const Int_t nfile =1 ;
   //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[1]={"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+2]={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+2]={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+2]={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]) ;

    
   
   } 

  cout << "End MySelector::SlaveBegin(TTree * /*tree*/)" << endl ;
  
  

}

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]++ ;
    
  Printf("MySelector::Process(Long64_t entry)\n") ;

   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) ;
  

  for(Int_t ifile=0;ifile<1;ifile++) {

    // Calculated zero rates
    cout << "Calculate zero rates " << endl ;
    cout << "ifile = " << ifile << endl ;
    cout << "fnexitconv[ifile] =" << fnexitconv[ifile] << endl ;
    cout << "fnevent[ifile] =" << fnevent[ifile] << endl ;
       fzerorateconv[ifile]= ((Double_t)(fnexitconv[ifile])/(Double_t)(fnevent[ifile]))*100. ;
       cout << "fzerorateconv[ifile]= " <<  fzerorateconv[ifile] << endl ;
    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 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() ;

    


}

The analysis launches but it crashes, producing the following output:

I tried to debug it by adding some screen printing with cout but it works only in Terminate because only the lines

cout << "Calculate zero rates " << endl ; cout << "ifile = " << ifile << endl
are visible in the error output message (I oulined them in red in the Quote part above).

Question 1: The cout instruction does not work in Begin(), Init() and Process() parts of the Selector How can I print messages on-screen then ?

Question 2: It looks like the crash occurs in the Terminal part and is related to variables fnexitconv[ifile], fnexitdosim[ifile] and fnexit[ifile] calculated in the Process(). Is it due to a bad merging of these variables at the end ? How to correct that ?

Many thanks for your help,

Dear Ganis,

I found out the answer to question 1. I modified in the analysis_multiple_runs_proof to use the Proof Manager

p->UploadPackage("packages/dosimconvevent.par");
  //p->Exec(".! tar -zxvf packages/dosimconvevent.par", kTRUE) ;
  p->EnablePackage("dosimconvevent");
  Printf("Enabled packages...\n");
  p->ShowEnabledPackages() ;
  //To retrieve log files
  TProofMgr* mgr=p->GetManager() ;
  TProofLog* log=mgr->GetSessionLogs() ;
  TString log_file_name="log_workers.txt" ;
  Int_t flag=log->Save("*",log_file_name) ;
  
  //p->Load("packages/dosimconvevent/libDosimConvEvent.so") ;
  //p->Load("packages/dosimconvevent/libDosimConvCalorimeterHitData.so") ;
  c->SetProof() ;
  c->Process("MySelector.C+") ;

After running, the generated log_workers.txt file contains the path to the log file on each worker. The cout printing put in the MySelector files appear. I put below the output corresponding to Worker 0:

The other files are roughly similar. I outline in [color=#0040FF]Blue some cout printing I include in the MySelector files[/color]. It looks like the crash does not occur in SlaveBegin(), nor in Init(). Processing looks also fine since the Terminate() process is reached if I am not mistaken. Since no printing out added in Terminate() is in the log files , I strongly suspect that the crash occurs there. Beside, [color=#FF0000]an error message I outlined in red [/color] is visible and is the same on all workers but I do not understand its meaning. Could you help me, please ?

Cheers,

Hi,

In PROOF the workers a physically separated processes. In the case of PROOF-lite, the one of yours, you have your local process, the ROOT session where you issue the commands and run your steering macro, and N workers processes, communicating via unix sockets.

Now, SlaveBegin, Process, SlaveTerminate are only executed on the workers, so the print-outs you put there go into the log files of those processes, as you have found out.

Output objects are created on the workers and sent back to the steering process where they are merged and stored in the output list. In general there is no way to attach them automatically to members of the selector (there is one, actually, but it works only for simple members); so, what you have to do in Terminate is to retrieve from the OutputList the objects that you need. In your case all the histograms tables that you have put there. You can use fOutputList->FindObject("name_of_obj")
and cast it to the type of you object.

Hope it helps.

G. Ganis

Dear Gerardo,

I think I have found out why the program crashes but I do not still have found how to correct it. It seems to be in the final merging of my histograms and counters of interest.

The current version of MySelector.h is:

//////////////////////////////////////////////////////////
// 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 "DosimConvEvent.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 :
   TTree*          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).

  cout << "Begin : MySelector::Init(TTree *tree)" << endl ;

   // Set branch addresses and branch pointers
   if (!tree) return;
   fChain = tree ;
   fChain->SetMakeClass(1);

   findex++ ;

   if (findex < 0) return ;
   
   fnevent[findex]= fChain->GetEntries() ;
   cout << "fnevent[findex] = " << fnevent[findex] << endl ; 

   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) ;

    cout << "End : MySelector::Init(TTree *tree)" << endl ;
   
}

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

MySelector.C is the following:

#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>
#include "DosimConvEvent.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).


  cout << "Begin : MySelector::SlaveBegin(TTree * /*tree*/)" << endl ;
   TString option = GetOption();

   // Info("Slave Begin","Begin MySelector::SlaveBegin(TTree * /*tree*/)") << endl ;

   //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
	      // if(fChain) {
	      //fnfile= fChain->GetNtrees() ;
    
	      //}  

   // 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") ;

   //}

   //const Int_t nfile= static_cast<const Int_t>(fnfile) ;
   const Int_t nfile =1 ;
   //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] ;
    for(Int_t ie=0;ie<nfile;ie++) {
      fnevent[ie]=0 ;
    }
     
    // Histograms parameters

    char* titlehisto[1]={"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+2]={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+2]={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+2]={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

    fOutput->Add(fhconv[iii]) ;
    fOutput->Add(fhdosim[iii]) ;
    fOutput->Add(fhtot[iii]) ;
    fOutput->Add(fh2D[iii]) ;

    
   
   } 

  cout << "End MySelector::SlaveBegin(TTree * /*tree*/)" << endl ;
  
  

}

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) ;

  // cout << "Begin MySelector::Process(Long64_t entry)" << endl ;

  if(findex < 0) {
    cout << "FATAL ERROR on findex, findex == " << findex << endl ;
    Abort("FATAL ERROR on findex") ;
  }


  //cout << "findex = " << findex << endl ;
  

  etotconv=fconvevt->GetEtot() ;
  if(fhconv[findex]) fhconv[findex]->Fill(etotconv) ;

  etotdosim=fdosimevt->GetEtot() ;
  if(fhdosim[findex]) fhdosim[findex]->Fill(etotdosim) ;

  if(fh2D[findex]) fh2D[findex]->Fill(etotconv,etotdosim) ;


  etot=etotconv+etotdosim ;
  if(fhtot[findex]) 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]++ ;

  
    
  //cout << "End MySelector::Process(Long64_t entry)" << endl ;


   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.

  cout << "Begin MySelector::SlaveTerminate()" << endl ;
  cout << "findex " << findex << endl ;
  cout << "fnevent[findex] " << fnevent[findex] << endl ;
  cout << "fnexitconv[findex] " << fnexitconv[findex] << endl ;
  cout << " fnexitdosim[findex] " <<  fnexitdosim[findex] << endl ;
   cout << " fnexit[findex] " <<  fnexit[findex] << endl ;

  cout << "End MySelector::SlaveTerminate()" << endl ;
  

}

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.

  cout << endl  ;
  cout << endl ;

   cout << "Begin  MySelector::Terminate()" << endl ;
   cout << "findex = " << findex << endl ;
  
   fhconv[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Conv1"));

cout << "Conv1 found !!" << endl ;
fhdosim[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Dosim1"));
cout << "Dosim1 found !!" << endl ;

  fhtot[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Conv+Dosim1"));
cout << "Conv+Dosim1 found !!" << endl ;
  fh2D[0] = dynamic_cast<TH2D*>(fOutput->FindObject("Bidim1"));
   cout << "Bidim1 found !!" << endl ;
 

  if ( (fhconv[0] == 0) || (fhdosim[0]==0) || (fhtot[0]==0) || (fh2D[0] == 0)) {
    cout << "ERROR : Histogram(s) missing !!!! " << endl ;
    return ;
  }
  
  

 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) ;
  

  for(Int_t ifile=0;ifile<1;ifile++) {
    cout << "In Loop on files" << endl ;
    // Calculated zero rates
    cout << "Calculate zero rates " << endl ;
    cout << "ifile = " << ifile << endl ;
    //  cout << "fnexitconv[ifile] =" << fnexitconv[ifile] << endl ;
    //cout << "fnevent[ifile] =" << fnevent[ifile] << endl ;
    //      fzerorateconv[ifile]= ((Double_t)(fnexitconv[ifile])/(Double_t)(fnevent[ifile]))*100. ;
    //       cout << "fzerorateconv[ifile]= " <<  fzerorateconv[ifile] << endl ;
    //    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 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() ;

    


}

The analysis_multipleruns_proof.C file is the same than in my previous post.

The message on screen is the following:

The crash occurs in the Terminate() part (see part in red corresponding to the visible print out) where I certainly do not merge correctly my histograms , although I put an Add instruction in the SlaveBegin() part.
The FindOject() instruction, completed with a dynamic cast , crashes the program. What surprises me also is that the findex variable which is incremented in the Init() part from -1 to 0, is equal to 0 during the whole Process() but is back to -1 in Terminate() !!

Question 1:: Is it normal that 1 worker is still sending data when Terminate() starts ?

Question 2: How can I do to get the merged histograms since the Add() instructions in SlaveBegin() and the FindObject() in Terminate() does not work ?

Question 3: The counters fnexitconv, fnexitdosim, fnexit are calculated on each worker. How can I do to get the values calculated on each worker to finally sum them ?

Question 4:: Why is findex back to -1 in the Terminate Part whereas it is incremented in Init() ? How can I fix that ?

Hello,

I think I found out the answer to the question 2 of my former post. The crash in MySelector.C was due to :

fhconv[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Conv1"));

So I commented this line and wrote:

//fhconv[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Conv1"));
TH1D* hc =  dynamic_cast<TH1D*>(fOutput->FindObject("Conv1"));

It looks like that the crash is triggered by an attempt to simultaneously access and write on the memory of the same object. I did the same corrections for the other histograms I want to get from the output list.

So the corrected MySelector.C file is now the following:

#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>
#include "DosimConvEvent.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).


  cout << "Begin : MySelector::SlaveBegin(TTree * /*tree*/)" << endl ;
   TString option = GetOption();

   // Info("Slave Begin","Begin MySelector::SlaveBegin(TTree * /*tree*/)") << endl ;

   //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
	      // if(fChain) {
	      //fnfile= fChain->GetNtrees() ;
    
	      //}  

   // 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") ;

   //}

   //const Int_t nfile= static_cast<const Int_t>(fnfile) ;
   const Int_t nfile =1 ;
   //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] ;
    for(Int_t ie=0;ie<nfile;ie++) {
      fnevent[ie]=0 ;
    }
     
    // Histograms parameters

    char* titlehisto[1]={"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+2]={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+2]={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+2]={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

    fOutput->Add(fhconv[iii]) ;
    fOutput->Add(fhdosim[iii]) ;
    fOutput->Add(fhtot[iii]) ;
    fOutput->Add(fh2D[iii]) ;

    
   
   } 

  cout << "End MySelector::SlaveBegin(TTree * /*tree*/)" << endl ;
  
  

}

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.
  //cout << "Begin MySelector::Process(Long64_t entry)" << endl ;
  Double_t etotconv, etotdosim, etot ; 
  
  Int_t nb;
  //nb = MySelector::GetEntry(entry) ;
  nb= fChain->GetTree()->GetEntry(entry) ;
  //cout << "nb = " << nb << endl ;

  if(findex < 0) {
    cout << "FATAL ERROR on findex, findex == " << findex << endl ;
    Abort("FATAL ERROR on findex") ;
  }


  //cout << "findex = " << findex << endl ;
  

  etotconv=fconvevt->GetEtot() ;
  //if(fconvevt) fconvevt->Print() ;
  //if(etotconv > 1.e-3) cout << "Etot in Conv = " << etotconv << " MeV" << endl ;
  if(fhconv[findex]) fhconv[findex]->Fill(etotconv) ;

  etotdosim=fdosimevt->GetEtot() ;
  if(fhdosim[findex]) fhdosim[findex]->Fill(etotdosim) ;

  if(fh2D[findex]) fh2D[findex]->Fill(etotconv,etotdosim) ;


  etot=etotconv+etotdosim ;
  if(fhtot[findex]) 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]++ ;

  
    
  //cout << "End MySelector::Process(Long64_t entry)" << endl ;
  //cout << "**************************" << endl ;


   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.

  cout << "Begin MySelector::SlaveTerminate()" << endl ;
  cout << "findex " << findex << endl ;
  cout << "fnevent[findex] " << fnevent[findex] << endl ;
  cout << "fnexitconv[findex] " << fnexitconv[findex] << endl ;
  cout << " fnexitdosim[findex] " <<  fnexitdosim[findex] << endl ;
   cout << " fnexit[findex] " <<  fnexit[findex] << endl ;

  cout << "End MySelector::SlaveTerminate()" << endl ;
  

}

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.

  cout << endl  ;
  cout << endl ;

   cout << "Begin  MySelector::Terminate()" << endl ;
   cout << "findex = " << findex << endl ;
  
   Int_t fs=GetStatus() ;

   if(fs==0) {

     //fhconv[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Conv1"));
     TH1D* hc =  dynamic_cast<TH1D*>(fOutput->FindObject("Conv1"));
     if(hc) cout << "Conv1 found !!" << endl ;
//fhdosim[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Dosim1"));
 TH1D* hd=  dynamic_cast<TH1D*>(fOutput->FindObject("Dosim1"));
 if(hd) cout << "Dosim1 found !!" << endl ;

//fhtot[0] = dynamic_cast<TH1D*>(fOutput->FindObject("Conv+Dosim1"));

  TH1D* ht = dynamic_cast<TH1D*>(fOutput->FindObject("Conv+Dosim1"));
  if (ht) cout << "Conv+Dosim1 found !!" << endl ;
//fh2D[0] = dynamic_cast<TH2D*>(fOutput->FindObject("Bidim1"));
 TH2D* hbidim =  dynamic_cast<TH2D*>(fOutput->FindObject("Bidim1"));
 if(hbidim) cout << "Bidim1 found !!" << endl ;
 

 if ( (!hc) || (!hd) || (!ht) || (!hbidim)) {
    cout << "ERROR : Histogram(s) missing !!!! " << endl ;
    return ;
  }
  
  

 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) ;
  

  for(Int_t ifile=0;ifile<1;ifile++) {
    cout << "In Loop on files" << endl ;
    // Calculated zero rates
    cout << "Calculate zero rates " << endl ;
    cout << "ifile = " << ifile << endl ;
    //  cout << "fnexitconv[ifile] =" << fnexitconv[ifile] << endl ;
    //cout << "fnevent[ifile] =" << fnevent[ifile] << endl ;
    //      fzerorateconv[ifile]= ((Double_t)(fnexitconv[ifile])/(Double_t)(fnevent[ifile]))*100. ;
    //       cout << "fzerorateconv[ifile]= " <<  fzerorateconv[ifile] << endl ;
    //    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 << "Loop 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 1" << endl ;
  gPad->SetLogy() ;
  gPad->SetLogx() ;
  
 
  //fhconv[ifile]->Draw() ;
  hc->Draw() ;
  //cout << "hc drawn !! " << endl ;
  
  //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() ;
  hd->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() ;
  ht->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") ;

  hbidim->Draw() ;
    //}
    //else {
    //h2D->Draw("COL") ;
    //}
  c4->cd(ifile+1)->Update() ;
   
  //TPaveStats *st= (TPaveStats*)fh2D[ifile]->FindObject("stats") ;
  TPaveStats *st= (TPaveStats*)hbidim->FindObject("stats") ;
  st->SetX1NDC(0.52) ;
  st->SetX2NDC(0.78) ;
  st->SetY1NDC(0.62) ;
  st->SetY2NDC(0.88) ;
  //fh2D[ifile]->Draw("COLZ") ;
  hbidim->Draw() ;
  
  } // end loop 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() ;

   } // End if fs


}

In the MySelector.h file I also comment the line:

since I do not want to see the tree branches in decomposed object mode.

The MySelector.h file is then currently:

//////////////////////////////////////////////////////////
// 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 "DosimConvEvent.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 :
   TTree*          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).

  //cout << "Begin : MySelector::Init(TTree *tree)" << endl ;

   // Set branch addresses and branch pointers
   if (!tree) return;
   fChain = tree ;
   //fChain->SetMakeClass(1);

   findex++ ;

   if (findex < 0) return ;
   
   fnevent[findex]= fChain->GetEntries() ;
   cout << "fnevent[findex] = " << fnevent[findex] << endl ; 

   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) ;

   //cout << "End : MySelector::Init(TTree *tree)" << endl ;
   
}

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 << "Begin :  MySelector::Notify() " << endl ;
  
  cout << "Reading file: " << fChain->GetCurrentFile()->GetName() << endl ;
  cout << "File index: " << findex << endl ;
  cout <<"Number of Events " << fnevent[findex] << endl ;

  
  cout << "End :  MySelector::Notify() " << endl ;
   cout << "**********************************************" << endl ;
   return kTRUE;
}

#endif // #ifdef MySelector_cxx

Anyway, I did not find solutions to the questions 1, 3 and 4 of my former post. Do you have any suggestions ?

Many thanks,

Good afternoon,

I found out in the ROOT dosumentation that the template classes TParameter, TParameter … inherit from the TObject class and can be added in a TList. I can thus use such class to merge my counters in the Terminal process.

Cheers,

Hi,

Not really: what makes you think that it happens?

For the remaining questions, it may help to clarify that on the client (local ROOT) session only Begin and Terminate are executed, while SlaveBegin, Process and SlaveTerminate are executed only on the workers.

So

Find object in Terminate works. What happens is that ‘fhconv’ is only defined in SlaveBegin and therefore in Terminate is NULL. If you need to re-use the pointers with the same name in Terminate, to avoid duplications of code I suggest that you create an internal method - e.g. InitHist(Bool_t worker) - where you put all your histogram initialisation stuff (now in SlaveBegin) and you call it in Begin as InitHist(0) and in SlaveBegin as InitHist(1); the boolean should control whether the histograms are added to the output list or not.

You can use TParameter as, I have seen, you have found out. You can control whether the content is added or multiplied at merge. If you want to calculate also averages or RMS, you can use the class TStatistic (see http://root.cern.ch/root/html/TStatistic.html).

For the same reason, you need to put it into a TParameter or TStatistic.

Hope it helps.

G. Ganis