The issue was that retrieving an array of histograms from the selector output list is more complicated than I thought. My original TSelector code was:
TSelector_test.h
#ifndef TSelector_test_h
#define TSelector_test_h
#include "TROOT.h"
#include "TChain.h"
#include "TFile.h"
#include "TSelector.h"
#include "TProofServ.h"
#include "TH1.h"
#include <iostream>
const Int_t kMaxfParticles = 1293;
class TSelector_test : public TSelector {
public :
TTree *fChain; //!pointer to the analyzed TTree or TChain
// Declaration of leaf types
TH1 *fPosX; // X position of the particles
TH1F fIndexHis[4];
// Declaration of leaf types
Int_t Ndata_P_tr_p;
Double_t P_tr_x[kMaxfParticles]; //[fNParticles]
Double_t P_gtr_dp[kMaxfParticles]; //[fNParticles]
Double_t P_hgcer_npe[4];
// List of branches
TBranch *b_Ndata_P_tr_p;
TBranch *b_P_tr_x;
TBranch *b_P_gtr_dp;
TBranch *b_P_hgcer_npe;
TSelector_test(TTree * = 0): fChain(0), fPosX(0), fIndexHis{0,0,0,0} { }
virtual ~TSelector_test() { }
virtual Int_t Version() const { return 2; }
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 Terminate();
ClassDef(TSelector_test,0);
};
#endif
#ifdef TSelector_test_cxx
void TSelector_test::Init(TTree *tree)
{
// Set branch addresses and branch pointers
if (!tree) return;
fChain = tree;
fChain->SetMakeClass(1);
// Connect the branches with their member variables.
tree->SetBranchAddress("Ndata.P.tr.p", &Ndata_P_tr_p, &b_Ndata_P_tr_p);
tree->SetBranchAddress("P.tr.x", P_tr_x, &b_P_tr_x);
tree->SetBranchAddress("P.gtr.dp", &P_gtr_dp, &b_P_gtr_dp);
tree->SetBranchAddress("P.hgcer.npe", &P_hgcer_npe, &b_P_hgcer_npe);
}
Bool_t TSelector_test::Notify()
{
return kTRUE;
}
#endif // #ifdef TSelector_test_cxx
TSelector_test.C
#define TSelector_test_cxx
#include "TSelector_test.h"
#include "TH1.h"
#include "TStyle.h"
void TSelector_test::SlaveBegin(TTree * /*tree*/)
{
TString option = GetOption();
fPosX = new TH1F("hPosX", "Position in X", 20, -5, 5);
// enable bin errors:
fPosX->Sumw2();
// Add to output list (needed for PROOF)
GetOutputList()->Add(fPosX);
fIndexHis[0] = new TH1F("IndexHis1", "TEST OF INDEX", 20, -5, 5);
fIndexHis[1] = new TH1F("IndexHis2", "TEST OF INDEX", 20, -5, 5);
fIndexHis[2] = new TH1F("IndexHis3", "TEST OF INDEX", 20, -5, 5);
fIndexHis[3] = new TH1F("IndexHis4", "TEST OF INDEX", 20, -5, 5);
GetOutputList()->Add(fIndexHis[0]);
GetOutputList()->Add(fIndexHis[1]);
GetOutputList()->Add(fIndexHis[2]);
GetOutputList()->Add(fIndexHis[3]);
}
Bool_t TSelector_test::Process(Long64_t entry)
{
// We only need the number of particles...
b_Ndata_P_tr_p->GetEntry(entry);
// ... and their position in X...
b_P_tr_x->GetEntry(entry);
// ... and their momentum
b_P_gtr_dp->GetEntry(entry);
//TEST OF INDEX HISTOGRAM
b_P_hgcer_npe->GetEntry(entry);
for (int iParticle = 0; iParticle < Ndata_P_tr_p; ++iParticle) {
if (P_gtr_dp[iParticle] < 40.0)
{
fPosX->Fill(P_tr_x[iParticle]);
for (Int_t ipmt = 0; ipmt < 4; ipmt++)
{
fIndexHis[ipmt]->Fill(P_tr_x[iParticle]);
cout << fIndexHis[ipmt]->GetEntries() << endl;
}
}
}
return kTRUE;
}
void TSelector_test::Terminate()
{
// Fit the histogram:
fPosX->Fit("pol2");
// and draw it:
fPosX->Draw();
cout << fIndexHis[0]->GetEntries() << endl;
}
The cout statement in the Process section accessing fIndexHis[] would work as intended, I could see it’s output on each worker’s .log file. However when I try to cout in the Terminate section, the cout would cause a segmentation fault, due to that histogram not actually existing. Clearly the histograms were not added to the output list properly. The solution was to change how I define the array of histograms:
new TSelector_test.h
#ifndef TSelector_test_h
#define TSelector_test_h
#include "TROOT.h"
#include "TChain.h"
#include "TFile.h"
#include "TSelector.h"
#include "TProofServ.h"
#include "TH1.h"
#include <iostream>
const Int_t kMaxfParticles = 1293;
class TSelector_test : public TSelector {
public :
TTree *fChain; //!pointer to the analyzed TTree or TChain
// Declaration of leaf types
TH1 *fPosX; // X position of the particles
TH1F **fIndexHis;
// Declaration of leaf types
Int_t Ndata_P_tr_p;
Double_t P_tr_x[kMaxfParticles]; //[fNParticles]
Double_t P_gtr_dp[kMaxfParticles]; //[fNParticles]
Double_t P_hgcer_npe[4];
// List of branches
TBranch *b_Ndata_P_tr_p;
TBranch *b_P_tr_x;
TBranch *b_P_gtr_dp;
TBranch *b_P_hgcer_npe;
TSelector_test(TTree * = 0): fChain(0) {fPosX = 0, fIndexHis = 0; }
virtual ~TSelector_test() { }
virtual Int_t Version() const { return 2; }
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 Terminate();
ClassDef(TSelector_test,0);
};
#endif
#ifdef TSelector_test_cxx
void TSelector_test::Init(TTree *tree)
{
// Set branch addresses and branch pointers
if (!tree) return;
fChain = tree;
// To use SetBranchAddress() with simple types (e.g. double, int)
// instead of objects (e.g. std::vector<Particle>).
fChain->SetMakeClass(1);
// Connect the branches with their member variables.
tree->SetBranchAddress("Ndata.P.tr.p", &Ndata_P_tr_p, &b_Ndata_P_tr_p);
tree->SetBranchAddress("P.tr.x", P_tr_x, &b_P_tr_x);
tree->SetBranchAddress("P.gtr.dp", &P_gtr_dp, &b_P_gtr_dp);
tree->SetBranchAddress("P.hgcer.npe", &P_hgcer_npe, &b_P_hgcer_npe);
}
Bool_t TSelector_test::Notify()
{
return kTRUE;
}
#endif // #ifdef TSelector_test_cxx
TSelector_test.C
#define TSelector_test_cxx
#include "TSelector_test.h"
#include "TH1.h"
#include "TStyle.h"
void TSelector_test::SlaveBegin(TTree * /*tree*/)
{
TString option = GetOption();
fPosX = new TH1F("hPosX", "Position in X", 20, -5, 5);
// enable bin errors:
fPosX->Sumw2();
// Add to output list (needed for PROOF)
GetOutputList()->Add(fPosX);
fIndexHis = new TH1F*[4];
fIndexHis[0] = new TH1F("IndexHis1", "TEST OF INDEX", 20, -5, 5);
fIndexHis[1] = new TH1F("IndexHis2", "TEST OF INDEX", 20, -5, 5);
fIndexHis[2] = new TH1F("IndexHis3", "TEST OF INDEX", 20, -5, 5);
fIndexHis[3] = new TH1F("IndexHis4", "TEST OF INDEX", 20, -5, 5);
GetOutputList()->Add(fIndexHis[0]);
GetOutputList()->Add(fIndexHis[1]);
GetOutputList()->Add(fIndexHis[2]);
GetOutputList()->Add(fIndexHis[3]);
}
Bool_t TSelector_test::Process(Long64_t entry)
{
// We only need the number of particles...
b_Ndata_P_tr_p->GetEntry(entry);
// ... and their position in X...
b_P_tr_x->GetEntry(entry);
// ... and their momentum
b_P_gtr_dp->GetEntry(entry);
//TEST OF INDEX HISTOGRAM
b_P_hgcer_npe->GetEntry(entry);
// *** 2. *** Do the actual analysis
for (int iParticle = 0; iParticle < Ndata_P_tr_p; ++iParticle) {
if (P_gtr_dp[iParticle] < 40.0)
{
fPosX->Fill(P_tr_x[iParticle]);
fIndexHis[0]->Fill(P_tr_x[iParticle]);
}
}
return kTRUE;
}
void TSelector_test::Terminate()
{
// Fit the histogram:
fPosX->Fit("pol2");
// and draw it:
fPosX->Draw();
TH1F* ccc[4];
ccc[0] = dynamic_cast<TH1F*> (GetOutputList()->FindObject("IndexHis1"));
cout << "WHAT: " << ccc[0]->GetEntries() << endl;
}
Where using this method I can access the histogram information on the client. It is a little annoying to have to change all the histogram names, but at least I can have arrays of histograms in PROOF this way.