Hello,
I am getting a segmentation violation while processing a TSelector (via TChain::process(“mySelector.C”) call) when the TChain changes file.
The TTree in TChain contains 4 branches :
- 3 branches with UInt_t
- 1 branch with a TTree.
Here is the declaration of the tree and its branches :
rootStyleDataTree_ = new TTree("RootStyleDataTree", "RootStyleDataTree");
rootStyleDataTree_->Branch("evDate", ¤tEventDate_, "currentEventDate/i");
rootStyleDataTree_->Branch("evTime", ¤tEventTime_, "currentEventTime/i");
rootStyleDataTree_->Branch("evNum", ¤tEventNumber_, "currentEventNumber/i");
rootStyleDataTree_->Branch("atomTree", "TTree", ¤tAtomTree_, 128000, 0);
To fill the tree I just loop over many events and use the TTree::fill() function. And at the end I save the tree with TTree::write().
I think I don’t do anything crazy in the TSelector “.h” and “.cxx”:
.h :
//////////////////////////////////////////////////////////
// This class has been automatically generated on
// Fri Feb 1 13:58:51 2013 by ROOT version 5.34/03
// from TChain RootStyleDataTree/
//////////////////////////////////////////////////////////
#ifndef testSelectorBis_h
#define testSelectorBis_h
#include <TROOT.h>
#include <TChain.h>
#include <TFile.h>
#include <TSelector.h>
#include <TH1.h>
#include <TStopwatch.h>
#include <iostream>
using namespace std;
// Header file for the classes stored in the TTree if any.
#include <TTree.h>
// Fixed size dimensions of array or collections stored in the TTree if any.
class testSelectorBis : public TSelector {
public :
TTree *fChain; //!pointer to the analyzed TTree or TChain
TH1D *histo;
TStopwatch chrono;
// Declaration of leaf types
UInt_t evDate;
UInt_t evTime;
UInt_t evNum;
TTree *atomTree;
// List of branches
TBranch *b_currentEventDate; //!
TBranch *b_currentEventTime; //!
TBranch *b_currentEventNumber; //!
TBranch *b_atomTree; //!
testSelectorBis(TTree * /*tree*/ =0) : fChain(0) {histo = 0;}
virtual ~testSelectorBis() { }
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(testSelectorBis,0);
};
#endif
#ifdef testSelectorBis_cxx
void testSelectorBis::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 << "INIT" << endl;
// Set object pointer
atomTree = 0;
// Set branch addresses and branch pointers
if (!tree) return;
fChain = tree;
fChain->SetMakeClass(1);
fChain->SetBranchAddress("evDate", &evDate, &b_currentEventDate);
fChain->SetBranchAddress("evTime", &evTime, &b_currentEventTime);
fChain->SetBranchAddress("evNum", &evNum, &b_currentEventNumber);
fChain->SetBranchAddress("atomTree", &atomTree, &b_atomTree);
}
Bool_t testSelectorBis::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 << "CHANGING FILE !!" << endl;
return kTRUE;
}
#endif // #ifdef testSelectorBis_cxx
and .C
#define testSelectorBis_cxx
// The class definition in testSelectorBis.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("testSelectorBis.C")
// Root > T->Process("testSelectorBis.C","some options")
// Root > T->Process("testSelectorBis.C+")
//
#include "testSelectorBis.h"
#include <TH2.h>
#include <TStyle.h>
#include <TCanvas.h>
#include <iostream>
using namespace std;
void testSelectorBis::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();
cout << "Begin !" << endl;
gDirectory->Delete("histo");
chrono.Start();
}
void testSelectorBis::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();
histo = new TH1D("histo", "tof", 600, 200,400);
fOutput->Add(histo);
}
Bool_t testSelectorBis::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 testSelectorBis::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.
fChain->GetTree()->GetEntry(entry);
cout << "Entry : " << entry << endl;
cout << "event Date_num : " << evDate << "_" << evNum << endl;
Double_t temps;
atomTree->SetBranchAddress("Time", &temps);
for(int at = 0; at < atomTree->GetEntries(); at++)
{
atomTree->GetEntry(at);
histo->Fill(temps);
}
return kTRUE;
}
void testSelectorBis::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 testSelectorBis::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.
histo = dynamic_cast<TH1D *>(fOutput->FindObject("histo"));
TCanvas* canvas;
if(!(canvas = (TCanvas*)gROOT->FindObject("profil tdv")))
{
canvas = new TCanvas("profil tdv");
canvas->SetTitle("profil tdv");
}
else canvas->Clear();
canvas->cd(1);
histo->Draw("");
canvas->Update();
chrono.Stop();
cout << "Real Time : " << chrono.RealTime() << endl;
cout << "Cpu Time : " << chrono.CpuTime() << endl;
}
the “.h” is basically the one generated by ROOT with two supplementary member (histo & chrono) and with a prompt in Notify for Debugging sake.
In the “.C” I just fill histo and draw it at the end. I also prompt the time spent by the analysis. I tried both GetEntry(entry);
and fChain->GetTree()->GetEntry(entry);
but the result was the same.
I create my TChain with the following script (I have 11 files):
{
TChain chain("RootStyleDataTree");
chain.Add("$HOME/Workdir/Lattice/rootTree.root");
for(int f = 1; f <= 10; f++)
{
chain.Add(TString::Format("$HOME/Workdir/Lattice/rootTree_%d.root", f));
}
}
and run the analysis with :
.x LoadTChain.cxx
chain.Process("testSelectorBis.C+")
If my TChain has only one file everything is working fine but when I try to process more than 1 file, after processing the first file I get :
I really don’t see were I’m doing something wrong… Any idea ?