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.
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.
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:
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.