Strange Differences Between Fit Results Using Custom vs Predefined Functions in ROOT


ROOT Version: 6.28/06
Platform: macosxarm64
Compiler: clang-1403.0.22.14.1


Hi,

As the title suggested, I’m seeing some strange differences in the fit results when using custom-defined functions as opposed to ROOT’s predefined functions, despite the functions being mathematically equivalent.

Here’s my macro:

Double_t Gaussian(Double_t* x, Double_t* par) {
    // Parameters:
    // par[0]: amplitude
    // par[1]: mean
    // par[2]: standard deviation (width)
    return par[0]*exp(-0.5*((x[0]-par[1])/par[2])*((x[0]-par[1])/par[2]));
}

Double_t LinearBackground(Double_t* x, Double_t* par) {
    // Parameters:
    // par[0]: y-intercept
    // par[1]: slope
    return par[0] + par[1]*x[0];
}

Double_t TotalFunction(Double_t *x, Double_t *par) {
    return Gaussian(x,&par[0]) + 
           Gaussian(x,&par[3]) + 
           LinearBackground(x,&par[6]);
}

void find_my_data(Double_t xmin, Double_t xmax)
{
    // Reset all existing global objects in ROOT to start with a clean slate
    gROOT->Reset();

    // Read in a 1D histogram
    TFile *inputFile = TFile::Open("/path/to/file/file.root","READ");
    TH1F *xavg_hist = (TH1F*)inputFile->Get("xavg_1d");

    for (int i = 1; i <= xavg_hist->GetNbinsX(); i++) {
        double entries = xavg_hist->GetBinContent(i);
        xavg_hist->SetBinError(i, sqrt(entries));
    }   

    // Defining parameters to use in both fits
    Double_t pars[8] = {51.1, -6.8, 0.6, 1158., -10.76, 1.17, 85.6, -2.1};

    // Fit with custom function
    TF1 *f = new TF1("f", TotalFunction, xmin, xmax, 8);
    f->SetParameters(pars);
    xavg_hist->Fit(f,"R");

    // Second Fit: Using ROOT's Predefined Functions
    TF1 *f_predefined = new TF1("f_predefined", "gaus(0)+gaus(3)+pol1(6)", xmin, xmax);
    f_predefined->SetParameters(pars); 
    xavg_hist->Fit(f_predefined, "R");


    gStyle->SetOptFit(1111);

    // Change the appearance of the second fit function
    f->SetLineColor(kBlack);
    f->SetLineStyle(2);     
    f->SetLineWidth(2); 
    
    xavg_hist->Draw();
    f->Draw("same");
    f_predefined->Draw("same");
}

Attached is an image of the fit results, with the fit using ROOT’s predefined functions shown in red. As you can see here, the predefined function fit appears to be more reasonable with the data compared to the custom function fit.

I have ensured (as best as I can) that the same parameters and settings are used for both fits. At this point, I’m not quite sure if there is something else I can check. Please let me know if you notice a mistake in my macro, or if this is a bug.

Hi @Pete!

I can’t see a problem with your macro. The mathematical definition is exactly the same for the custom and the predefined function. Does it make a difference which function you’re fitting first? What is the output printed to the terminal?

It would be nice if you could provide a fill reproducer, including the histogram bin contents, so that we can help you to investigate the problem.

Cheers,
Jonas

Hi @jonas,

It seems like I have “solved” the issue. I tried to switch the order of the fits, and that did not produce anything new. Then, I started to write a new macro to extract the bin contents to make a fill reproducer, and for some reason, the fits in this new macro produced the same results. I’m still not sure why this is the case, but my best guess at this point is my previous macro was somehow corrupted. Thank you for your help!

I see, I’m happy you found a workaround.

One thing I saw in your code that might hint to some corruption is this:

TF1("f", TotalFunction, xmin, xmax, 8)

Many ROOT internals require the objects to have a unique name. "f" is quite generic, and maybe you also named another TF1 in your macro the same. So I would check that all your ROOT objects have unique names, maybe that fixes the problem.

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