Skip to content

Commit

Permalink
Merge pull request #860 from lmfit/param_vary_setter
Browse files Browse the repository at this point in the history
make Parameter.vary a property
  • Loading branch information
newville authored Apr 7, 2023
2 parents 52012fd + 8e5c5d2 commit a03ac0f
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 9 deletions.
1 change: 1 addition & 0 deletions doc/whatsnew.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ New features:

Bug fixes/enhancements:

- fix bug when setting ``param.vary=True`` for a constrained parameter (Issue #859; PR #860)
- fix bug in reported uncertainties for constrained parameters by better propating uncertainties (Issue #855; PR #856)
- Coercing of user input data and independent data for ``Model`` to float64 ndarrays is somewhat less aggressive and
will not increase the precision of numpy ndarrays (see :ref:`model_data_coercion_section` for details). The resulting
Expand Down
6 changes: 4 additions & 2 deletions examples/doc_builtinmodels_peakmodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@
axes[0].plot(x, out.best_fit, '-', label='Voigt Model\ngamma constrained')
axes[0].legend()

# free gamma parameter
pars['gamma'].set(value=0.7, vary=True, expr='')
# allow the gamma parameter to vary in the fit
pars['gamma'].vary = True
out_gamma = mod.fit(y, pars, x=x)
print(out.fit_report(correl_mode='table'))

axes[1].plot(x, y, '-')
axes[1].plot(x, out_gamma.best_fit, '-', label='Voigt Model\ngamma unconstrained')
axes[1].legend()
Expand Down
24 changes: 18 additions & 6 deletions lmfit/parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,7 +639,7 @@ def __init__(self, name, value=None, vary=True, min=-inf, max=inf,
self.min = min
self.max = max
self.brute_step = brute_step
self.vary = vary
self._vary = vary
self._expr = expr
self._expr_ast = None
self._expr_eval = None
Expand Down Expand Up @@ -702,7 +702,7 @@ def set(self, value=None, vary=None, min=None, max=None, expr=None,
"""
if vary is not None:
self.vary = vary
self._vary = vary
if vary:
self.__set_expression('')

Expand Down Expand Up @@ -751,13 +751,13 @@ def _init_bounds(self):

def __getstate__(self):
"""Get state for pickle."""
return (self.name, self.value, self.vary, self.expr, self.min,
return (self.name, self.value, self._vary, self.expr, self.min,
self.max, self.brute_step, self.stderr, self.correl,
self.init_value, self.user_data)

def __setstate__(self, state):
"""Set state for pickle."""
(self.name, _value, self.vary, self.expr, self.min, self.max,
(self.name, _value, self._vary, self.expr, self.min, self.max,
self.brute_step, self.stderr, self.correl, self.init_value,
self.user_data) = state
self._expr_ast = None
Expand All @@ -772,7 +772,7 @@ def __repr__(self):
"""Return printable representation of a Parameter object."""
s = []
sval = f"value={repr(self._getval())}"
if not self.vary and self._expr is None:
if not self._vary and self._expr is None:
sval += " (fixed)"
elif self.stderr is not None:
sval += f" +/- {self.stderr:.3g}"
Expand Down Expand Up @@ -882,6 +882,18 @@ def value(self, val):
if self._expr_eval is not None:
self._expr_eval.symtable[self.name] = self._val

@property
def vary(self):
"""Return whether the parameter is variable"""
return self._vary

@vary.setter
def vary(self, val):
"""Set whether a parameter is varied"""
self._vary = val
if val:
self.__set_expression('')

@property
def expr(self):
"""Return the mathematical expression used to constrain the value in fit."""
Expand All @@ -901,7 +913,7 @@ def __set_expression(self, val):
val = None
self._expr = val
if val is not None:
self.vary = False
self._vary = False
if not hasattr(self, '_expr_eval'):
self._expr_eval = None
if val is None:
Expand Down
31 changes: 30 additions & 1 deletion tests/test_parameters.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
"""Tests for the Parameters class."""


from copy import copy, deepcopy
import os
import pickle

import numpy as np
from numpy.testing import assert_allclose
import pytest

import lmfit
from lmfit.models import VoigtModel


@pytest.fixture
Expand Down Expand Up @@ -605,3 +606,31 @@ def test_create_params():
assert pars1['d'].value == 11
assert pars1['e'].value == 10000
assert pars1['e'].brute_step == 4


def test_unset_constrained_param():
"""test 'unsetting' a constrained parameter by
just setting `param.vary = True`
"""
data = np.loadtxt(os.path.join(os.path.dirname(__file__), '..',
'examples', 'test_peak.dat'))
x = data[:, 0]
y = data[:, 1]

# initial fit
mod = VoigtModel()
params = mod.guess(y, x=x)
out1 = mod.fit(y, params, x=x)

assert out1.nvarys == 3
assert out1.chisqr < 20.0

# now just gamma to vary
params['gamma'].vary = True
out2 = mod.fit(y, params, x=x)

assert out2.nvarys == 4
assert out2.chisqr < out1.chisqr
assert out2.rsquared > out1.rsquared
assert out2.params['gamma'].correl['sigma'] < -0.6

0 comments on commit a03ac0f

Please sign in to comment.