def test_fittingUndoRedo(): m_value = 6 c_value = 2 x = np.linspace(-5, 5, 100) dy = np.random.rand(*x.shape) class Line(BaseObj): def __init__(self, m: Parameter, c: Parameter): super(Line, self).__init__('basic_line', m=m, c=c) @classmethod def default(cls): m = Parameter('m', m_value) c = Parameter('c', c_value) return cls(m=m, c=c) @classmethod def from_pars(cls, m_value: float, c_value: float): m = Parameter('m', m_value) c = Parameter('c', c_value) return cls(m=m, c=c) def __call__(self, x: np.ndarray) -> np.ndarray: return self.m.raw_value * x + self.c.raw_value l1 = Line.default() m_sp = 4 c_sp = -3 l2 = Line.from_pars(m_sp, c_sp) l2.m.fixed = False l2.c.fixed = False y = l1(x) + 0.125 * (dy - 0.5) from easyCore.Fitting.Fitting import Fitter f = Fitter(l2, l2) from easyCore import borg borg.stack.enabled = True res = f.fit(x, y) assert l1.c.raw_value == pytest.approx(l2.c.raw_value, rel=l2.c.error * 2) assert l1.m.raw_value == pytest.approx(l2.m.raw_value, rel=l2.m.error * 2) assert borg.stack.undoText() == 'Fitting routine' borg.stack.undo() assert l2.m.raw_value == m_sp assert l2.c.raw_value == c_sp assert borg.stack.redoText() == 'Fitting routine' borg.stack.redo() assert l2.m.raw_value == res.p[f'p{borg.map.convert_id_to_key(l2.m)}'] assert l2.c.raw_value == res.p[f'p{borg.map.convert_id_to_key(l2.c)}']
def __init__(self, parent=None, sample=None, fit_func=""): super().__init__(parent) self.fitter = CoreFitter(sample, fit_func) self.parent = parent # Multithreading # self._fitter_thread = None self._fit_finished = True self._fit_results = self._defaultFitResults() self._current_minimizer_method_index = 0 self._current_minimizer_method_name = self.fitter.available_methods()[0] # noqa: E501 self.fit_thread = Thread(target=self.fit_threading) self.finished.connect(self._setFitResults)
from easyCore.Objects.ObjectClasses import Parameter, BaseObj from easyCore.Fitting.Fitting import Fitter import matplotlib.pyplot as plt d = xr.Dataset() b = BaseObj('line', m=Parameter('m', 1), c=Parameter('c', 1)) def fit_fun(x, *args, **kwargs): # In the real case we would gust call the evaluation fn without reference to the BaseObj return b.c.raw_value + b.m.raw_value * x f = Fitter() f.initialize(b, fit_fun) nx = 1E3 x_min = 0 x_max = 100 x = np.linspace(x_min, x_max, num=int(nx)) y1 = 2 * x - 1 + 5 * (np.random.random(size=x.shape) - 0.5) x2 = x + 20 y2 = 2 * x2 - 1 + 5 * (np.random.random(size=x2.shape) - 0.5) d.easyCore.add_coordinate('x1', x) d.easyCore.add_variable('y1', ['x1'], y1, auto_sigma=True) d.easyCore.add_coordinate('x2', x2) d.easyCore.add_variable('y2', ['x2'], y2, auto_sigma=True)
return self.m.raw_value @property def intercept(self): if self.interface: return self.interface().get_value('c') else: return self.c.raw_value def __repr__(self): return f'Line: m={self.m}, c={self.c}' interface = InterfaceFactory() line = Line(interface_factory=interface) f = Fitter(line, interface.fit_func) # y = 2x -1 x = np.array([1, 2, 3]) y = np.array([2, 4, 6]) - 1 f_res = f.fit(x, y) print('\n######### Interface 1 #########\n') print(f_res) print(line) # This gets the interface name `'Interface2'` other_interface = interface.available_interfaces[1] # Switch over the interfaces line.interface.switch(other_interface)
__author__ = 'github.com/wardsimon' __version__ = '0.0.1' import numpy as np from easyCore.Objects.Base import Parameter, BaseObj from easyCore.Fitting.Fitting import Fitter # This is a simple example of creating an object which has fitable parameters b = BaseObj('line', m=Parameter('m', 1), c=Parameter('c', 1)) def fit_fun(x): # In the real case we would gust call the evaluation fn without reference to the BaseObj return b.c.raw_value + b.m.raw_value * x f = Fitter() f.initialize(b, fit_fun) x = np.array([1, 2, 3]) y = np.array([2, 4, 6]) - 1 f_res = f.fit(x, y) print(f_res.fit_report())
data_set.easyCore.add_variable('I', ['tth'], data_y) data_set.easyCore.sigma_attach('I', data_e) S.parameters.wavelength = 1.912 S.parameters.u_resolution = 1.4 S.parameters.v_resolution = -0.42 S.parameters.w_resolution = 0.38 S.parameters.x_resolution = 0.0 S.parameters.y_resolution = 0.0 bg = PointBackground(linked_experiment='PbSO4') bg.append(BackgroundPoint.from_pars(data_x[0], 200)) bg.append(BackgroundPoint.from_pars(data_x[-1], 200)) S.set_background(bg) f = Fitter(S, interface.fit_func) # Vary the scale and the BG points S.pattern.scale.fixed = False S.pattern.zero_shift.fixed = False S.parameters.resolution_u.fixed = False S.parameters.resolution_v.fixed = False S.parameters.resolution_w.fixed = False S.backgrounds[0][0].y.fixed = True S.backgrounds[0][1].y.fixed = True result = f.fit(data_x, data_y) # result = data_set['I'].easyCore.fit(f) if result.success: print("The fit has been successful: {}".format(result.success))
raise NotImplementedError def __repr__(self): return f'Line: m={self.m}, c={self.c}' @staticmethod def __gitem(key: str) -> Callable: def inner(obj): obj.interface.get_value(key) return lambda obj: inner(obj) @staticmethod def __sitem(obj, key): def inner(value): obj.interface.set_value(key, value) return inner l = Line(interface=Interface()) l.interface f = Fitter(l, l.fit_func) x = np.array([1, 2, 3]) y = np.array([2, 4, 6]) - 1 f_res = f.fit(x, y) print(f_res) print(l)
def fit_experiment(self, experiment_name, fitter=None): dataarray_name = self.name + '_' + experiment_name + '_I' if fitter is None: fitter = Fitter(self, self.interface.fit_func) return self.datastore.store[dataarray_name].easyCore.fit(fitter)
class FitterLogic(QObject): """ Logic related to the fitter setup """ fitFinished = Signal() fitStarted = Signal() currentMinimizerChanged = Signal() finished = Signal(dict) def __init__(self, parent=None, sample=None, fit_func=""): super().__init__(parent) self.fitter = CoreFitter(sample, fit_func) self.parent = parent # Multithreading # self._fitter_thread = None self._fit_finished = True self._fit_results = self._defaultFitResults() self._current_minimizer_method_index = 0 self._current_minimizer_method_name = self.fitter.available_methods()[0] # noqa: E501 self.fit_thread = Thread(target=self.fit_threading) self.finished.connect(self._setFitResults) def fit_threading(self): data = self.data method = self.minimizer_name self._fit_finished = False self.fitStarted.emit() exp_data = data.experiments[0] x = exp_data.x y = exp_data.y weights = 1 / exp_data.e res = self.fitter.fit(x, y, weights=weights, method=method) self.finished.emit(res) def _defaultFitResults(self): return { "success": None, "nvarys": None, "GOF": None, "redchi2": None } def _setFitResults(self, res): if self.fit_thread.is_alive(): self.fit_thread.join() self._fit_results = { "success": res.success, "nvarys": res.n_pars, "GOF": float(res.goodness_of_fit), "redchi2": float(res.reduced_chi) } self._fit_finished = True self.fitFinished.emit() # must reinstantiate the thread object self.fit_thread = Thread(target=self.fit_threading) def fit(self, data): self.data = data self.minimizer_name = self._current_minimizer_method_name if not self.fit_thread.is_alive(): self.is_fitting_now = True self.fit_thread.start() ########### QTHREADS ################# # def fit_qthreads(self, data, minimizer_name): # # if running, stop the thread # if not self._fit_finished: # self.onStopFit() # borg.stack.endMacro() # need this to close the undo stack properly # return # self._fit_finished = False # self.fitStarted.emit() # exp_data = data.experiments[0] # x = exp_data.x # y = exp_data.y # weights = 1 / exp_data.e # method = minimizer_name # args = (x, y) # kwargs = {"weights": weights, "method": method} # self._fitter_thread = Fitter(self.parent, self.fitter, 'fit', *args, **kwargs) # noqa: E501 # self._fitter_thread.finished.connect(self._setFitResults) # self._fitter_thread.setTerminationEnabled(True) # self._fitter_thread.failed.connect(self._setFitResultsFailed) # self._fitter_thread.start() # def _setFitResultsFailed(self, res): # self.finishFitting() # def finishFitting(self): # self._fit_finished = True # self.fitFinished.emit() # def onStopFit(self): # """ # Slot for thread cancelling and reloading parameters # """ # self._fitter_thread.terminate() # self._fitter_thread.wait() # self._fitter_thread = None # self._fit_results['success'] = 'cancelled' # self._fit_results['nvarys'] = None # self._fit_results['GOF'] = None # self._fit_results['redchi2'] = None # self._setFitResultsFailed("Fitting stopped") # def setFitFinished(self, fit_finished: bool): # if self._fit_finished == fit_finished: # return # self._fit_finished = fit_finished def currentMinimizerIndex(self): current_name = self.fitter.current_engine.name index = self.fitter.available_engines.index(current_name) return index def setCurrentMinimizerIndex(self, new_index: int): if self.currentMinimizerIndex() == new_index: return new_name = self.fitter.available_engines[new_index] self.fitter.switch_engine(new_name) self.currentMinimizerChanged.emit() def onCurrentMinimizerChanged(self): idx = 0 minimizer_name = self.fitter.current_engine.name if minimizer_name == 'lmfit': idx = self.minimizerMethodNames().index('leastsq') elif minimizer_name == 'bumps': idx = self.minimizerMethodNames().index('lm') if -1 < idx != self._current_minimizer_method_index: # Bypass the property as it would be added to the stack. self._current_minimizer_method_index = idx self._current_minimizer_method_name = self.minimizerMethodNames()[idx] # noqa: E501 self.currentMinimizerChanged.emit() return def minimizerMethodNames(self): current_minimizer = self.fitter.available_engines[self.currentMinimizerIndex()] # noqa: E501 tested_methods = { 'lmfit': ['leastsq', 'powell', 'cobyla'], 'bumps': ['newton', 'lm'], 'DFO_LS': ['leastsq'] } return tested_methods[current_minimizer] def currentMinimizerMethodIndex(self, new_index: int): if self._current_minimizer_method_index == new_index: return self._current_minimizer_method_index = new_index self._current_minimizer_method_name = self.minimizerMethodNames()[new_index] # noqa: E501
_defaults = [Parameter('m', 1), Parameter('c', 0)] def __init__(self): super().__init__(self.__class__.__name__, *self._defaults) @property def gradient(self): return self.m.raw_value @property def intercept(self): return self.c.raw_value def fit_func(self, x: np.ndarray) -> np.ndarray: return self.gradient * x + self.intercept def __repr__(self): return f'Line: m={self.m}, c={self.c}' l = Line() f = Fitter() f.initialize(l, l.fit_func) x = np.array([1, 2, 3]) y = np.array([2, 4, 6]) - 1 f_res = f.fit(x, y) print(f_res.fit_report()) print(l)
import numpy as np from easyCore.Fitting.Fitting import Fitter from Example1.interface import InterfaceFactory from Example1.Line import Line # This is a much more complex case where we have calculators, interfaces, interface factory and an # inherited object (from `BaseObj`). In this case the Line class is available with/without an interface # With an interface it connects to one of the calculator interfaces. This calculator interface then translates # interface commands to calculator specific commands interface = InterfaceFactory() line = Line(interface_factory=interface) f = Fitter(line, interface.fit_func) x = np.array([1, 2, 3]) y = 2*x - 1 f_res = f.fit(x, y) print('\n######### Interface 1 #########\n') print(f_res) print(line) # Now lets change fitting engine f.switch_engine('bumps') # Reset the values so we don't cheat line.m = 1
def fit_fun(x, *args, **kwargs): # In the real case we would gust call the evaluation fn without reference to the BaseObj return b.c.raw_value + b.m.raw_value * x nx = 1E3 x_min = 0 x_max = 100 x = np.linspace(x_min, x_max, num=int(nx)) y = 2 * x - 1 + 5 * (np.random.random(size=x.shape) - 0.5) d.easyCore.add_coordinate('x', x) d.easyCore.add_variable('y', ['x'], y, auto_sigma=False) f = Fitter() f.initialize(b, fit_fun) fig, ax = plt.subplots(2, 3, sharey='row') for idx, minimizer in enumerate(['lmfit', 'bumps', 'DFO_LS']): b.m = m_starting_point b.c = c_starting_point f.switch_engine(minimizer) f_res = d['y'].easyCore.fit(f, vectorize=True) print(f_res.p) d['y'].plot(ax=ax[0, idx]) f_res.y_calc.unstack().plot(ax=ax[0, idx]) temp = d['y'] - f_res.y_calc
import numpy as np from easyCore.Objects.ObjectClasses import Parameter, BaseObj from easyCore.Fitting.Fitting import Fitter # This is a simple example of creating an object which has fitable parameters b = BaseObj('line', m=Parameter('m', 1), c=Parameter('c', 1)) def fit_fun(x): # In the real case we would gust call the evaluation fn without reference to the BaseObj return b.c.raw_value + b.m.raw_value * x f = Fitter() f.initialize(b, fit_fun) f.switch_engine('bumps') x = np.array([1, 2, 3]) y = np.array([2, 4, 6]) - 1 method = 'dream' dream_kwargs = { k: v for k, v in [('samples', 10000), ('burn', 100), ('pop', 10), ( 'init', 'eps'), ('thin', 1), ('alpha', 0.01), ('outliers', 'none'), ('trim', False), ('steps', 0)] }