Minimizer issue: inconsistent results across ROOT versions

Dear experts,

I have a simple code that fits two mass peaks simultaneously. The setup is pretty simple, RooGaussian + RooChebychev, where the mean and sigma of the gaussian are shared between the two mass regions (RooCategory). I have experienced issues in reproducing the fit results with different ROOT versions.

  • The fit result looks good in ROOT 6.30/02 (I also tested it in 6.26/11)
  • The fit result is totally off in ROOT 6.34/02 (I also tested it in 6.32/10 with the same outcome)

Since ROOT 6.30/02 and 6.34/02 are the versions provided in the LCG environments 105 and 107 respectively, I believe this issue is related to the one recently reported by @nicolo.trevisani.

These plots show the result in ROOT 6.30/02 and older versions. The two plots correspond to the two mass regions in the simultaneous fit:

While here is what I get with ROOT 6.34/02:

RooFit log in ROOT 6.30/02:

[#1] INFO:Eval -- RooRealVar::setRange(dimu_OS1) new range named 'fit_nll_signal_mumu_data' created with bounds [0.98,1.08]
[#1] INFO:Fitting -- RooAbsOptTestStatistic::ctor(nll_signal_mumu_data) constructing test statistic for sub-range named fit_range_signal
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: activating const optimization
Minuit2Minimizer: Minimize with max-calls 1000 convergence for edm < 1 strategy 1
Info in <Minuit2>: MnSeedGenerator Computing seed using NumericalGradient calculator
Info in <Minuit2>: MnSeedGenerator Initial state: FCN =      -6540.139974 Edm =      -336.8412911 NCalls =      9
Info in <Minuit2>: NegativeG2LineSearch Doing a NegativeG2LineSearch since one of the G2 component is negative
Info in <Minuit2>: MnSeedGenerator Negative G2 found - new state: 
  Minimum value : -6759.661969
  Edm           : 1.708732621
  Internal parameters:	[                0    -0.3905360998]	
  Internal gradient  :	[     -9.246451549     -18.78991127]	
  Internal covariance matrix:
[[    0.078044331              0]
 [              0  0.00045993433]]]
Info in <Minuit2>: MnSeedGenerator Initial state  
  Minimum value : -6759.661969
  Edm           : 1.708732621
  Internal parameters:	[                0    -0.3905360998]	
  Internal gradient  :	[     -9.246451549     -18.78991127]	
  Internal covariance matrix:
[[    0.078044331              0]
 [              0  0.00045993433]]]
