Segmentation violation using TSelector on a TChain

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", &currentEventDate_, "currentEventDate/i");
    rootStyleDataTree_->Branch("evTime", &currentEventTime_, "currentEventTime/i");
    rootStyleDataTree_->Branch("evNum", &currentEventNumber_, "currentEventNumber/i");
    rootStyleDataTree_->Branch("atomTree", "TTree", &currentAtomTree_, 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 ?

Hi again,

I looked a little bit deeper at my problem and found a solution. I just added the following line in the TSelector::Notify() method :

So that the branches of the chain are properly set when changing files.

Now its working fine even with PROOF.
So… Problem solved ! :laughing:

But I still don’t know if Its a real bug in ROOT when using TChain containing TTree, or if it’s just a bug in my brain and Its normal to use this Init function in Notify.

Best regards !