RooAddPdf Components() plotting problem

Dear Experts,

I am using RooAddPdf to combine a convoluted pdf with one another RooAbsPdf:

// convolution with resPdf
RooFFTConvPdf fConv("fConv", "fConv", *X, *resPdf, histPdf);
//
// resPdf passed as component, where Frac is a real number
RooAddPdf model("model","model",RooArgList(fConv, *resPdf), RooArgList(Frac));

//Plotting of pdf

RooPlot *ffr = X->frame();
model.plotOn(ffr,LineColor(kBlue),Components(RooArgSet(*resPdf)));
model.plotOn(ffr,LineColor(kRed),Components(RooArgSet(fConv)));

It should plot two components of model, but surprisingly it is plotting model pdf twice one overlapped other . :frowning:
While I could successfully draw both pdf (*resPdf & fConv) on a same frame, to check whether they are same:

‘fConv->plotOn(ffr2);’
‘resPdf->plotOn(ffr2);’

But they are different pdf as they should.

In simple words, RooAddPdf cannot distinguish it’s own components.
Please share if you see any solution to this problem.
Thanks in advance!

Hi @hym,

I am inviting @jonas to this thread. I am sure he can help you with this.

Cheers,
J.

Hi @hym!

I have tried this for myself, i.e. plotting the components of a RooAddPdf that are a RooFFTConvPdf and something else like a RooGaussian. Which ROOT version are you using? The version 6.22 is working for me.

One thing that is striking me as suspicious in your code is that you are reusing resPdf. So first you do the convolution of a histogram with a resolution function, and then you add the same resolution function on top of that? I’m not sure if this is really intended. In any case, this might cause the problem that causes the components to not be recognized correctly.

Can you please modify your code such that the second PDF in the RooAddPdf is not something that is also used in the convolution?

Here is the example code that works correctly for me:

void example() {

    using namespace RooFit;

    RooRealVar mes("mes","mes", 0.0, 20.0);

    RooRealVar sigmean1("sigmean1","sigmean1", 5.0, 0.0, 10.0);
    RooRealVar sigwidth1("sigwidth1","sigwidth1", 1.0, 0.01, 10);
    RooGaussian gaus1("gaus1","gaus1", mes, sigmean1, sigwidth1);

    RooRealVar sigmean2("sigmean2","sigmean2", 5.0, 0.0, 10.0);
    RooRealVar sigwidth2("sigwidth2","sigwidth2", 1.0, 0.01, 10);
    RooGaussian gaus2("gaus2","gaus2", mes, sigmean2, sigwidth2);

    RooRealVar sigmean3("sigmean3","sigmean3", 5.0, 0.0, 10.0);
    RooRealVar sigwidth3("sigwidth3","sigwidth3", 1.0, 0.01, 10);
    RooGaussian gaus3("gaus3","gaus3", mes, sigmean3, sigwidth3);

    RooFFTConvPdf conv("conv", "conv", mes, gaus1, gaus2);

    RooRealVar frac("frac","frac", 0.5, 0.0, 1.0);
    RooAddPdf model("model","model",RooArgList(conv, gaus3), RooArgList(frac));

    //Plotting of pdf
    TCanvas c1("c1","c1",900,700);
    RooPlot *mesframe = mes.frame();
    model.plotOn(mesframe, LineColor(kBlack));
    model.plotOn(mesframe, LineColor(kRed), Components(RooArgSet(conv)));
    model.plotOn(mesframe, LineColor(kBlue), Components(RooArgSet(gaus3)));
    mesframe->Draw();

    c1.SaveAs("plot.png"); 
}

Please let me know if this approach works for you or if you have further questions!

Cheers,
Jonas

1 Like

Dear @jonas ,
Thank you for looking at the problem and your solutions. I see your point.

Perheps, this is the case because I took your example and switched gaus3 to gaus1, and then it is doing the same thing here as well.
So I would like to make a copy of the resPdf, but here I am not sure what is the ideal way to make a copy of a RooAbsPdf.
Your suggestions will be helpful here, if you could tell me how to make it in this case.

Thank you very much!

All of the RooFit PDFs implement a sort of copy constructor where you can create a new object just as the old one but with a different name. Since your issue is related to the name, this is exactly what you can use here.

In my example, this would mean constructing gaus3 like this, where the second argument is the new name:

RooAbsPdf gaus3{gaus1, "gaus3"};

I don’t know what class your resPdf is, but you should be able to do the same with it.

I hope that this works for you and that adding this one more line is not too inconvenient!

Thanks @jonas for reply.

I applied the following line in your example code

RooGaussian gaus3 = {gaus2, "gaus3"};

and It works very well there, BUT in my case, my resPdf is pointer variable e.g. RooAbsPdf *resPdf;
I tried to do the same with pointer type but it did not work. And also same thing I tried with your code and it did not work (errors). Could you also please check the same for case where gaus1 is *gaus1 ?

You can’t use the same code with a pointer; so you have to dereference to pointer with the * operator.

In my example this would mean:

RooGaussian * gaus1 = new RooGaussian("gaus1","gaus1",
                                      mes, sigmean1, sigwidth1);
RooGaussian gaus3{*gaus1, "gaus3"};

Does this work for you?

Hi @jonas

  1. Running this in your example works perfectly fine. It serves the purpose, BUT

  2. Running the following in my code

RooAbsPdf resPdf_copy{*resPdf, "resPdf_copy"};

gives

error: variable type 'RooAbsPdf' is an abstract class RooAbsPdf resPdf_copy{*resPdf, "resPdf_copy"};
^
note: unimplemented pure virtual method 'clone' in 'RooAbsPdf'
virtual TObject* clone(const char* newname=0) const = 0 ;
^
/home/himanshu/anaconda3/envs/conda_new/etc/../include/RooAbsReal.h:391:20: note: unimplemented pure virtual method 'evaluate' in 'RooAbsPdf' virtual Double_t evaluate() const = 0 ;

Hi @hym!

You can’t create a RooAbsPdf like this because it’s a virtual class. You need to create an object that is of the same class as your resPdf. You should look this up in your code or ask the resPdf what class it is with

std::cout << resPdf.ClassName() << std::endl;

Let’s hope it works now, otherwise let me know!

Hi @jonas

Thanks! It is RooHistPdf as per its classname. I tried to do something as following-

RooHistPdf *resPdf_copy{*resPdf, "resPdf_copy"};

which gives

error: excess elements in scalar initializer

RooHistPdf *resPdf_copy{*resPdf , "resPdf_copy"};

If you construct the copy like this, you can’t assign it to a pointer. So either you do

RooHistPdf resPdf_copy{*resPdf , "resPdf_copy"};

or if you really want to have the pointer you can create it on the heap:

RooHistPdf * resPdf_copy = new RooHistPdf(*resPdf , "resPdf_copy");

The first option of creating the object on the stack is preferred. If your code needs a pointer later, you can always get a pointer with &resPdf_copy.

Dear @jonas
Thank you very much for your suggestions and help! :tada: :confetti_ball:
It is now solved. I was taking resPdf as RooAbsPdf. This was the problem. After initializing it with RooHistPdf, it worked as per your suggestion.

Thank you again for your efforts :slight_smile:

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.