Error on DoEvalPar with custom fit model and ROOT::Fit::Fitter

Hello all,

I’m trying to implement a custom fitter which will be able to fit several peaks on a spectrum to different set functions (gaussians, voigts and histogram-like backgrounds). I’ve already managed to do so by using ROOT::Fitter::FitFCN but now I wanted to access the confidence intervals calculations. After searching through the web (this post on the forum shed some light), I found that to do so I must set a proper model function to the fitter (via SetFunction()), so the ROOT::Fit::FitResult can access it.

That’s why I rewrote the model function class inheriting from IParametricFunctionMultiDimTempl<double> and overriding all the needed methods, as mentioned in the manual. So far so good, because when I try to run the fitter as in this minimal example I keep getting a segmentation fault. I tracked down the issue to the DoEvalPar function that I’ve overridden: the const double* p vector is null!

How can that be? Both Parameters() and SetParameters() are (I think) correctly implemented, and I think that it is the Fitter class that manages this vector. The Clone() method is also explicited. You can access the class in this repository.

Any help would be highly appreciated!


ROOT Version: 6.30/00
Platform: Ubuntu 22.04
Compiler: precompiled binary with g++ 11.4.0


Dear Miguel,

Thanks for the post. I am sorry to hear you are encountering difficulties with the ROOT fitter. I start by adding in the loop @moneta.
In the meantime, what could be helpful is a minimal reproducer of the behaviour you experience.

Best,
Danilo

Hello Miguel,

The problem I think is caused baby the fact that the filter might call the User provided model function calling DoEvalPar(x, nullptr), i.e. not passing a vector of parameter. This is done to avoid setting parameter values for each data point. For this reason there is a SetParameter` function as well.
In your implementation of the ModelFunction::DoEvalPar you should have a check if it is a nullptr, and if it is used the cached data vector:

double Fitters::Model::DoEvalPar(const double* xx, const double* p) const
{
    const double * pars =  (p) ? p : fPars.data();  
    UnpackParameters(pars);
  ......
}

Indeed, that solves the issue! Thanks a lot for the explanation.

In the meantime, I developed a workaround by writing a custom objective function (a simple chi2, inheriting from IMultiGenFunc and with internal access to the Model and the BinData) and passing it to the ROOT::Fit::Fitter with SetFCN(IMultiGenFunction& fcn, IModelFuntion& func). This way, I can access the model function in the TFitResult to scan and obtain confidence intervals, which was my original aim.

Greetings!

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