catch errors in fit preparation

This commit is contained in:
Dominik Demuth 2023-09-07 19:52:53 +02:00
parent e2e52cebde
commit a406908a69
4 changed files with 79 additions and 60 deletions

View File

@ -298,7 +298,8 @@ class ParameterSingleWidget(QtWidgets.QWidget):
self._name = name
self.label.setText(convert(name))
self.label.setToolTip('If this is bold then this parameter is only for this data. otherwise the general parameter is used and displayed')
self.label.setToolTip('If this is bold then this parameter is only for this data. '
'Otherwise, the general parameter is used and displayed')
self.value_line.setValidator(QtGui.QDoubleValidator())
self.value_line.textChanged.connect(lambda: self.valueChanged.emit(self.value) if self.value is not None else 0)

View File

@ -916,10 +916,12 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.action_odr_fit: 'odr'
}[self.ac_group.checkedAction()]
self.fit_dialog.fit_button.setEnabled(False)
self.management.start_fit(parameter, links, fit_options)
self.status.setText('Fit running...'.format(self.management.fitter.step))
self.fit_timer.start(500)
fit_is_ready = self.management.prepare_fit(parameter, links, fit_options)
if fit_is_ready:
self.management.start_fit()
self.fit_dialog.fit_button.setEnabled(False)
self.status.setText('Fit running...'.format(self.management.fitter.step))
self.fit_timer.start(500)
@QtCore.pyqtSlot(dict, int, bool)
def show_fit_preview(self, funcs: dict, num: int, show: bool):

View File

