Merge branch 'fit'

This commit is contained in:
Dominik Demuth 2023-05-19 18:14:29 +02:00
commit 8d06240205
5 changed files with 62 additions and 12 deletions

View File

@ -181,6 +181,7 @@ class QFitParameterWidget(QtWidgets.QWidget, Ui_FormFit):
for i, value in enumerate(self.data_values[sid]): for i, value in enumerate(self.data_values[sid]):
w = self.data_parameter[i] w = self.data_parameter[i]
w.blockSignals(True) w.blockSignals(True)
w.show_as_local_parameter(value is not None)
if value is None: if value is None:
w.value = self.glob_values[i] w.value = self.glob_values[i]
else: else:
@ -293,6 +294,7 @@ class ParameterSingleWidget(QtWidgets.QWidget):
self._name = name self._name = name
self.label.setText(convert(name)) self.label.setText(convert(name))
self.label.setToolTip('IIf 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.setValidator(QtGui.QDoubleValidator())
self.value_line.textChanged.connect(lambda: self.valueChanged.emit(self.value) if self.value is not None else 0) self.value_line.textChanged.connect(lambda: self.valueChanged.emit(self.value) if self.value is not None else 0)
@ -309,10 +311,12 @@ class ParameterSingleWidget(QtWidgets.QWidget):
layout.addSpacerItem(QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)) layout.addSpacerItem(QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum))
self.value_line = QtWidgets.QLineEdit(self) self.value_line = QtWidgets.QLineEdit(self)
self.value_line.textEdited.connect(lambda x: self.show_as_local_parameter(True))
layout.addWidget(self.value_line) layout.addWidget(self.value_line)
self.reset_button = QtWidgets.QToolButton(self) self.reset_button = QtWidgets.QToolButton(self)
self.reset_button.setText('Use global') self.reset_button.setText('Use global')
self.reset_button.clicked.connect(lambda: self.show_as_local_parameter(False))
layout.addWidget(self.reset_button) layout.addWidget(self.reset_button)
self.setLayout(layout) self.setLayout(layout)
@ -327,3 +331,9 @@ class ParameterSingleWidget(QtWidgets.QWidget):
@value.setter @value.setter
def value(self, val): def value(self, val):
self.value_line.setText(f'{float(val):.5g}') self.value_line.setText(f'{float(val):.5g}')
def show_as_local_parameter(self, is_local):
if is_local:
self.label.setStyleSheet('font-weight: bold;')
else:
self.label.setStyleSheet('')

View File

@ -113,8 +113,8 @@ class QFitResult(QtWidgets.QDialog, Ui_Dialog):
res = self._results[set_id] res = self._results[set_id]
self.param_tableWidget.setRowCount(len(res.parameter)) self.param_tableWidget.setRowCount(len(res.parameter))
for j, pvalue in enumerate(res.parameter.values()): for j, (pkey, pvalue) in enumerate(res.parameter.items()):
name = pvalue.name name = pkey
p_header = QtWidgets.QTableWidgetItem(convert(name, 'tex', 'str', brackets=True)) p_header = QtWidgets.QTableWidgetItem(convert(name, 'tex', 'str', brackets=True))
self.param_tableWidget.setVerticalHeaderItem(j, p_header) self.param_tableWidget.setVerticalHeaderItem(j, p_header)

View File

@ -653,12 +653,10 @@ class UpperManagement(QtCore.QObject):
else: else:
continue continue
for key, pvalue in data.parameter.items(): for fit_key, pvalue in data.parameter.items():
name = pvalue.full_name
fit_key = key + data.model_name
if fit_key not in fit_dict: if fit_key not in fit_dict:
fit_dict[fit_key] = [[], name] fit_dict[fit_key] = [[], fit_key]
err = 0 if pvalue.error is None else pvalue.error err = 0 if pvalue.error is None else pvalue.error

View File

