Problem with derived class

Hi,

I have problems accessing data from a custom class derived from TObject:

class Tmap : public TObject {
private:
    std::map< int,std::vector<double> *> *fT;

public :
    Tmap(void);
    virtual ~Tmap(){};
     void TAdd(int key, vector<double> *v, double number);
    virtual bool TExist(int key);
    virtual std::map< int,std::vector<double>* >* GetTmap(void) const{ return fT; }
    ClassDef(Tmap,1)
};

ClassImp(Tmap)
Tmap::Tmap(void){
    fT = new map<int, std::vector<double>*>();
}
void Tmap::TAdd(int key, std::vector<double> *v, double number){
    v->push_back(number); // fill with values
    // insert record into structure
    fT->insert(std::pair<int, std::vector<double>*>(key, v));
}
bool Tmap::TExist(int key){
    bool exist;
    if ( fT->find(key) == fT->end()){
        return false;
    }
    else{
        return true;}
}
#endif

The class works fine without implementing it in TSelector. Tmap class contains all the processed data from TTree events and is analyzed in the Terminate() part of the TSelector derived class Selector (TSelector is run in PROOF ).
Simplified overview of my code:

class Selector : public TSelector {
public :
    Tmap* LYZ_Q;
       Tmap* LYZ_M;
    Selector(void)
      :LYZ_Q(0),
        LYZ_M(0),
        {}
         virtual~Selector(void){}
    virtual void Init(TTree* tree);
    virtual void Begin(TTree *tree);
    virtual void SlaveBegin(TTree*);
    virtual bool Process(Long64_t entry);
    virtual void SlaveTerminate();
    virtual void Terminate(void);
    virtual TList  *GetOutputList() const { return fOutput; }
    virtual void    SetOption(const char *option) { fOption = option; }
    virtual void    SetObject(TObject *obj) { fObject = obj; }
    virtual void    SetInputList(TList *input) { fInput = input; }
    virtual int Version() const { return 2; }
    virtual Bool_t SetTree(TTree* tree);
    ClassDef(Selector,1);
};

void Selector::SlaveBegin(TTree* tree){
    SetTree(tree);
    v2_LYZ = new TH2F("v2_LYZ", "v_{2} Distribution", 100, 0, 150, 100, 0, 0.5);
    fOutput->Add(v2_LYZ);

    LYZ_Q = new Tmap();
    LYZ_M = new Tmap();
    fOutput->Add(LYZ_Q);
    fOutput->Add(LYZ_M);
}

bool Selector::Process(Long64_t entry )
{ 
 t->GetEntry(entry);
 Q_theta(particles_intersection_mcp,2, h->c, "c",   LYZ_Q,  LYZ_M);
 }
 
 void Selector::Terminate()
{
   LYZ(LYZ_Q, LYZ_M, v2_LYZ );
   TFile* output = TFile::Open("output.root","RECREATE");
       v2_LYZ->Write();
}
#endif

If I print some values of Tmap LYZ_Q in process() it works fine, but in the Terminate() it can’t be accessed and I get:

