Likelihood and minimization: Recover from regions where the function is not defined.
We demonstrate improved recovery from disallowed parameters. For this, we use a polynomial PDF of the form
\[
\mathrm{Pol2} = \mathcal{N} \left( c + a_1 \cdot x + a_2 \cdot x^2 + 0.01 \cdot x^3 \right),
\]
where \( \mathcal{N} \) is a normalisation factor. Unless the parameters are chosen carefully, this function can be negative, and hence, it cannot be used as a PDF. In this case, RooFit passes an error to the minimiser, which might try to recover.
import ROOT
x = ROOT.RooRealVar("x", "x", -15, 15)
a1 = ROOT.RooRealVar("a1", "a1", -0.5, -10.0, 20.0)
a2 = ROOT.RooRealVar("a2", "a2", 0.2, -10.0, 20.0)
a3 = ROOT.RooRealVar("a3", "a3", 0.01)
pdf = ROOT.RooPolynomial("pol3", "c + a1 * x + a2 * x*x + 0.01 * x*x*x", x, [a1, a2, a3])
data = pdf.generate(x, 10000)
c = ROOT.TCanvas()
frame = x.frame()
data.plotOn(frame, Name="data")
ROOT.RooMsgService.instance().getStream(0).removeTopic(ROOT.RooFit.Plotting)
ROOT.RooMsgService.instance().getStream(1).removeTopic(ROOT.RooFit.Plotting)
a1.setVal(10.0)
a2.setVal(-1.0)
fitWithoutRecovery = pdf.fitTo(
data,
Save=True,
RecoverFromUndefinedRegions=0.0,
PrintEvalErrors=-1,
PrintLevel=-1,
)
pdf.plotOn(frame, LineColor="r", Name="noRecovery")
print("\n\n\n-------------- Starting second fit ---------------\n\n")
a1.setVal(10.0)
a2.setVal(-1.0)
fitWithRecovery = pdf.fitTo(
data,
Save=True,
RecoverFromUndefinedRegions=1.0,
PrintEvalErrors=-1,
PrintLevel=0,
)
pdf.plotOn(frame, LineColor="b", Name="recovery")
fitWithoutRecovery.Print()
print(
"Without recovery, the fitter encountered {}".
format(fitWithoutRecovery.numInvalidNLL())
+ " invalid function values. The parameters are unchanged.\n"
)
fitWithRecovery.Print()
print(
"With recovery, the fitter encountered {}".
format(fitWithoutRecovery.numInvalidNLL())
+ " invalid function values, but the parameters are fitted.\n"
)
legend = ROOT.TLegend(0.5, 0.7, 0.9, 0.9)
legend.SetBorderSize(0)
legend.SetFillStyle(0)
legend.AddEntry("data", "Data", "P")
legend.AddEntry("noRecovery", "Without recovery (cannot be plotted)", "L")
legend.AddEntry("recovery", "With recovery", "L")
frame.Draw()
legend.Draw()
c.Draw()
c.SaveAs("rf612_recoverFromInvalidParameters.png")
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t format
[#1] INFO:Fitting -- RooAbsPdf::fitTo(pol3_over_pol3_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- using CPU computation library compiled with -mavx2
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_pol3_over_pol3_Int[x]_pol3Data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: activating const optimization
[#0] ERROR:Minimization -- RooMinimizer: all function calls during minimization gave invalid NLL values!
[#0] ERROR:Minimization -- RooMinimizer: all function calls during minimization gave invalid NLL values!
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization
[#0] ERROR:Eval -- RooAbsReal::logEvalError(pol3) evaluation error,
origin : RooPolynomial::pol3[ x=x coefList=(a1,a2,a3) ]
message : p.d.f normalization integral is zero or negative: -2220.000000
server values: x=x=0, coefList=(a1 = 10 +/- 0,a2 = -1 +/- 0,a3 = 0.01)
[#1] INFO:Fitting -- RooAbsPdf::fitTo(pol3_over_pol3_Int[x]) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_pol3_over_pol3_Int[x]_pol3Data) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: activating const optimization
Minuit2Minimizer: Minimize with max-calls 1000 convergence for edm < 1 strategy 1
Minuit2Minimizer : Valid minimum - status = 0
FVAL = -1002.2262595660759
Edm = 2.95538313214564806e-09
Nfcn = 251
a1 = -0.498159 +/- 0.0227242 (limited)
a2 = 0.198316 +/- 0.00564906 (limited)
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization
RooFitResult: minimized FCN value: 0, estimated distance to minimum: 0
covariance matrix quality: Not calculated at all
Status : MINIMIZE=-1 HESSE=302
Floating Parameter FinalValue +/- Error
-------------------- --------------------------
a1 1.0000e+01 +/- 0.00e+00
a2 -1.0000e+00 +/- 0.00e+00
RooFitResult: minimized FCN value: 29650.9, estimated distance to minimum: 2.95925e-09
covariance matrix quality: Full, accurate covariance matrix
Status : MINIMIZE=0 HESSE=0
Floating Parameter FinalValue +/- Error
-------------------- --------------------------
a1 -4.9816e-01 +/- 2.27e-02
a2 1.9832e-01 +/- 5.65e-03
-------------- Starting second fit ---------------
Without recovery, the fitter encountered 23 invalid function values. The parameters are unchanged.
With recovery, the fitter encountered 23 invalid function values, but the parameters are fitted.
- Date
- June 2021
- Author
- Harshal Shende, Stephan Hageboeck (C++ version)
Definition in file rf612_recoverFromInvalidParameters.py.