@ -68,6 +68,7 @@ class MultiModel:
self._kwargs_right = {} self._kwargs_right = {}
self._kwargs_left = {} self._kwargs_left = {}
self.fun_kwargs = {} self.fun_kwargs = {}
self.idx = (left_idx, right_idx)
# mapping kwargs to kwargs of underlying functions # mapping kwargs to kwargs of underlying functions
self._ext_int_kw = {} self._ext_int_kw = {}
@ -178,13 +179,13 @@ class MultiModel:
if isinstance(self._left, MultiModel): if isinstance(self._left, MultiModel):
yield from self._left.sub_name() yield from self._left.sub_name()
elif hasattr(self._left, 'name'): elif hasattr(self._left, 'name'):
yield self._left.name yield f'{self._left.name}({self.idx[0]})'
else: else:
yield self.name + '(lhs)' yield self.name + '(lhs)'
if isinstance(self._right, MultiModel): if isinstance(self._right, MultiModel):
yield from self._right.sub_name() yield from self._right.sub_name()
elif hasattr(self._right, 'name'): elif hasattr(self._right, 'name'):
yield self._right.name yield f'{self._right.name}({self.idx[1]})'
else: else:
yield self.name + '(rhs)' yield self.name + '(rhs)'

View File

@ -63,9 +63,23 @@ class FitResultCreator:
parameters = OrderedDict([(k, v) for k, v in zip(pnames, p)]) parameters = OrderedDict([(k, v) for k, v in zip(pnames, p)])
p_final = [p.value for p in parameters.values()] p_final = [p.value for p in parameters.values()]
_y = model.func(p_final, _x, **fun_kwargs)
resid = model.func(p_final, x_orig, **fun_kwargs) - y_orig resid = model.func(p_final, x_orig, **fun_kwargs) - y_orig
actual_mode = -1
if 'complex_mode' in fun_kwargs:
actual_mode = fun_kwargs['complex_mode']
fun_kwargs['complex_mode'] = 0
_y = model.func(p_final, _x, **fun_kwargs)
if not actual_mode < 0:
if actual_mode == 1:
_y.imag = 0
elif actual_mode == 2:
_y.real = 0
fun_kwargs['complex_mode'] = actual_mode
stats = FitResultCreator.calc_statistics(_y, resid, nobs, nvar) stats = FitResultCreator.calc_statistics(_y, resid, nobs, nvar)
varied = [p.var for p in parameters.values()] varied = [p.var for p in parameters.values()]
@ -356,20 +370,47 @@ class FitResult(Points):
def with_new_x(self, x_values): def with_new_x(self, x_values):
if self.func is None: if self.func is None:
raise ValueError('no fit function available to calcualate new y values') raise ValueError('no fit function available to calculate new y values')
actual_mode = -1
if 'complex_mode' in self.fun_kwargs:
actual_mode = self.fun_kwargs['complex_mode']
self.fun_kwargs['complex_mode'] = 0
new_fit = self.copy() new_fit = self.copy()
y_values = self.func.func(self.p_final, x_values, **self.fun_kwargs) y_values = self.func.func(self.p_final, x_values, **self.fun_kwargs)
if not actual_mode < 0:
if actual_mode == 1:
y_values.imag = 0
elif actual_mode == 2:
y_values.real = 0
self.fun_kwargs['complex_mode'] = actual_mode
new_fit.set_data(x_values, y_values) new_fit.set_data(x_values, y_values)
return new_fit return new_fit
def sub(self, x_values): def sub(self, x_values):
part_functions = [] part_functions = []
actual_mode = -1
if 'complex_mode' in self.fun_kwargs:
actual_mode = self.fun_kwargs['complex_mode']
self.fun_kwargs['complex_mode'] = 0
for sub_name, sub_y in zip(self.func.sub_name(), self.func.sub(self.p_final, x_values, **self.fun_kwargs)): for sub_name, sub_y in zip(self.func.sub_name(), self.func.sub(self.p_final, x_values, **self.fun_kwargs)):
if np.iscomplexobj(sub_y): if not actual_mode < 0:
if actual_mode == 1:
sub_y.imag = 0
elif actual_mode == 2:
sub_y.real = 0
part_functions.append(Signal(x_values, sub_y, name=sub_name)) part_functions.append(Signal(x_values, sub_y, name=sub_name))
else: else:
part_functions.append(Points(x_values, sub_y, name=sub_name)) part_functions.append(Points(x_values, sub_y, name=sub_name))
if actual_mode < 0:
self.fun_kwargs['complex_mode'] = actual_mode
return part_functions return part_functions