@ -424,9 +424,9 @@ class UpperManagement(QtCore.QObject):
for d in self.data.values():
d.mask = np.ones_like(d.mask, dtype=bool)
def start_fit(self, parameter: dict, links: list, fit_options: dict):
def prepare_fit(self, parameter: dict, links: list, fit_options: dict) -> bool:
if self._fit_active:
return
return False
self.__fit_options = (parameter, links, fit_options)
@ -436,67 +436,80 @@ class UpperManagement(QtCore.QObject):
fit_mode = fit_options['fit_mode']
we_option = fit_options['we']
for model_id, model_p in parameter.items():
m = Model(model_p['func'])
models[model_id] = m
self.fitter.fitmethod = fit_mode
m_complex = model_p['complex']
# all-encompassing error catch
try:
for model_id, model_p in parameter.items():
m = Model(model_p['func'])
models[model_id] = m
# sets are not in active order but in order they first appeared in fit dialog
# iterate over order of set id in active order and access parameter inside loop
# instead of directly looping
list_ids = list(model_p['parameter'].keys())
set_order = [self.active_id.index(i) for i in list_ids]
for pos in set_order:
set_id = list_ids[pos]
m_complex = model_p['complex']
data_i = self.data[set_id]
set_params = model_p['parameter'][set_id]
# sets are not in active order but in order they first appeared in fit dialog
# iterate over order of set id in active order and access parameter inside loop
# instead of directly looping
list_ids = list(model_p['parameter'].keys())
set_order = [self.active_id.index(i) for i in list_ids]
for pos in set_order:
set_id = list_ids[pos]
if we_option.lower() == 'deltay':
we = data_i.y_err**2
else:
we = we_option
data_i = self.data[set_id]
set_params = model_p['parameter'][set_id]
if m_complex is None or m_complex == 1:
_y = data_i.y.real
elif m_complex == 2 and np.iscomplexobj(data_i.y):
_y = data_i.y.imag
else:
_y = data_i.y
if we_option.lower() == 'deltay':
we = data_i.y_err**2
else:
we = we_option
_x = data_i.x
if m_complex is None or m_complex == 1:
_y = data_i.y.real
elif m_complex == 2 and np.iscomplexobj(data_i.y):
_y = data_i.y.imag
else:
_y = data_i.y
if fit_limits == 'none':
inside = slice(None)
elif fit_limits == 'x':
x_lim, _ = self.graphs[self.current_graph].ranges
inside = np.where((_x >= x_lim[0]) & (_x <= x_lim[1]))
else:
inside = np.where((_x >= fit_limits[0]) & (_x <= fit_limits[1]))
_x = data_i.x
if isinstance(we, str):
d = fit_d.Data(_x[inside], _y[inside], we=we, idx=set_id)
else:
d = fit_d.Data(_x[inside], _y[inside], we=we[inside], idx=set_id)
if fit_limits == 'none':
inside = slice(None)
elif fit_limits == 'x':
x_lim, _ = self.graphs[self.current_graph].ranges
inside = np.where((_x >= x_lim[0]) & (_x <= x_lim[1]))
else:
inside = np.where((_x >= fit_limits[0]) & (_x <= fit_limits[1]))
d.set_model(m)
d.set_parameter(set_params[0], var=model_p['var'],
lb=model_p['lb'], ub=model_p['ub'],
fun_kwargs=set_params[1])
if isinstance(we, str):
d = fit_d.Data(_x[inside], _y[inside], we=we, idx=set_id)
else:
d = fit_d.Data(_x[inside], _y[inside], we=we[inside], idx=set_id)
self.fitter.add_data(d)
d.set_model(m)
d.set_parameter(set_params[0], var=model_p['var'],
lb=model_p['lb'], ub=model_p['ub'],
fun_kwargs=set_params[1])
model_globs = model_p['glob']
if model_globs:
m.set_global_parameter(**model_p['glob'])
self.fitter.add_data(d)
for links_i in links:
self.fitter.set_link_parameter((models[links_i[0]], links_i[1]),
(models[links_i[2]], links_i[3]))
model_globs = model_p['glob']
if model_globs:
m.set_global_parameter(**model_p['glob'])
for links_i in links:
self.fitter.set_link_parameter((models[links_i[0]], links_i[1]),
(models[links_i[2]], links_i[3]))
return True
except Exception as e:
logger.error('Fit preparation failed', *e.args)
QtWidgets.QMessageBox.warning(QtWidgets.QWidget(),
'Fit prep failed',
f'Fit preparation failed with message\n{e.args}')
return False
def start_fit(self):
with busy_cursor():
self.fit_worker = FitWorker(self.fitter, fit_mode)
self.fit_worker = FitWorker(self.fitter)
self.fit_thread = QtCore.QThread()
self.fit_worker.moveToThread(self.fit_thread)
@ -532,7 +545,8 @@ class UpperManagement(QtCore.QObject):
for set_id, set_parameter in parameter.items():
new_values = [v.value for v in res[set_id].parameter.values()]
parameter[set_id] = (new_values, set_parameter[1])
self.start_fit(*self.__fit_options)
if self.prepare_fit(*self.__fit_options):
self.start_fit()
def make_fits(self, res: dict, opts: list, param_graph: str, show_fit: bool, parts: bool, extrapolate: list) -> None:
"""
@ -1270,16 +1284,15 @@ class UpperManagement(QtCore.QObject):
class FitWorker(QtCore.QObject):
finished = QtCore.pyqtSignal(list, bool)
def __init__(self, fitter, mode):
def __init__(self, fitter):
super().__init__()
self.fitter = fitter
self.mode = mode
@QtCore.pyqtSlot()
def run(self):
try:
res = self.fitter.run(mode=self.mode)
res = self.fitter.run()
success = True
except Exception as e:
res = [e]

View File

@ -23,7 +23,7 @@ class FitAbortException(Exception):
class FitRoutine(object):
def __init__(self, mode='lsq'):
self._fitmethod = mode
self.fitmethod = mode
self.data = []
self.fit_model = None
self._no_own_model = []
@ -169,10 +169,13 @@ class FitRoutine(object):
logger.info('Fit aborted by user')
self._abort = True
def run(self, mode='lsq'):
def run(self, mode: str=None):
self._abort = False
self.parameter = Parameters()
if mode is None:
mode = self.fitmethod
fit_groups, linked_parameter = self.prepare_links()
for data_groups in fit_groups: