class Curve(BaseObj): """ Simple descriptor of a line. """ _defaults = [ Parameter('A', 1.0), Parameter('p', np.pi), Parameter('x_shift', 0.0) ] def __init__(self, interface_factory: InterfaceFactory = None): """ Create a line and add an interface if requested :param interface_factory: interface controller object :type interface_factory: InterfaceFactory """ self.interface = interface_factory super().__init__(self.__class__.__name__, *self._defaults) self._set_interface() def _set_interface(self): if self.interface: # If an interface is given, generate bindings for parameter in self.get_parameters(): name = parameter.name self.set_binding(name, self.interface.generate_bindings) def __repr__(self): return f'Curve: A={self.A}, p={self.p}, x_shift={self.x_shift}'
class Line(BaseObj): """ Simple descriptor of a line. """ _defaults = [Parameter('m', 1), Parameter('c', 0)] def __init__(self, interface_factory: InterfaceFactory = None): """ Create a line and add an interface if requested :param interface_factory: interface controller object :type interface_factory: InterfaceFactory """ self.interface = interface_factory super().__init__(self.__class__.__name__, *self._defaults) self._set_interface() def _set_interface(self): if self.interface: # If an interface is given, generate bindings for parameter in self.get_parameters(): name = parameter.name self.set_binding(name, self.interface.generate_bindings) def __repr__(self): return f'Line: m={self.m}, c={self.c}'
def test_parameter_min(value): d = Parameter('test', -0.1) if d.raw_value < value: with pytest.raises(ValueError): d.min = value else: d.min = value assert d.min == value
def test_parameter_fixed(value): d = Parameter('test', -np.inf) if isinstance(value, bool): d.fixed = value assert d.fixed == value else: with pytest.raises(ValueError): d.fixed = value
def test_parameter_error(value): d = Parameter('test', 1) if value >= 0: d.error = value assert d.error == value else: with pytest.raises(ValueError): d.error = value
def test_parameter_max(value): d = Parameter('test', 2147483649) if d.raw_value > value: with pytest.raises(ValueError): d.max = value else: d.max = value assert d.max == value
def setup_pars(): d = { 'name': 'test', 'par1': Parameter('p1', 0.1, fixed=True), 'des1': Descriptor('d1', 0.1), 'par2': Parameter('p2', 0.1), 'des2': Descriptor('d2', 0.1), 'par3': Parameter('p3', 0.1), } return d
class Line(BaseObj): _defaults = [Parameter('m', 1), Parameter('c', 0)] def __init__(self, interface=None): self.interface = interface super().__init__(self.__class__.__name__, *self._defaults) if self.interface: for parameter in self.get_parameters(): name = parameter.name setattr(self.__class__.__dict__[name], '_callback', property(self.__gitem(name), self.__sitem(self, name))) @property def gradient(self): if self.interface: return self.interface.get_value('m') else: 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 fit_func(self, x: np.ndarray) -> np.ndarray: if self.interface: return self.interface.fit_func(x) else: 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
class Sin(BaseObj): _defaults = [ Parameter('amplitude', 3.5, min=0.0), Parameter('period', np.pi, min=0.0), Parameter('x_shift', 0), Parameter('y_shift', 0) ] def __init__(self, interface_factory: InterfaceFactory = None): super().__init__(self.__class__.__name__, *self._defaults) self.interface = interface_factory if self.interface is not None: self.interface.generate_bindings(self) def __repr__(self): return f'{self.__class__.__name__}: amplitude={self.amplitude}, period={self.period}, x_shift={self.x_shift}, ' \ f'y_shift={self.y_shift} '
def test_parameter_repr(): d = Parameter('test', 1) assert repr( d) == f'<{d.__class__.__name__} \'test\' = 1.0+/-0, bounds=[-inf:inf]>' d = Parameter('test', 1, units='cm') assert repr( d ) == f'<{d.__class__.__name__} \'test\' = 1.0+/-0 centimeter, bounds=[-inf:inf]>' d = Parameter('test', 1, fixed=True) assert repr( d ) == f'<{d.__class__.__name__} \'test\' = 1.0+/-0 (fixed), bounds=[-inf:inf]>' d = Parameter('test', 1, units='cm', fixed=True) assert repr( d ) == f'<{d.__class__.__name__} \'test\' = 1.0+/-0 centimeter (fixed), bounds=[-inf:inf]>'
def test_parameter_advanced_creation(element, expected): if len(element[0]) > 0: value = element[0][1] else: value = element[1]['value'] if 'min' in element[1].keys(): if element[1]['min'] > value: with pytest.raises(ValueError): d = Parameter(*element[0], **element[1]) elif 'max' in element[1].keys(): if element[1]['max'] < value: with pytest.raises(ValueError): d = Parameter(*element[0], **element[1]) else: d = Parameter(*element[0], **element[1]) for field in expected.keys(): ref = expected[field] obtained = getattr(d, field) if isinstance(obtained, (ureg.Unit, Q_)): obtained = str(obtained) assert obtained == ref
class Line(BaseObj): """ Simple descriptor of a line. """ _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}'
def from_pars(cls, power: int, amp: float): """ Construct a background factor from a power and amplitude as an integer/float respectively. :param power: Power to which x will be raised. :type power: int :param amp: Amplitude for which x will be multiplied by :type amp: float :return: Constructed background factor :rtype: BackgroundFactor """ power = Descriptor('power', power) amp = Parameter('amplitude', amp, fixed=True) return cls(power, amp)
def from_pars(cls, x: float, y: float): """ Construct a background point from x, y floats. :param x: background x-position. :type x: float :param y: background intensity/y-position :type y: float :return: Constructed background point :rtype: BackgroundPoint """ x = Descriptor('x', x) y = Parameter('intensity', y, fixed=True) return cls(x, y)
def default(cls) -> "Cell": """ Default constructor for a crystallographic unit cell. :return: Default crystallographic unit cell container :rtype: Cell """ length_a = Parameter('length_a', **CELL_DETAILS['length']) length_b = Parameter('length_b', **CELL_DETAILS['length']) length_c = Parameter('length_c', **CELL_DETAILS['length']) angle_alpha = Parameter('angle_alpha', **CELL_DETAILS['angle']) angle_beta = Parameter('angle_beta', **CELL_DETAILS['angle']) angle_gamma = Parameter('angle_gamma', **CELL_DETAILS['angle']) return cls(length_a, length_b, length_c, angle_alpha, angle_beta, angle_gamma)
def test_parameter_as_dict(): d = Parameter('test', 1) result = d.as_dict() expected = { '@module': 'easyCore.Objects.Base', '@class': 'Parameter', '@version': '0.0.1', 'name': 'test', 'value': 1.0, 'error': 0.0, 'min': -np.inf, 'max': np.inf, 'fixed': False, 'units': 'dimensionless' } for key in expected.keys(): if key == 'callback': continue assert result[key] == expected[key] # Check that additional arguments work d = Parameter('test', 1, units='km', url='https://www.boo.com') result = d.as_dict() expected = { '@module': 'easyCore.Objects.Base', '@class': 'Parameter', '@version': '0.0.1', 'name': 'test', 'units': 'kilometer', 'value': 1.0, 'error': 0.0, 'min': -np.inf, 'max': np.inf, 'fixed': False, 'url': 'https://www.boo.com' } for key in expected.keys(): if key == 'callback': continue assert result[key] == expected[key]
def from_parameters(cls, length_a: float, length_b: float, length_c: float, angle_alpha: float, angle_beta: float, angle_gamma: float, ang_unit: str = 'deg') -> "Cell": """ Constructor of a crystallographic unit cell when parameters are known. :param length_a: Unit cell length a :type length_a: float :param length_b: Unit cell length b :type length_b: float :param length_c: Unit cell length c :type length_c: float :param angle_alpha: Unit cell angle alpha :type angle_alpha: float :param angle_beta: Unit cell angle beta :type angle_beta: float :param angle_gamma: Unit cell angle gamma :type angle_gamma: float :param ang_unit: unit for supplied angles. Default is degree ('deg'). Radian is also valid ('rad'/'radian') :type ang_unit: str :return: Crystallographic unit cell container :rtype: Cell """ if ang_unit.startswith('rad'): angle_alpha = np.rad2deg(angle_alpha) angle_beta = np.rad2deg(angle_beta) angle_gamma = np.rad2deg(angle_gamma) default_options = deepcopy(CELL_DETAILS) del default_options['length']['value'] del default_options['angle']['value'] length_a = Parameter('length_a', length_a, **default_options['length']) length_b = Parameter('length_b', length_b, **default_options['length']) length_c = Parameter('length_c', length_c, **default_options['length']) angle_alpha = Parameter('angle_alpha', angle_alpha, **default_options['angle']) angle_beta = Parameter('angle_beta', angle_beta, **default_options['angle']) angle_gamma = Parameter('angle_gamma', angle_gamma, **default_options['angle']) return cls(length_a=length_a, length_b=length_b, length_c=length_c, angle_alpha=angle_alpha, angle_beta=angle_beta, angle_gamma=angle_gamma)
def test_parameter_advanced_convert_unit(conv_unit: str, data_in: dict, result: dict): d = Parameter('test', 273, units='kelvin', **data_in) d.convert_unit(conv_unit) for key in result.keys(): assert pytest.approx(getattr(d, key), result[key])
def test_Parameter_value_get(element, expected): d = Parameter('test', 1, units=element) assert str(d.value) == expected
__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())
__author__ = 'github.com/wardsimon' __version__ = '0.1.0' from easyCore import np from easyCore.Datasets.xarray import xr import matplotlib.pyplot as plt from easyCore.Objects.Base import Parameter, BaseObj from easyCore.Fitting.Fitting import Fitter d = xr.Dataset() m_starting_point = 1 c_starting_point = 1 b = BaseObj('line', m=Parameter('m', m_starting_point), c=Parameter('c', c_starting_point)) 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)