diff --git a/EasyReflectometry/calculators/calculator_base.py b/EasyReflectometry/calculators/calculator_base.py index 359d18a1..fb7f3aa7 100644 --- a/EasyReflectometry/calculators/calculator_base.py +++ b/EasyReflectometry/calculators/calculator_base.py @@ -1,6 +1,7 @@ from __future__ import annotations from abc import ABCMeta +from typing import Callable import numpy as np from easyCore.Objects.core import ComponentSerializer @@ -173,3 +174,6 @@ def sld_profile(self, model_id: str) -> tuple[np.ndarray, np.ndarray]: :return: z and sld(z) """ return self._wrapper.sld_profile(model_id) + + def set_resolution_function(self, resolution_function: Callable[[np.array], np.array]) -> None: + return self._wrapper.set_resolution_function(resolution_function) diff --git a/EasyReflectometry/calculators/refl1d/wrapper.py b/EasyReflectometry/calculators/refl1d/wrapper.py index 5d25a926..68ae5ed4 100644 --- a/EasyReflectometry/calculators/refl1d/wrapper.py +++ b/EasyReflectometry/calculators/refl1d/wrapper.py @@ -6,6 +6,8 @@ from refl1d import model from refl1d import names +from EasyReflectometry.experiment.resolution_functions import is_constant_resolution_function + from ..wrapper_base import WrapperBase PADDING_RANGE = 3.5 @@ -162,17 +164,20 @@ def calculate(self, q_array: np.ndarray, model_name: str) -> np.ndarray: argmin = np.argmin(q_array) argmax = np.argmax(q_array) dq_vector = self._resolution_function(q_array) - dq_vector_normalized_to_refnx = dq_vector * q_array / 100 / (2 * np.sqrt(2 * np.log(2))) + + if is_constant_resolution_function(self._resolution_function): + # Get percentage of Q and change from sigma to FWHM + dq_vector = dq_vector * q_array / 100 / (2 * np.sqrt(2 * np.log(2))) q = names.QProbe( - q_array, - dq_vector_normalized_to_refnx, + Q=q_array, + dQ=dq_vector, intensity=self.storage['model'][model_name]['scale'], background=self.storage['model'][model_name]['bkg'], ) q.calc_Qo = np.linspace( - q_array[argmin] - PADDING_RANGE * dq_vector_normalized_to_refnx[argmin], - q_array[argmax] + PADDING_RANGE * dq_vector_normalized_to_refnx[argmax], + q_array[argmin] - PADDING_RANGE * dq_vector[argmin], + q_array[argmax] + PADDING_RANGE * dq_vector[argmax], UPSCALE_FACTOR * len(q_array), ) R = names.Experiment(probe=q, sample=structure).reflectivity()[1] diff --git a/EasyReflectometry/calculators/refnx/wrapper.py b/EasyReflectometry/calculators/refnx/wrapper.py index c8579d87..14d562bf 100644 --- a/EasyReflectometry/calculators/refnx/wrapper.py +++ b/EasyReflectometry/calculators/refnx/wrapper.py @@ -5,6 +5,8 @@ from easyCore import np from refnx import reflect +from EasyReflectometry.experiment.resolution_functions import is_constant_resolution_function + from ..wrapper_base import WrapperBase @@ -125,9 +127,16 @@ def calculate(self, q_array: np.ndarray, model_name: str) -> np.ndarray: structure, scale=self.storage['model'][model_name].scale.value, bkg=self.storage['model'][model_name].bkg.value, - dq=self.storage['model'][model_name].dq.value, + dq_type='pointwise', ) - return model(q_array) + + dq_vector = self._resolution_function(q_array) + if is_constant_resolution_function(self._resolution_function): + # FWHM Percentage resolution is constant given as + # For a constant resolution percentage refnx supports to pass a scalar value rather than a vector + dq_vector = dq_vector[0] + + return model(x=q_array, x_err=dq_vector) def sld_profile(self, model_name: str) -> Tuple[np.ndarray, np.ndarray]: """ diff --git a/EasyReflectometry/calculators/wrapper_base.py b/EasyReflectometry/calculators/wrapper_base.py index 0da6a5bf..4e3f5f5b 100644 --- a/EasyReflectometry/calculators/wrapper_base.py +++ b/EasyReflectometry/calculators/wrapper_base.py @@ -5,6 +5,8 @@ from EasyReflectometry.experiment import constant_resolution_function +DEFAULT_RESOLUTION_FWHM_PERCENTAGE = 5.0 + class WrapperBase: def __init__(self): @@ -15,7 +17,7 @@ def __init__(self): 'item': {}, 'model': {}, } - self._resolution_function = constant_resolution_function(5) + self._resolution_function = constant_resolution_function(DEFAULT_RESOLUTION_FWHM_PERCENTAGE) def reset_storage(self): """Reset the storage area to blank.""" @@ -204,7 +206,7 @@ def get_item_value(self, name: str, key: str) -> float: item = getattr(item, key) return getattr(item, 'value') - def set_resolution_function(self, resolution_function: Callable[[np.array], float]) -> None: + def set_resolution_function(self, resolution_function: Callable[[np.array], np.array]) -> None: """Set the resolution function for the calculator. :param resolution_function: The resolution function diff --git a/EasyReflectometry/experiment/model.py b/EasyReflectometry/experiment/model.py index 47be346d..590e2441 100644 --- a/EasyReflectometry/experiment/model.py +++ b/EasyReflectometry/experiment/model.py @@ -11,6 +11,7 @@ from easyCore.Objects.ObjectClasses import BaseObj from easyCore.Objects.ObjectClasses import Parameter +from EasyReflectometry.experiment.resolution_functions import is_constant_resolution_function from EasyReflectometry.parameter_utils import get_as_parameter from EasyReflectometry.sample import BaseAssembly from EasyReflectometry.sample import Layer @@ -86,8 +87,11 @@ def __init__( scale=scale, background=background, ) + if not callable(resolution_function): + raise ValueError('Resolution function must be a callable.') + self.resolution_function = resolution_function + # Must be set after resolution function self.interface = interface - self._resolution_function = resolution_function def add_item(self, *assemblies: list[BaseAssembly]) -> None: """Add a layer or item to the model sample. @@ -133,12 +137,33 @@ def remove_item(self, idx: int) -> None: self.interface().remove_item_from_model(self.sample[idx].uid, self.uid) del self.sample[idx] - def set_resolution_function(self, resolution_function: Callable[[np.array], float]) -> None: - """Set the resolution function for the model. + @property + def resolution_function(self) -> Callable[[np.array], np.array]: + """Return the resolution function.""" + return self._resolution_function - :param resolution_function: Resolution function to set. - """ + @resolution_function.setter + def resolution_function(self, resolution_function: Callable[[np.array], np.array]) -> None: + """Set the resolution function for the model.""" self._resolution_function = resolution_function + if self.interface is not None: + self.interface().set_resolution_function(self._resolution_function) + + @property + def interface(self): + """ + Get the current interface of the object + """ + return self._interface + + @interface.setter + def interface(self, new_interface) -> None: + """Set the interface for the model.""" + # From super class + self._interface = new_interface + if new_interface is not None: + self.generate_bindings() + self._interface().set_resolution_function(self._resolution_function) @property def uid(self) -> int: @@ -149,7 +174,7 @@ def uid(self) -> int: @property def _dict_repr(self) -> dict[str, dict[str, str]]: """A simplified dict representation.""" - if self._resolution_function.__qualname__.split('.')[0] == 'constant_resolution_function': + if is_constant_resolution_function(self._resolution_function): resolution_value = self._resolution_function([0])[0] resolution = f'{resolution_value} %' else: diff --git a/EasyReflectometry/experiment/resolution_functions.py b/EasyReflectometry/experiment/resolution_functions.py index b8c0c81b..0e0cae13 100644 --- a/EasyReflectometry/experiment/resolution_functions.py +++ b/EasyReflectometry/experiment/resolution_functions.py @@ -1,4 +1,12 @@ +"""Resolution functions for the resolution of the experiment. +When a percentage is provided we assume that the resolution is a +Gaussian distribution with a FWHM of the percentage of the q value. +To convert from a sigma value to a FWHM value we use the formula +FWHM = 2.35 * sigma [2 * np.sqrt(2 * np.log(2)) * sigma]. +""" + from typing import Callable +from typing import Union import numpy as np @@ -9,12 +17,12 @@ def constant_resolution_function(constant: float) -> Callable[[np.array], np.arr :param constant: The constant resolution value. """ - def _constant(q: np.array) -> np.array: + def _constant(q: Union[np.array, float]) -> np.array: """Function that calculates the resolution at a given q value. The function uses the data points from the encapsulating function and produces a linearly interpolated between them. """ - return np.ones(len(q)) * constant + return np.ones(np.array(q).size) * constant return _constant @@ -34,3 +42,8 @@ def _linear(q: np.array) -> np.array: return np.interp(q, q_data_points, resolution_points) return _linear + + +def is_constant_resolution_function(resolution_function: Callable[[np.array], np.array]) -> bool: + """Check if the resolution function is a constant.""" + return 'constant' in resolution_function.__name__ diff --git a/docs/tutorials/_static/repeating_layers.ort b/docs/tutorials/_static/repeating_layers.ort index 64574974..8663a7c9 100644 --- a/docs/tutorials/_static/repeating_layers.ort +++ b/docs/tutorials/_static/repeating_layers.ort @@ -9,7 +9,7 @@ # start_date: 2022-02-01 # title: Ni-Ti Multilayer # instrument: Simulation -# probe: x-rays +# probe: x-ray # sample: # name: Ni-Ti Multilayer on Si # category: gas / lsolidiquid diff --git a/tests/calculators/refl1d/test_refl1d_wrapper.py b/tests/calculators/refl1d/test_refl1d_wrapper.py index 1706f7e4..7f646a45 100644 --- a/tests/calculators/refl1d/test_refl1d_wrapper.py +++ b/tests/calculators/refl1d/test_refl1d_wrapper.py @@ -180,7 +180,6 @@ def test_calculate(self): p.update_material('Material3', rho=4.000, irho=0.000) p.create_model('MyModel') p.update_model('MyModel', bkg=1e-7) - p.update_model('MyModel', bkg=1e-7, dq=5.0) p.create_layer('Layer1') p.assign_material_to_layer('Material1', 'Layer1') p.create_layer('Layer2') @@ -209,7 +208,7 @@ def test_calculate(self): ] assert_almost_equal(p.calculate(q, 'MyModel'), expected) - def test_calculate2(self): + def test_calculate_three_items(self): p = Refl1dWrapper() p.create_material('Material1') p.update_material('Material1', rho=0.000, irho=0.000) @@ -252,7 +251,6 @@ def test_calculate2(self): 2.5347996e-07, ] assert_almost_equal(p.calculate(q, 'MyModel'), expected) - assert_almost_equal(p.calculate(q, 'MyModel'), expected) def test_sld_profile(self): p = Refl1dWrapper() diff --git a/tests/calculators/refnx/test_refnx_wrapper.py b/tests/calculators/refnx/test_refnx_wrapper.py index 2eb31cb2..6ce6cdc3 100644 --- a/tests/calculators/refnx/test_refnx_wrapper.py +++ b/tests/calculators/refnx/test_refnx_wrapper.py @@ -1,6 +1,7 @@ """ Tests for Refnx wrapper. """ + __author__ = 'github.com/arm61' __version__ = '0.0.1' @@ -8,11 +9,14 @@ import unittest import numpy as np +from numpy.testing import assert_allclose from numpy.testing import assert_almost_equal from numpy.testing import assert_equal from refnx import reflect from EasyReflectometry.calculators.refnx.wrapper import RefnxWrapper +from EasyReflectometry.experiment import constant_resolution_function +from EasyReflectometry.experiment import linear_spline_resolution_function class TestRefnx(unittest.TestCase): @@ -212,7 +216,7 @@ def test_calculate(self): ] assert_almost_equal(p.calculate(q, 'MyModel'), expected) - def test_calculate2(self): + def test_calculate_three_items(self): p = RefnxWrapper() p.create_material('Material1') p.update_material('Material1', real=0.000, imag=0.000) @@ -254,7 +258,6 @@ def test_calculate2(self): 2.5424356e-07, ] assert_almost_equal(p.calculate(q, 'MyModel'), expected) - assert_almost_equal(p.calculate(q, 'MyModel'), expected) def test_sld_profile(self): p = RefnxWrapper() @@ -280,3 +283,283 @@ def test_sld_profile(self): p.add_item('Item', 'MyModel') assert_almost_equal(p.sld_profile('MyModel')[1][0], 0) assert_almost_equal(p.sld_profile('MyModel')[1][-1], 4) + + ### Tests from https://github.com/reflectivity/analysis/tree/master/validation/test/unpolarised + def test_calculate_github_test0(self): + p = RefnxWrapper() + p.create_material('Material1') + p.update_material('Material1', real=2.070, imag=0.000) + p.create_material('Material2') + p.update_material('Material2', real=3.450, imag=0.100) + p.create_material('Material3') + p.update_material('Material3', real=5.000, imag=0.01) + p.create_material('Material4') + p.update_material('Material4', real=6.000, imag=0.000) + p.create_model('MyModel') + p.create_layer('Layer1') + p.assign_material_to_layer('Material1', 'Layer1') + p.create_layer('Layer2') + p.assign_material_to_layer('Material2', 'Layer2') + p.update_layer('Layer2', thick=100, rough=3.0) + p.create_layer('Layer3') + p.assign_material_to_layer('Material3', 'Layer3') + p.update_layer('Layer3', thick=200, rough=1.0) + p.create_layer('Layer4') + p.assign_material_to_layer('Material4', 'Layer4') + p.update_layer('Layer4', rough=5.0) + p.create_item('Item1') + p.add_layer_to_item('Layer1', 'Item1') + p.create_item('Item2') + p.add_layer_to_item('Layer2', 'Item2') + p.create_item('Item3') + p.add_layer_to_item('Layer3', 'Item3') + p.create_item('Item4') + p.add_layer_to_item('Layer4', 'Item4') + p.add_item('Item1', 'MyModel') + p.add_item('Item2', 'MyModel') + p.add_item('Item3', 'MyModel') + p.add_item('Item4', 'MyModel') + p.set_resolution_function(constant_resolution_function(0)) + p.update_model('MyModel', bkg=0) + q = np.array( + [ + 5.000000000000000104e-03, + 3.717499999999999971e-02, + 5.449999999999999983e-02, + 1.005349999999999994e-01, + 2.955650000000000222e-01, + ] + ) + expected = [ + 9.665000503913141472e-01, + 3.486325360684768590e-04, + 8.540420179439664689e-05, + 5.815959818366009312e-06, + 4.999742968030015832e-08, + ] + assert_almost_equal(p.calculate(q, 'MyModel'), expected) + + def test_calculate_github_test2(self): + p = RefnxWrapper() + p.create_material('Material1') + p.update_material('Material1', real=0.000, imag=0.000) + p.create_material('Material2') + p.update_material('Material2', real=6.360, imag=0.000) + p.create_model('MyModel') + p.create_layer('Layer1') + p.assign_material_to_layer('Material1', 'Layer1') + p.create_layer('Layer2') + p.assign_material_to_layer('Material2', 'Layer2') + p.update_layer('Layer2', rough=3.0) + p.create_item('Item1') + p.add_layer_to_item('Layer1', 'Item1') + p.create_item('Item2') + p.add_layer_to_item('Layer2', 'Item2') + p.add_item('Item1', 'MyModel') + p.add_item('Item2', 'MyModel') + p.set_resolution_function(constant_resolution_function(0)) + p.update_model('MyModel', bkg=0) + q = np.array( + [ + 5.000000000000000104e-03, + 7.564500000000000390e-02, + 1.433050000000000157e-01, + 2.368350000000000177e-01, + 5.920499999999999652e-01, + ] + ) + expected = [ + 1.000000000000000222e00, + 1.964576414578978456e-04, + 1.280698699505669096e-05, + 1.234290141526865827e-06, + 2.222536631965092181e-09, + ] + assert_almost_equal(p.calculate(q, 'MyModel'), expected) + + def test_calculate_github_test4_constant_resolution(self): + p = RefnxWrapper() + p.create_material('Material1') + p.update_material('Material1', real=2.070, imag=0.000) + p.create_material('Material2') + p.update_material('Material2', real=3.450, imag=0.100) + p.create_material('Material3') + p.update_material('Material3', real=5.000, imag=0.01) + p.create_material('Material4') + p.update_material('Material4', real=6.000, imag=0.000) + p.create_model('MyModel') + p.create_layer('Layer1') + p.assign_material_to_layer('Material1', 'Layer1') + p.create_layer('Layer2') + p.assign_material_to_layer('Material2', 'Layer2') + p.update_layer('Layer2', thick=100, rough=3.0) + p.create_layer('Layer3') + p.assign_material_to_layer('Material3', 'Layer3') + p.update_layer('Layer3', thick=200, rough=1.0) + p.create_layer('Layer4') + p.assign_material_to_layer('Material4', 'Layer4') + p.update_layer('Layer4', rough=5.0) + p.create_item('Item1') + p.add_layer_to_item('Layer1', 'Item1') + p.create_item('Item2') + p.add_layer_to_item('Layer2', 'Item2') + p.create_item('Item3') + p.add_layer_to_item('Layer3', 'Item3') + p.create_item('Item4') + p.add_layer_to_item('Layer4', 'Item4') + p.add_item('Item1', 'MyModel') + p.add_item('Item2', 'MyModel') + p.add_item('Item3', 'MyModel') + p.add_item('Item4', 'MyModel') + p.set_resolution_function(constant_resolution_function(5)) + p.update_model('MyModel', bkg=0) + assert_allclose(p.calculate(test4_dat[:, 0], 'MyModel'), test4_dat[:, 1], rtol=0.03) + + def test_calculate_github_test4_spline_resolution(self): + p = RefnxWrapper() + p.create_material('Material1') + p.update_material('Material1', real=2.070, imag=0.000) + p.create_material('Material2') + p.update_material('Material2', real=3.450, imag=0.100) + p.create_material('Material3') + p.update_material('Material3', real=5.000, imag=0.01) + p.create_material('Material4') + p.update_material('Material4', real=6.000, imag=0.000) + p.create_model('MyModel') + p.create_layer('Layer1') + p.assign_material_to_layer('Material1', 'Layer1') + p.create_layer('Layer2') + p.assign_material_to_layer('Material2', 'Layer2') + p.update_layer('Layer2', thick=100, rough=3.0) + p.create_layer('Layer3') + p.assign_material_to_layer('Material3', 'Layer3') + p.update_layer('Layer3', thick=200, rough=1.0) + p.create_layer('Layer4') + p.assign_material_to_layer('Material4', 'Layer4') + p.update_layer('Layer4', rough=5.0) + p.create_item('Item1') + p.add_layer_to_item('Layer1', 'Item1') + p.create_item('Item2') + p.add_layer_to_item('Layer2', 'Item2') + p.create_item('Item3') + p.add_layer_to_item('Layer3', 'Item3') + p.create_item('Item4') + p.add_layer_to_item('Layer4', 'Item4') + p.add_item('Item1', 'MyModel') + p.add_item('Item2', 'MyModel') + p.add_item('Item3', 'MyModel') + p.add_item('Item4', 'MyModel') + p.update_model('MyModel', bkg=0) + sigma_to_fhwm = 2.355 + p.set_resolution_function(linear_spline_resolution_function(test4_dat[:, 0], sigma_to_fhwm * test4_dat[:, 3])) + assert_allclose(p.calculate(test4_dat[:, 0], 'MyModel'), test4_dat[:, 1], rtol=0.03) + + +# https://github.com/reflectivity/analysis/tree/master/validation/test/unpolarised +# validation/test/unpolarised/data/test4.dat +test4_dat_raw = """ +4.999999999999999237e-03 9.660499468321636085e-01 0.000000000000000000e+00 1.061652250360023761e-04 +5.208965929570049704e-03 9.646283312283907563e-01 0.000000000000000000e+00 1.106022080235347408e-04 +5.426665211084315613e-03 9.631435299315659337e-01 0.000000000000000000e+00 1.152246266659623608e-04 +5.653462839144248603e-03 9.615923806647335148e-01 0.000000000000000000e+00 1.200402309100852380e-04 +5.889739062638551202e-03 9.599715341545977942e-01 0.000000000000000000e+00 1.250570945976711191e-04 +6.135890022268412555e-03 9.582774463689063271e-01 0.000000000000000000e+00 1.302836290020575514e-04 +6.392328414716996060e-03 9.565063736552937845e-01 0.000000000000000000e+00 1.357285969304924749e-04 +6.659484184576673627e-03 9.546543728325473932e-01 0.000000000000000000e+00 1.414011274158563051e-04 +6.937805245194089872e-03 9.527173094019888433e-01 0.000000000000000000e+00 1.473107310223976691e-04 +7.227758229641680597e-03 9.506908787954021500e-01 0.000000000000000000e+00 1.534673157911454707e-04 +7.529829273074612438e-03 9.485706483542604150e-01 0.000000000000000000e+00 1.598812038517289096e-04 +7.844524827784976270e-03 9.463521322252024248e-01 0.000000000000000000e+00 1.665631487284599923e-04 +8.172372512319661317e-03 9.440309187595408158e-01 0.000000000000000000e+00 1.735243533696914056e-04 +8.513921996085575816e-03 9.416028824956215182e-01 0.000000000000000000e+00 1.807764889306791788e-04 +8.869745920925360336e-03 9.390645344556776131e-01 0.000000000000000000e+00 1.883317143414410305e-04 +9.240440861208627787e-03 9.364136032254166686e-01 0.000000000000000000e+00 1.962026966924171388e-04 +9.626628324048536189e-03 9.336500112051923095e-01 0.000000000000000000e+00 2.044026324721134858e-04 +1.002895579132056722e-02 9.307775499924635376e-01 0.000000000000000000e+00 2.129452696923334900e-04 +1.044809780523061650e-02 9.278068446083937992e-01 0.000000000000000000e+00 2.218449309380942302e-04 +1.088475709925237553e-02 9.247608214119300563e-01 0.000000000000000000e+00 2.311165373808706110e-04 +1.133966577633027141e-02 9.216853828676729865e-01 0.000000000000000000e+00 2.407756337954316216e-04 +1.181358653632318123e-02 9.186719597214783040e-01 0.000000000000000000e+00 2.508384146222077419e-04 +1.230731395474697620e-02 9.159110487636203946e-01 0.000000000000000000e+00 2.613217511188890515e-04 +1.282167581495980910e-02 9.138467828784078151e-01 0.000000000000000000e+00 2.722432196467755149e-04 +1.335753449602358582e-02 9.108355606753477662e-01 0.000000000000000000e+00 2.836211311393017432e-04 +1.391578841856870238e-02 7.335981045780506360e-01 0.000000000000000000e+00 2.954745618021484190e-04 +1.449737355108597463e-02 2.213862971885717790e-01 0.000000000000000000e+00 3.078233850964063527e-04 +1.510326497917135677e-02 5.065074610089120161e-02 0.000000000000000000e+00 3.206883050584202191e-04 +1.573447854035441712e-02 1.590368472895162949e-02 0.000000000000000000e+00 3.340908910121754400e-04 +1.639207252725145142e-02 4.800075501038165819e-03 0.000000000000000000e+00 3.480536137324245511e-04 +1.707714946189881067e-02 1.223948799745163416e-03 0.000000000000000000e+00 3.625998831191868982e-04 +1.779085794424128605e-02 5.046568494808504907e-04 0.000000000000000000e+00 3.777540874467854378e-04 +1.853439457787469519e-02 8.404754652332931120e-04 0.000000000000000000e+00 3.935416342532259133e-04 +1.930900597627142543e-02 1.458717108645946623e-03 0.000000000000000000e+00 4.099889929384741916e-04 +2.011599085285246946e-02 2.022184226696178543e-03 0.000000000000000000e+00 4.271237391430496191e-04 +2.095670219841026111e-02 2.397327154528816270e-03 0.000000000000000000e+00 4.449746009813422727e-04 +2.183254954953296745e-02 2.551634050707026792e-03 0.000000000000000000e+00 4.635715072071680543e-04 +2.274500135183342431e-02 2.503723878205208874e-03 0.000000000000000000e+00 4.829456373923148504e-04 +2.369558742194500037e-02 2.297014419596041072e-03 0.000000000000000000e+00 5.031294742022117319e-04 +2.468590151241202915e-02 1.984702877815211226e-03 0.000000000000000000e+00 5.241568578563629999e-04 +2.571760398377520920e-02 1.620535097096735370e-03 0.000000000000000000e+00 5.460630428648573405e-04 +2.679242458833201376e-02 1.252789959601383627e-03 0.000000000000000000e+00 5.688847571360784120e-04 +2.791216537023925512e-02 9.202954264280633354e-04 0.000000000000000000e+00 5.926602635547127294e-04 +2.907870368682024739e-02 6.499790081461440973e-04 0.000000000000000000e+00 6.174294241333008141e-04 +3.029399535614193950e-02 4.557902347035073598e-04 0.000000000000000000e+00 6.432337668448841412e-04 +3.156007793613933854e-02 3.389679007057118062e-04 0.000000000000000000e+00 6.701165552488013702e-04 +3.287907414078505841e-02 2.896305199626667578e-04 0.000000000000000000e+00 6.981228610263705585e-04 +3.425319539903139837e-02 2.895827802138814912e-04 0.000000000000000000e+00 7.272996395480660261e-04 +3.568474556249201513e-02 3.160833603894238047e-04 0.000000000000000000e+00 7.576958085988904973e-04 +3.717612476807939659e-02 3.461421601729252370e-04 0.000000000000000000e+00 7.893623303939302548e-04 +3.872983346207417577e-02 3.607471650414172397e-04 0.000000000000000000e+00 8.223522970216000675e-04 +4.034847659237329048e-02 3.483107825318375100e-04 0.000000000000000000e+00 8.567210194578371010e-04 +4.203476797594541542e-02 3.066260485666312411e-04 0.000000000000000000e+00 8.925261203004783862e-04 +4.379153484881635749e-02 2.427846473412773824e-04 0.000000000000000000e+00 9.298276303793059786e-04 +4.562172260621279868e-02 1.708603072276521735e-04 0.000000000000000000e+00 9.686880894037319147e-04 +4.752839974081164709e-02 1.076850793981012493e-04 0.000000000000000000e+00 1.009172650816869167e-03 +4.951476298737475523e-02 6.765012337432836328e-05 0.000000000000000000e+00 1.051349191031792632e-03 +5.158414268239425865e-02 5.796797455235872996e-05 0.000000000000000000e+00 1.095288423233128482e-03 +5.374000834773436097e-02 7.600076548404877867e-05 0.000000000000000000e+00 1.141064015934773043e-03 +5.598597450763168060e-02 1.098724565425083957e-04 0.000000000000000000e+00 1.188752716492522165e-03 +5.832580674880616378e-02 1.425800498622337880e-04 0.000000000000000000e+00 1.238434479778678654e-03 +6.076342803384361668e-02 1.584158826364232800e-04 0.000000000000000000e+00 1.290192602234388778e-03 +6.330292527843461858e-02 1.492439980337561915e-04 0.000000000000000000e+00 1.344113861524451250e-03 +6.594855620349690528e-02 1.177519033425392445e-04 0.000000000000000000e+00 1.400288662028740172e-03 +6.870475647367019212e-02 7.577842573871102763e-05 0.000000000000000000e+00 1.458811186414187651e-03 +7.157614713415108576e-02 3.813747620286129380e-05 0.000000000000000000e+00 1.519779553541433575e-03 +7.456754235833716604e-02 1.502718568743208691e-05 0.000000000000000000e+00 1.583295982970901261e-03 +7.768395751926998605e-02 7.432986794932621371e-06 0.000000000000000000e+00 1.649466966344109589e-03 +8.093061759840886049e-02 8.479436602724126006e-06 0.000000000000000000e+00 1.718403445927546482e-03 +8.431296594583481685e-02 9.720659036587660457e-06 0.000000000000000000e+00 1.790221000618471897e-03 +8.783667340657071165e-02 7.475971384271801476e-06 0.000000000000000000e+00 1.865040039724485304e-03 +9.150764782831966038e-02 4.045160813957839975e-06 0.000000000000000000e+00 1.942986004841762470e-03 +9.533204396656239088e-02 3.178505467676818043e-06 0.000000000000000000e+00 2.024189580170434287e-03 +9.931627380361947310e-02 4.953666565173862248e-06 0.000000000000000000e+00 2.108786911619698213e-03 +1.034670172989808762e-01 5.966968494098515925e-06 0.000000000000000000e+00 2.196919835070051605e-03 +1.077912335889252976e-01 4.395731401080907728e-06 0.000000000000000000e+00 2.288736114175310681e-03 +1.122961726542076877e-01 2.838663311476676714e-06 0.000000000000000000e+00 2.384389688103147591e-03 +1.169893874753767798e-01 4.376365975608713520e-06 0.000000000000000000e+00 2.484040929629491301e-03 +1.218787466961013116e-01 7.365431957590666160e-06 0.000000000000000000e+00 2.587856914019505839e-03 +1.269724478157380210e-01 7.444758004751446953e-06 0.000000000000000000e+00 2.696011699145979719e-03 +1.322790309332581016e-01 4.174506384415917617e-06 0.000000000000000000e+00 2.808686617314733527e-03 +1.378073930655767942e-01 1.378897368540984724e-06 0.000000000000000000e+00 2.926070579286359132e-03 +1.435668030642915372e-01 8.179962055944333663e-07 0.000000000000000000e+00 3.048360391003989995e-03 +1.495669171558374755e-01 7.196203711450000268e-07 0.000000000000000000e+00 3.175761083558122696e-03 +1.558177951311167375e-01 4.074965533304633985e-07 0.000000000000000000e+00 3.308486256941745463e-03 +1.623299172117425582e-01 5.697106402976437542e-07 0.000000000000000000e+00 3.446758438172057518e-03 +1.691142016211787946e-01 6.318259741325602534e-07 0.000000000000000000e+00 3.590809454379265478e-03 +1.761820228902321317e-01 5.884226632043859758e-07 0.000000000000000000e+00 3.740880821487923939e-03 +1.835452309275898974e-01 1.086074476142989135e-06 0.000000000000000000e+00 3.897224149142521597e-03 +1.912161708873765797e-01 1.080905569118702644e-06 0.000000000000000000e+00 4.060101562556204732e-03 +1.992077038670377609e-01 4.319349827800466143e-07 0.000000000000000000e+00 4.229786141989877457e-03 +2.075332284702559316e-01 1.748578430054353337e-07 0.000000000000000000e+00 4.406562380598564102e-03 +2.162067032710481007e-01 1.052279192866519288e-07 0.000000000000000000e+00 4.590726661412603340e-03 +2.252426702167101280e-01 1.207279972283447134e-07 0.000000000000000000e+00 4.782587754253420607e-03 +2.346562790088451700e-01 1.538042650955484403e-07 0.000000000000000000e+00 4.982467333417002313e-03 +2.444633125033515431e-01 2.521547835091313121e-07 0.000000000000000000e+00 5.190700516992979158e-03 +2.546802131719588802e-01 2.588416113893713325e-07 0.000000000000000000e+00 5.407636428723615156e-03 +2.653241106696743179e-01 9.730928539681922884e-08 0.000000000000000000e+00 5.633638783344635526e-03 +2.764128505543612668e-01 3.779049549799957986e-08 0.000000000000000000e+00 5.869086496389332337e-03 +2.879650242066011945e-01 3.707321909920906896e-08 0.000000000000000000e+00 6.114374319478338426e-03 +2.999999999999999334e-01 6.224636414855785008e-08 0.000000000000000000e+00 6.369913502160142078e-03 +""" + +test4_dat_rows = test4_dat_raw.split('\n')[1:-1] +test4_dat = np.array([np.array(row.split()) for row in test4_dat_rows], dtype=float) diff --git a/tests/experiment/test_model.py b/tests/experiment/test_model.py index ef966542..4e269837 100644 --- a/tests/experiment/test_model.py +++ b/tests/experiment/test_model.py @@ -340,11 +340,41 @@ def test_uid(self): p = Model() assert_equal(p.uid, p._borg.map.convert_id_to_key(p)) - def test_set_resolution_function(self): + def test_resolution_function(self): mock_resolution_function = MagicMock() - model = Model() - model.set_resolution_function(mock_resolution_function) - assert model._resolution_function == mock_resolution_function + interface = CalculatorFactory() + interface.switch('refl1d') + model = Model(interface=interface) + + # Then + model.resolution_function = mock_resolution_function + + # Expect + assert model.resolution_function == mock_resolution_function + + def test_resolution_function_interface_refl1d(self): + mock_resolution_function = MagicMock() + interface = CalculatorFactory() + interface.switch('refl1d') + model = Model(interface=interface) + + # Then + model.resolution_function = mock_resolution_function + + # Expect + assert model.interface()._wrapper._resolution_function == mock_resolution_function + + def test_set_resolution_function_interface_refnx(self): + mock_resolution_function = MagicMock() + interface = CalculatorFactory() + interface.switch('refnx') + model = Model(interface=interface) + + # Then + model.resolution_function = mock_resolution_function + + # Expect + assert model.interface()._wrapper._resolution_function == mock_resolution_function def test_repr(self): model = Model() @@ -357,7 +387,7 @@ def test_repr(self): def test_repr_resolution_function(self): resolution_function = linear_spline_resolution_function([0, 10], [0, 10]) model = Model() - model.set_resolution_function(resolution_function) + model.resolution_function = resolution_function assert ( model.__repr__() == 'EasyModel:\n scale: 1.0\n background: 1.0e-08\n resolution: function of Q\n sample:\n EasySample:\n - EasyMultilayer:\n EasyLayers:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1 / angstrom ** 2\n isld: 0.000e-6 1 / angstrom ** 2\n thickness: 10.000 angstrom\n roughness: 3.300 angstrom\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1 / angstrom ** 2\n isld: 0.000e-6 1 / angstrom ** 2\n thickness: 10.000 angstrom\n roughness: 3.300 angstrom\n - EasyMultilayer:\n EasyLayers:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1 / angstrom ** 2\n isld: 0.000e-6 1 / angstrom ** 2\n thickness: 10.000 angstrom\n roughness: 3.300 angstrom\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1 / angstrom ** 2\n isld: 0.000e-6 1 / angstrom ** 2\n thickness: 10.000 angstrom\n roughness: 3.300 angstrom\n' # noqa: E501 @@ -367,7 +397,7 @@ def test_dict_round_trip(self): resolution_function = linear_spline_resolution_function([0, 10], [0, 10]) interface = CalculatorFactory() model = Model(interface=interface) - model.set_resolution_function(resolution_function) + model.resolution_function = resolution_function surfactant = SurfactantLayer.default() model.add_item(surfactant) multilayer = Multilayer.default() diff --git a/tests/test_fitting.py b/tests/test_fitting.py index 8842b719..45564467 100644 --- a/tests/test_fitting.py +++ b/tests/test_fitting.py @@ -7,6 +7,7 @@ from EasyReflectometry.calculators import CalculatorFactory from EasyReflectometry.data import load from EasyReflectometry.experiment import Model +from EasyReflectometry.experiment import constant_resolution_function from EasyReflectometry.fitting import Fitter from EasyReflectometry.sample import Layer from EasyReflectometry.sample import Material @@ -20,6 +21,7 @@ def test_fitting(self): 'tests/_static/example.ort', ) data = load(fpath) + resolution_function = constant_resolution_function(0.02) si = Material.from_pars(2.07, 0, 'Si') sio2 = Material.from_pars(3.47, 0, 'SiO2') film = Material.from_pars(2.0, 0, 'Film') @@ -35,7 +37,7 @@ def test_fitting(self): superphase, name='Film Structure', ) - model = Model(sample, 1, 1e-6, 0.02, 'Film Model') + model = Model(sample, 1, 1e-6, resolution_function, 'Film Model') # Thicknesses sio2_layer.thickness.bounds = (15, 50) film_layer.thickness.bounds = (200, 300)