How to merge custom class?

I can’t find any documentation on how to merge custom class. I tried to implement a class incapsulating two TH1F as pointers. It crashes when merging…

header:

#ifndef TEffHistogram_H
#define TEffHistogram_H

#include "TNamed.h"
#include "TCollection.h"
#include "TH1F.h"

class TEffHistogram: public TNamed
{
public:
    TEffHistogram();
    TEffHistogram(char* name, Int_t nbinsx, Double_t xlow, Double_t xup);
    TEffHistogram(const TEffHistogram& rhs);
    ~TEffHistogram();
    void Fill(bool selected, double var);
    virtual Long64_t Merge(TCollection *list);
protected:
    ClassDef(TEffHistogram,1);
private:
    TH1F *_histo_all;
    TH1F *_histo_sel;
};

#endif

#include "TEffHistogram.h"
#include "TList.h"

ClassImp(TEffHistogram)

#include <string>

TEffHistogram::TEffHistogram() {}



TEffHistogram::TEffHistogram(char* name, Int_t nbinsx, Double_t xlow, Double_t xup)
{
    SetName(name);
    _histo_all = new TH1F((name + std::string("_all")).c_str(),
			  "all", nbinsx, xlow, xup);
    _histo_sel = new TH1F((name + std::string("_sel")).c_str(),
			  "selected", nbinsx, xlow, xup);
}


TEffHistogram::TEffHistogram(const TEffHistogram& rhs)
    : TNamed()
{
    _histo_all = static_cast<TH1F*>(rhs._histo_all->Clone());
    _histo_sel = static_cast<TH1F*>(rhs._histo_sel->Clone());
}


TEffHistogram::~TEffHistogram()
{
    delete _histo_sel;
    delete _histo_all;
}


void TEffHistogram::Fill(bool selected, double var)
{
    if (selected) {
	_histo_sel->Fill(var);
    }
    _histo_all->Fill(var);
}


Long64_t TEffHistogram::Merge(TCollection *list)
{ 
        if (!list) return 0;
	if (list->IsEmpty())
	    return 0;

	TList *list_sel = new TList();
	TList *list_all = new TList();
	
        TIter next(list);
        while (TObject *o = next()) {
	    TEffHistogram *temp = dynamic_cast<TEffHistogram*>(o);
	    list_sel->Add(temp->_histo_all);
	    list_all->Add(temp->_histo_sel);
        }

	_histo_all = static_cast<TH1F*>(list_all->At(0)->Clone());
	_histo_sel = static_cast<TH1F*>(list_sel->At(0)->Clone());
	
	Long64_t m1 = _histo_all->Merge(list_all);
	Long64_t m2 = _histo_sel->Merge(list_sel);
	
	if (m1!=m2) {
	    Error("Merge", "m1 != m2");
	}
	
        return m1;
}

You must implement a “Merge” function in your class.
However, looking at the name of your class, it could be that its functionality is already implemented (including the Merge function) in the class TEfficiency.
see: root.cern.ch/root/html/TEfficiency.html

Rene

[quote=“brun”]You must implement a “Merge” function in your class.
[/quote]
Ok, this is obvious, but how? There are tens of details… If you look to my code I’ve done it. Who call the Merge function? How is created the object before the merging? With the default constructor? Etc…

[quote]
However, looking at the name of your class, it could be that its functionality is already implemented (including the Merge function) in the class TEfficiency.
see: root.cern.ch/root/html/TEfficiency.html
Rene[/quote]

I know it, I’m using this example to learn how to merge object with proof because it’s very simple.

I have put some information at
root.cern.ch/drupal/content/merg … ed-classes

Hope it helps.

Gerri

[quote=“ganis”]I have put some information at
root.cern.ch/drupal/content/merg … ed-classes

Hope it helps.

Gerri[/quote]

thank you very much, but I have a lot of question, for example, when the Merge object is called exactly? How the object are created? With the default constructor? When in the Terminate method I call:

TH1F *my_histo = static_cast<TH1F*>fOuput->FindObject("my_histo");

somewhere a TH1F object may exists because Merge is not static. And the problem is that if I call TH1F with the default constructor I can’t set the binning that are needed to be set to do a merging.

