Understanding RooAddPdf::fixCoefRange

Hi all

I’m fitting a template, which will be later used as a fixed shape in a fit with a different range.

Since the template uses a RooAddPdf, it is my understanding that I should use RooAddPdf::fixCoefRange, or the shape will be different when used in the main fit (it is, I tried).

However, I’m not sure I understand exactly that method: it says that it ties the coefficient normalization to a specific named range instead of the fit range, but even if I set the normalization range to the fit range the fit appears different.

void test() {
    using namespace RooFit;
    
    RooRealVar x("x", "", 0, 2);
    
    RooRealVar c1("c1", "", 0.5, 0, 10);
    RooRealVar c2("c2", "", 2, 0, 10);
    
    RooExponential exp1("exp1", "", x, c1);
    RooExponential exp2("exp2", "", x, c2);
    
    RooRealVar frac("frac", "", 0.15, 0, 1);
    
    RooAddPdf model("model", "", RooArgList(exp1, exp2), frac);
    
    auto data = model.generate(x, 100000);
    
    x.setRange("norm", 0, 2);
    model.fixCoefRange("norm");
    
    model.fitTo(*data, Save(true), PrintLevel(-1))->Print("V");
    
    auto frame = x.frame();
    data->plotOn(frame);
    model.plotOn(frame);
    frame->Draw();
}

Am I misunderstanding something? What is the correct way to export the model so that it will not change when using a different range?

Thank you in advance.
Enrico

May be @moneta can help.

Hello
I noticed that the example posted here works if I move the fixCoefRange call after fitting.

However, this still does not work in my actual code, possibly due to the use of RooEffProd ( it actually looks worse, which is why I posted the first snippet as it was).

Here’s another macro that reproduces the problem better

void testWithEff() {
    using namespace RooFit;
    
    RooRealVar x("x", "", 5.42, 5.85);
    
    RooRealVar slope1("slope1", "", 2.8229e+00, 0, 10);
    RooRealVar slope2("slope2", "", 1.3120e+01, 0, 10);
    
    RooExponential exp1("exp1", "", x, slope1);
    RooExponential exp2("exp2", "", x, slope2);
    
    RooRealVar frac("frac", "", 2.1921e-01, 0, 1);
    
    RooAddPdf model("model", "", RooArgList(exp1, exp2), frac);
    
    RooFormulaVar eff("eff", "", "(1+TMath::Erf((x-5.4531e+00)/5.0913e-03))*(1+TMath::Erf((5.6972e+00-x)/0.0093147))/4", x);
    
    RooEffProd modelWithEff("modelWithEff", "", model, eff);
    
    auto data = modelWithEff.generate(x, 100000);
    
    auto frame = x.frame();
    data->plotOn(frame);
    modelWithEff.plotOn(frame);
    
    modelWithEff.fitTo(*data, Save(true), PrintLevel(-1))->Print("V");
    
    modelWithEff.plotOn(frame, LineColor(kGreen));
    
    x.setRange("norm", x.getMin(), x.getMax());
    model.fixCoefRange("norm");
    modelWithEff.plotOn(frame, LineColor(kRed));

    frame->Draw();
}

What am I doing wrong?

Hi,

In case of a RooAddPdf the components pdf needs to be normalized within a given range. This fixes the definition of the coefficients, and this range passed in RooAddPdf::fixCoefRange defines this normalisation range.
Now when using the RooEffProd for fitting, I think it sets as fitting range the one where the data are, and this range is used internally for interpreting the coefficient of the RooAddPdf.
The best is that you set a range for fitting and you re-use that range for plotting. Example code:

    x.setRange("norm", x.getMin(), x.getMax());

    modelWithEff.fitTo(*data, Range("norm"), Save(true), PrintLevel(-1))->Print("V");
    
    modelWithEff.plotOn(frame, LineColor(kGreen), NormRange("norm"));

    model.fixCoefRange("norm");

    modelWithEff.plotOn(frame, LineColor(kRed));

    frame->Draw();

That seem to work for the RooAddPdf, but I noticed that I have another more subtle difference also in templates that do not contain a RooAddPdf.
I need to investigate more, but this question is solved.
Thank you

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