From 02f8a3bb31307736fec278af08a626dd5a1cba28 Mon Sep 17 00:00:00 2001 From: Dominik Demuth Date: Sat, 8 Apr 2023 18:37:07 +0000 Subject: [PATCH] fitting (#43) adjustments to fit to see if fit is at least running, could help with #39 Co-authored-by: Dominik Demuth Reviewed-on: https://gitea.pkm.physik.tu-darmstadt.de/IPKM/nmreval/pulls/43 --- src/gui_qt/lib/utils.py | 2 +- src/gui_qt/main/mainwindow.py | 7 ++++++- src/gui_qt/main/management.py | 12 ++++++------ src/nmreval/fit/minimizer.py | 20 +++++++++++++++----- src/nmreval/io/asciireader.py | 4 ++-- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/gui_qt/lib/utils.py b/src/gui_qt/lib/utils.py index d2c1680..2849e3f 100644 --- a/src/gui_qt/lib/utils.py +++ b/src/gui_qt/lib/utils.py @@ -58,7 +58,7 @@ class RdBuCMap: elif val < self.min: col = QtGui.QColor.fromRgb(*RdBuCMap._rdbu[-1]) else: - col = QtGui.QColor.fromRgb(*(float(self.spline[i](val)) for i in range(3))) + col = QtGui.QColor.fromRgb(*(int(self.spline[i](val)) for i in range(3))) return col diff --git a/src/gui_qt/main/mainwindow.py b/src/gui_qt/main/mainwindow.py index c5979bf..b02d79e 100644 --- a/src/gui_qt/main/mainwindow.py +++ b/src/gui_qt/main/mainwindow.py @@ -66,7 +66,6 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): self._block_window_change = False self.fname = None - self.tim = QtCore.QTimer() self.settings = QtCore.QSettings('NMREVal', 'settings') self._init_gui() @@ -887,6 +886,11 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): 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)) + tim = QtCore.QTimer() + tim.setInterval(500) + tim.timeout.connect(lambda: self.status.setText(f'Fit running... ({self.management.fitter.step} evaluations)')) + tim.start(500) @QtCore.pyqtSlot(dict, int, bool) def show_fit_preview(self, funcs: dict, num: int, show: bool): @@ -910,6 +914,7 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow): @QtCore.pyqtSlot(list) def show_fit_results(self, results: list): self.fit_dialog.fit_button.setEnabled(True) + self.status.setText('') if results: res_dialog = QFitResult(results, self.management, parent=self) res_dialog.add_graphs(self.management.graphs.list()) diff --git a/src/gui_qt/main/management.py b/src/gui_qt/main/management.py index 6d71fb2..1c7000b 100644 --- a/src/gui_qt/main/management.py +++ b/src/gui_qt/main/management.py @@ -398,7 +398,7 @@ class UpperManagement(QtCore.QObject): self.__fit_options = (parameter, links, fit_options) - fitter = FitRoutine() + self.fitter = FitRoutine() models = {} fit_limits = fit_options['limits'] fit_mode = fit_options['fit_mode'] @@ -442,18 +442,18 @@ class UpperManagement(QtCore.QObject): lb=model_p['lb'], ub=model_p['ub'], fun_kwargs=set_params[1]) - fitter.add_data(d) + self.fitter.add_data(d) model_globs = model_p['glob'] if model_globs: m.set_global_parameter(**model_p['glob']) for links_i in links: - fitter.set_link_parameter((models[links_i[0]], links_i[1]), - (models[links_i[2]], links_i[3])) + self.fitter.set_link_parameter((models[links_i[0]], links_i[1]), + (models[links_i[2]], links_i[3])) with busy_cursor(): - self.fit_worker = FitWorker(fitter, fit_mode) + self.fit_worker = FitWorker(self.fitter, fit_mode) self.fit_thread = QtCore.QThread() self.fit_worker.moveToThread(self.fit_thread) @@ -469,7 +469,7 @@ class UpperManagement(QtCore.QObject): @QtCore.pyqtSlot(list, bool) def end_fit(self, result: list, success: bool): - print('FIT FINISHED') + logger.info('FIT FINISHED') if success: self.fitFinished.emit(result) else: diff --git a/src/nmreval/fit/minimizer.py b/src/nmreval/fit/minimizer.py index f157962..2655e4a 100644 --- a/src/nmreval/fit/minimizer.py +++ b/src/nmreval/fit/minimizer.py @@ -1,3 +1,4 @@ +import time import warnings from itertools import product @@ -31,6 +32,7 @@ class FitRoutine(object): self.result = [] self.linked = [] self._abort = False + self.step = 0 def add_data(self, x, y=None, we=None, idx=None): if isinstance(x, Data): @@ -165,7 +167,7 @@ class FitRoutine(object): self.find_paths(neighbor, graph, coupled_nodes, visited_nodes) def abort(self): - print('ABORT ???') + logger.info('Fit aborted by user') self._abort = True def run(self, mode='lsq'): @@ -311,14 +313,17 @@ class FitRoutine(object): return r def _least_squares_single(self, data, p0, lb, ub, var): + self.step = 0 + def cost(p): + self.step += 1 if self._abort: raise FitAbortException(f'Fit aborted by user') return self.__cost_scipy(p, data, var, data.para_keys) with np.errstate(all='ignore'): - res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=1000 * len(p0)) + res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=500 * len(p0)) err, corr, partial_corr = self._calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape) self.make_results(data, res.x, var, data.para_keys, res.jac.shape, @@ -326,12 +331,13 @@ class FitRoutine(object): def _least_squares_global(self, data, p0, lb, ub, var, data_pars): def cost(p): + self.step += 1 if self._abort: raise FitAbortException(f'Fit aborted by user') return self.__cost_scipy_glob(p, data, var, data_pars) with np.errstate(all='ignore'): - res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=1000 * len(p0)) + res = optimize.least_squares(cost, p0, bounds=(lb, ub), max_nfev=500 * len(p0)) err, corr, partial_corr = self._calc_error(res.jac, np.sum(res.fun**2), *res.jac.shape) for v, var_pars_k in zip(data, data_pars): @@ -340,25 +346,27 @@ class FitRoutine(object): def _nm_single(self, data, p0, lb, ub, var): def cost(p): + self.step += 1 if self._abort: raise FitAbortException(f'Fit aborted by user') return (self.__cost_scipy(p, data, var, data.para_keys)**2).sum() with np.errstate(all='ignore'): res = optimize.minimize(cost, p0, bounds=[(b1, b2) for (b1, b2) in zip(lb, ub)], - method='Nelder-Mead', options={'maxiter': 1000 * len(p0)}) + method='Nelder-Mead', options={'maxiter': 500 * len(p0)}) self.make_results(data, res.x, var, data.para_keys, (len(data), len(p0))) def _nm_global(self, data, p0, lb, ub, var, data_pars): def cost(p): + self.step += 1 if self._abort: raise FitAbortException(f'Fit aborted by user') return (self.__cost_scipy_glob(p, data, var, data_pars)**2).sum() with np.errstate(all='ignore'): res = optimize.minimize(cost, p0, bounds=[(b1, b2) for (b1, b2) in zip(lb, ub)], - method='Nelder-Mead', options={'maxiter': 1000 * len(p0)}) + method='Nelder-Mead', options={'maxiter': 500 * len(p0)}) for v, var_pars_k in zip(data, data_pars): self.make_results(v, res.x, var, var_pars_k, (sum(len(d) for d in data), len(p0))) @@ -367,6 +375,7 @@ class FitRoutine(object): odr_data = odr.Data(data.x, data.y) def func(p, _): + self.step += 1 if self._abort: raise FitAbortException(f'Fit aborted by user') return self.__cost_odr(p, data, var_pars, data.para_keys) @@ -390,6 +399,7 @@ class FitRoutine(object): def _odr_global(self, data, p0, var, data_pars): def func(p, _): + self.step += 1 if self._abort: raise FitAbortException(f'Fit aborted by user') return self.__cost_odr_glob(p, data, var, data_pars) diff --git a/src/nmreval/io/asciireader.py b/src/nmreval/io/asciireader.py index c10c158..58a5881 100644 --- a/src/nmreval/io/asciireader.py +++ b/src/nmreval/io/asciireader.py @@ -155,8 +155,8 @@ class AsciiReader: # more than one axis, append column number kwargs['name'] = filename + '_' + str(y[j-1]) - if j+num_y+1 < raw_data.shape[2]: - kwargs['y_err'] = raw_data[i, j+num_y+1] + if j+num_y < raw_data.shape[2]: + kwargs['y_err'] = raw_data[i, :, j+num_y] imported_sets.append(cls(x=raw_data[i, :, 0], y=raw_data[i, :, j:j+single_len].T, **kwargs))