Repository: lmfit/lmfit-py

Issue:
Incorrect value in MinimizerResult.init_values
#### First Time Issue Code
Yes, I read the instructions and I am sure this is a GitHub Issue.

#### Description
Using the [simple example] from the documentation and printing `result.init_values` (or `result.init_vals`) as in the MWE below reveals an incorrect initial value for `amp`. It should be `10` but it is `10.954451150103322`.

[simple example]: https://lmfit.github.io/lmfit-py/parameters.html#simple-example

###### A Minimal, Complete, and Verifiable example
```python
import numpy as np

from lmfit import Minimizer, Parameters, report_fit

# create data to be fitted
x = np.linspace(0, 15, 301)
np.random.seed(2021)
data = (5.0 * np.sin(2.0*x - 0.1) * np.exp(-x*x*0.025) +
        np.random.normal(size=x.size, scale=0.2))


# define objective function: returns the array to be minimized
def fcn2min(params, x, data):
    """Model a decaying sine wave and subtract data."""
    amp = params['amp']
    shift = params['shift']
    omega = params['omega']
    decay = params['decay']
    model = amp * np.sin(x*omega + shift) * np.exp(-x*x*decay)
    return model - data


# create a set of Parameters
params = Parameters()
params.add('amp', value=10, min=0)
params.add('decay', value=0.1)
params.add('shift', value=0.0, min=-np.pi/2., max=np.pi/2.)
params.add('omega', value=3.0)

# do fit, here with the default leastsq algorithm
minner = Minimizer(fcn2min, params, fcn_args=(x, data))
result = minner.minimize()

# calculate final result
final = data + result.residual

# write error report
report_fit(result)

# now print the inital values
print(result.init_values)
```

This gives the output
```
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 59
    # data points      = 301
    # variables        = 4
    chi-square         = 12.1867036
    reduced chi-square = 0.04103267
    Akaike info crit   = -957.236198
    Bayesian info crit = -942.407756
[[Variables]]
    amp:    5.03087926 +/- 0.04005805 (0.80%) (init = 10)
    decay:  0.02495454 +/- 4.5395e-04 (1.82%) (init = 0.1)
    shift: -0.10264934 +/- 0.01022298 (9.96%) (init = 0)
    omega:  2.00026304 +/- 0.00326184 (0.16%) (init = 3)
[[Correlations]] (unreported correlations are < 0.100)
    C(shift, omega) = -0.785
    C(amp, decay)   = 0.584
    C(amp, shift)   = -0.118
{'amp': 10.954451150103322, 'decay': 0.1, 'shift': 0.0, 'omega': 3.0}
```

`report_fit` correctly reports an initial value of `10` for `amp` but `result.init_values` does not.

###### Version information
```
Python: 3.9.13 | packaged by conda-forge | (main, May 27 2022, 16:50:36) [MSC v.1929 64 bit (AMD64)]

lmfit: 1.0.3, scipy: 1.9.3, numpy: 1.23.4,asteval: 0.9.27, uncertainties: 3.1.7
```




Discussion:
@schtandard OK, thanks... that's not good!  

It looks to me like that is still the "internal value", before bounds are applied. I'll check that out.


Resolving patch:
diff --git a/lmfit/minimizer.py b/lmfit/minimizer.py
--- a/lmfit/minimizer.py
+++ b/lmfit/minimizer.py
@@ -710,6 +710,7 @@ def prepare_fit(self, params=None):
         # and which are defined expressions.
         result.var_names = []  # note that this *does* belong to self...
         result.init_vals = []
+        result._init_vals_internal = []
         result.params.update_constraints()
         result.nfev = 0
         result.call_kws = {}
@@ -725,7 +726,8 @@ def prepare_fit(self, params=None):
                 par.vary = False
             if par.vary:
                 result.var_names.append(name)
-                result.init_vals.append(par.setup_bounds())
+                result._init_vals_internal.append(par.setup_bounds())
+                result.init_vals.append(par.value)
 
             par.init_value = par.value
             if par.name is None:
@@ -953,11 +955,12 @@ def scalar_minimize(self, method='Nelder-Mead', params=None, max_nfev=None,
         """
         result = self.prepare_fit(params=params)
         result.method = method
-        variables = result.init_vals
+        variables = result._init_vals_internal
         params = result.params
 
         self.set_max_nfev(max_nfev, 2000*(result.nvarys+1))
         fmin_kws = dict(method=method, options={'maxiter': 2*self.max_nfev})
+        # fmin_kws = dict(method=method, options={'maxfun': 2*self.max_nfev})
         fmin_kws.update(self.kws)
 
         if 'maxiter' in kws:
@@ -1661,7 +1664,7 @@ def leastsq(self, params=None, max_nfev=None, **kws):
         result = self.prepare_fit(params=params)
         result.method = 'leastsq'
         result.nfev -= 2  # correct for "pre-fit" initialization/checks
-        variables = result.init_vals
+        variables = result._init_vals_internal
 
         # note we set the max number of function evaluations here, and send twice that
         # value to the solver so it essentially never stops on its own
@@ -1779,7 +1782,7 @@ def basinhopping(self, params=None, max_nfev=None, **kws):
         basinhopping_kws.update(self.kws)
         basinhopping_kws.update(kws)
 
-        x0 = result.init_vals
+        x0 = result._init_vals_internal
         result.call_kws = basinhopping_kws
         try:
             ret = scipy_basinhopping(self.penalty, x0, **basinhopping_kws)
@@ -2072,7 +2075,7 @@ def ampgo(self, params=None, max_nfev=None, **kws):
         ampgo_kws.update(self.kws)
         ampgo_kws.update(kws)
 
-        values = result.init_vals
+        values = result._init_vals_internal
         result.method = f"ampgo, with {ampgo_kws['local']} as local solver"
         result.call_kws = ampgo_kws
         try:
@@ -2212,8 +2215,7 @@ def dual_annealing(self, params=None, max_nfev=None, **kws):
         result.method = 'dual_annealing'
         self.set_max_nfev(max_nfev, 200000*(result.nvarys+1))
 
-        da_kws = dict(maxiter=1000, local_search_options={},
-                      initial_temp=5230.0, restart_temp_ratio=2e-05,
+        da_kws = dict(initial_temp=5230.0, restart_temp_ratio=2e-05,
                       visit=2.62, accept=-5.0, maxfun=2*self.max_nfev,
                       seed=None, no_local_search=False, callback=None,
                       x0=None)


Test patch:
diff --git a/tests/test_NIST_Strd.py b/tests/test_NIST_Strd.py
--- a/tests/test_NIST_Strd.py
+++ b/tests/test_NIST_Strd.py
@@ -118,7 +118,7 @@ def build_usage():
 --------
   -m  name of fitting method.  One of:
           leastsq, nelder, powell, lbfgsb, bfgs,
-          tnc, cobyla, slsqp, cg, newto-cg
+          tnc, cobyla, slsqp, cg, newton-cg
       leastsq (Levenberg-Marquardt) is the default
 """
     return usage
@@ -183,115 +183,114 @@ def RunNIST_Model(model):
     out1 = NIST_Dataset(model, start='start1', plot=False, verbose=False)
     out2 = NIST_Dataset(model, start='start2', plot=False, verbose=False)
     assert(out1 or out2)
-    return out1 or out2
 
 
 def test_Bennett5():
-    return RunNIST_Model('Bennett5')
+    RunNIST_Model('Bennett5')
 
 
 def test_BoxBOD():
-    return RunNIST_Model('BoxBOD')
+    RunNIST_Model('BoxBOD')
 
 
 def test_Chwirut1():
-    return RunNIST_Model('Chwirut1')
+    RunNIST_Model('Chwirut1')
 
 
 def test_Chwirut2():
-    return RunNIST_Model('Chwirut2')
+    RunNIST_Model('Chwirut2')
 
 
 def test_DanWood():
-    return RunNIST_Model('DanWood')
+    RunNIST_Model('DanWood')
 
 
 def test_ENSO():
-    return RunNIST_Model('ENSO')
+    RunNIST_Model('ENSO')
 
 
 def test_Eckerle4():
-    return RunNIST_Model('Eckerle4')
+    RunNIST_Model('Eckerle4')
 
 
 def test_Gauss1():
-    return RunNIST_Model('Gauss1')
+    RunNIST_Model('Gauss1')
 
 
 def test_Gauss2():
-    return RunNIST_Model('Gauss2')
+    RunNIST_Model('Gauss2')
 
 
 def test_Gauss3():
-    return RunNIST_Model('Gauss3')
+    RunNIST_Model('Gauss3')
 
 
 def test_Hahn1():
-    return RunNIST_Model('Hahn1')
+    RunNIST_Model('Hahn1')
 
 
 def test_Kirby2():
-    return RunNIST_Model('Kirby2')
+    RunNIST_Model('Kirby2')
 
 
 def test_Lanczos1():
-    return RunNIST_Model('Lanczos1')
+    RunNIST_Model('Lanczos1')
 
 
 def test_Lanczos2():
-    return RunNIST_Model('Lanczos2')
+    RunNIST_Model('Lanczos2')
 
 
 def test_Lanczos3():
-    return RunNIST_Model('Lanczos3')
+    RunNIST_Model('Lanczos3')
 
 
 def test_MGH09():
-    return RunNIST_Model('MGH09')
+    RunNIST_Model('MGH09')
 
 
 def test_MGH10():
-    return RunNIST_Model('MGH10')
+    RunNIST_Model('MGH10')
 
 
 def test_MGH17():
-    return RunNIST_Model('MGH17')
+    RunNIST_Model('MGH17')
 
 
 def test_Misra1a():
-    return RunNIST_Model('Misra1a')
+    RunNIST_Model('Misra1a')
 
 
 def test_Misra1b():
-    return RunNIST_Model('Misra1b')
+    RunNIST_Model('Misra1b')
 
 
 def test_Misra1c():
-    return RunNIST_Model('Misra1c')
+    RunNIST_Model('Misra1c')
 
 
 def test_Misra1d():
-    return RunNIST_Model('Misra1d')
+    RunNIST_Model('Misra1d')
 
 
 def test_Nelson():
-    return RunNIST_Model('Nelson')
+    RunNIST_Model('Nelson')
 
 
 def test_Rat42():
-    return RunNIST_Model('Rat42')
+    RunNIST_Model('Rat42')
 
 
 def test_Rat43():
-    return RunNIST_Model('Rat43')
+    RunNIST_Model('Rat43')
 
 
 def test_Roszman1():
-    return RunNIST_Model('Roszman1')
+    RunNIST_Model('Roszman1')
 
 
 def test_Thurber():
-    return RunNIST_Model('Thurber')
+    RunNIST_Model('Thurber')
 
 
 if __name__ == '__main__':