Info in <Minuit2>: VariableMetricBuilder Start iterating until Edm is < 0.001 with call limit = 1000
Info in <Minuit2>: VariableMetricBuilder    0 - FCN =      -6759.661969 Edm =       1.708732621 NCalls =     26
Info in <Minuit2>: VariableMetricBuilder    1 - FCN =      -6761.250973 Edm =     0.07328111069 NCalls =     32
Info in <Minuit2>: VariableMetricBuilder    2 - FCN =      -6761.337042 Edm =   1.380802967e-05 NCalls =     38
Info in <Minuit2>: VariableMetricBuilder After Hessian
Info in <Minuit2>: VariableMetricBuilder    3 - FCN =      -6761.337042 Edm =   1.619328576e-05 NCalls =     48
Minuit2Minimizer : Valid minimum - status = 0
FVAL  = -6761.33704188590127
Edm   = 1.61932857624699604e-05
Nfcn  = 48
M_mumu	  = 1.01973	 +/-  0.000397116	(limited)
width	  = 0.0188872	 +/-  0.00032099	(limited)
Info in <Minuit2>: Minuit2Minimizer::Hesse Using max-calls 1000
Info in <Minuit2>: Minuit2Minimizer::Hesse Hesse is valid - matrix is accurate
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization
[#1] INFO:Eval -- RooRealVar::setRange(dimu_OS1) new range named 'fit_nll_simul_model_datatofit' created with bounds [0.9,1.16]
RooAbsTestStatistic::initSimMode: creating slave calculator #0 for state looseBDT (7828 dataset entries)
[#1] INFO:Fitting -- RooAbsOptTestStatistic::ctor(looseBDT) constructing test statistic for sub-range named fit_range
RooAbsTestStatistic::initSimMode: creating slave calculator #1 for state tightBDT (3530 dataset entries)
[#1] INFO:Fitting -- RooAbsOptTestStatistic::ctor(tightBDT) constructing test statistic for sub-range named fit_range
[#1] INFO:Fitting -- RooAbsTestStatistic::initSimMode: created 2 slave calculators.
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: activating const optimization
[#1] INFO:Minimization --  The following expressions will be evaluated in cache-and-track mode: (signal_mumu,bmodel_ctrl)
[#1] INFO:Minimization --  The following expressions will be evaluated in cache-and-track mode: (signal_mumu,bmodel)
Minuit2Minimizer: Minimize with max-calls 4000 convergence for edm < 1 strategy 1
Info in <Minuit2>: MnSeedGenerator Computing seed using NumericalGradient calculator
Info in <Minuit2>: MnSeedGenerator Initial state: FCN =      -95360.13639 Edm =      -1154.076539 NCalls =     33
Info in <Minuit2>: NegativeG2LineSearch Doing a NegativeG2LineSearch since one of the G2 component is negative
Info in <Minuit2>: MnSeedGenerator Negative G2 found - new state: 
  Minimum value : -97081.5748
  Edm           : 758.9011992
  Internal parameters:	[      0.375208442                0     0.6435011088     0.6435011088    -0.6376432924                0                0    -0.3928146854]	
  Internal gradient  :	[      25.31044218      417.4800536      9.957564737      320.6898948     -3.140052728        162.39212       588.010494      794.3649351]	
  Internal covariance matrix:
[[     0.18647605              0              0              0              0              0              0              0]
 [              0   0.0019809103              0              0              0              0              0              0]
 [              0              0   0.0014842965              0              0              0              0              0]
 [              0              0              0   0.0090653991              0              0              0              0]
 [              0              0              0              0  0.00066566041              0              0              0]
 [              0              0              0              0              0   0.0041729091              0              0]
 [              0              0              0              0              0              0  0.00095230311              0]
 [              0              0              0              0              0              0              0   0.0019003106]]]
Info in <Minuit2>: MnSeedGenerator Initial state  
  Minimum value : -97081.5748
  Edm           : 758.9011992
  Internal parameters:	[      0.375208442                0     0.6435011088     0.6435011088    -0.6376432924                0                0    -0.3928146854]	
  Internal gradient  :	[      25.31044218      417.4800536      9.957564737      320.6898948     -3.140052728        162.39212       588.010494      794.3649351]	
  Internal covariance matrix:
[[     0.18647605              0              0              0              0              0              0              0]
 [              0   0.0019809103              0              0              0              0              0              0]
 [              0              0   0.0014842965              0              0              0              0              0]
 [              0              0              0   0.0090653991              0              0              0              0]
 [              0              0              0              0  0.00066566041              0              0              0]
 [              0              0              0              0              0   0.0041729091              0              0]
 [              0              0              0              0              0              0  0.00095230311              0]
 [              0              0              0              0              0              0              0   0.0019003106]]]
Info in <Minuit2>: VariableMetricBuilder Start iterating until Edm is < 0.001 with call limit = 4000
Info in <Minuit2>: VariableMetricBuilder    0 - FCN =       -97081.5748 Edm =       758.9011992 NCalls =     62
Info in <Minuit2>: VariableMetricBuilder    1 - FCN =      -97425.06857 Edm =       141.2002291 NCalls =     86
Info in <Minuit2>: VariableMetricBuilder    2 - FCN =      -97490.89187 Edm =       64.54300277 NCalls =    104
Info in <Minuit2>: VariableMetricBuilder    3 - FCN =      -97518.81138 Edm =       11.94799931 NCalls =    122
Info in <Minuit2>: VariableMetricBuilder    4 - FCN =      -97523.53194 Edm =       3.395830549 NCalls =    140
Info in <Minuit2>: VariableMetricBuilder    5 - FCN =       -97525.0164 Edm =      0.4153871578 NCalls =    158
Info in <Minuit2>: VariableMetricBuilder    6 - FCN =       -97525.4484 Edm =     0.02006770115 NCalls =    176
Info in <Minuit2>: VariableMetricBuilder    7 - FCN =       -97525.4665 Edm =   0.0002343436795 NCalls =    194
Info in <Minuit2>: VariableMetricBuilder After Hessian
Info in <Minuit2>: VariableMetricBuilder    8 - FCN =       -97525.4665 Edm =   0.0001879779896 NCalls =    261
Minuit2Minimizer : Valid minimum - status = 0
FVAL  = -97525.4665035848157
Edm   = 0.000187977989554814859
Nfcn  = 261
M_mumu	  = 1.01878	 +/-  0.000282703	(limited)
Nb	  = 1570.53	 +/-  46.7777	(limited)
Nb_ctrl	  = 6548.31	 +/-  90.2702	(limited)
Ns	  = 1958.77	 +/-  50.7567	(limited)
Ns_ctrl	  = 1278.53	 +/-  53.8043	(limited)
a0	  = -0.362474	 +/-  0.0423579	(limited)
b0	  = -0.286239	 +/-  0.0210441	(limited)
width	  = 0.0117274	 +/-  0.000270008	(limited)
Info in <Minuit2>: Minuit2Minimizer::Hesse Using max-calls 4000
Info in <Minuit2>: Minuit2Minimizer::Hesse Hesse is valid - matrix is accurate
[#1] INFO:Fitting -- RooAbsPdf::fitTo(simul_model) Calculating sum-of-weights-squared correction matrix for covariance matrix
Info in <Minuit2>: Minuit2Minimizer::Hesse Using max-calls 4000
Info in <Minuit2>: Minuit2Minimizer::Hesse Hesse is valid - matrix is accurate
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization

  RooFitResult: minimized FCN value: -97525.5, estimated distance to minimum: 0.000187445
                covariance matrix quality: Full, accurate covariance matrix
                Status : MINIMIZE=0 HESSE=0 HESSE=0 

    Floating Parameter  InitialValue    FinalValue +/-  Error     GblCorr.
  --------------------  ------------  --------------------------  --------
                M_mumu    1.0197e+00    1.0188e+00 +/-  2.84e-04  <none>
                    Nb    1.7650e+03    1.5705e+03 +/-  4.68e+01  <none>
               Nb_ctrl    6.2624e+03    6.5483e+03 +/-  9.04e+01  <none>
                    Ns    2.8240e+03    1.9588e+03 +/-  5.08e+01  <none>
               Ns_ctrl    6.2624e+03    1.2785e+03 +/-  5.38e+01  <none>
                    a0    0.0000e+00   -3.6247e-01 +/-  4.24e-02  <none>
                    b0    0.0000e+00   -2.8624e-01 +/-  2.10e-02  <none>
                 width    1.8887e-02    1.1727e-02 +/-  2.70e-04  <none>

RooFit log in ROOT 6.34/02:

[#1] INFO:Eval -- RooRealVar::setRange(dimu_OS1) new range named 'fit_nll_signal_mumu_data' created with bounds [0.98,1.08]
[#1] INFO:Fitting -- RooAbsPdf::fitTo(signal_mumu_over_signal_mumu_Int[dimu_OS1|fit_range_signal]) 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_signal_mumu_over_signal_mumu_Int[dimu_OS1|fit_range_signal]_data) 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
Info in <Minuit2>: MnSeedGenerator Computing seed using NumericalGradient calculator
Info in <Minuit2>: MnSeedGenerator Initial state: FCN =      -6540.139974 Edm =       138022.4473 NCalls =      9
Info in <Minuit2>: NegativeG2LineSearch Doing a NegativeG2LineSearch since one of the G2 component is negative
Info in <Minuit2>: MnSeedGenerator Negative G2 found - new state: 
  Minimum value : -6759.661969
  Edm           : 1.708732621
  Internal parameters:	[                0    -0.3905360998]	
  Internal gradient  :	[     -9.246451549     -18.78991127]	
  Internal covariance matrix:
[[    0.078044331              0]
 [              0  0.00045993433]]]
Info in <Minuit2>: MnSeedGenerator Initial state  
  Minimum value : -6759.661969
  Edm           : 1.708732621
  Internal parameters:	[                0    -0.3905360998]	
  Internal gradient  :	[     -9.246451549     -18.78991127]	
  Internal covariance matrix:
[[    0.078044331              0]
 [              0  0.00045993433]]]
Info in <Minuit2>: VariableMetricBuilder Start iterating until Edm is < 0.001 with call limit = 1000
Info in <Minuit2>: VariableMetricBuilder    0 - FCN =      -6759.661969 Edm =       1.708732621 NCalls =     26
Info in <Minuit2>: VariableMetricBuilder    1 - FCN =      -6761.250973 Edm =     0.07328111069 NCalls =     32
Info in <Minuit2>: VariableMetricBuilder    2 - FCN =      -6761.337042 Edm =   1.380802967e-05 NCalls =     38
Info in <Minuit2>: VariableMetricBuilder After Hessian
Info in <Minuit2>: VariableMetricBuilder    3 - FCN =      -6761.337042 Edm =   1.619328585e-05 NCalls =     48
Minuit2Minimizer : Valid minimum - status = 0
FVAL  = -6761.33704188590127
Edm   = 1.61932858511379351e-05
Nfcn  = 48
M_mumu	  = 1.01973	 +/-  0.000397116	(limited)
width	  = 0.0188872	 +/-  0.00032099	(limited)
Info in <Minuit2>: Minuit2Minimizer::Hesse Using max-calls 1000
Info in <Minuit2>: Minuit2Minimizer::Hesse Hesse is valid - matrix is accurate
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization
[#1] INFO:Eval -- RooRealVar::setRange(dimu_OS1) new range named 'fit_nll_simul_model_datatofit' created with bounds [0.9,1.16]
[#1] INFO:Fitting -- RooAbsPdf::fitTo(simul_model) fixing normalization set for coefficient determination to observables in data
[#1] INFO:Fitting -- RooAddition::defaultErrorLevel(nll_simul_model_datatofit) Summation contains a RooNLLVar, using its error level
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: activating const optimization
Minuit2Minimizer: Minimize with max-calls 4000 convergence for edm < 1 strategy 1
Info in <Minuit2>: MnSeedGenerator Computing seed using NumericalGradient calculator
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name _tightBDT_signal_mumu_over_signal_mumu_Int[dimu_OS1]_Int[] is already in this set
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name _tightBDT_bmodel_over_bmodel_Int[dimu_OS1]_Int[] is already in this set
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name _looseBDT_signal_mumu_over_signal_mumu_Int[dimu_OS1]_Int[] is already in this set
[#0] ERROR:InputArguments -- RooArgSet::checkForDup: ERROR argument with name _looseBDT_bmodel_ctrl_over_bmodel_ctrl_Int[dimu_OS1]_Int[] is already in this set
Info in <Minuit2>: MnSeedGenerator Initial state: FCN =      -66667.33607 Edm =       4947424.615 NCalls =     33
Info in <Minuit2>: NegativeG2LineSearch Doing a NegativeG2LineSearch since one of the G2 component is negative
Info in <Minuit2>: MnSeedGenerator Negative G2 found - new state: 
  Minimum value : -70794.20641
  Edm           : 2382.596038
  Internal parameters:	[     -1.553566819                0     0.6435011088     -4.679872678     -1.504705178                0                0      1.559260277]	
  Internal gradient  :	[     0.3836497869     -1697.017873     -3099.523339      15.23508383      9.686819045      135.1214134      726.4935634     -10.20517518]	
  Internal covariance matrix:
[[    0.089816107              0              0              0              0              0              0              0]
 [              0   0.0015378866              0              0              0              0              0              0]
 [              0              0  0.00046715083              0              0              0              0              0]
 [              0              0              0   0.0042688608              0              0              0              0]
 [              0              0              0              0    0.014028471              0              0              0]
 [              0              0              0              0              0   0.0068249823              0              0]
 [              0              0              0              0              0              0  0.00092151164              0]
 [              0              0              0              0              0              0              0    0.002260788]]]
Info in <Minuit2>: MnSeedGenerator Initial state  
  Minimum value : -70794.20641
  Edm           : 2382.596038
  Internal parameters:	[     -1.553566819                0     0.6435011088     -4.679872678     -1.504705178                0                0      1.559260277]	
  Internal gradient  :	[     0.3836497869     -1697.017873     -3099.523339      15.23508383      9.686819045      135.1214134      726.4935634     -10.20517518]	
  Internal covariance matrix:
[[    0.089816107              0              0              0              0              0              0              0]
 [              0   0.0015378866              0              0              0              0              0              0]
 [              0              0  0.00046715083              0              0              0              0              0]
 [              0              0              0   0.0042688608              0              0              0              0]
 [              0              0              0              0    0.014028471              0              0              0]
 [              0              0              0              0              0   0.0068249823              0              0]
 [              0              0              0              0              0              0  0.00092151164              0]
 [              0              0              0              0              0              0              0    0.002260788]]]
Info in <Minuit2>: VariableMetricBuilder Start iterating until Edm is < 0.001 with call limit = 4000
Info in <Minuit2>: VariableMetricBuilder    0 - FCN =      -70794.20641 Edm =       2382.596038 NCalls =    179
Info in <Minuit2>: VariableMetricBuilder    1 - FCN =      -73527.13564 Edm =       8.125858153 NCalls =    202
Info in <Minuit2>: VariableMetricBuilder    2 - FCN =      -73536.24614 Edm =      0.3369509244 NCalls =    220
Info in <Minuit2>: VariableMetricBuilder    3 - FCN =      -73536.50858 Edm =     0.04668680801 NCalls =    238
Info in <Minuit2>: VariableMetricBuilder    4 - FCN =      -73536.54625 Edm =    0.004214518765 NCalls =    256
Info in <Minuit2>: VariableMetricBuilder    5 - FCN =      -73536.54991 Edm =   0.0001099576611 NCalls =    273
Info in <Minuit2>: VariableMetricBuilder After Hessian
Info in <Minuit2>: VariableMetricBuilder    6 - FCN =      -73536.54991 Edm =   0.0001633640581 NCalls =    334
Minuit2Minimizer : Valid minimum - status = 0
FVAL  = -73536.549905802487
Edm   = 0.00016336405813592651
Nfcn  = 334
M_mumu	  = 1.017	 +/-  7.87593e-05	(limited)
Nb	  = 3530	 +/-  0.976784	(limited)
Nb_ctrl	  = 7828	 +/-  0.675656	(limited)
Ns	  = 3530	 +/-  4.7914	(limited)
Ns_ctrl	  = 2.36629e-05	 +/-  6.92393	(limited)
a0	  = -0.485823	 +/-  0.0439686	(limited)
b0	  = -0.330843	 +/-  0.0204784	(limited)
width	  = 0.05	 +/-  2.22373e-05	(limited)
Info in <Minuit2>: Minuit2Minimizer::Hesse Using max-calls 4000
Info in <Minuit2>: Minuit2Minimizer::Hesse Hesse is valid - matrix is accurate
[#1] INFO:Fitting -- RooAbsPdf::fitTo(simul_model) Calculating sum-of-weights-squared correction matrix for covariance matrix
Info in <Minuit2>: Minuit2Minimizer::Hesse Using max-calls 4000
Info in <Minuit2>: Minuit2Minimizer::Hesse Hesse is valid - matrix is accurate
[#1] INFO:Minimization -- RooAbsMinimizerFcn::setOptimizeConst: deactivating const optimization

  RooFitResult: minimized FCN value: -73536.5, estimated distance to minimum: 0.00016331
                covariance matrix quality: Full, accurate covariance matrix
                Status : MINIMIZE=0 HESSE=0 HESSE=0 

    Floating Parameter  InitialValue    FinalValue +/-  Error     GblCorr.
  --------------------  ------------  --------------------------  --------
                M_mumu    1.0197e+00    1.0170e+00 +/-  6.04e-08  <none>
                    Nb    1.7650e+03    3.5300e+03 +/-  1.13e-02  <none>
               Nb_ctrl    6.2624e+03    7.8280e+03 +/-  8.30e-03  <none>
                    Ns    2.8240e+03    3.5300e+03 +/-  1.26e-01  <none>
               Ns_ctrl    6.2624e+03    2.3663e-05 +/-  2.56e-02  <none>
                    a0    0.0000e+00   -4.8582e-01 +/-  4.40e-02  <none>
                    b0    0.0000e+00   -3.3084e-01 +/-  2.05e-02  <none>
                 width    1.8887e-02    5.0000e-02 +/-  6.45e-08  <none>

Can you please let me know if any change in the minimizer was done in recent ROOT/RooFit versions? I would be happy to provide a reproducer if needed.

Thank you and best,
Federica

maybe @jonas knows

Are you sure your RooChebyshev is correctly defined so that it does not go into negative probabilities? See [RF] Handling of the negative values in RooChebychev causes fit divergence · Issue #12452 · root-project/root · GitHub

could you also try with ROOT 6.38.02 ?