Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undoing changes from PR #1682 #1915

Merged
merged 1 commit into from
Oct 12, 2021
Merged
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
79 changes: 17 additions & 62 deletions src/sas/sascalc/fit/BumpsFitting.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@
import traceback

import numpy as np
from uncertainties import ufloat, correlated_values

from bumps import fitters
from bumps.parameter import unique as unique_parameters

try:
from bumps.options import FIT_CONFIG
# Default bumps to use the Levenberg-Marquardt optimizer
Expand Down Expand Up @@ -282,73 +279,35 @@ def fit(self, msg_q=None,
result = run_bumps(problem, handler, curr_thread)
if handler is not None:
handler.update_fit(last=True)
propagate_errors = all(model.constraints for model in models)
uncertainty_error = None
if propagate_errors:
# TODO: shouldn't reference internal parameters of fit problem
varying = problem._parameters
# Propagate uncertainty through the parameter expressions
# We are going to abuse bumps a little here and stuff uncertainty
# objects into the parameter values, then update all the
# derived parameters with uncertainty propagation. We need to
# avoid triggering a model recalc since the uncertainty objects
# will not be working with sasmodels.
# TODO: if dream then use forward MC to evaluate uncertainty
# TODO: move uncertainty propagation into bumps
# TODO: should scale stderr by sqrt(chisq/DOF) if dy is unknown
values, errs, cov = result['value'], result["stderr"], result[
'covariance']
assert values is not None
# Turn all parameters (fixed and varying) into uncertainty objects with
# zero uncertainty.
for p in unique_parameters(problem.model_parameters()):
p.value = ufloat(p.value, 0)
# then update the computed standard deviation of fitted parameters
if len(varying) < 2:
varying[0].value = ufloat(values[0], errs[0])
else:
fitted = (correlated_values(values, cov) if not errs else
[ufloat(value, np.nan) for value in values])

for p, v in zip(varying, fitted):
p.value = v
try:
problem.setp_hook()
except np.linalg.LinAlgError:
fitted = [ufloat(value, err) for value, err in zip(
values, errs)]
uncertainty_error = True
for p, v in zip(varying, fitted):
p.value = v
problem.setp_hook()
except TypeError:
propagate_errors = False
uncertainty_error = True

# TODO: shouldn't reference internal parameters of fit problem
varying = problem._parameters
# collect the results
all_results = []
for M in problem.models:
fitness = M.fitness
par_names = fitness.fitted_par_names + fitness.computed_par_names
pars = fitness.fitted_pars + fitness.computed_pars
R = FResult(model=fitness.model,
data=fitness.data,
param_list=par_names)
fitted_index = [varying.index(p) for p in fitness.fitted_pars]
param_list = fitness.fitted_par_names + fitness.computed_par_names
R = FResult(model=fitness.model, data=fitness.data,
param_list=param_list)
R.theory = fitness.theory()
R.residuals = fitness.residuals()
R.index = fitness.data.idx
R.fitter_id = self.fitter_id
# TODO: should scale stderr by sqrt(chisq/DOF) if dy is unknown
R.success = result['success']
if R.success:
R.pvec = (np.array([p.value.n for p in pars]) if
propagate_errors else result['value'])
R.stderr = (np.array([p.value.s for p in pars]) if
propagate_errors else result["stderr"])
DOF = max(1, fitness.numpoints() - len(fitness.fitted_pars))
R.fitness = np.sum(R.residuals ** 2) / DOF
if result['stderr'] is None:
R.stderr = np.NaN*np.ones(len(param_list))
else:
R.stderr = np.hstack((result['stderr'][fitted_index],
np.NaN*np.ones(len(fitness.computed_pars))))
R.pvec = np.hstack((result['value'][fitted_index],
[p.value for p in fitness.computed_pars]))
R.fitness = np.sum(R.residuals**2)/(fitness.numpoints() - len(fitted_index))
else:
R.pvec = np.asarray([p.value for p in pars])
R.stderr = np.NaN * np.ones(len(pars))
R.stderr = np.NaN*np.ones(len(param_list))
R.pvec = np.asarray([p.value for p in fitness.fitted_pars+fitness.computed_pars])
R.fitness = np.NaN
R.convergence = result['convergence']
if result['uncertainty'] is not None:
Expand Down Expand Up @@ -408,19 +367,15 @@ def abort_test():
success = best is not None
try:
stderr = fitdriver.stderr() if success else None
cov = (fitdriver.cov() if not hasattr(fitdriver.fitter, 'state') else
np.cov(fitdriver.fitter.state.draw().points.T))
except Exception as exc:
errors.append(str(exc))
errors.append(traceback.format_exc())
stderr = None
cov = None
return {
'value': best if success else None,
'stderr': stderr,
'success': success,
'convergence': convergence,
'uncertainty': getattr(fitdriver.fitter, 'state', None),
'errors': '\n'.join(errors),
'covariance': cov,
}