Can you look to my code? it’s very trivial and it can open my mind.

Ok, the way PROOF works is that each worker instantiates his copy of the selector and runs SlaveBegin, which is the place where usually the objects containing the results, e.g. histograms, are created and added to the output list (fOutput). Once the worker is done, it run SlaveTerminates and it sends back its output list to the master. At this point the master goes through the lists of output objects and calls the Merge method (if found; otherwise it sends back to the client N_workers objects of a given type). What you get in Terminate is already the merged object (Terminate is only executed on the client).
So, the only thing you have to care about is to provide the Merge method. Then PROOF does the rest. In the detail, the first object received is adopted and the others are merged to the first one.

So, to summarize:

In the master at the end of processing

The way you do it in SlaveBegin of your selector.

As I wrote above, the binning is the one you choose by your self when you create the histograms; and therefore the same for all the instances to be merged. If you do not choose a binning, PROOF has an automatic way to synchronize the binning between workers.

Yes, post it and then I will have a look.

Gerri

[quote=“ganis”]In the detail, the first object received is adopted and the others are merged to the first one.
[/quote]
perfect, this is the important detail that I need. I coudn’t understand how the object was created, but it’s not created: it is the first in the list.

[quote]

Yes, post it and then I will have a look.
Gerri[/quote]
Scroll to the top.

Are the default constructor and the copy constructor to be implemented?
Why I get these errors:

00:38:10 23271 Wrk-0.23 | Error in <TExMap::Add>: key 346649 is not unique
00:38:10 23271 Wrk-0.23 | Error in <TExMap::Add>: key 452131 is not unique
00:38:10 23271 Wrk-0.23 | Error in <TExMap::Add>: key 115403 is not unique
00:38:10 23271 Wrk-0.23 | Error in <TExMap::Add>: key 285799 is not unique
00:38:10 23271 Wrk-0.23 | Error in <TExMap::Add>: key 139755 is not unique

Hi,

Attached is a revised version of your example and a test selector. The default constructor should initialize the members, the pointers, to 0.

Run it like this:

root [] TProof *p = TProof::Open("<master>")
root [] p->Load("TEffHistogram.cxx+")
root [] p->Process("TestSel.C+", 100000)

you should get a canvas with the two histograms.

Hope it helps.

Gerri
wiso.tar.gz (2.43 KB)

1 Like

Hi,

Is root.cern.ch/merging-customized-classes still valid? I tried to run on custom made classes and with the “void” return type I got the errors below. I checked the TH1, TTree and TGraph classes and all have a return type of Long64_t or int, so I used Long64_t too and it runs. I see a discrepancy in the number of events processed and the right number, but It might be some other problem, I’m not sure yet.

/home/acampove/Work/RootCoreBin/obj/x86_64-slc6-gcc48-opt/Reweight/obj/ReweightCINT.cxx:344:44: error: void value not ignored as it ought to be return ((::NDMatrix*)obj)->Merge(coll); ^ /home/acampove/Work/RootCoreBin/obj/x86_64-slc6-gcc48-opt/Reweight/obj/ReweightCINT.cxx:345:4: warning: control reaches end of non-void function [-Wreturn-type] } ^ make: *** [/home/acampove/Work/RootCoreBin/obj/x86_64-slc6-gcc48-opt/Reweight/obj/ReweightCINT.o] Error 1 RootCore: Error failed to compile package Reweight

1 Like

Dear rooter_03,

The errors comes from the way the call is handled in ReweightCINT, they are what you expect, right?

In internal usage in ROOT the return value is ignored, but ReweightCINT does not ignore the return type.
If you are using ROOT 6 you may want perhaps to define the function as ‘auto ReweightCINT’.

G Ganis

Hi,

I thought the return type had to be void because of the link I showed you before. ReweightCINT is auto generated somewhere when I build my code and for some reason it expects the return type to be non-void. Making it Long64_t definitely fixes the problem. The disagreement in the number of events comes from the fact that I did not write the Merge function correctly. Now everything seems to be working fine.

Thanks.

1 Like