Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ classifiers = [
requires-python = ">=3.11"
dependencies = [
"asteval",
"bumps<1.0.0",
"bumps",
"DFO-LS",
"lmfit",
"numpy",
Expand Down
2 changes: 1 addition & 1 deletion src/easyscience/base_classes/based_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@

from ..io import SerializerComponent
from ..variable import Parameter
from ..variable.descriptor_base import DescriptorBase

if TYPE_CHECKING:
from ..fitting.calculators import InterfaceFactoryTemplate
from ..variable.descriptor_base import DescriptorBase


class BasedBase(SerializerComponent):
Expand Down
10 changes: 5 additions & 5 deletions src/easyscience/fitting/minimizers/minimizer_bumps.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def all_methods() -> List[str]:
@staticmethod
def supported_methods() -> List[str]:
# only a small subset
methods = ['scipy.leastsq', 'amoeba', 'newton', 'lm']
methods = ['amoeba', 'newton', 'lm']
return methods

def fit(
Expand Down Expand Up @@ -133,7 +133,7 @@ def fit(

try:
model_results = bumps_fit(problem, **method_dict, **minimizer_kwargs, **kwargs)
self._set_parameter_fit_result(model_results, stack_status)
self._set_parameter_fit_result(model_results, stack_status, problem._parameters)
results = self._gen_fit_results(model_results)
except Exception as e:
for key in self._cached_pars.keys():
Expand Down Expand Up @@ -200,7 +200,7 @@ def _make_func(x, y, weights):

return _outer(self)

def _set_parameter_fit_result(self, fit_result, stack_status: bool):
def _set_parameter_fit_result(self, fit_result, stack_status: bool, par_list: List[BumpsParameter]):
"""
Update parameters to their final values and assign a std error to them.

Expand All @@ -219,7 +219,7 @@ def _set_parameter_fit_result(self, fit_result, stack_status: bool):
global_object.stack.enabled = True
global_object.stack.beginMacro('Fitting routine')

for index, name in enumerate(self._cached_model._pnames):
for index, name in enumerate([par.name for par in par_list]):
dict_name = name[len(MINIMIZER_PARAMETER_PREFIX) :]
pars[dict_name].value = fit_result.x[index]
pars[dict_name].error = fit_result.dx[index]
Expand All @@ -242,7 +242,7 @@ def _gen_fit_results(self, fit_results, **kwargs) -> FitResults:
results.success = fit_results.success
pars = self._cached_pars
item = {}
for index, name in enumerate(self._cached_model._pnames):
for index, name in enumerate(self._cached_model.pars.keys()):
dict_name = name[len(MINIMIZER_PARAMETER_PREFIX) :]

item[name] = pars[dict_name].value
Expand Down
37 changes: 28 additions & 9 deletions tests/unit_tests/fitting/minimizers/test_minimizer_bumps.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ def test_init_exception(self) -> None:

def test_all_methods(self, minimizer: Bumps) -> None:
# When Then Expect
assert minimizer.all_methods() == ['amoeba', 'de', 'dream', 'newton', 'scipy.leastsq', 'lm']
assert minimizer.all_methods() == ['amoeba', 'de', 'dream', 'newton', 'lm']

def test_supported_methods(self, minimizer: Bumps) -> None:
# When Then Expect
assert set(minimizer.supported_methods()) == set(['scipy.leastsq','newton', 'lm', 'amoeba'])
assert set(minimizer.supported_methods()) == set(['newton', 'lm', 'amoeba'])

def test_fit(self, minimizer: Bumps, monkeypatch) -> None:
# When
Expand All @@ -47,28 +47,40 @@ def test_fit(self, minimizer: Bumps, monkeypatch) -> None:
mock_bumps_fit = MagicMock(return_value='fit')
monkeypatch.setattr(easyscience.fitting.minimizers.minimizer_bumps, "bumps_fit", mock_bumps_fit)

mock_FitProblem = MagicMock(return_value='fit_problem')
# Prepare a mock parameter with .name = 'pmock_parm_1'
mock_bumps_param = MagicMock()
mock_bumps_param.name = 'pmock_parm_1'
# Patch FitProblem to have _parameters attribute as expected
mock_FitProblem_instance = MagicMock()
mock_FitProblem_instance._parameters = [mock_bumps_param]
mock_FitProblem = MagicMock(return_value=mock_FitProblem_instance)
monkeypatch.setattr(easyscience.fitting.minimizers.minimizer_bumps, "FitProblem", mock_FitProblem)

mock_model = MagicMock()
mock_model_function = MagicMock(return_value=mock_model)
minimizer._make_model = MagicMock(return_value=mock_model_function)
minimizer._set_parameter_fit_result = MagicMock()
minimizer._gen_fit_results = MagicMock(return_value='gen_fit_results')

cached_par = MagicMock()
cached_par.value = 1
cached_pars = {'mock_parm_1': cached_par}
minimizer._cached_pars = cached_pars

# Patch _set_parameter_fit_result to a real function that will not raise KeyError
def fake_set_parameter_fit_result(fit_result, stack_status, par_list):
# Simulate what the real function does: update _cached_pars
for index, name in enumerate([par.name for par in par_list]):
dict_name = name[len('p'):] # Remove prefix 'p'
minimizer._cached_pars[dict_name].value = 42 # Arbitrary value
minimizer._set_parameter_fit_result = fake_set_parameter_fit_result

# Then
result = minimizer.fit(x=1.0, y=2.0)

# Expect
assert result == 'gen_fit_results'
mock_bumps_fit.assert_called_once_with('fit_problem', method='amoeba')
mock_bumps_fit.assert_called_once_with(mock_FitProblem_instance, method='amoeba')
minimizer._make_model.assert_called_once_with(parameters=None)
minimizer._set_parameter_fit_result.assert_called_once_with('fit', False)
minimizer._gen_fit_results.assert_called_once_with('fit')
mock_model_function.assert_called_once_with(1.0, 2.0, 1.4142135623730951)
mock_FitProblem.assert_called_once_with(mock_model)
Expand Down Expand Up @@ -107,15 +119,22 @@ def test_set_parameter_fit_result_no_stack_status(self, minimizer: Bumps):
minimizer._cached_pars['b'].value = 'b'

mock_cached_model = MagicMock()
mock_cached_model._pnames = ['pa', 'pb']
mock_cached_model.pars = {'pa':0, 'pb': 0}
minimizer._cached_model = mock_cached_model

mock_fit_result = MagicMock()
mock_fit_result.x = [1.0, 2.0]
mock_fit_result.dx = [0.1, 0.2]

# The new argument: par_list (list of mock parameters)
mock_par_a = MagicMock()
mock_par_a.name = 'pa'
mock_par_b = MagicMock()
mock_par_b.name = 'pb'
par_list = [mock_par_a, mock_par_b]

# Then
minimizer._set_parameter_fit_result(mock_fit_result, False)
minimizer._set_parameter_fit_result(mock_fit_result, False, par_list)

# Expect
assert minimizer._cached_pars['a'].value == 1.0
Expand All @@ -136,7 +155,7 @@ def test_gen_fit_results(self, minimizer: Bumps, monkeypatch):
mock_cached_model.x = 'x'
mock_cached_model.y = 'y'
mock_cached_model.dy = 'dy'
mock_cached_model._pnames = ['ppar_1', 'ppar_2']
mock_cached_model.pars = {'ppar_1': 0, 'ppar_2': 0}
minimizer._cached_model = mock_cached_model

mock_cached_par_1 = MagicMock()
Expand Down
Loading