*** Break *** segmentation violation
 Generating stack trace...
 0x000000010c9285ac in TProofPlayerLite::Finalize(bool, bool) (in libProofPlayer.so) + 732
 0x000000010c928114 in TProofPlayerLite::Process(TDSet*, char const*, char const*, long long, long long) (in libProofPlayer.so) + 3700
 0x000000010c92725f in TProofPlayerLite::Process(TDSet*, TSelector*, char const*, long long, long long) (in libProofPlayer.so) + 127
 0x000000010c0bcbc3 in TProofLite::Process(TDSet*, char const*, char const*, long long, long long) (in libProof.so) + 3555
 0x000000010c09528f in TProof::Process(TDSet*, TSelector*, char const*, long long, long long) (in libProof.so) + 63
 0x000000010c890238 in <unknown function>
 0x000000010c890051 in <unknown function>
 0x00000001015345fd in cling::Interpreter::RunFunction(clang::FunctionDecl const*, cling::Value*) (in libCling.so) + 317
 0x0000000101533a89 in cling::Interpreter::EvaluateInternal(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, cling::CompilationOptions, cling::Value*, cling::Transaction**) (in l
 0x0000000101572ca2 in cling::MetaSema::actOnxCommand(llvm::StringRef, llvm::StringRef, cling::Value*) (in libCling.so) + 434
 0x000000010156bea9 in cling::MetaParser::isXCommand(cling::MetaSema::ActionResult&, cling::Value*) (in libCling.so) + 745
 0x000000010156b617 in cling::MetaParser::isCommand(cling::MetaSema::ActionResult&, cling::Value*) (in libCling.so) + 135
 0x000000010156b3ea in cling::MetaParser::isMetaCommand(cling::MetaSema::ActionResult&, cling::Value*) (in libCling.so) + 42
 0x0000000101570a72 in cling::MetaProcessor::process(char const*, cling::Interpreter::CompilationResult&, cling::Value*) (in libCling.so) + 274
 0x00000001014293a7 in TCling::ProcessLine(char const*, TInterpreter::EErrorCode*) (in libCling.so) + 3111
 0x000000010142c5f9 in TCling::ProcessLineSynch(char const*, TInterpreter::EErrorCode*) (in libCling.so) + 121
 0x0000000101005de9 in TApplication::ExecuteFile(char const*, int*, bool) (in libCore.so) + 2329
 0x0000000101325b96 in TRint::ProcessLineNr(char const*, char const*, int*) (in libRint.so) + 118
 0x00000001013258ff in TRint::Run(bool) (in libRint.so) + 943
 0x0000000100f91e8f in main (in root.exe) + 79
 0x00007fff9252b5c9 in start (in libdyld.dylib) + 1
 0x0000000000000004 in <unknown function>
Root > 

I have been through most of the previous posts, but I couldn’t find any help there, and I hope someone can help me. (I just found out that PROOF have its own forum… sorry for posting it at ROOT support)

Thanks.

Dear AZG,

The problem is that in PROOF, Begin and Treminate are executed in the steering process (the ROOT shell where you invoke the commands), the other in the workers processes.
I’ll post you in a short while a modification to your code which should solve the issue.

G Ganis

Thanks a lot G Ganis.
I will wait for your reply :smiley:

Hi,

Looking again at your code, what is missing, I believe, is to retrieve the wanted object from the output list.
However, you have this call in Terminate:

  LYZ(LYZ_Q, LYZ_M, v2_LYZ );

which is not clear to me what it does.

This is what would do (and similar for the Tmap objects):

class Selector : public TSelector {
public :
    Tmap* LYZ_Q;
       Tmap* LYZ_M;
    Selector(void)
      :LYZ_Q(0),
        LYZ_M(0),
        {}
         virtual~Selector(void){}
    virtual void Init(TTree* tree);
    virtual void Begin(TTree *tree);
    virtual void SlaveBegin(TTree*);
    virtual bool Process(Long64_t entry);
    virtual void SlaveTerminate();
    virtual void Terminate(void);
    virtual TList  *GetOutputList() const { return fOutput; }
    virtual void    SetOption(const char *option) { fOption = option; }
    virtual void    SetObject(TObject *obj) { fObject = obj; }
    virtual void    SetInputList(TList *input) { fInput = input; }
    virtual int Version() const { return 2; }
    virtual Bool_t SetTree(TTree* tree);
    ClassDef(Selector,1);
};

void Selector::SlaveBegin(TTree* tree){
    SetTree(tree);
    v2_LYZ = new TH2F("v2_LYZ", "v_{2} Distribution", 100, 0, 150, 100, 0, 0.5);
    fOutput->Add(v2_LYZ);

    LYZ_Q = new Tmap();
    LYZ_M = new Tmap();
    fOutput->Add(LYZ_Q);
    fOutput->Add(LYZ_M);
}

bool Selector::Process(Long64_t entry )
{ 
 t->GetEntry(entry);
 Q_theta(particles_intersection_mcp,2, h->c, "c",   LYZ_Q,  LYZ_M);
 }
 
 void Selector::Terminate()
{
   LYZ(LYZ_Q, LYZ_M, v2_LYZ );
   v2_LYZ = (TH2F *) fOutput->FindObject("v2_LYZ");
   TFile* output = TFile::Open("output.root","RECREATE");
       v2_LYZ->Write();
}
#endif

Hope it helps.

G Ganis

Ps: you should also specify the ROOT / OS versions …

Dear G Ganis,

Thanks for the reply. I am sorry for not being clear enough.
I am using mac OS X 10.10.5 with ROOT 6.06/04.
The following function fills up the Tmap (LYZ_Q, LYZ_M):

Q_theta(particles_intersection_mcp,2, h->c, "c",   LYZ_Q,  LYZ_M);

The following function use all the entries in the Tmap (Tmap contains some values for all events and analysis it in LYZ to calculate the average v2 flow, and plot it at v2_LYZ histogram):

LYZ(LYZ_Q, LYZ_M, v2_LYZ );

After doing:

LYZ_Q = (Tmap *)fOutput->FindObject(LYZ_Q);
cout << “value = " << LYZ_Q->GetTmap()->at(3)->at(0)<<endl;

When I load it for the first time it works, but if I load the script again I get the following error:

Error in <THashTable::FindObject>: argument is a null pointer

 *** Break *** segmentation violation
Number is:  Generating stack trace...
 0x0000000118360114 in TProofPlayerLite::Process(TDSet*, char const*, char const*, long long, long long) (in libProofPlayer.so) + 3700
 0x000000011835f25f in TProofPlayerLite::Process(TDSet*, TSelector*, char const*, long long, long long) (in libProofPlayer.so) + 127
 0x0000000117af5bc3 in TProofLite::Process(TDSet*, char const*, char const*, long long, long long) (in libProof.so) + 3555
 0x0000000117ace28f in TProof::Process(TDSet*, TSelector*, char const*, long long, long long) (in libProof.so) + 63
 0x000000011767b238 in <unknown function>
 0x000000011767b051 in <unknown function>
 0x000000010cf6d5fd in cling::Interpreter::RunFunction(clang::FunctionDecl const*, cling::Value*) (in libCling.so) + 317
 0x000000010cf6ca89 in cling::Interpreter::EvaluateInternal(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, cling::CompilationOptions, cling::Value*, cling::Transaction**) (in l
 0x000000010cfabca2 in cling::MetaSema::actOnxCommand(llvm::StringRef, llvm::StringRef, cling::Value*) (in libCling.so) + 434
 0x000000010cfa4ea9 in cling::MetaParser::isXCommand(cling::MetaSema::ActionResult&, cling::Value*) (in libCling.so) + 745
 0x000000010cfa4617 in cling::MetaParser::isCommand(cling::MetaSema::ActionResult&, cling::Value*) (in libCling.so) + 135
 0x000000010cfa43ea in cling::MetaParser::isMetaCommand(cling::MetaSema::ActionResult&, cling::Value*) (in libCling.so) + 42
 0x000000010cfa9a72 in cling::MetaProcessor::process(char const*, cling::Interpreter::CompilationResult&, cling::Value*) (in libCling.so) + 274
 0x000000010ce623a7 in TCling::ProcessLine(char const*, TInterpreter::EErrorCode*) (in libCling.so) + 3111
 0x000000010ce655f9 in TCling::ProcessLineSynch(char const*, TInterpreter::EErrorCode*) (in libCling.so) + 121
 0x000000010ca3bde9 in TApplication::ExecuteFile(char const*, int*, bool) (in libCore.so) + 2329
 0x000000010cd5db96 in TRint::ProcessLineNr(char const*, char const*, int*) (in libRint.so) + 118
 0x000000010cd5d8ff in TRint::Run(bool) (in libRint.so) + 943
 0x000000010c9c9e8f in main (in root.exe) + 79
 0x00007fff97f1a5c9 in start (in libdyld.dylib) + 1
 0x0000000000000004 in <unknown function>

I am not sure what I am doing wrong since I am getting this error :confused:

Dear AZG,

Difficult to say without seeing exactly what you do. Can you provide more details (i.e. posting also your macro invoking PROOF)?

G Ganis

Dear Ganis

I have tried to shorten the code as much as possible. To load the code type: root -l runProof.C\(1,-1\)

Lib.C files contains all the custom classes, but I couldn’t upload the root file which my code analyses because its too large (40mb).

AZG
Selector.C (8.18 KB)
Lib.C (59.6 KB)
runProof.C (721 Bytes)

Dear AZG,

Thanks for the code. Perhaps you can put the file in some place where I can access it.

Anyhow, I have noticed that Tmap is not named and this instruction

LYZ_Q = (Tmap *)fOutput->FindObject(LYZ_Q);

is looking for the answer using the answer.
Can you try by deriving Tmap from TNamed and give a (unique) name to the objects that you add to the output list?
I suspect that a wrong, invalid object is picked up the second time (and perhaps even the first time you do not get what you would like).

G Ganis

Dear Ganis,

Thanks again for the reply. I derived Tmap from TNamed and using:

LYZ_Q = new Tmap; LYZ_M = new Tmap; LYZ_Q->SetName ("LQ"); LYZ_M->SetName ("LM"); to set the name, and I get this following error:

Value = 9454.906677put objects ... / (4 workers still sending)   
Value = 4465.170803put objects ... \ (3 workers still sending)   
Value = -776.996244put objects ... / (2 workers still sending)   
Error in <TSelectorList::CheckDuplicateName>: an object with the same name: LQ is already in the list
Error in <TSelectorList::CheckDuplicateName>: an object with the same name: LM is already in the list
Error in <TSelectorList::CheckDuplicateName>: an object with the same name: LQ is already in the list
Error in <TSelectorList::CheckDuplicateName>: an object with the same name: LM is already in the list
Error in <TSelectorList::CheckDuplicateName>: an object with the same name: LQ is already in the list
Error in <TSelectorList::CheckDuplicateName>: an object with the same name: LM is already in the list
libc++abi.dylib: terminating with uncaught exception of type std::out_of_range: map::at:  key not found

I have managed to upload the root file and can be download from: http://free.mailbigfile.com/9f5c9e50ba584a587cb449564bceafe8/listFiles.php

I have uploaded the files again with the minor changes.

Hope there is a solution.

AZG
Lib.C (59.6 KB)
runProof.C (721 Bytes)
Selector.C (8.36 KB)

The link to root file is expired, but use this link instead: http://free.mailbigfile.com/c711f2b63c0aa61846aa0e1c35fc3708/listFiles.php

AZG

Dear AZG,

I think the problem is related to the fact that the new class Tmap has no Merge method .
The Merge method is the one called by PROOF (and also the hadd program) to add together two or more objects.
Think of two histograms: merging them means adding their bin content. But there is no general rule to add (or merge) objects, so it must be provided by the class designer.
In your case it is not obvious to me how to add two Tmap .
Tmap contains

          std::map< int,std::vector<double> *> *fQ;
          std::vector<double>* fQContainer;

The first, fQ, is filled in Tmap:

void Tmap::TAdd(int key,double Qnumber){
    
    fQContainer->push_back(Qnumber);
    fQ->insert(std::pair<int, std::vector<double>*>(key, fQContainer));
    
}

so that the second member of the pair is always the same, what changes is only ‘key’ and the content of the vector pointed to by fQContainer. (Is this the result of the simplification? Otherwise the same result could be achieved with

          std::vector< int> *fQ;
          std::vector<double>* fQContainer;

and

void Tmap::TAdd(int key,double Qnumber){
    
    fQContainer->push_back(Qnumber);
    fQ->push_back(key);
    
}

)

To design the Merge method it helps thinking to what the result would look like if only filled by one process.
A possible Merge in your case could be:

// Merge Tmap objects in collection 'li' into itself
Long64_t Tmap::Merge(TCollection *li)
{

    Long64_t rc = 0;

    // If empty list, nothing to do
    if (!li || li->GetSize() < 1) return rc;

    // Loop over the objects in the collection
    TIter nxtm(li);
    Tmap *m = 0;
    // (Assume objects in the collection are Tmap; a check could be added ...)
    while ( (m = (Tmap *) nxtm())) {
        // link to the container
        std::map< int,std::vector<double>* >* tm = m->GetTmap();
        std::map< int,std::vector<double>* >::iterator tm_type;
        unsigned int i = 0;
        for(tm_type tm_iter = tm->begin(); tm_iter != tm->end(); tm_iter++) {
            int key = tm_iter->first;
            std::vector<double> cont = *(tm_iter->second);
            TAdd(key, cont[i]);
            i++;
        }
        rc += i;
    }
    return rc;    
}

Implementing something like that (see new version of Lib.C) the warnings are removed and the code seems to run.
Have a look and let me know.

G Ganis
runProof.C (1022 Bytes)
Selector.C (8.37 KB)
Lib.C (60.6 KB)

Dear Ganis,

It makes sense now! Thank you so much :smiley:

AZG