diff --git a/docs/src/dictionay.rst b/docs/src/dictionay.rst
new file mode 100644
index 00000000..e213d43d
--- /dev/null
+++ b/docs/src/dictionay.rst
@@ -0,0 +1,20 @@
+Dictionary
+==========
+The following serves to clarify what we mean by the terms we use in this project.
+
+Sample
+------
+A sample is an ideal representation of a the full physical setup.
+This includes the layer(s) under investigation, the surrounding superphase, and the subphase.
+
+Calculator
+----------
+A calculator is the physics engine which calculates the reflectivity curve from our inputted sample parameters.
+We rely on third party software to provide the necessary calculators.
+Different calculators might have different capabilities and limitations.
+
+Model
+-----
+A model combines a sample and calculator.
+The model is also responsible for including instrumental effects such as background, scale, and resolution.
+
diff --git a/docs/src/index.rst b/docs/src/index.rst
index bb6d5d89..140fe5d4 100644
--- a/docs/src/index.rst
+++ b/docs/src/index.rst
@@ -11,6 +11,7 @@
calculators
experiment/experiment
tutorials/tutorials
+ dictionary
contributing
authors
api/api
diff --git a/docs/src/sample/material_library.rst b/docs/src/sample/material_library.rst
index 684b0185..7007675d 100644
--- a/docs/src/sample/material_library.rst
+++ b/docs/src/sample/material_library.rst
@@ -22,7 +22,7 @@ The construction of a :py:class:`Material` is achieved as shown below.
name='Boron'
)
-The above object will have the properties of :py:attr:`sld` and :py:attr:`isld`, which will have values of :code:`6.908 1 / angstrom ** 2` and :code:`-0.278 1 / angstrom ** 2` respectively.
+The above object will have the properties of :py:attr:`sld` and :py:attr:`isld`, which will have values of :code:`6.908 1/angstrom^2` and :code:`-0.278 1/angstrom^2` respectively.
As is shown in the `tutorials`_, a material can be used to construct a :py:class:`Layer` from which `slab models`_ are created.
:py:class:`MaterialDensity`
@@ -78,7 +78,7 @@ So to produce a :py:class:`MaterialSolvated` that is 20 % D2O in a polymer, the
name='Solvated Polymer'
)
-For the :py:attr:`solvated_polymer` object, the :py:attr:`sld` will be :code:`2.872 1 / angstrom ** 2` (the weighted average of the two scattering length densities).
+For the :py:attr:`solvated_polymer` object, the :py:attr:`sld` will be :code:`2.872 1/angstrom^2` (the weighted average of the two scattering length densities).
The :py:class:`MaterialSolvated` includes a constraint such that if the value of either constituent scattering length densities (both real and imaginary components) or the fraction changes, then the resulting material :py:attr:`sld` and :py:attr:`isld` will change appropriately.
.. _`assemblies`: ./assemblies_library.html
diff --git a/docs/src/tutorials/fitting/repeating.ipynb b/docs/src/tutorials/fitting/repeating.ipynb
index 5d0e2514..074fed86 100644
--- a/docs/src/tutorials/fitting/repeating.ipynb
+++ b/docs/src/tutorials/fitting/repeating.ipynb
@@ -35,8 +35,11 @@
"\n",
"import numpy as np\n",
"import scipp as sc\n",
- "import easyreflectometry\n",
+ "import pooch\n",
"import refl1d\n",
+ "\n",
+ "import easyreflectometry\n",
+ "\n",
"from easyreflectometry.data import load\n",
"from easyreflectometry.sample import Layer\n",
"from easyreflectometry.sample import Sample\n",
@@ -46,7 +49,8 @@
"from easyreflectometry.experiment import PercentageFhwm\n",
"from easyreflectometry.calculators import CalculatorFactory\n",
"from easyreflectometry.fitting import Fitter\n",
- "from easyreflectometry.plot import plot"
+ "from easyreflectometry.plot import plot\n",
+ "from easyscience.fitting import AvailableMinimizers"
]
},
{
@@ -78,18 +82,22 @@
"## Reading in experimental data\n",
"\n",
"The data that we will investigate in this tutorial was generated with [GenX](https://aglavic.github.io/genx/) and is stored in an `.ort` [format file](https://github.com/reflectivity/file_format/blob/master/specification.md).\n",
- "Use link to [download](repeating_layers.ort) the ort data."
+ "We use `pooch` to fetch the file from the repository."
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "609174e5-1371-412d-a29f-cb05bfe36df0",
+ "id": "7121c7e9",
"metadata": {},
"outputs": [],
"source": [
- "data = load('repeating_layers.ort')\n",
- "data"
+ "file_path = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/fitting/repeating_layers.ort\",\n",
+ " known_hash=\"a5ffca9fd24f1d362266251723aec7ce9f34f123e39a38dfc4d829c758e6bf90\",\n",
+ ")\n",
+ "data = load(file_path)"
]
},
{
@@ -265,7 +273,8 @@
"outputs": [],
"source": [
"fitter = Fitter(model)\n",
- "analysed = fitter.fit(data, method='differential_evolution')\n",
+ "fitter.switch_minimizer(AvailableMinimizers.LMFit_differential_evolution)\n",
+ "analysed = fitter.fit(data)\n",
"analysed"
]
},
@@ -316,8 +325,22 @@
}
],
"metadata": {
+ "kernelspec": {
+ "display_name": "erl_1_311",
+ "language": "python",
+ "name": "python3"
+ },
"language_info": {
- "name": "python"
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
}
},
"nbformat": 4,
diff --git a/docs/src/tutorials/fitting/simple_fitting.ipynb b/docs/src/tutorials/fitting/simple_fitting.ipynb
index 136a98ad..dab3008d 100644
--- a/docs/src/tutorials/fitting/simple_fitting.ipynb
+++ b/docs/src/tutorials/fitting/simple_fitting.ipynb
@@ -29,8 +29,11 @@
"source": [
"%matplotlib inline\n",
"\n",
- "import easyreflectometry\n",
+ "import pooch\n",
"import refnx\n",
+ "\n",
+ "import easyreflectometry\n",
+ "\n",
"from easyreflectometry.data import load\n",
"from easyreflectometry.sample import Layer\n",
"from easyreflectometry.sample import Sample\n",
@@ -71,7 +74,7 @@
"\n",
"`easyreflectometry` has support for the `.ort` file format, a [standard file format for reduced reflectivity data developed by the Open Reflectometry Standards Organisation](https://www.reflectometry.org/working_groups/file_formats/).\n",
"To load in a dataset, we use the `load` function.\n",
- "Use link to [download](example.ort) the ort data."
+ "We use `pooch` to fetch the file from the repository."
]
},
{
@@ -81,7 +84,12 @@
"metadata": {},
"outputs": [],
"source": [
- "data = load('example.ort')"
+ "file_path = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/fitting/example.ort\",\n",
+ " known_hash=\"82d0c95c069092279a799a8131ad3710335f601d9f1080754b387f42e407dfab\",\n",
+ ")\n",
+ "data = load(file_path)"
]
},
{
@@ -514,8 +522,22 @@
}
],
"metadata": {
+ "kernelspec": {
+ "display_name": "erl_1_311",
+ "language": "python",
+ "name": "python3"
+ },
"language_info": {
- "name": "python"
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
}
},
"nbformat": 4,
diff --git a/docs/src/tutorials/magnetism.ipynb b/docs/src/tutorials/magnetism.ipynb
new file mode 100644
index 00000000..28589ddc
--- /dev/null
+++ b/docs/src/tutorials/magnetism.ipynb
@@ -0,0 +1,577 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "a60117e3-d089-4375-ac7c-12a52ed47271",
+ "metadata": {},
+ "source": [
+ "# Magnetism\n",
+ "\n",
+ "Magntism is only available in Refl1d and it does not support RepeatingMultilayer\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f5d0bd58",
+ "metadata": {},
+ "source": [
+ "## Setup\n",
+ "First configure matplotlib to place figures in notebook and import needed modules"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "29d5d62d-af4a-416d-bbe2-1338d32b30f5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "%matplotlib inline\n",
+ "\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "import scipp as sc\n",
+ "import refl1d\n",
+ "import refl1d.names\n",
+ "\n",
+ "import easyreflectometry\n",
+ "\n",
+ "from easyreflectometry.calculators import CalculatorFactory\n",
+ "from easyreflectometry.experiment import Model\n",
+ "from easyreflectometry.experiment import PercentageFhwm\n",
+ "from easyreflectometry.sample import Layer\n",
+ "from easyreflectometry.sample import Material\n",
+ "from easyreflectometry.sample import Multilayer\n",
+ "from easyreflectometry.sample import Sample"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8fd3e8f7-84ac-41c4-a89d-922ed82a001e",
+ "metadata": {},
+ "source": [
+ "For reference we fetch the version of the software packages we are using. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "549734c1-bbd9-41f3-8a20-d7a8ded37802",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f'numpy: {np.__version__}')\n",
+ "print(f'scipp: {sc.__version__}')\n",
+ "print(f'easyreflectometry: {easyreflectometry.__version__}')\n",
+ "print(f'refl1d: {refl1d.__version__}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "dad78ccc-1e6f-47cd-8557-c4fa6c736f4b",
+ "metadata": {},
+ "source": [
+ "## Building our model\n",
+ "\n",
+ "The system that was used to produce the data shown above is based on a silicon subphase with two layers upon it. \n",
+ "These two layers are charachterized by having a scattering length density (SLD) of respectively 4 and 8.\n",
+ "Both layers have a rougness of 0 but their thicknesses are 100 and 150 angstrom respectively.\n",
+ "We show the model that will be used graphically below. \n",
+ "\n",
+ "
\n",
+ " \n",
+ "\n",
+ "\n",
+ " A slab model description of the two layer.\n",
+ "\n",
+ "\n",
+ "To construct such a layer structure, first we create each of the materials, the associated layers, and the sub and super phases. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0f95d620-35b7-4b47-a3b4-9e33d5525b50",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "sld_4 = Material(sld=4.0, isld=0, name='Sld 4')\n",
+ "sld_4_layer = Layer(material=sld_4, thickness=100, roughness=0, name='SLD 4 Layer')\n",
+ "\n",
+ "sld_8 = Material(sld=8.0, isld=0, name='Sld 8')\n",
+ "sld_8_layer = Layer(material=sld_8, thickness=150, roughness=0, name='SLD 8 Layer')\n",
+ "\n",
+ "vacuum = Material(sld=0, isld=0, name='Vacuum')\n",
+ "superphase = Layer(material=vacuum, thickness=0, roughness=0, name='Vacuum Superphase')\n",
+ "\n",
+ "si = Material(sld=2.047, isld=0, name='Si')\n",
+ "subphase = Layer(material=si, thickness=0, roughness=0, name='Si Subphase')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f63ec440-089f-46cf-8ff5-be5012ad8dc8",
+ "metadata": {},
+ "source": [
+ "We then create a model for the two layered structures."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2af8c30b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "two_layers = Multilayer([sld_4_layer, sld_8_layer], name='SLD 4/8 Layer')\n",
+ "sample = Sample(superphase, two_layers, subphase, name='Two Layer Sample')\n",
+ "model = Model(\n",
+ " sample=sample,\n",
+ " scale=1,\n",
+ " background=0,\n",
+ " name='Two Layer Model',\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a1d3ad93",
+ "metadata": {},
+ "source": [
+ "We also need a Refl1d sample"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b0259cd0",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "refl1d_sld_4 = refl1d.names.SLD(name=\"Sld 4\", rho=4.0, irho=0)\n",
+ "refl1d_sld_8 = refl1d.names.SLD(name=\"Sld 8\", rho=8.0, irho=0)\n",
+ "refl1d_vacuum = refl1d.names.SLD(name=\"Vacuum\", rho=0, irho=0)\n",
+ "refl1d_si = refl1d.names.SLD(name=\"Si\", rho=2.047, irho=0)\n",
+ "\n",
+ "# Refl1d model is inverted as compared to EasyReflectometry, so the order of the layers is reversed\n",
+ "refl1d_sample = (\n",
+ " refl1d_si(0, 0) | \n",
+ " refl1d_sld_8(150, 0) |\n",
+ " refl1d_sld_4(100, 0) | \n",
+ " refl1d_vacuum(0, 0)\n",
+ ") "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8f0581b9-7690-4b17-9a4f-766ed92aaba2",
+ "metadata": {},
+ "source": [
+ "## Prepare interface factory\n",
+ "\n",
+ "We will use the [Ref1d](https://refl1d.readthedocs.io/en/latest/) and [Refnx](https://refnx.readthedocs.io/) calculator for our analysis. "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "f1500603-d85d-4e16-b697-e1bf16502991",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "interface = CalculatorFactory()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0481604e-3973-4e5d-a0ee-2f5915461d71",
+ "metadata": {},
+ "source": [
+ "## Comparisons\n",
+ "To validate the implementation we do some comparisons of the reflectevity determined in EasyReflectometry using different calculators or directly in Refl1d."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "18010202",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "model_coords = np.linspace(\n",
+ " start=0.001,\n",
+ " stop=0.3,\n",
+ " num=1000,\n",
+ ")\n",
+ "\n",
+ "def plot_apply_makeup():\n",
+ " ax = plt.gca()\n",
+ " ax.set_xlim([-0.01, 0.35])\n",
+ " ax.set_ylim([1e-8, 2.5])\n",
+ " plt.legend()\n",
+ " plt.yscale('log')\n",
+ " plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "61bae570",
+ "metadata": {},
+ "source": [
+ "### Refl1d and EasyReflectometry without magnetism\n",
+ "First we will ensure that the Refl1d calculator is correctly implemented in EasyReflectometry when no magnetic effects are present."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cdf959c8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Refl1d\n",
+ "probe = refl1d.names.QProbe(\n",
+ " Q=model_coords,\n",
+ " dQ=np.zeros(len(model_coords)),\n",
+ " intensity=1,\n",
+ " background=0,\n",
+ " )\n",
+ "experiment = refl1d.names.Experiment(probe=probe, sample=refl1d_sample)\n",
+ "model_data_no_magnetism_ref1d_raw = experiment.reflectivity()[1]\n",
+ "\n",
+ "plt.plot(model_coords, model_data_no_magnetism_ref1d_raw, '-k', label='Refl1d', linewidth=4)\n",
+ "\n",
+ "# EasyReflectometry\n",
+ "interface.switch('refl1d')\n",
+ "model.interface = interface\n",
+ "model.resolution_function = PercentageFhwm(0)\n",
+ "model_interface = model.interface()\n",
+ "model_interface.magnetism = False\n",
+ "model_data_no_magnetism_ref1d_easy = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_no_magnetism_ref1d_easy, 'r-', label=f'EasyReflectometry ({model_interface.name})', linewidth=2)\n",
+ "\n",
+ "plot_apply_makeup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "60d1896d-06ca-4bd2-b44c-d3788304220c",
+ "metadata": {},
+ "source": [
+ "### EasyReflectometry with and without magnetic layers\n",
+ "We have now reached the point where we can do sa simulation for a sample with magnetic layers. For this sample we should see a difference in the determined reflectivity."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "bf311973",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Without magnetic layers\n",
+ "interface.switch('refl1d')\n",
+ "model.interface = interface\n",
+ "model_interface = model.interface()\n",
+ "model_interface.include_magnetism = True\n",
+ "model_data_magnetism = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_magnetism, '-k', label=f'Without magnetic layers ({model_interface.name})', linewidth=4)\n",
+ "\n",
+ "# With magnetic layers\n",
+ "interface.switch('refl1d')\n",
+ "model.interface = interface\n",
+ "model_interface = model.interface()\n",
+ "model_interface.include_magnetism = True\n",
+ "model_interface._wrapper.update_layer(list(model_interface._wrapper.storage['layer'].keys())[1], magnetism_rhoM=10, magnetism_thetaM=70)\n",
+ "model_interface._wrapper.update_layer(list(model_interface._wrapper.storage['layer'].keys())[2], magnetism_rhoM=5, magnetism_thetaM=175)\n",
+ "model_data_magnetism_layer_1 = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_magnetism_layer_1, 'r-', label=f'With magnetic layers ({model_interface.name})', linewidth=2)\n",
+ "\n",
+ "plot_apply_makeup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e3659a17",
+ "metadata": {},
+ "source": [
+ "As expected do we see a difference in the reflectivity profile for a sample with and without magnetic layers."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8320f6e8",
+ "metadata": {},
+ "source": [
+ "### EasyReflectometry and Refl1d with magnetism\n",
+ "The final comparison is to confirm that that we are able to reproduce the raw Refl1d reflectometry in EasyReflectometry when acocunting for magnetism."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "18cb7037",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Refl1d model is inverted as compared to EasyReflectometry, so the order of the layers is reversed\n",
+ "refl1d_sample = (\n",
+ " refl1d_si(0, 0) | \n",
+ " refl1d_sld_8(150, 0, magnetism=refl1d.names.Magnetism(rhoM=5, thetaM=175)) |\n",
+ " refl1d_sld_4(100, 0, magnetism=refl1d.names.Magnetism(rhoM=10, thetaM=70)) | \n",
+ " refl1d_vacuum(0, 0)\n",
+ ") \n",
+ "probe = refl1d.names.QProbe(\n",
+ " Q=model_coords,\n",
+ " dQ=np.zeros(len(model_coords)),\n",
+ " intensity=1,\n",
+ " background=0,\n",
+ " )\n",
+ "\n",
+ "four_probes = [probe, None, None, None]\n",
+ "polarized_probe = refl1d.names.PolarizedQProbe(xs=four_probes, name='polarized')\n",
+ "experiment = refl1d.names.Experiment(probe=polarized_probe, sample=refl1d_sample)\n",
+ "model_data_magnetism_ref1d = experiment.reflectivity()[0][1]\n",
+ "plt.plot(model_coords, model_data_magnetism_ref1d, '-k', label='Refl1d', linewidth=4)\n",
+ "\n",
+ "# EasyReflectometry\n",
+ "interface.switch('refl1d')\n",
+ "model.interface = interface\n",
+ "model_interface = model.interface()\n",
+ "model_interface.include_magnetism = True\n",
+ "model_interface._wrapper.update_layer(list(model_interface._wrapper.storage['layer'].keys())[1], magnetism_rhoM=10, magnetism_thetaM=70)\n",
+ "model_interface._wrapper.update_layer(list(model_interface._wrapper.storage['layer'].keys())[2], magnetism_rhoM=5, magnetism_thetaM=175)\n",
+ "model_data_magnetism_easy = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_magnetism_easy, 'r-', label=f'EasyReflect ({model_interface.name})', linewidth=2)\n",
+ "\n",
+ "plot_apply_makeup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d52efccc",
+ "metadata": {},
+ "source": [
+ "The two models agree when the magnetic parameters are the same."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7033f755",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(max(abs(model_data_magnetism_easy - model_data_magnetism_ref1d)))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "971baee6",
+ "metadata": {},
+ "source": [
+ "# Afterthoughts \n",
+ "Just for completion we will do a few additional calculations and comparisons of reflectivity."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7af84a69",
+ "metadata": {},
+ "source": [
+ "## Refl1d polarized probe for a single layer sample\n",
+ " This study is done with magnetism to show the results for polarized probe."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "352c35e9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# The magnetism is set to 8. \n",
+ "# This would double (pp) and cancel out (mm) the magnitude of the reflectivity oscillations when its angle is set to 90.\n",
+ "# This would give the strongest spin-flipping (pm and mp) when its angle is set to 0.\n",
+ "# However we set the angle to 45, so the reflectivity oscillations are not doubled or cancelled out, and the spin-flipping is not maximized.\n",
+ "refl1d_sample = (\n",
+ " refl1d_si(0, 0) | \n",
+ " refl1d_sld_8(150, 0, magnetism=refl1d.names.Magnetism(rhoM=8, thetaM=45)) |\n",
+ " refl1d_vacuum(0, 0)\n",
+ ") \n",
+ "\n",
+ "probe_pp = refl1d.names.QProbe(\n",
+ " Q=model_coords,\n",
+ " dQ=np.zeros(len(model_coords)),\n",
+ " intensity=1,\n",
+ " background=0,\n",
+ " )\n",
+ "probe_pm = refl1d.names.QProbe(\n",
+ " Q=model_coords,\n",
+ " dQ=np.zeros(len(model_coords)),\n",
+ " intensity=1,\n",
+ " background=0,\n",
+ " )\n",
+ "probe_mp = refl1d.names.QProbe(\n",
+ " Q=model_coords,\n",
+ " dQ=np.zeros(len(model_coords)),\n",
+ " intensity=1,\n",
+ " background=0,\n",
+ " )\n",
+ "probe_mm = refl1d.names.QProbe(\n",
+ " Q=model_coords,\n",
+ " dQ=np.zeros(len(model_coords)),\n",
+ " intensity=1,\n",
+ " background=0,\n",
+ " )\n",
+ "\n",
+ "four_probes = [probe_pp, probe_pm, probe_mp, probe_mm]\n",
+ "polarized_probe = refl1d.names.PolarizedQProbe(xs=four_probes, name='polarized')\n",
+ "experiment = refl1d.names.Experiment(probe=polarized_probe, sample=refl1d_sample)\n",
+ "model_data_magnetism_ref1d_raw_pp = experiment.reflectivity()[0][1]\n",
+ "model_data_magnetism_ref1d_raw_pm = experiment.reflectivity()[1][1]\n",
+ "model_data_magnetism_ref1d_raw_mp = experiment.reflectivity()[2][1]\n",
+ "model_data_magnetism_ref1d_raw_mm = experiment.reflectivity()[3][1]\n",
+ "\n",
+ "plt.plot(model_coords, model_data_magnetism_ref1d_raw_pp, '-k', label='Refl1d pp', linewidth=4)\n",
+ "plt.plot(model_coords, model_data_magnetism_ref1d_raw_mm, '-r', label='Refl1d mm', linewidth=2)\n",
+ "plt.plot(model_coords, model_data_magnetism_ref1d_raw_pm, ':k', label='Refl1d pm', linewidth=4)\n",
+ "plt.plot(model_coords, model_data_magnetism_ref1d_raw_mp, ':r', label='Refl1d mp', linewidth=2)\n",
+ "\n",
+ "plot_apply_makeup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac52936c",
+ "metadata": {},
+ "source": [
+ "## Refl1 and Refnx in EasyReflectometry.\n",
+ "This study is done without magnetism as Refnx does not support this yet."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "e59d3153-f0da-4fce-a4f0-a424010acbec",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Refnx\n",
+ "interface.switch('refnx')\n",
+ "model.interface = interface\n",
+ "model_interface = model.interface()\n",
+ "model_data_no_magnetism_refnx = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_no_magnetism_refnx, 'k-', label=f'EasyReflectometry ({model_interface.name})', linewidth=5)\n",
+ "\n",
+ "# Refl1d\n",
+ "interface.switch('refl1d')\n",
+ "model.interface = interface\n",
+ "model_interface = model.interface()\n",
+ "model_data_no_magnetism_ref1d = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_no_magnetism_ref1d, 'r-', label=f'EasyReflectometry ({model_interface.name})', linewidth=2)\n",
+ "\n",
+ "plot_apply_makeup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "97e3094a",
+ "metadata": {},
+ "source": [
+ "## EasyReflectometry with and without magnetism but no magnetic layers\n",
+ "We also want to confirm that we can enable the ability to account for magnetism without causing any significant changes to the reflectivity as determined for a sample without any magnetic layers."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b087e848",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# With Magnitism\n",
+ "interface.switch('refl1d')\n",
+ "model.interface = interface\n",
+ "model_interface = model.interface()\n",
+ "model_interface.magnetism = True\n",
+ "model_data_magnetism = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_magnetism, '-k', label=f'With magnetism ({model_interface.name})', linewidth=4)\n",
+ "\n",
+ "# Without Magnitism\n",
+ "interface.switch('refl1d')\n",
+ "model.interface = interface\n",
+ "model_interface = model.interface()\n",
+ "model_interface.magnetism = False\n",
+ "model_data_no_magnetism = model.interface().fit_func(\n",
+ " model_coords,\n",
+ " model.unique_name,\n",
+ ")\n",
+ "plt.plot(model_coords, model_data_no_magnetism, 'r-', label=f'Without magnetism ({model_interface.name})', linewidth=2)\n",
+ "\n",
+ "plot_apply_makeup()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1b41ed2",
+ "metadata": {},
+ "source": [
+ "We don't see any significant change in the determined reflectivity when enabling the ability to account for magnetism. However, there is a small difference, which is due to the fact that we are using `PolarizedQProbe` (Refl1d) when handling magnetic samples whereas non-magnetic samples are handled with a `QProbe` (Refl1d)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "00c25554",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(max(abs(model_data_no_magnetism - model_data_magnetism)))"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "erl_311",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/src/tutorials/sample/example.ort b/docs/src/tutorials/sample/example.ort
deleted file mode 100644
index 968fa7bb..00000000
--- a/docs/src/tutorials/sample/example.ort
+++ /dev/null
@@ -1,448 +0,0 @@
-# # ORSO reflectivity data file | 0.1 standard | YAML encoding | https://www.reflectometry.org/
-# data_source:
-# owner:
-# name: Andrew Nelson
-# affiliation: ANSTO
-# contact: Andrew.Nelson@ansto.gov.au
-# experiment:
-# facility: ANSTO
-# start_date: 2021-05-12
-# title: Example data file from refnx docs
-# instrument: platypus
-# probe: neutron
-# sample:
-# name: Polymer Film
-# category: solid / liquid
-# composition: Si / SiO2 / Film / D2O
-# measurement:
-# instrument_settings:
-# wavelength:
-# magnitude: 12
-# unit: angstrom
-# incident_angle:
-# magnitude: 3
-# unit: deg
-# data_files:
-# - Unknown.nxs
-# scheme: angle-dispersive
-# reduction:
-# software: ess
-# timestamp: 2022-01-27T15:33:59+01:00
-# corrections:
-# - footprint
-# - incident intensity
-# - detector efficiency
-# columns:
-# - {name: Qz, unit: 1/angstrom, dimension: WW transfer}
-# - {name: R, dimension: reflectivity}
-# - {name: sR, dimension: error-reflectivity}
-# - {name: sQz, unit: 1/angstrom, dimension: resolution-WW transfer}
-## Qz RQz sR sQz
-8.060220000e-03 7.095810000e-01 8.506760000e-02 1.407419648e-04
-8.136620000e-03 8.622810000e-01 1.123700000e-01 1.420996057e-04
-8.263750000e-03 9.086470000e-01 7.900470000e-02 1.443588017e-04
-8.370670000e-03 7.732920000e-01 7.927280000e-02 1.462583099e-04
-8.450330000e-03 1.057970000e+00 1.259590000e-01 1.476732801e-04
-8.530830000e-03 1.015660000e+00 1.132950000e-01 1.491031133e-04
-8.612170000e-03 7.347170000e-01 6.115660000e-02 1.505473850e-04
-8.694370000e-03 7.692160000e-01 6.170580000e-02 1.520069445e-04
-8.777430000e-03 1.115740000e+00 1.127300000e-01 1.534813672e-04
-8.861360000e-03 9.723030000e-01 8.971600000e-02 1.549710776e-04
-8.946160000e-03 7.512140000e-01 5.493930000e-02 1.564760759e-04
-9.031850000e-03 7.976490000e-01 5.671220000e-02 1.579963619e-04
-9.118440000e-03 9.221890000e-01 6.858410000e-02 1.595327850e-04
-9.205930000e-03 9.757550000e-01 7.293950000e-02 1.610844959e-04
-9.294320000e-03 8.195040000e-01 5.216170000e-02 1.626523440e-04
-9.383640000e-03 7.883200000e-01 4.794730000e-02 1.642367538e-04
-9.473890000e-03 7.947010000e-01 4.602240000e-02 1.658368761e-04
-9.565080000e-03 8.744000000e-01 5.151640000e-02 1.674535601e-04
-9.657210000e-03 8.396620000e-01 4.742850000e-02 1.690872306e-04
-9.750300000e-03 8.008720000e-01 4.399580000e-02 1.707370382e-04
-9.844360000e-03 1.117100000e+00 7.373300000e-02 1.724042569e-04
-9.939390000e-03 8.884110000e-01 4.954100000e-02 1.740884620e-04
-1.003540000e-02 7.791290000e-01 3.898730000e-02 1.757896536e-04
-1.013240000e-02 7.999680000e-01 3.899740000e-02 1.775086809e-04
-1.023040000e-02 8.431240000e-01 4.159800000e-02 1.792451193e-04
-1.032940000e-02 9.613320000e-01 4.925360000e-02 1.809989689e-04
-1.048680000e-02 8.805440000e-01 2.990830000e-02 1.837851690e-04
-1.063270000e-02 7.557350000e-01 3.208510000e-02 1.863700799e-04
-1.073590000e-02 9.712310000e-01 4.534850000e-02 1.881969711e-04
-1.084010000e-02 8.955490000e-01 3.905420000e-02 1.900425474e-04
-1.094540000e-02 8.625890000e-01 3.580720000e-02 1.919068087e-04
-1.105180000e-02 8.909920000e-01 3.612570000e-02 1.937906045e-04
-1.115930000e-02 9.003480000e-01 3.679240000e-02 1.956930853e-04
-1.126790000e-02 8.459270000e-01 3.218810000e-02 1.976151006e-04
-1.137760000e-02 9.431520000e-01 3.655330000e-02 1.995570749e-04
-1.148840000e-02 9.956310000e-01 3.901160000e-02 2.015185836e-04
-1.160040000e-02 9.695940000e-01 3.636230000e-02 2.034996267e-04
-1.171350000e-02 9.051810000e-01 3.204100000e-02 2.055014781e-04
-1.182780000e-02 8.933810000e-01 3.061190000e-02 2.075232887e-04
-1.194330000e-02 9.196020000e-01 3.146770000e-02 2.095659076e-04
-1.205990000e-02 9.189980000e-01 3.060970000e-02 2.116293349e-04
-1.217770000e-02 7.810560000e-01 2.355420000e-02 2.137135706e-04
-1.229680000e-02 8.649150000e-01 2.720250000e-02 2.158190394e-04
-1.241700000e-02 8.435160000e-01 2.550150000e-02 2.179457412e-04
-1.253850000e-02 9.984180000e-01 3.197220000e-02 2.200945253e-04
-1.266120000e-02 8.812600000e-01 2.602730000e-02 2.222645425e-04
-1.278520000e-02 8.835690000e-01 2.558620000e-02 2.244570667e-04
-1.291050000e-02 9.376700000e-01 2.746510000e-02 2.266716733e-04
-1.303700000e-02 1.019200000e+00 3.051070000e-02 2.289087870e-04
-1.316480000e-02 8.455260000e-01 2.262690000e-02 2.311684076e-04
-1.329390000e-02 8.738040000e-01 2.324680000e-02 2.334509599e-04
-1.342430000e-02 8.659530000e-01 2.249060000e-02 2.357568686e-04
-1.355610000e-02 8.779820000e-01 2.244910000e-02 2.380861337e-04
-1.368920000e-02 9.475450000e-01 2.489850000e-02 2.404387551e-04
-1.382370000e-02 8.881540000e-01 2.209620000e-02 2.428155821e-04
-1.395950000e-02 8.913620000e-01 2.181480000e-02 2.452161902e-04
-1.409670000e-02 8.884560000e-01 2.150920000e-02 2.476410039e-04
-1.423530000e-02 9.137170000e-01 2.225860000e-02 2.500908727e-04
-1.437530000e-02 8.103640000e-01 1.882890000e-02 2.525649471e-04
-1.451680000e-02 7.385480000e-01 1.688270000e-02 2.550645011e-04
-1.465970000e-02 6.865100000e-01 1.597420000e-02 2.575891102e-04
-1.480400000e-02 5.822400000e-01 1.350210000e-02 2.601396235e-04
-1.494980000e-02 4.468550000e-01 1.006260000e-02 2.627156166e-04
-1.509700000e-02 3.924610000e-01 9.155490000e-03 2.653175139e-04
-1.524580000e-02 3.205170000e-01 7.319590000e-03 2.679461649e-04
-1.539610000e-02 2.810060000e-01 6.399090000e-03 2.706011448e-04
-1.554790000e-02 2.401000000e-01 5.442390000e-03 2.732828784e-04
-1.570120000e-02 2.208810000e-01 5.024370000e-03 2.759917903e-04
-1.585610000e-02 1.920330000e-01 4.314410000e-03 2.787278805e-04
-1.601260000e-02 1.798490000e-01 4.051590000e-03 2.814919983e-04
-1.617070000e-02 1.600690000e-01 3.562020000e-03 2.842837190e-04
-1.633030000e-02 1.531290000e-01 3.467770000e-03 2.871038920e-04
-1.649160000e-02 1.342200000e-01 3.016000000e-03 2.899525174e-04
-1.665450000e-02 1.283300000e-01 2.888530000e-03 2.928300196e-04
-1.681900000e-02 1.247940000e-01 2.861820000e-03 2.957363988e-04
-1.698530000e-02 1.091270000e-01 2.483100000e-03 2.986720796e-04
-1.715320000e-02 1.044290000e-01 2.353920000e-03 3.016374867e-04
-1.732280000e-02 9.468300000e-02 2.091620000e-03 3.046326200e-04
-1.758810000e-02 8.969110000e-02 1.439380000e-03 3.093191777e-04
-1.784190000e-02 8.091440000e-02 1.872780000e-03 3.138010489e-04
-1.801850000e-02 7.465440000e-02 1.714220000e-03 3.169189092e-04
-1.819680000e-02 7.036610000e-02 1.634230000e-03 3.200686191e-04
-1.837700000e-02 6.904450000e-02 1.605300000e-03 3.232497539e-04
-1.855890000e-02 6.270550000e-02 1.461460000e-03 3.264631629e-04
-1.874270000e-02 5.939150000e-02 1.400070000e-03 3.297088462e-04
-1.892840000e-02 5.754770000e-02 1.360950000e-03 3.329872283e-04
-1.911590000e-02 5.138330000e-02 1.226680000e-03 3.362987340e-04
-1.930540000e-02 4.922670000e-02 1.178240000e-03 3.396437879e-04
-1.949670000e-02 4.521740000e-02 1.079620000e-03 3.430219654e-04
-1.969000000e-02 4.245560000e-02 1.022250000e-03 3.464349651e-04
-1.988520000e-02 4.126130000e-02 9.947810000e-04 3.498819376e-04
-2.008240000e-02 3.523330000e-02 8.777900000e-04 3.533637323e-04
-2.028150000e-02 3.352710000e-02 8.367470000e-04 3.568803492e-04
-2.048270000e-02 3.326840000e-02 8.339590000e-04 3.604326376e-04
-2.068590000e-02 3.166440000e-02 7.898860000e-04 3.640210222e-04
-2.089120000e-02 2.916000000e-02 7.496130000e-04 3.676450784e-04
-2.109850000e-02 2.652010000e-02 7.063830000e-04 3.713060800e-04
-2.130800000e-02 2.518290000e-02 6.713890000e-04 3.750036024e-04
-2.151950000e-02 2.387570000e-02 6.426930000e-04 3.787384951e-04
-2.173310000e-02 2.289290000e-02 6.330680000e-04 3.825111825e-04
-2.194900000e-02 2.086460000e-02 5.931280000e-04 3.863216648e-04
-2.216690000e-02 2.087710000e-02 5.920100000e-04 3.901703665e-04
-2.238710000e-02 1.822280000e-02 5.292050000e-04 3.940581370e-04
-2.260950000e-02 1.773460000e-02 5.251520000e-04 3.979849764e-04
-2.283410000e-02 1.587140000e-02 4.818770000e-04 4.019513092e-04
-2.306100000e-02 1.432550000e-02 4.516190000e-04 4.059575601e-04
-2.329020000e-02 1.427760000e-02 4.522490000e-04 4.100041538e-04
-2.352170000e-02 1.266240000e-02 4.198450000e-04 4.140919397e-04
-2.375550000e-02 1.221280000e-02 4.137860000e-04 4.182204929e-04
-2.399170000e-02 1.046080000e-02 3.745320000e-04 4.223906630e-04
-2.423020000e-02 1.061330000e-02 3.810520000e-04 4.266016005e-04
-2.447120000e-02 9.879030000e-03 3.641280000e-04 4.308567027e-04
-2.471450000e-02 8.372030000e-03 3.313930000e-04 4.351542710e-04
-2.496030000e-02 7.670480000e-03 3.077050000e-04 4.394943054e-04
-2.520860000e-02 7.344890000e-03 3.049780000e-04 4.438810525e-04
-2.545940000e-02 6.798650000e-03 2.898680000e-04 4.483102657e-04
-2.571270000e-02 5.916300000e-03 2.671780000e-04 4.527819450e-04
-2.596850000e-02 5.344980000e-03 2.515360000e-04 4.573003369e-04
-2.622690000e-02 5.122650000e-03 2.474120000e-04 4.618611950e-04
-2.648800000e-02 4.750310000e-03 2.379530000e-04 4.664730124e-04
-2.675160000e-02 4.307150000e-03 2.238500000e-04 4.711272958e-04
-2.701790000e-02 4.018170000e-03 2.200510000e-04 4.758325386e-04
-2.728680000e-02 3.539150000e-03 2.046530000e-04 4.805802475e-04
-2.755850000e-02 3.818190000e-03 2.079440000e-04 4.853789156e-04
-2.783290000e-02 2.864750000e-03 1.819210000e-04 4.902285431e-04
-2.811000000e-02 2.795800000e-03 1.766910000e-04 4.951206367e-04
-2.839000000e-02 2.621500000e-03 1.750020000e-04 5.000679362e-04
-2.867270000e-02 2.484770000e-03 1.694560000e-04 5.050619484e-04
-2.895830000e-02 2.420090000e-03 1.709250000e-04 5.101069199e-04
-2.924670000e-02 2.359260000e-03 1.700600000e-04 5.151986041e-04
-2.953810000e-02 1.978560000e-03 1.600210000e-04 5.203454942e-04
-2.983230000e-02 1.947200000e-03 1.582820000e-04 5.255475902e-04
-3.012960000e-02 1.735930000e-03 1.527310000e-04 5.307963989e-04
-3.042980000e-02 1.894590000e-03 1.603050000e-04 5.361004136e-04
-3.073300000e-02 1.696680000e-03 1.525740000e-04 5.414596341e-04
-3.103920000e-02 1.793690000e-03 1.592450000e-04 5.468698140e-04
-3.134860000e-02 1.786860000e-03 1.552020000e-04 5.523351998e-04
-3.166100000e-02 1.872010000e-03 1.583950000e-04 5.578557915e-04
-3.197660000e-02 1.688180000e-03 1.499840000e-04 5.634315891e-04
-3.229530000e-02 1.732370000e-03 1.543250000e-04 5.690625926e-04
-3.261730000e-02 1.537600000e-03 1.453960000e-04 5.747530487e-04
-3.294240000e-02 1.541340000e-03 1.497560000e-04 5.804987107e-04
-3.327080000e-02 1.700330000e-03 1.572080000e-04 5.863038252e-04
-3.360260000e-02 2.142240000e-03 1.728870000e-04 5.921683922e-04
-3.393760000e-02 1.944020000e-03 1.686890000e-04 5.980924118e-04
-3.422050000e-02 1.914000000e-03 1.077140000e-04 6.019483327e-04
-3.466450000e-02 1.986410000e-03 1.438280000e-04 6.103523719e-04
-3.502190000e-02 1.849740000e-03 1.279740000e-04 6.165099550e-04
-3.538500000e-02 1.932640000e-03 1.227080000e-04 6.227354838e-04
-3.571620000e-02 2.188990000e-03 1.495980000e-04 6.288506008e-04
-3.607730000e-02 2.314320000e-03 1.503450000e-04 6.351568151e-04
-3.646770000e-02 1.831770000e-03 1.041590000e-04 6.416328939e-04
-3.682630000e-02 1.797150000e-03 1.012920000e-04 6.480155472e-04
-3.716160000e-02 2.278740000e-03 1.417330000e-04 6.543599810e-04
-3.754210000e-02 2.183390000e-03 1.294600000e-04 6.609379784e-04
-3.794040000e-02 1.799000000e-03 9.624980000e-05 6.676221409e-04
-3.831280000e-02 1.828080000e-03 9.734640000e-05 6.742680840e-04
-3.868400000e-02 1.949850000e-03 1.082600000e-04 6.809692330e-04
-3.906920000e-02 2.042140000e-03 1.122450000e-04 6.877680540e-04
-3.947340000e-02 1.659460000e-03 8.395540000e-05 6.946772869e-04
-3.986330000e-02 1.620310000e-03 8.073380000e-05 7.016035062e-04
-4.026580000e-02 1.588620000e-03 7.617690000e-05 7.086189042e-04
-4.066080000e-02 1.582510000e-03 7.829120000e-05 7.156810150e-04
-4.107010000e-02 1.429900000e-03 7.034450000e-05 7.228323046e-04
-4.147810000e-02 1.336120000e-03 6.498820000e-05 7.300472933e-04
-4.187440000e-02 1.721900000e-03 9.200060000e-05 7.373174879e-04
-4.230490000e-02 1.404890000e-03 6.788170000e-05 7.446980943e-04
-4.273170000e-02 1.146480000e-03 5.315150000e-05 7.521381533e-04
-4.315460000e-02 1.030130000e-03 4.872800000e-05 7.596504046e-04
-4.358350000e-02 1.018640000e-03 4.851630000e-05 7.672348483e-04
-4.401550000e-02 1.060250000e-03 5.148880000e-05 7.748999775e-04
-4.445490000e-02 9.115610000e-04 4.517670000e-05 7.826415457e-04
-4.489830000e-02 7.795360000e-04 3.746760000e-05 7.904553063e-04
-4.534700000e-02 5.957570000e-04 2.867780000e-05 7.983539991e-04
-4.579470000e-02 6.476450000e-04 3.286690000e-05 8.063333774e-04
-4.625120000e-02 5.268390000e-04 2.666210000e-05 8.143891946e-04
-4.671240000e-02 4.365460000e-04 2.240950000e-05 8.225299441e-04
-4.717830000e-02 3.696050000e-04 1.929650000e-05 8.307471325e-04
-4.764690000e-02 3.315640000e-04 1.808550000e-05 8.390577463e-04
-4.812080000e-02 2.545840000e-04 1.440620000e-05 8.474405525e-04
-4.859940000e-02 2.090800000e-04 1.312430000e-05 8.559167841e-04
-4.908280000e-02 1.929370000e-04 1.261590000e-05 8.644779478e-04
-4.957100000e-02 1.309220000e-04 9.992220000e-06 8.731240437e-04
-5.006400000e-02 1.098230000e-04 9.080510000e-06 8.818635651e-04
-5.056190000e-02 9.565480000e-05 8.370090000e-06 8.906880186e-04
-5.106550000e-02 7.925720000e-05 7.699130000e-06 8.995974043e-04
-5.157340000e-02 7.956050000e-05 6.898560000e-06 9.086044619e-04
-5.208640000e-02 7.224950000e-05 6.102730000e-06 9.177006984e-04
-5.260450000e-02 7.825130000e-05 6.391360000e-06 9.268903603e-04
-5.312790000e-02 8.637120000e-05 6.561860000e-06 9.361734476e-04
-5.365650000e-02 1.331620000e-04 8.789840000e-06 9.455499603e-04
-5.419050000e-02 1.436320000e-04 8.178840000e-06 9.550241449e-04
-5.472980000e-02 1.586820000e-04 8.565340000e-06 9.645917550e-04
-5.527450000e-02 1.900070000e-04 9.755240000e-06 9.742612837e-04
-5.582470000e-02 2.354200000e-04 1.141720000e-05 9.840284844e-04
-5.638040000e-02 2.339320000e-04 1.034520000e-05 9.938933571e-04
-5.694170000e-02 2.433900000e-04 1.059550000e-05 1.003855902e-03
-5.750870000e-02 2.708580000e-04 1.125130000e-05 1.013924612e-03
-5.808130000e-02 3.109660000e-04 1.233550000e-05 1.024095240e-03
-5.865970000e-02 3.483270000e-04 1.357860000e-05 1.034367788e-03
-5.924390000e-02 3.329570000e-04 1.275590000e-05 1.044750747e-03
-5.983400000e-02 3.546590000e-04 1.322360000e-05 1.055235624e-03
-6.043000000e-02 3.544670000e-04 1.306610000e-05 1.065826667e-03
-6.103190000e-02 3.855150000e-04 1.408930000e-05 1.076523875e-03
-6.164000000e-02 3.325090000e-04 1.201760000e-05 1.087335742e-03
-6.225410000e-02 3.330870000e-04 1.197150000e-05 1.098253773e-03
-6.287440000e-02 3.303070000e-04 1.197230000e-05 1.109286464e-03
-6.350090000e-02 3.224690000e-04 1.162910000e-05 1.120433812e-03
-6.413370000e-02 2.744620000e-04 9.948790000e-06 1.131691573e-03
-6.477280000e-02 2.792430000e-04 1.025370000e-05 1.143063992e-03
-6.541840000e-02 2.389380000e-04 8.960850000e-06 1.154555315e-03
-6.607040000e-02 2.330280000e-04 8.726650000e-06 1.166165544e-03
-6.672900000e-02 1.863430000e-04 7.236140000e-06 1.177890432e-03
-6.739420000e-02 1.649490000e-04 6.619500000e-06 1.189738471e-03
-6.806600000e-02 1.332440000e-04 5.541570000e-06 1.201709662e-03
-6.874460000e-02 1.153760000e-04 4.971620000e-06 1.213799758e-03
-6.943000000e-02 8.250330000e-05 3.951150000e-06 1.226017252e-03
-7.012230000e-02 6.719230000e-05 3.570180000e-06 1.238357898e-03
-7.082150000e-02 5.033220000e-05 2.926230000e-06 1.250825942e-03
-7.152780000e-02 3.336120000e-05 2.509700000e-06 1.263421384e-03
-7.224110000e-02 2.290520000e-05 2.116380000e-06 1.276148471e-03
-7.293380000e-02 1.879440000e-05 1.860530000e-06 1.288068702e-03
-7.366830000e-02 1.553440000e-05 1.798210000e-06 1.301292643e-03
-7.440150000e-02 1.824520000e-05 1.951840000e-06 1.314359459e-03
-7.514050000e-02 2.235620000e-05 1.801000000e-06 1.327506960e-03
-7.587210000e-02 2.773620000e-05 1.890140000e-06 1.340293500e-03
-7.664020000e-02 3.931010000e-05 2.300950000e-06 1.354192651e-03
-7.739640000e-02 4.596690000e-05 2.332400000e-06 1.367582209e-03
-7.810610000e-02 5.541310000e-05 2.459260000e-06 1.379328330e-03
-7.886820000e-02 6.726050000e-05 2.729570000e-06 1.392692408e-03
-7.979530000e-02 7.650640000e-05 2.773090000e-06 1.409143772e-03
-8.072890000e-02 7.794720000e-05 2.857410000e-06 1.425518696e-03
-8.153340000e-02 8.505420000e-05 2.990400000e-06 1.439910454e-03
-8.233180000e-02 9.685690000e-05 3.222700000e-06 1.454408377e-03
-8.316050000e-02 9.462400000e-05 3.166210000e-06 1.469122877e-03
-8.402520000e-02 8.585640000e-05 2.824460000e-06 1.484058201e-03
-8.486480000e-02 8.101440000e-05 2.662540000e-06 1.499057224e-03
-8.573420000e-02 7.655920000e-05 2.549780000e-06 1.514268578e-03
-8.655530000e-02 7.385430000e-05 2.485840000e-06 1.529496917e-03
-8.743720000e-02 6.249710000e-05 2.190920000e-06 1.545009780e-03
-8.831630000e-02 5.495430000e-05 2.001270000e-06 1.560658534e-03
-8.911080000e-02 5.694540000e-05 2.081580000e-06 1.576247836e-03
-9.004160000e-02 4.229200000e-05 1.729710000e-06 1.592304265e-03
-9.095460000e-02 3.367540000e-05 1.458910000e-06 1.608462612e-03
-9.185040000e-02 2.545640000e-05 1.249630000e-06 1.624727124e-03
-9.274350000e-02 2.092210000e-05 1.159760000e-06 1.641140268e-03
-9.362890000e-02 1.531120000e-05 1.060140000e-06 1.657689303e-03
-9.455270000e-02 1.265650000e-05 9.577530000e-07 1.674480395e-03
-9.551780000e-02 9.331240000e-06 8.621390000e-07 1.691509297e-03
-9.647710000e-02 8.901520000e-06 7.828970000e-07 1.708691077e-03
-9.741890000e-02 1.079150000e-05 8.938470000e-07 1.725991763e-03
-9.842590000e-02 1.213680000e-05 9.113080000e-07 1.743589710e-03
-9.942010000e-02 1.540800000e-05 9.077770000e-07 1.761323549e-03
-1.004250000e-01 1.938030000e-05 9.602530000e-07 1.779248486e-03
-1.014340000e-01 2.091160000e-05 1.040890000e-06 1.797347534e-03
-1.024990000e-01 2.519250000e-05 1.078370000e-06 1.815722611e-03
-1.034980000e-01 2.818800000e-05 1.132170000e-06 1.834144401e-03
-1.045460000e-01 2.998100000e-05 1.178530000e-06 1.852837973e-03
-1.056080000e-01 3.056280000e-05 1.150490000e-06 1.871735383e-03
-1.066820000e-01 2.819030000e-05 1.099070000e-06 1.890832384e-03
-1.077580000e-01 2.692630000e-05 1.037400000e-06 1.910111989e-03
-1.088310000e-01 2.541920000e-05 1.012560000e-06 1.929574198e-03
-1.099160000e-01 2.282700000e-05 9.367100000e-07 1.949244491e-03
-1.110400000e-01 1.769170000e-05 7.904500000e-07 1.969169580e-03
-1.121170000e-01 1.547510000e-05 7.625400000e-07 1.989209328e-03
-1.132440000e-01 1.172580000e-05 6.688050000e-07 2.009529352e-03
-1.143190000e-01 1.050270000e-05 6.598050000e-07 2.029959788e-03
-1.154640000e-01 8.121530000e-06 5.847030000e-07 2.050708720e-03
-1.166450000e-01 4.988840000e-06 5.267190000e-07 2.071720941e-03
-1.177620000e-01 4.909990000e-06 5.360960000e-07 2.092830835e-03
-1.189250000e-01 5.304340000e-06 5.240840000e-07 2.114229497e-03
-1.201290000e-01 5.689050000e-06 4.912340000e-07 2.135895696e-03
-1.213460000e-01 6.444710000e-06 5.061070000e-07 2.157799706e-03
-1.225860000e-01 7.456190000e-06 5.058030000e-07 2.179954265e-03
-1.238230000e-01 8.248420000e-06 5.025600000e-07 2.202325401e-03
-1.250910000e-01 1.067490000e-05 5.845390000e-07 2.224964074e-03
-1.263610000e-01 1.131620000e-05 5.722280000e-07 2.247827816e-03
-1.276430000e-01 1.104400000e-05 5.762550000e-07 2.270937863e-03
-1.289320000e-01 1.062580000e-05 5.655340000e-07 2.294294212e-03
-1.302100000e-01 9.337660000e-06 5.254720000e-07 2.317858646e-03
-1.315470000e-01 8.922800000e-06 5.000680000e-07 2.341754314e-03
-1.328540000e-01 6.436110000e-06 4.446880000e-07 2.365841081e-03
-1.341620000e-01 6.181130000e-06 4.556250000e-07 2.390178397e-03
-1.355150000e-01 4.685680000e-06 4.034780000e-07 2.414821469e-03
-1.368240000e-01 4.667540000e-06 3.809290000e-07 2.439659885e-03
-1.382040000e-01 4.262500000e-06 3.763010000e-07 2.464842276e-03
-1.395890000e-01 3.884300000e-06 3.571580000e-07 2.490292204e-03
-1.409890000e-01 3.699480000e-06 3.796620000e-07 2.516022408e-03
-1.424300000e-01 3.659930000e-06 3.543380000e-07 2.542066861e-03
-1.438510000e-01 4.559390000e-06 3.665690000e-07 2.568357617e-03
-1.452630000e-01 4.580880000e-06 3.470620000e-07 2.594911663e-03
-1.467500000e-01 4.829290000e-06 3.503920000e-07 2.621826671e-03
-1.482250000e-01 4.930920000e-06 3.533300000e-07 2.649009215e-03
-1.497100000e-01 4.781000000e-06 3.612560000e-07 2.676489022e-03
-1.512250000e-01 4.644840000e-06 3.397110000e-07 2.704291571e-03
-1.527360000e-01 4.365080000e-06 3.324590000e-07 2.732374397e-03
-1.542610000e-01 3.807060000e-06 3.253780000e-07 2.760775718e-03
-1.558250000e-01 3.544150000e-06 3.053880000e-07 2.789516767e-03
-1.573660000e-01 2.632690000e-06 2.773550000e-07 2.818538093e-03
-1.589410000e-01 2.129680000e-06 2.570610000e-07 2.847903395e-03
-1.605110000e-01 2.509080000e-06 2.684170000e-07 2.877574452e-03
-1.621370000e-01 2.606260000e-06 2.683540000e-07 2.907627704e-03
-1.637550000e-01 2.467960000e-06 2.618110000e-07 2.937986711e-03
-1.654040000e-01 2.437690000e-06 2.457080000e-07 2.968710928e-03
-1.670350000e-01 2.818460000e-06 2.626350000e-07 2.999740899e-03
-1.687360000e-01 3.201910000e-06 2.677220000e-07 3.031182793e-03
-1.704100000e-01 3.020960000e-06 2.548660000e-07 3.062934688e-03
-1.721190000e-01 2.398550000e-06 2.324640000e-07 3.095064532e-03
-1.738390000e-01 2.458240000e-06 2.385460000e-07 3.127555337e-03
-1.755740000e-01 2.033660000e-06 2.231960000e-07 3.160419844e-03
-1.773360000e-01 1.684040000e-06 2.048280000e-07 3.193666546e-03
-1.790870000e-01 1.293830000e-06 2.007650000e-07 3.227265717e-03
-1.809070000e-01 1.439670000e-06 1.882070000e-07 3.261306534e-03
-1.827150000e-01 1.540200000e-06 1.999980000e-07 3.295708314e-03
-1.845350000e-01 1.338490000e-06 1.864820000e-07 3.330500781e-03
-1.863830000e-01 1.615990000e-06 1.863690000e-07 3.365705170e-03
-1.882470000e-01 1.493470000e-06 1.883860000e-07 3.401317233e-03
-1.901260000e-01 2.059680000e-06 1.920700000e-07 3.437345464e-03
-1.920380000e-01 1.690150000e-06 1.767700000e-07 3.473806849e-03
-1.939540000e-01 1.488370000e-06 1.792740000e-07 3.510675908e-03
-1.959000000e-01 1.403820000e-06 1.747280000e-07 3.547990861e-03
-1.978600000e-01 1.346890000e-06 1.705690000e-07 3.585734722e-03
-1.998450000e-01 9.477100000e-07 1.617790000e-07 3.623937217e-03
-2.018330000e-01 1.089550000e-06 1.735020000e-07 3.662568619e-03
-2.038630000e-01 1.246350000e-06 1.654660000e-07 3.701684134e-03
-2.059040000e-01 1.227370000e-06 1.644900000e-07 3.741254037e-03
-2.079590000e-01 1.168960000e-06 1.584560000e-07 3.781286820e-03
-2.100420000e-01 1.161720000e-06 1.521980000e-07 3.821807963e-03
-2.121400000e-01 1.216890000e-06 1.588540000e-07 3.862808973e-03
-2.142570000e-01 1.317570000e-06 1.546070000e-07 3.904298343e-03
-2.163990000e-01 1.032790000e-06 1.472920000e-07 3.946293059e-03
-2.185700000e-01 1.030660000e-06 1.514730000e-07 3.988805862e-03
-2.207810000e-01 5.945350000e-07 1.511720000e-07 4.031853738e-03
-2.229880000e-01 7.279960000e-07 1.429280000e-07 4.075394220e-03
-2.252160000e-01 7.806310000e-07 1.485250000e-07 4.119465528e-03
-2.274670000e-01 1.063390000e-06 1.499300000e-07 4.164076155e-03
-2.297410000e-01 6.526970000e-07 1.296680000e-07 4.209234596e-03
-2.320370000e-01 1.074380000e-06 1.484530000e-07 4.254932355e-03
-2.343560000e-01 8.687630000e-07 1.468620000e-07 4.301220393e-03
-2.366980000e-01 9.218680000e-07 1.450820000e-07 4.348060490e-03
-2.390640000e-01 6.471490000e-07 1.368090000e-07 4.395495113e-03
-2.414540000e-01 5.363930000e-07 1.356880000e-07 4.443524261e-03
-2.438670000e-01 6.337170000e-07 1.304030000e-07 4.492147934e-03
-2.463040000e-01 6.292700000e-07 1.365570000e-07 4.541408598e-03
-2.487660000e-01 6.332920000e-07 1.224530000e-07 4.591263788e-03
-2.512530000e-01 1.037050000e-06 1.354090000e-07 4.641713503e-03
-2.537640000e-01 8.252860000e-07 1.431610000e-07 4.692842675e-03
-2.563010000e-01 6.268250000e-07 1.192570000e-07 4.744608839e-03
-2.588630000e-01 5.252590000e-07 1.227410000e-07 4.797054460e-03
-2.614500000e-01 5.218320000e-07 1.309180000e-07 4.850137073e-03
-2.640640000e-01 3.916590000e-07 1.213700000e-07 4.903941609e-03
-2.667030000e-01 4.724390000e-07 1.399730000e-07 4.958425602e-03
-2.693690000e-01 5.595360000e-07 1.391510000e-07 5.013589053e-03
-2.720620000e-01 6.640700000e-07 1.448670000e-07 5.069474428e-03
-2.747820000e-01 4.593780000e-07 1.514660000e-07 5.126081726e-03
-2.775290000e-01 3.669610000e-07 1.435460000e-07 5.183453413e-03
-2.803030000e-01 5.315310000e-07 1.483080000e-07 5.241589490e-03
-2.831050000e-01 4.289140000e-07 1.361450000e-07 5.300447491e-03
-2.859350000e-01 5.520060000e-07 1.419830000e-07 5.360112348e-03
-2.887930000e-01 5.702640000e-07 1.529000000e-07 5.420541594e-03
-2.916800000e-01 5.047310000e-07 1.364290000e-07 5.481777696e-03
-2.945960000e-01 6.619230000e-07 1.407930000e-07 5.543863119e-03
-2.975410000e-01 7.601320000e-07 1.607210000e-07 5.606755399e-03
-3.005160000e-01 4.685270000e-07 1.348870000e-07 5.670454534e-03
-3.035200000e-01 4.428600000e-07 1.471340000e-07 5.735087923e-03
-3.065540000e-01 4.899790000e-07 1.404300000e-07 5.800528167e-03
-3.096190000e-01 3.601630000e-07 1.337280000e-07 5.866902666e-03
-3.127140000e-01 2.905630000e-07 1.480620000e-07 5.934168953e-03
-3.158410000e-01 5.199630000e-07 1.515620000e-07 6.002327027e-03
-3.189980000e-01 4.666650000e-07 1.562560000e-07 6.071461822e-03
-3.221870000e-01 3.888830000e-07 1.570110000e-07 6.141530870e-03
-3.254080000e-01 4.467780000e-07 1.555120000e-07 6.212576639e-03
-3.286620000e-01 3.238850000e-07 1.525860000e-07 6.284599127e-03
-3.319470000e-01 3.787360000e-07 1.581800000e-07 6.357640802e-03
-3.352660000e-01 3.881990000e-07 1.539110000e-07 6.431701663e-03
-3.386180000e-01 4.428770000e-07 1.490980000e-07 6.506824176e-03
-3.420030000e-01 2.477870000e-07 1.463210000e-07 6.582965876e-03
-3.454230000e-01 2.857690000e-07 1.351350000e-07 6.660211693e-03
-3.488760000e-01 4.759640000e-07 1.536640000e-07 6.738561630e-03
-3.523640000e-01 4.496390000e-07 1.539560000e-07 6.818015684e-03
-3.558870000e-01 2.471470000e-07 1.443220000e-07 6.898573857e-03
-3.594450000e-01 2.167640000e-07 1.491810000e-07 6.980363546e-03
-3.630390000e-01 5.205850000e-07 1.573690000e-07 7.063257354e-03
-3.666690000e-01 5.246970000e-07 1.545410000e-07 7.147425144e-03
-3.703350000e-01 3.644030000e-07 1.550240000e-07 7.232781985e-03
-3.740370000e-01 4.597520000e-07 1.653080000e-07 7.319370343e-03
-3.777770000e-01 5.359220000e-07 1.820430000e-07 7.407232683e-03
-3.815540000e-01 4.268070000e-07 1.770030000e-07 7.496411472e-03
-3.853690000e-01 4.036660000e-07 1.811100000e-07 7.586906710e-03
-3.892220000e-01 2.554540000e-07 1.597290000e-07 7.678718396e-03
-3.931130000e-01 9.269720000e-08 1.654020000e-07 7.771931464e-03
-3.970440000e-01 1.106720000e-07 1.808880000e-07 7.866503446e-03
-4.010140000e-01 4.521630000e-07 1.731910000e-07 7.962519276e-03
-4.050230000e-01 3.780660000e-07 1.515970000e-07 8.059978953e-03
-4.090730000e-01 3.091360000e-07 1.571950000e-07 8.158924942e-03
-4.131630000e-01 3.417740000e-07 1.448180000e-07 8.259357245e-03
-4.172940000e-01 3.449240000e-07 1.595810000e-07 8.361318327e-03
-4.214660000e-01 2.518400000e-07 1.597570000e-07 8.464850655e-03
-4.256800000e-01 4.017370000e-07 1.538140000e-07 8.569954228e-03
-4.299360000e-01 3.172790000e-07 1.691300000e-07 8.676713978e-03
-4.342350000e-01 5.506310000e-07 1.611420000e-07 8.785087440e-03
-4.385770000e-01 5.085100000e-07 1.649900000e-07 8.895159545e-03
-4.429620000e-01 6.025930000e-07 1.738350000e-07 9.006930294e-03
-4.473910000e-01 4.384540000e-07 1.653500000e-07 9.120484618e-03
-4.518650000e-01 3.387570000e-07 1.876390000e-07 9.235822519e-03
-4.563830000e-01 4.358460000e-07 1.978260000e-07 9.352943995e-03
-4.609460000e-01 3.855790000e-07 1.761430000e-07 9.471933979e-03
-4.655550000e-01 3.834150000e-07 1.884540000e-07 9.592834938e-03
diff --git a/docs/src/tutorials/sample/material_solvated.ipynb b/docs/src/tutorials/sample/material_solvated.ipynb
index 2cad6851..39197d94 100644
--- a/docs/src/tutorials/sample/material_solvated.ipynb
+++ b/docs/src/tutorials/sample/material_solvated.ipynb
@@ -34,8 +34,11 @@
"\n",
"import numpy as np\n",
"import scipp as sc\n",
- "import easyreflectometry\n",
+ "import pooch\n",
"import refnx\n",
+ "\n",
+ "import easyreflectometry\n",
+ "\n",
"from easyreflectometry.data import load\n",
"from easyreflectometry.sample import Layer\n",
"from easyreflectometry.sample import Sample\n",
@@ -77,7 +80,7 @@
"source": [
"For information about the data being read in and the details of the model see [the previous tutorial](../fitting/simple_fitting.rst). \n",
"We will gloss over these details here.\n",
- "Use link to [download](example.ort) the ort data."
+ "We use `pooch` to fetch the file from the repository."
]
},
{
@@ -87,7 +90,12 @@
"metadata": {},
"outputs": [],
"source": [
- "data = load('example.ort')"
+ "file_path = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/fitting/example.ort\",\n",
+ " known_hash=\"82d0c95c069092279a799a8131ad3710335f601d9f1080754b387f42e407dfab\",\n",
+ ")\n",
+ "data = load(file_path)"
]
},
{
diff --git a/docs/src/tutorials/sample/monolayer.ipynb b/docs/src/tutorials/sample/monolayer.ipynb
index 837117e1..514673f3 100644
--- a/docs/src/tutorials/sample/monolayer.ipynb
+++ b/docs/src/tutorials/sample/monolayer.ipynb
@@ -30,8 +30,10 @@
"%matplotlib inline\n",
"\n",
"import refnx\n",
+ "import pooch\n",
"\n",
"import easyreflectometry\n",
+ "\n",
"from easyreflectometry.calculators import CalculatorFactory\n",
"from easyreflectometry.data import load\n",
"from easyreflectometry.plot import plot\n",
@@ -44,7 +46,7 @@
"from easyreflectometry.experiment import PercentageFhwm\n",
"from easyreflectometry.fitting import Fitter\n",
"from easyreflectometry.plot import plot\n",
- "\n"
+ "from easyscience.fitting import AvailableMinimizers\n"
]
},
{
@@ -75,7 +77,7 @@
"\n",
"As has been [shown previously](../fitting/simple_fitting.rst), we use the `load` function to read in our experimental data. \n",
"For this tutorial we will be looking at [DSPC](https://en.wikipedia.org/wiki/Distearoylphosphatidylcholine), a phospholipid molecule that will self-assemble into a monolayer at the air-water interface. \n",
- "The data being used has kindly been shared by the authors of [previous work on the system](#hollinshead2009). "
+ "The data being used has kindly been shared by the authors of [previous work on the system](#hollinshead2009). We use `pooch` to fetch the file from our repository."
]
},
{
@@ -85,7 +87,12 @@
"metadata": {},
"outputs": [],
"source": [
- "data = load('d70d2o.ort')\n",
+ "file_path = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/sample/d70d2o.ort\",\n",
+ " known_hash=\"d877793b3c415834791b2c114dceb12f4564c083b2e7bf51b7a9f289a58165a2\",\n",
+ ")\n",
+ "data = load(file_path)\n",
"plot(data)"
]
},
@@ -371,7 +378,8 @@
"calculator = CalculatorFactory()\n",
"model.interface = calculator\n",
"fitter = Fitter(model)\n",
- "analysed = fitter.fit(data, method='differential_evolution')"
+ "fitter.switch_minimizer(AvailableMinimizers.LMFit_differential_evolution)\n",
+ "analysed = fitter.fit(data)"
]
},
{
@@ -464,8 +472,22 @@
}
],
"metadata": {
+ "kernelspec": {
+ "display_name": "erl_1_311",
+ "language": "python",
+ "name": "python3"
+ },
"language_info": {
- "name": "python"
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
}
},
"nbformat": 4,
diff --git a/docs/src/tutorials/sample/multi_contrast.ipynb b/docs/src/tutorials/sample/multi_contrast.ipynb
index 72035055..fab42c39 100644
--- a/docs/src/tutorials/sample/multi_contrast.ipynb
+++ b/docs/src/tutorials/sample/multi_contrast.ipynb
@@ -29,8 +29,11 @@
"source": [
"%matplotlib inline\n",
"\n",
- "import easyreflectometry\n",
"import refnx\n",
+ "import pooch\n",
+ "\n",
+ "import easyreflectometry\n",
+ "\n",
"from easyreflectometry.data import load\n",
"from easyreflectometry.plot import plot\n",
"from easyreflectometry.sample import Material\n",
@@ -42,6 +45,8 @@
"from easyreflectometry.experiment import PercentageFhwm\n",
"from easyreflectometry.calculators import CalculatorFactory\n",
"from easyreflectometry.fitting import Fitter\n",
+ "from easyscience.fitting import AvailableMinimizers\n",
+ "\n",
"print(f'easyreflectometry: {easyreflectometry.__version__}')\n",
"print(f'refnx: {refnx.__version__}')"
]
@@ -55,7 +60,7 @@
"\n",
"We load in three different isotopic contrast that are stored in a single `.ort` file. \n",
"This `.ort` file uses the [mutliple data set syntax](https://github.com/reflectivity/file_format/blob/master/specification.md#multiple-data-sets) to indicate that different measurements are present in a single file.\n",
- "Use link to [download](multiple.ort) the ort data."
+ "We use `pooch` to fetch the file from the repository."
]
},
{
@@ -65,7 +70,12 @@
"metadata": {},
"outputs": [],
"source": [
- "data = load('multiple.ort')"
+ "file_path = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/sample/multiple.ort\",\n",
+ " known_hash=\"241bcb819cdae47fbbb310a99c2456c7332312719496b936a153dc7dee83e62c\",\n",
+ ")\n",
+ "data = load(file_path)"
]
},
{
@@ -366,7 +376,7 @@
"metadata": {},
"outputs": [],
"source": [
- "d13d2o.head_layer.thickness.raw_value, d70d2o.head_layer.thickness.raw_value, d83acmw.head_layer.thickness.raw_value"
+ "d13d2o.head_layer.thickness.value, d70d2o.head_layer.thickness.value, d83acmw.head_layer.thickness.value"
]
},
{
@@ -386,7 +396,7 @@
"metadata": {},
"outputs": [],
"source": [
- "d13d2o.head_layer.thickness.raw_value, d70d2o.head_layer.thickness.raw_value, d83acmw.head_layer.thickness.raw_value"
+ "d13d2o.head_layer.thickness.value, d70d2o.head_layer.thickness.value, d83acmw.head_layer.thickness.value"
]
},
{
@@ -501,7 +511,8 @@
"metadata": {},
"outputs": [],
"source": [
- "f = Fitter(d13d2o_model, d70d2o_model, d83acmw_model)"
+ "fitter = Fitter(d13d2o_model, d70d2o_model, d83acmw_model)\n",
+ "fitter.switch_minimizer(AvailableMinimizers.LMFit_scipy_least_squares)"
]
},
{
@@ -511,7 +522,7 @@
"metadata": {},
"outputs": [],
"source": [
- "analysed = f.fit(data)"
+ "analysed = fitter.fit(data)"
]
},
{
@@ -544,8 +555,22 @@
}
],
"metadata": {
+ "kernelspec": {
+ "display_name": "erl_1_311",
+ "language": "python",
+ "name": "python3"
+ },
"language_info": {
- "name": "python"
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.9"
}
},
"nbformat": 4,
diff --git a/docs/src/tutorials/sample/resolution_functions.ipynb b/docs/src/tutorials/sample/resolution_functions.ipynb
index 555f2aff..63f3d7c7 100644
--- a/docs/src/tutorials/sample/resolution_functions.ipynb
+++ b/docs/src/tutorials/sample/resolution_functions.ipynb
@@ -36,10 +36,10 @@
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"import scipp as sc\n",
- "\n",
+ "import refnx\n",
+ "import pooch\n",
"\n",
"import easyreflectometry\n",
- "import refnx\n",
"\n",
"from easyreflectometry.calculators import CalculatorFactory\n",
"from easyreflectometry.data import load\n",
@@ -71,7 +71,7 @@
"print(f'numpy: {np.__version__}')\n",
"print(f'scipp: {sc.__version__}')\n",
"print(f'easyreflectometry: {easyreflectometry.__version__}')\n",
- "print(f'Refl1D: {refnx.__version__}')"
+ "print(f'refnx: {refnx.__version__}')"
]
},
{
@@ -84,7 +84,7 @@
"The data that we will investigate in this tutorial was generated with `Refnx` and are stored in `.ort` [format file](https://github.com/reflectivity/file_format/blob/master/specification.md) files. In this tutorial we are investigation how we can include resolution effects when simulating and reproducing data measured in an experiment. For an `.ort` file the resoultion data for reflectivity is stored in the fourth column.\n",
"\n",
"IMPORTANT when using `easyreflectometry` functionality for loading an `.ort` file we store the resolution data as a variance (squared value). As a consequence one needs to take the squareroot of the loaded data to recover the raw values (fourth column).\n",
- "Use links to [download 0.0](mod_pointwise_two_layer_sample_dq-0.0.ort), [download 1.0](mod_pointwise_two_layer_sample_dq-1.0.ort), and [download 10.0](mod_pointwise_two_layer_sample_dq-10.0.ort) ort data."
+ "We use `pooch` to fetch the file from the repository."
]
},
{
@@ -94,10 +94,25 @@
"metadata": {},
"outputs": [],
"source": [
+ "file_path_0 = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/sample/mod_pointwise_two_layer_sample_dq-0.0.ort\",\n",
+ " known_hash=\"f8a3e7007b83f0de4e2c761134e7d1c55027f0099528bd56f746b50349369f50\",\n",
+ ")\n",
+ "file_path_1 = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/sample/mod_pointwise_two_layer_sample_dq-1.0.ort\",\n",
+ " known_hash=\"9d81a512cbe45f923806ad307e476b27535614b2e08a2bf0f4559ab608a34f7a\",\n",
+ ")\n",
+ "file_path_10 = pooch.retrieve(\n",
+ " # URL to one of Pooch's test files\n",
+ " url=\"https://raw.githubusercontent.com/EasyScience/EasyReflectometryLib/master/docs/src/tutorials/sample/mod_pointwise_two_layer_sample_dq-10.0.ort\",\n",
+ " known_hash=\"991395c0b6a91bf60c12d234c645143dcac1cab929944fc4e452020d44b787ad\",\n",
+ ")\n",
"dict_reference = {}\n",
- "dict_reference['0'] = load(\"mod_pointwise_two_layer_sample_dq-0.0.ort\")\n",
- "dict_reference['1'] = load(\"mod_pointwise_two_layer_sample_dq-1.0.ort\")\n",
- "dict_reference['10'] = load('mod_pointwise_two_layer_sample_dq-10.0.ort')"
+ "dict_reference['0'] = load(file_path_0)\n",
+ "dict_reference['1'] = load(file_path_1)\n",
+ "dict_reference['10'] = load(file_path_10)"
]
},
{
@@ -293,7 +308,7 @@
" model.resolution_function = resolution_function_dict[key]\n",
" model_data = model.interface().fit_func(\n",
" model_coords,\n",
- " model.uid,\n",
+ " model.unique_name,\n",
" )\n",
" plt.plot(model_coords, model_data, 'k-', label=f'Resolution: {key}%')\n",
" plt.plot(reference_coords, reference_data, 'rx', label=f'Reference')\n",
@@ -343,14 +358,14 @@
"model.resolution_function = resolution_function_dict[key]\n",
"model_data = model.interface().fit_func(\n",
" model_coords,\n",
- " model.uid,\n",
+ " model.unique_name,\n",
")\n",
"plt.plot(model_coords, model_data, 'k-', label=f'Variable', linewidth=5)\n",
"\n",
"model.resolution_function = PercentageFhwm(1.0)\n",
"model_data = model.interface().fit_func(\n",
" model_coords,\n",
- " model.uid,\n",
+ " model.unique_name,\n",
")\n",
"plt.plot(model_coords, model_data, 'r-', label=f'Percentage')\n",
"\n",
diff --git a/pyproject.toml b/pyproject.toml
index 45ca59eb..1bb784ef 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -29,11 +29,12 @@ classifiers = [
]
requires-python = ">=3.9,<3.12"
dependencies = [
- "easyscience>=0.6.0",
+ "easyscience>=1.0.1",
"scipp>=23.12.0",
"refnx>=0.1.15",
"refl1d>=0.8.14",
- "orsopy>=0.0.4"
+ "orsopy>=0.0.4",
+ "pint==0.23" # Only to ensure that unit is reported as dimensionless rather than empty string
]
[project.optional-dependencies]
@@ -47,6 +48,7 @@ dev = [
"jupyter>=1.0.0",
"jupyterlab",
"plopp",
+ "pooch",
"pytest>=5.2",
"pytest-cov>=3.0.0",
"ruff",
@@ -94,7 +96,7 @@ exclude = [
[tool.ruff.format]
quote-style = "single"
-[tool.ruff.per-file-ignores]
+[tool.ruff.lint.per-file-ignores]
# allow asserts in test files
"*test_*.py" = ["S101"]
diff --git a/src/easyreflectometry/__version__.py b/src/easyreflectometry/__version__.py
index a6221b3d..1a72d32e 100644
--- a/src/easyreflectometry/__version__.py
+++ b/src/easyreflectometry/__version__.py
@@ -1 +1 @@
-__version__ = '1.0.2'
+__version__ = '1.1.0'
diff --git a/src/easyreflectometry/calculators/bornagain/calculator.py b/src/easyreflectometry/calculators/bornagain/calculator.py
index b5ab44d5..3a17caef 100644
--- a/src/easyreflectometry/calculators/bornagain/calculator.py
+++ b/src/easyreflectometry/calculators/bornagain/calculator.py
@@ -1,12 +1,13 @@
__author__ = 'github.com/arm61'
import numpy as np
+from easyscience.Objects.Inferface import ItemContainer
+
from easyreflectometry.experiment import Model
from easyreflectometry.sample import Layer
from easyreflectometry.sample import Material
from easyreflectometry.sample import MaterialMixture
from easyreflectometry.sample import Multilayer
-from easyscience.Objects.Inferface import ItemContainer
from ..calculator_base import CalculatorBase
from .wrapper import BornAgainWrapper
@@ -66,7 +67,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
r_list = []
t_ = type(model)
if issubclass(t_, Material):
- key = model.uid
+ key = model.unique_name
if key not in self._wrapper.storage['material'].keys():
self._wrapper.create_material(key)
r_list.append(
@@ -78,7 +79,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
elif issubclass(t_, MaterialMixture):
- key = model.uid
+ key = model.unique_name
if key not in self._wrapper.storage['material'].keys():
self._wrapper.create_material(key)
r_list.append(
@@ -90,7 +91,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
elif issubclass(t_, Layer):
- key = model.uid
+ key = model.unique_name
if key not in self._wrapper.storage['layer'].keys():
self._wrapper.create_layer(key)
r_list.append(
@@ -101,9 +102,9 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
self._wrapper.update_layer,
)
)
- self.assign_material_to_layer(model.material.uid, key)
+ self.assign_material_to_layer(model.material.unique_name, key)
elif issubclass(t_, Multilayer):
- key = model.uid
+ key = model.unique_name
self._wrapper.create_item(key)
r_list.append(
ItemContainer(
@@ -114,7 +115,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
for i in model.layers:
- self.add_layer_to_item(i.uid, model.uid)
+ self.add_layer_to_item(i.unique_name, model.unique_name)
elif issubclass(t_, Model):
self._wrapper.create_model()
r_list.append(
@@ -126,7 +127,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
for i in model.structure:
- self.add_item_to_model(i.uid)
+ self.add_item_to_model(i.unique_name)
return r_list
def assign_material_to_layer(self, material_id: int, layer_id: int) -> None:
diff --git a/src/easyreflectometry/calculators/calculator_base.py b/src/easyreflectometry/calculators/calculator_base.py
index 36fb4da9..122e3cbc 100644
--- a/src/easyreflectometry/calculators/calculator_base.py
+++ b/src/easyreflectometry/calculators/calculator_base.py
@@ -54,7 +54,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
r_list = []
t_ = type(model)
if issubclass(t_, Material):
- key = model.uid
+ key = model.unique_name
if key not in self._wrapper.storage['material'].keys():
self._wrapper.create_material(key)
r_list.append(
@@ -66,7 +66,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
elif issubclass(t_, MaterialMixture):
- key = model.uid
+ key = model.unique_name
if key not in self._wrapper.storage['material'].keys():
self._wrapper.create_material(key)
r_list.append(
@@ -78,7 +78,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
elif issubclass(t_, Layer):
- key = model.uid
+ key = model.unique_name
if key not in self._wrapper.storage['layer'].keys():
self._wrapper.create_layer(key)
r_list.append(
@@ -89,9 +89,9 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
self._wrapper.update_layer,
)
)
- self.assign_material_to_layer(model.material.uid, key)
+ self.assign_material_to_layer(model.material.unique_name, key)
elif issubclass(t_, BaseAssembly):
- key = model.uid
+ key = model.unique_name
self._wrapper.create_item(key)
r_list.append(
ItemContainer(
@@ -102,9 +102,9 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
for i in model.layers:
- self.add_layer_to_item(i.uid, model.uid)
+ self.add_layer_to_item(i.unique_name, model.unique_name)
elif issubclass(t_, Model):
- key = model.uid
+ key = model.unique_name
self._wrapper.create_model(key)
r_list.append(
ItemContainer(
@@ -115,7 +115,7 @@ def create(self, model: Material | Layer | Multilayer | Model) -> list[ItemConta
)
)
for i in model.sample:
- self.add_item_to_model(i.uid, key)
+ self.add_item_to_model(i.unique_name, key)
return r_list
def assign_material_to_layer(self, material_id: str, layer_id: str) -> None:
@@ -177,3 +177,16 @@ def sld_profile(self, model_id: str) -> tuple[np.ndarray, np.ndarray]:
def set_resolution_function(self, resolution_function: Callable[[np.array], np.array]) -> None:
return self._wrapper.set_resolution_function(resolution_function)
+
+ @property
+ def include_magnetism(self):
+ return self._wrapper.magnetism
+
+ @include_magnetism.setter
+ def include_magnetism(self, magnetism: bool):
+ """
+ Set the magnetism flag for the calculator
+
+ :param magnetism: True if the calculator should include magnetism
+ """
+ self._wrapper.magnetism = magnetism
diff --git a/src/easyreflectometry/calculators/refl1d/wrapper.py b/src/easyreflectometry/calculators/refl1d/wrapper.py
index bed77817..020801b7 100644
--- a/src/easyreflectometry/calculators/refl1d/wrapper.py
+++ b/src/easyreflectometry/calculators/refl1d/wrapper.py
@@ -3,15 +3,15 @@
from typing import Tuple
import numpy as np
-from easyreflectometry.experiment.resolution_functions import PercentageFhwm
from refl1d import model
from refl1d import names
+from easyreflectometry.experiment.resolution_functions import PercentageFhwm
+
from ..wrapper_base import WrapperBase
RESOLUTION_PADDING = 3.5
OVERSAMPLING_FACTOR = 21
-MAGNETISM = False
ALL_POLARIZATIONS = False
@@ -30,8 +30,8 @@ def create_layer(self, name: str):
:param name: The name of the layer
"""
- if MAGNETISM: # A test with hardcoded magnetism in all layers
- magnetism = names.Magnetism(rhoM=0.2, thetaM=270)
+ if self._magnetism:
+ magnetism = names.Magnetism(rhoM=0.0, thetaM=0.0)
else:
magnetism = None
self.storage['layer'][name] = model.Slab(name=str(name), magnetism=magnetism)
@@ -47,17 +47,27 @@ def create_item(self, name: str):
)
del self.storage['item'][name].stack[0]
- def get_item_value(self, name: str, key: str) -> float:
+ def update_layer(self, name: str, **kwargs):
+ """Update a layer in a given item.
+
+ :param name: The layer name.
+ :param kwargs:
"""
- A function to get a given item value
+ kwargs_no_magnetism = {k: v for k, v in kwargs.items() if k != 'magnetism_rhoM' and k != 'magnetism_thetaM'}
+ super().update_layer(name, **kwargs_no_magnetism)
+ if any(item.startswith('magnetism') for item in kwargs.keys()):
+ magnetism = names.Magnetism(rhoM=kwargs['magnetism_rhoM'], thetaM=kwargs['magnetism_thetaM'])
+ self.storage['layer'][name].magnetism = magnetism
- :param name: The item name
+ def get_layer_value(self, name: str, key: str) -> float:
+ """A function to get a given layer value
+
+ :param name: The layer name
:param key: The given value keys
- :return: The desired value
"""
- item = self.storage['item'][name]
- item = getattr(item, key)
- return getattr(item, 'value')
+ if key in ['magnetism_rhoM', 'magnetism_thetaM']:
+ return getattr(self.storage['layer'][name].magnetism, key.split('_')[-1])
+ return super().get_layer_value(name, key)
def create_model(self, name: str):
"""
@@ -151,7 +161,7 @@ def calculate(self, q_array: np.ndarray, model_name: str) -> np.ndarray:
# Get percentage of Q and change from sigma to FWHM
dq_array = dq_array * q_array / 100 / (2 * np.sqrt(2 * np.log(2)))
- if not MAGNETISM:
+ if not self._magnetism:
probe = _get_probe(
q_array=q_array,
dq_array=dq_array,
@@ -159,6 +169,7 @@ def calculate(self, q_array: np.ndarray, model_name: str) -> np.ndarray:
storage=self.storage,
oversampling_factor=OVERSAMPLING_FACTOR,
)
+ # returns q, reflectivity
_, reflectivity = names.Experiment(probe=probe, sample=sample).reflectivity()
else:
polarized_probe = _get_polarized_probe(
@@ -173,11 +184,14 @@ def calculate(self, q_array: np.ndarray, model_name: str) -> np.ndarray:
if ALL_POLARIZATIONS:
raise NotImplementedError('Polarized reflectivity not yet implemented')
+ # returns q, reflectivity
# _, reflectivity_pp = polarized_reflectivity[0]
# _, reflectivity_pm = polarized_reflectivity[1]
# _, reflectivity_mp = polarized_reflectivity[2]
# _, reflectivity_mm = polarized_reflectivity[3]
else:
+ # Only pick the pp reflectivity
+ # returns q, reflectivity
_, reflectivity = polarized_reflectivity[0]
return reflectivity
@@ -236,7 +250,7 @@ def _get_polarized_probe(
storage: dict,
oversampling_factor: int = 1,
all_polarizations: bool = False,
-) -> names.QProbe:
+) -> names.PolarizedQProbe:
four_probes = []
for i in range(4):
if i == 0 or all_polarizations:
diff --git a/src/easyreflectometry/calculators/refnx/wrapper.py b/src/easyreflectometry/calculators/refnx/wrapper.py
index 8d29b82b..3ab62a9b 100644
--- a/src/easyreflectometry/calculators/refnx/wrapper.py
+++ b/src/easyreflectometry/calculators/refnx/wrapper.py
@@ -3,13 +3,26 @@
from typing import Tuple
import numpy as np
-from easyreflectometry.experiment.resolution_functions import PercentageFhwm
from refnx import reflect
+from easyreflectometry.experiment.resolution_functions import PercentageFhwm
+
from ..wrapper_base import WrapperBase
class RefnxWrapper(WrapperBase):
+ @property
+ def include_magnetism(self) -> bool:
+ return self._magnetism
+
+ @include_magnetism.setter
+ def include_magnetism(self, magnetism: bool) -> None:
+ """Set the magnetism flag.
+
+ :param magnetism: The magnetism flag
+ """
+ raise NotImplementedError('Magnetism is not supported by refnx')
+
def create_material(self, name: str):
"""
Create a material using SLD.
diff --git a/src/easyreflectometry/calculators/wrapper_base.py b/src/easyreflectometry/calculators/wrapper_base.py
index 37cbadd4..8f9440ee 100644
--- a/src/easyreflectometry/calculators/wrapper_base.py
+++ b/src/easyreflectometry/calculators/wrapper_base.py
@@ -9,6 +9,7 @@
class WrapperBase:
def __init__(self):
"""Constructor."""
+ self._magnetism = False
self.storage = {
'material': {},
'layer': {},
@@ -210,3 +211,15 @@ def set_resolution_function(self, resolution_function: ResolutionFunction) -> No
:param resolution_function: The resolution function
"""
self._resolution_function = resolution_function
+
+ @property
+ def magnetism(self) -> bool:
+ return self._magnetism
+
+ @magnetism.setter
+ def magnetism(self, magnetism: bool) -> None:
+ """Set the magnetism flag.
+
+ :param magnetism: The magnetism flag
+ """
+ self._magnetism = magnetism
diff --git a/src/easyreflectometry/experiment/model.py b/src/easyreflectometry/experiment/model.py
index 22d9d0db..681ad2bd 100644
--- a/src/easyreflectometry/experiment/model.py
+++ b/src/easyreflectometry/experiment/model.py
@@ -2,15 +2,16 @@
__author__ = 'github.com/arm61'
+import copy
from numbers import Number
from typing import Union
import numpy as np
-import yaml
+from easyscience.Objects.new_variable import Parameter
from easyscience.Objects.ObjectClasses import BaseObj
-from easyscience.Objects.ObjectClasses import Parameter
from easyreflectometry.parameter_utils import get_as_parameter
+from easyreflectometry.parameter_utils import yaml_dump
from easyreflectometry.sample import BaseAssembly
from easyreflectometry.sample import Layer
from easyreflectometry.sample import LayerCollection
@@ -100,7 +101,7 @@ def add_item(self, *assemblies: list[BaseAssembly]) -> None:
if issubclass(arg.__class__, BaseAssembly):
self.sample.append(arg)
if self.interface is not None:
- self.interface().add_item_to_model(arg.uid, self.uid)
+ self.interface().add_item_to_model(arg.unique_name, self.unique_name)
else:
raise ValueError(f'Object {arg} is not a valid type, must be a child of BaseAssembly.')
@@ -115,8 +116,8 @@ def duplicate_item(self, idx: int) -> None:
duplicate_layers.append(
Layer(
material=i.material,
- thickness=i.thickness.raw_value,
- roughness=i.roughness.raw_value,
+ thickness=i.thickness.value,
+ roughness=i.roughness.value,
name=i.name + ' duplicate',
interface=i.interface,
)
@@ -132,9 +133,10 @@ def remove_item(self, idx: int) -> None:
:param idx: Index of the item to remove.
"""
- if self.interface is not None:
- self.interface().remove_item_from_model(self.sample[idx].uid, self.uid)
+ item_unique_name = self.sample[idx].unique_name
del self.sample[idx]
+ if self.interface is not None:
+ self.interface().remove_item_from_model(item_unique_name, self.unique_name)
@property
def resolution_function(self) -> ResolutionFunction:
@@ -164,11 +166,6 @@ def interface(self, new_interface) -> None:
self.generate_bindings()
self._interface().set_resolution_function(self._resolution_function)
- @property
- def uid(self) -> int:
- """Return a UID from the borg map."""
- return self._borg.map.convert_id_to_key(self)
-
# Representation
@property
def _dict_repr(self) -> dict[str, dict[str, str]]:
@@ -181,8 +178,8 @@ def _dict_repr(self) -> dict[str, dict[str, str]]:
return {
self.name: {
- 'scale': self.scale.raw_value,
- 'background': self.background.raw_value,
+ 'scale': float(self.scale.value),
+ 'background': float(self.background.value),
'resolution': resolution,
'sample': self.sample._dict_repr,
}
@@ -190,7 +187,7 @@ def _dict_repr(self) -> dict[str, dict[str, str]]:
def __repr__(self) -> str:
"""String representation of the layer."""
- return yaml.dump(self._dict_repr, sort_keys=False)
+ return yaml_dump(self._dict_repr)
def as_dict(self, skip: list = None) -> dict:
"""Produces a cleaned dict using a custom as_dict method to skip necessary things.
@@ -200,26 +197,40 @@ def as_dict(self, skip: list = None) -> dict:
"""
if skip is None:
skip = []
+ skip.extend(['sample', 'resolution_function', 'interface'])
this_dict = super().as_dict(skip=skip)
this_dict['sample'] = self.sample.as_dict(skip=skip)
this_dict['resolution_function'] = self.resolution_function.as_dict()
+ if self.interface is None:
+ this_dict['interface'] = None
+ else:
+ this_dict['interface'] = self.interface().name
return this_dict
@classmethod
- def from_dict(cls, this_dict: dict) -> Model:
+ def from_dict(cls, passed_dict: dict) -> Model:
"""
Create a Model from a dictionary.
:param this_dict: dictionary of the Model
:return: Model
"""
+ # Causes circular import if imported at the top
+ from easyreflectometry.calculators import CalculatorFactory
+
+ this_dict = copy.deepcopy(passed_dict)
resolution_function = ResolutionFunction.from_dict(this_dict['resolution_function'])
del this_dict['resolution_function']
- sample = Sample.from_dict(this_dict['sample'])
- del this_dict['sample']
+ interface_name = this_dict['interface']
+ del this_dict['interface']
+ if interface_name is not None:
+ interface = CalculatorFactory()
+ interface.switch(interface_name)
+ else:
+ interface = None
model = super().from_dict(this_dict)
- model.sample = sample
model.resolution_function = resolution_function
+ model.interface = interface
return model
diff --git a/src/easyreflectometry/experiment/model_collection.py b/src/easyreflectometry/experiment/model_collection.py
index 373bb90e..7f8def28 100644
--- a/src/easyreflectometry/experiment/model_collection.py
+++ b/src/easyreflectometry/experiment/model_collection.py
@@ -2,6 +2,7 @@
__author__ = 'github.com/arm61'
+from typing import List
from typing import Optional
from easyreflectometry.sample.base_element_collection import SIZE_DEFAULT_COLLECTION
@@ -19,10 +20,18 @@ def __init__(
*models: Optional[tuple[Model]],
name: str = 'EasyModels',
interface=None,
+ populate_if_none: bool = True,
**kwargs,
):
if not models:
- models = [Model(interface=interface) for _ in range(SIZE_DEFAULT_COLLECTION)]
+ if populate_if_none:
+ models = [Model(interface=interface) for _ in range(SIZE_DEFAULT_COLLECTION)]
+ else:
+ models = []
+ # Needed to ensure an empty list is created when saving and instatiating the object as_dict -> from_dict
+ # Else collisions might occur in global_object.map
+ self.populate_if_none = False
+
super().__init__(name, interface, *models, **kwargs)
self.interface = interface
@@ -42,6 +51,11 @@ def remove_model(self, idx: int):
"""
del self[idx]
+ def as_dict(self, skip: List[str] | None = None) -> dict:
+ this_dict = super().as_dict(skip)
+ this_dict['populate_if_none'] = self.populate_if_none
+ return this_dict
+
@classmethod
def from_dict(cls, this_dict: dict) -> ModelCollection:
"""
@@ -50,11 +64,17 @@ def from_dict(cls, this_dict: dict) -> ModelCollection:
:param data: The dictionary for the collection
:return: An instance of the collection
"""
- collection = super().from_dict(this_dict) # type: ModelCollection
+ collection_dict = this_dict.copy()
+ # We neeed to call from_dict on the base class to get the models
+ dict_data = collection_dict['data']
+ del collection_dict['data']
+
+ collection = super().from_dict(collection_dict) # type: ModelCollection
+
+ for model_data in dict_data:
+ collection.add_model(Model.from_dict(model_data))
if len(collection) != len(this_dict['data']):
raise ValueError(f"Expected {len(collection)} models, got {len(this_dict['data'])}")
- for i, model_data in enumerate(this_dict['data']):
- collection[i] = Model.from_dict(model_data)
return collection
diff --git a/src/easyreflectometry/fitting.py b/src/easyreflectometry/fitting.py
index 13ca1452..92f7794a 100644
--- a/src/easyreflectometry/fitting.py
+++ b/src/easyreflectometry/fitting.py
@@ -2,7 +2,8 @@
import numpy as np
import scipp as sc
-from easyscience.Fitting.Fitting import MultiFitter as easyFitter
+from easyscience.fitting import AvailableMinimizers
+from easyscience.fitting.multi_fitter import MultiFitter as easyFitter
from easyreflectometry.experiment import Model
@@ -16,18 +17,18 @@ def __init__(self, *args: Model):
:param args: Reflectometry model
"""
- # This lets the uid be passed with the fit_func.
- def func_wrapper(func, uid):
+ # This lets the unique_name be passed with the fit_func.
+ def func_wrapper(func, unique_name):
def wrapped(*args, **kwargs):
- return func(*args, uid, **kwargs)
+ return func(*args, unique_name, **kwargs)
return wrapped
- self._fit_func = [func_wrapper(m.interface.fit_func, m.uid) for m in args]
+ self._fit_func = [func_wrapper(m.interface.fit_func, m.unique_name) for m in args]
self._models = args
self.easy_f = easyFitter(args, self._fit_func)
- def fit(self, data: sc.DataGroup, method: str = 'least_squares', id: int = 0) -> sc.DataGroup:
+ def fit(self, data: sc.DataGroup, id: int = 0) -> sc.DataGroup:
"""
Perform the fitting and populate the DataGroups with the result.
@@ -38,14 +39,14 @@ def fit(self, data: sc.DataGroup, method: str = 'least_squares', id: int = 0) ->
x = [data['coords'][f'Qz_{i}'].values for i in refl_nums]
y = [data['data'][f'R_{i}'].values for i in refl_nums]
dy = [1 / np.sqrt(data['data'][f'R_{i}'].variances) for i in refl_nums]
- result = self.easy_f.fit(x, y, weights=dy, method=method)
+ result = self.easy_f.fit(x, y, weights=dy)
new_data = data.copy()
for i, _ in enumerate(result):
id = refl_nums[i]
new_data[f'R_{id}_model'] = sc.array(
dims=[f'Qz_{id}'], values=self._fit_func[i](data['coords'][f'Qz_{id}'].values)
)
- sld_profile = self.easy_f._fit_objects[i].interface.sld_profile(self._models[i].uid)
+ sld_profile = self.easy_f._fit_objects[i].interface.sld_profile(self._models[i].unique_name)
new_data[f'SLD_{id}'] = sc.array(dims=[f'z_{id}'], values=sld_profile[1] * 1e-6, unit=sc.Unit('1/angstrom') ** 2)
new_data['attrs'][f'R_{id}_model'] = {'model': sc.scalar(self._models[i].as_dict())}
new_data['coords'][f'z_{id}'] = sc.array(
@@ -53,6 +54,14 @@ def fit(self, data: sc.DataGroup, method: str = 'least_squares', id: int = 0) ->
)
return new_data
+ def switch_minimizer(self, minimizer: AvailableMinimizers) -> None:
+ """
+ Switch the minimizer for the fitting.
+
+ :param minimizer: Minimizer to be switched to
+ """
+ self.easy_f.switch_minimizer(minimizer)
+
def _flatten_list(this_list: list) -> list:
"""
diff --git a/src/easyreflectometry/parameter_utils.py b/src/easyreflectometry/parameter_utils.py
index 3dceea99..e4e1a821 100644
--- a/src/easyreflectometry/parameter_utils.py
+++ b/src/easyreflectometry/parameter_utils.py
@@ -1,11 +1,19 @@
from copy import deepcopy
from numbers import Number
+from typing import Optional
from typing import Union
-from easyscience.Objects.ObjectClasses import Parameter
+import yaml
+from easyscience import global_object
+from easyscience.Objects.new_variable import Parameter
-def get_as_parameter(name: str, value: Union[Parameter, Number, None], default_dict: dict) -> Parameter:
+def get_as_parameter(
+ name: str,
+ value: Union[Parameter, Number, None],
+ default_dict: dict,
+ unique_name_prefix: Optional[str] = None,
+) -> Parameter:
"""
This function creates a parameter for the variable `name`. A parameter has a value and metadata.
If the value already is a parameter, it is returned.
@@ -16,6 +24,10 @@ def get_as_parameter(name: str, value: Union[Parameter, Number, None], default_d
param name: The name of the parameter
param default_dict: Dictionary with entry for `name` containing the default value and metadata for the parameter
"""
+ # This is a parameter, return it
+ if isinstance(value, Parameter):
+ return value
+
# Ensure we got the dictionary for the parameter with the given name
# Should leave the passed dictionary unchanged
if name not in default_dict:
@@ -23,6 +35,10 @@ def get_as_parameter(name: str, value: Union[Parameter, Number, None], default_d
else:
parameter_dict = deepcopy(default_dict[name])
+ # Add specific unique name prefix if requested
+ if unique_name_prefix is not None:
+ parameter_dict['unique_name'] = global_object.generate_unique_name(unique_name_prefix + 'Parameter')
+
if value is None:
# Create a default parameter using both value and metadata from dictionary
return Parameter(name, **parameter_dict)
@@ -30,6 +46,9 @@ def get_as_parameter(name: str, value: Union[Parameter, Number, None], default_d
# Create a parameter using provided value and metadata from dictionary
del parameter_dict['value']
return Parameter(name, value, **parameter_dict)
- elif not isinstance(value, Parameter):
- raise ValueError(f'{name} must be a Parameter, a number, or None.')
- return value
+
+ raise ValueError(f'{name} must be a Parameter, a number, or None.')
+
+
+def yaml_dump(dict_repr: dict) -> str:
+ return yaml.dump(dict_repr, sort_keys=False, allow_unicode=True)
diff --git a/src/easyreflectometry/sample/assemblies/base_assembly.py b/src/easyreflectometry/sample/assemblies/base_assembly.py
index 1982dc0a..bf408c50 100644
--- a/src/easyreflectometry/sample/assemblies/base_assembly.py
+++ b/src/easyreflectometry/sample/assemblies/base_assembly.py
@@ -1,7 +1,7 @@
from typing import Any
from typing import Optional
-from easyscience.Fitting.Constraints import ObjConstraint
+from easyscience.fitting.Constraints import ObjConstraint
from ..base_core import BaseCore
from ..elements.layers.layer import Layer
@@ -109,7 +109,10 @@ def _enable_thickness_constraints(self):
# Make sure that the thickness parameter is enabled
for i in range(len(self.layers)):
self.layers[i].thickness.enabled = True
- self.front_layer.thickness.value = self.front_layer.thickness.raw_value
+ # Make sure that the thickness constraint is applied
+ for i in range(1, len(self.layers)):
+ self.front_layer.thickness.user_constraints[f'thickness_{i}']()
+
else:
raise Exception('Roughness constraints not setup')
@@ -148,7 +151,9 @@ def _enable_roughness_constraints(self):
# Make sure that the roughness parameter is enabled
for i in range(len(self.layers)):
self.layers[i].roughness.enabled = True
- self.front_layer.roughness.value = self.front_layer.roughness.raw_value
+ # Make sure that the roughness constraint is applied
+ for i in range(1, len(self.layers)):
+ self.front_layer.roughness.user_constraints[f'roughness_{i}']()
else:
raise Exception('Roughness constraints not setup')
diff --git a/src/easyreflectometry/sample/assemblies/gradient_layer.py b/src/easyreflectometry/sample/assemblies/gradient_layer.py
index 61829198..05800a8a 100644
--- a/src/easyreflectometry/sample/assemblies/gradient_layer.py
+++ b/src/easyreflectometry/sample/assemblies/gradient_layer.py
@@ -1,5 +1,6 @@
from typing import Optional
+from easyscience import global_object
from numpy import arange
from ..elements.layers.layer import Layer
@@ -73,7 +74,7 @@ def __init__(
@property
def thickness(self) -> float:
"""Get the thickness of the gradient layer in Angstrom."""
- return self.front_layer.thickness.raw_value * self._discretisation_elements
+ return self.front_layer.thickness.value * self._discretisation_elements
@thickness.setter
def thickness(self, thickness: float) -> None:
@@ -86,7 +87,7 @@ def thickness(self, thickness: float) -> None:
@property
def roughness(self) -> float:
"""Get the Roughness of the gradient layer in Angstrom."""
- return self.front_layer.roughness.raw_value
+ return self.front_layer.roughness.value
@roughness.setter
def roughness(self, roughness: float) -> None:
@@ -100,8 +101,8 @@ def roughness(self, roughness: float) -> None:
def _dict_repr(self) -> dict[str, str]:
"""A simplified dict representation."""
return {
- 'thickness': self.thickness,
- 'discretisation_elements': self._discretisation_elements,
+ 'thickness': float(self.thickness), # Conversion to float is necessary to prevent property reference in dict
+ 'discretisation_elements': int(self._discretisation_elements), # Same as above
'back_layer': self.back_layer._dict_repr,
'front_layer': self.front_layer._dict_repr,
}
@@ -139,13 +140,13 @@ def _prepare_gradient_layers(
interface=None,
) -> LayerCollection:
gradient_sld = _linear_gradient(
- front_value=front_material.sld.raw_value,
- back_value=back_material.sld.raw_value,
+ front_value=front_material.sld.value,
+ back_value=back_material.sld.value,
discretisation_elements=discretisation_elements,
)
gradient_isld = _linear_gradient(
- front_value=front_material.isld.raw_value,
- back_value=back_material.isld.raw_value,
+ front_value=front_material.isld.value,
+ back_value=back_material.isld.value,
discretisation_elements=discretisation_elements,
)
gradient_layers = []
@@ -157,6 +158,7 @@ def _prepare_gradient_layers(
roughness=0.0,
name=str(i),
interface=interface,
+ unique_name=global_object.generate_unique_name('GradientLayer'),
)
gradient_layers.append(layer)
return LayerCollection(gradient_layers)
diff --git a/src/easyreflectometry/sample/assemblies/multilayer.py b/src/easyreflectometry/sample/assemblies/multilayer.py
index 12accaf2..d57d78b3 100644
--- a/src/easyreflectometry/sample/assemblies/multilayer.py
+++ b/src/easyreflectometry/sample/assemblies/multilayer.py
@@ -1,9 +1,11 @@
from __future__ import annotations
+from typing import Optional
from typing import Union
+from easyreflectometry.sample.base_element_collection import SIZE_DEFAULT_COLLECTION
+
from ..elements.layers.layer import Layer
-from ..elements.layers.layer_collection import SIZE_DEFAULT_COLLECTION
from ..elements.layers.layer_collection import LayerCollection
from .base_assembly import BaseAssembly
@@ -25,6 +27,7 @@ def __init__(
name: str = 'EasyMultilayer',
interface=None,
type: str = 'Multi-layer',
+ populate_if_none: Optional[bool] = True,
):
"""Constructor.
@@ -34,11 +37,18 @@ def __init__(
:param type: Type of the constructed instance, defaults to 'Multi-layer'
"""
if layers is None:
- layers = LayerCollection()
+ if populate_if_none:
+ layers = LayerCollection([Layer(interface=interface) for _ in range(SIZE_DEFAULT_COLLECTION)])
+ else:
+ layers = LayerCollection()
elif isinstance(layers, Layer):
layers = LayerCollection(layers, name=layers.name)
elif isinstance(layers, list):
layers = LayerCollection(*layers, name='/'.join([layer.name for layer in layers]))
+ # Needed to ensure an empty list is created when saving and instatiating the object as_dict -> from_dict
+ # Else collisions might occur in global_object.map
+ self.populate_if_none = False
+
super().__init__(name, layers=layers, type=type, interface=interface)
def add_layer(self, *layers: tuple[Layer]) -> None:
@@ -50,7 +60,7 @@ def add_layer(self, *layers: tuple[Layer]) -> None:
if issubclass(arg.__class__, Layer):
self.layers.append(arg)
if self.interface is not None:
- self.interface().add_layer_to_item(arg.uid, self.uid)
+ self.interface().add_layer_to_item(arg.unique_name, self.unique_name)
def duplicate_layer(self, idx: int) -> None:
"""Duplicate a given layer.
@@ -61,8 +71,8 @@ def duplicate_layer(self, idx: int) -> None:
to_duplicate = self.layers[idx]
duplicate_layer = Layer(
material=to_duplicate.material,
- thickness=to_duplicate.thickness.raw_value,
- roughness=to_duplicate.roughness.raw_value,
+ thickness=to_duplicate.thickness.value,
+ roughness=to_duplicate.roughness.value,
name=to_duplicate.name + ' duplicate',
)
self.add_layer(duplicate_layer)
@@ -73,7 +83,7 @@ def remove_layer(self, idx: int) -> None:
:param idx: index of layer to remove
"""
if self.interface is not None:
- self.interface().remove_layer_from_item(self.layers[idx].uid, self.uid)
+ self.interface().remove_layer_from_item(self.layers[idx].unique_name, self.unique_name)
del self.layers[idx]
# Representation
diff --git a/src/easyreflectometry/sample/assemblies/repeating_multilayer.py b/src/easyreflectometry/sample/assemblies/repeating_multilayer.py
index c2965c40..ba26fef6 100644
--- a/src/easyreflectometry/sample/assemblies/repeating_multilayer.py
+++ b/src/easyreflectometry/sample/assemblies/repeating_multilayer.py
@@ -1,7 +1,11 @@
+from typing import Optional
from typing import Union
+from easyscience import global_object
+from easyscience.Objects.new_variable import Parameter
+
from easyreflectometry.parameter_utils import get_as_parameter
-from easyscience.Objects.ObjectClasses import Parameter
+from easyreflectometry.sample.base_element_collection import SIZE_DEFAULT_COLLECTION
from ..elements.layers.layer import Layer
from ..elements.layers.layer_collection import LayerCollection
@@ -37,7 +41,9 @@ def __init__(
layers: Union[LayerCollection, Layer, list[Layer], None] = None,
repetitions: Union[Parameter, int, None] = None,
name: str = 'EasyRepeatingMultilayer',
+ unique_name: Optional[str] = None,
interface=None,
+ populate_if_none: bool = True,
):
"""Constructor.
@@ -46,15 +52,28 @@ def __init__(
:param name: Name for the repeating multi layer, defaults to 'EasyRepeatingMultilayer'.
:param interface: Calculator interface, defaults to `None`.
"""
+ if unique_name is None:
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
if layers is None:
- layers = LayerCollection()
+ if populate_if_none:
+ layers = LayerCollection([Layer(interface=interface) for _ in range(SIZE_DEFAULT_COLLECTION)])
+ else:
+ layers = LayerCollection()
elif isinstance(layers, Layer):
layers = LayerCollection(layers, name=layers.name)
elif isinstance(layers, list):
layers = LayerCollection(*layers, name='/'.join([layer.name for layer in layers]))
+ # Needed to ensure an empty list is created when saving and instatiating the object as_dict -> from_dict
+ # Else collisions might occur in global_object.map
+ self.populate_if_none = False
- repetitions = get_as_parameter('repetitions', repetitions, DEFAULTS)
+ repetitions = get_as_parameter(
+ name='repetitions',
+ value=repetitions,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Repetitions',
+ )
super().__init__(
layers=layers,
@@ -70,5 +89,5 @@ def __init__(
def _dict_repr(self) -> dict:
"""A simplified dict representation."""
d_dict = {self.name: self.layers._dict_repr}
- d_dict[self.name]['repetitions'] = self.repetitions.raw_value
+ d_dict[self.name]['repetitions'] = float(self.repetitions.value)
return d_dict
diff --git a/src/easyreflectometry/sample/assemblies/surfactant_layer.py b/src/easyreflectometry/sample/assemblies/surfactant_layer.py
index e675f6fb..56a7cb0c 100644
--- a/src/easyreflectometry/sample/assemblies/surfactant_layer.py
+++ b/src/easyreflectometry/sample/assemblies/surfactant_layer.py
@@ -2,8 +2,8 @@
from typing import Optional
-from easyscience.Fitting.Constraints import ObjConstraint
-from easyscience.Objects.ObjectClasses import Parameter
+from easyscience.fitting.Constraints import ObjConstraint
+from easyscience.Objects.new_variable import Parameter
from ..elements.layers.layer_area_per_molecule import LayerAreaPerMolecule
from ..elements.layers.layer_collection import LayerCollection
@@ -117,10 +117,12 @@ def constrain_area_per_molecule(self, status: bool):
"""Set the status for the area per molecule constraint such that the head and tail layers have the
same area per molecule.
- :param x: Boolean description the wanted of the constraint.
+ :param status: Boolean description the wanted of the constraint.
"""
self.tail_layer._area_per_molecule.user_constraints['area_per_molecule'].enabled = status
- self.tail_layer._area_per_molecule.value = self.tail_layer._area_per_molecule.raw_value
+ if status:
+ # Apply the constraint by running it
+ self.tail_layer._area_per_molecule.user_constraints['area_per_molecule']()
@property
def conformal_roughness(self) -> bool:
@@ -129,10 +131,12 @@ def conformal_roughness(self) -> bool:
@conformal_roughness.setter
def conformal_roughness(self, status: bool):
- """Set the status for the roughness to be the same for both layers."""
+ """Set the status for the roughness to be the same for both layers.
+
+ :param status: Boolean description the wanted of the constraint.
+ """
if status:
self._enable_roughness_constraints()
- self.tail_layer.roughness.value = self.tail_layer.roughness.raw_value
else:
self._disable_roughness_constraints()
diff --git a/src/easyreflectometry/sample/base_core.py b/src/easyreflectometry/sample/base_core.py
index 4779c51f..c17c3722 100644
--- a/src/easyreflectometry/sample/base_core.py
+++ b/src/easyreflectometry/sample/base_core.py
@@ -1,8 +1,9 @@
from abc import abstractmethod
-import yaml
from easyscience.Objects.ObjectClasses import BaseObj
+from easyreflectometry.parameter_utils import yaml_dump
+
class BaseCore(BaseObj):
def __init__(
@@ -19,13 +20,6 @@ def __init__(
@abstractmethod
def _dict_repr(self) -> dict[str, str]: ...
- @property
- def uid(self) -> int:
- """
- :return: UID from the borg map
- """
- return self._borg.map.convert_id_to_key(self)
-
def __repr__(self) -> str:
"""
String representation of the layer.
@@ -33,7 +27,7 @@ def __repr__(self) -> str:
:return: a string representation of the layer
:rtype: str
"""
- return yaml.dump(self._dict_repr, sort_keys=False)
+ return yaml_dump(self._dict_repr)
# For classes with special serialization needs one must adopt the dict produced by super
# def as_dict(self, skip: list = None) -> dict:
diff --git a/src/easyreflectometry/sample/base_element_collection.py b/src/easyreflectometry/sample/base_element_collection.py
index d59cc9cc..ab839920 100644
--- a/src/easyreflectometry/sample/base_element_collection.py
+++ b/src/easyreflectometry/sample/base_element_collection.py
@@ -1,10 +1,10 @@
-from typing import Any
from typing import List
from typing import Optional
-import yaml
from easyscience.Objects.Groups import BaseCollection
+from easyreflectometry.parameter_utils import yaml_dump
+
SIZE_DEFAULT_COLLECTION = 2
@@ -19,13 +19,6 @@ def __init__(
super().__init__(name, *args, **kwargs)
self.interface = interface
- @property
- def uid(self) -> int:
- """
- :return: UID from the borg map
- """
- return self._borg.map.convert_id_to_key(self)
-
@property
def names(self) -> list:
"""
@@ -39,7 +32,7 @@ def __repr__(self) -> str:
:return: a string representation of the collection
"""
- return yaml.dump(self._dict_repr, sort_keys=False)
+ return yaml_dump(self._dict_repr)
@property
def _dict_repr(self) -> dict:
@@ -61,17 +54,3 @@ def as_dict(self, skip: Optional[List[str]] = None) -> dict:
for collection_element in self:
this_dict['data'].append(collection_element.as_dict(skip=skip))
return this_dict
-
- @classmethod
- def from_dict(cls, data: dict) -> Any:
- """
- Create an instance of a collection from a dictionary.
-
- :param data: The dictionary for the collection
- :return: An instance of the collection
- """
- collection = super().from_dict(data)
- # Remove the default elements
- for i in range(SIZE_DEFAULT_COLLECTION):
- del collection[0]
- return collection
diff --git a/src/easyreflectometry/sample/elements/layers/layer.py b/src/easyreflectometry/sample/elements/layers/layer.py
index 9d837dd8..08a75c54 100644
--- a/src/easyreflectometry/sample/elements/layers/layer.py
+++ b/src/easyreflectometry/sample/elements/layers/layer.py
@@ -1,9 +1,12 @@
__author__ = 'github.com/arm61'
+from typing import Optional
from typing import Union
import numpy as np
+from easyscience import global_object
+from easyscience.Objects.new_variable import Parameter
+
from easyreflectometry.parameter_utils import get_as_parameter
-from easyscience.Objects.ObjectClasses import Parameter
from ...base_core import BaseCore
from ..materials.material import Material
@@ -13,7 +16,7 @@
'description': 'The thickness of the layer in angstroms',
'url': 'https://github.com/reflectivity/edu_outreach/blob/master/refl_maths/paper.tex',
'value': 10.0,
- 'units': 'angstrom',
+ 'unit': 'angstrom',
'min': 0.0,
'max': np.Inf,
'fixed': True,
@@ -22,7 +25,7 @@
'description': 'The interfacial roughness, Nevot-Croce, for the layer in angstroms.',
'url': 'https://doi.org/10.1051/rphysap:01980001503076100',
'value': 3.3,
- 'units': 'angstrom',
+ 'unit': 'angstrom',
'min': 0.0,
'max': np.Inf,
'fixed': True,
@@ -45,6 +48,7 @@ def __init__(
thickness: Union[Parameter, float, None] = None,
roughness: Union[Parameter, float, None] = None,
name: str = 'EasyLayer',
+ unique_name: Optional[str] = None,
interface=None,
):
"""Constructor.
@@ -58,8 +62,21 @@ def __init__(
if material is None:
material = Material(interface=interface)
- thickness = get_as_parameter('thickness', thickness, DEFAULTS)
- roughness = get_as_parameter('roughness', roughness, DEFAULTS)
+ if unique_name is None:
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
+
+ thickness = get_as_parameter(
+ name='thickness',
+ value=thickness,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Thickness',
+ )
+ roughness = get_as_parameter(
+ name='roughness',
+ value=roughness,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Roughness',
+ )
super().__init__(
name=name,
@@ -67,6 +84,7 @@ def __init__(
material=material,
thickness=thickness,
roughness=roughness,
+ unique_name=unique_name,
)
def assign_material(self, material: Material) -> None:
@@ -76,7 +94,7 @@ def assign_material(self, material: Material) -> None:
"""
self.material = material
if self.interface is not None:
- self.interface().assign_material_to_layer(self.material.uid, self.uid)
+ self.interface().assign_material_to_layer(self.material.unique_name, self.unique_name)
# Representation
@property
@@ -85,7 +103,7 @@ def _dict_repr(self) -> dict[str, str]:
return {
self.name: {
'material': self.material._dict_repr,
- 'thickness': f'{self.thickness.raw_value:.3f} {self.thickness.unit}',
- 'roughness': f'{self.roughness.raw_value:.3f} {self.roughness.unit}',
+ 'thickness': f'{self.thickness.value:.3f} {self.thickness.unit}',
+ 'roughness': f'{self.roughness.value:.3f} {self.roughness.unit}',
}
}
diff --git a/src/easyreflectometry/sample/elements/layers/layer_area_per_molecule.py b/src/easyreflectometry/sample/elements/layers/layer_area_per_molecule.py
index f9e5a0bd..230c4709 100644
--- a/src/easyreflectometry/sample/elements/layers/layer_area_per_molecule.py
+++ b/src/easyreflectometry/sample/elements/layers/layer_area_per_molecule.py
@@ -1,11 +1,14 @@
+from typing import Optional
from typing import Union
import numpy as np
+from easyscience import global_object
+from easyscience.fitting.Constraints import FunctionalConstraint
+from easyscience.Objects.new_variable import Parameter
+
from easyreflectometry.parameter_utils import get_as_parameter
from easyreflectometry.special.calculations import area_per_molecule_to_scattering_length_density
from easyreflectometry.special.calculations import neutron_scattering_length
-from easyscience.Fitting.Constraints import FunctionalConstraint
-from easyscience.Objects.ObjectClasses import Parameter
from ..materials.material import Material
from ..materials.material_solvated import DEFAULTS as MATERIAL_SOLVATED_DEFAULTS
@@ -18,7 +21,7 @@
'area_per_molecule': {
'description': 'Surface coverage',
'value': 48.2,
- 'units': 'angstrom ** 2',
+ 'unit': 'angstrom^2',
'min': 0,
'max': np.inf,
'fixed': True,
@@ -27,7 +30,7 @@
'description': 'The real scattering length for a molecule formula in angstrom.',
'url': 'https://www.ncnr.nist.gov/resources/activation/',
'value': 4.186,
- 'units': 'angstrom',
+ 'unit': 'angstrom',
'min': -np.Inf,
'max': np.Inf,
'fixed': True,
@@ -36,7 +39,7 @@
'description': 'The real scattering length for a molecule formula in angstrom.',
'url': 'https://www.ncnr.nist.gov/resources/activation/',
'value': 0.0,
- 'units': 'angstrom',
+ 'unit': 'angstrom',
'min': -np.Inf,
'max': np.Inf,
'fixed': True,
@@ -72,6 +75,7 @@ def __init__(
area_per_molecule: Union[Parameter, float, None] = None,
roughness: Union[Parameter, float, None] = None,
name: str = 'EasyLayerAreaPerMolecule',
+ unique_name: Optional[str] = None,
interface=None,
):
"""Constructor.
@@ -88,19 +92,48 @@ def __init__(
if solvent is None:
solvent = Material(6.36, 0, 'D2O', interface=interface)
+ if unique_name is None:
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
+
# Create the solvated molecule and corresponding constraints
if molecular_formula is None:
molecular_formula = DEFAULTS['molecular_formula']
- molecule = Material(sld=0.0, isld=0.0, name=molecular_formula, interface=interface)
+ molecule_material = Material(
+ sld=0.0,
+ isld=0.0,
+ name=molecular_formula,
+ interface=interface,
+ unique_name=unique_name + 'Material',
+ )
- thickness = get_as_parameter('thickness', thickness, DEFAULTS)
- _area_per_molecule = get_as_parameter('area_per_molecule', area_per_molecule, DEFAULTS)
- _scattering_length_real = get_as_parameter('scattering_length_real', 0.0, DEFAULTS['sl'])
- _scattering_length_imag = get_as_parameter('scattering_length_imag', 0.0, DEFAULTS['isl'])
+ thickness = get_as_parameter(
+ name='thickness',
+ value=thickness,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Thickness',
+ )
+ _area_per_molecule = get_as_parameter(
+ name='area_per_molecule',
+ value=area_per_molecule,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_AreaPerMolecule',
+ )
+ _scattering_length_real = get_as_parameter(
+ name='scattering_length_real',
+ value=0.0,
+ default_dict=DEFAULTS['sl'],
+ unique_name_prefix=f'{unique_name}_Sl',
+ )
+ _scattering_length_imag = get_as_parameter(
+ name='scattering_length_imag',
+ value=0.0,
+ default_dict=DEFAULTS['isl'],
+ unique_name_prefix=f'{unique_name}_Isl',
+ )
# Constrain the real part of the sld value for the molecule
constraint_sld_real = FunctionalConstraint(
- dependent_obj=molecule.sld,
+ dependent_obj=molecule_material.sld,
func=area_per_molecule_to_scattering_length_density,
independent_objs=[_scattering_length_real, thickness, _area_per_molecule],
)
@@ -110,7 +143,7 @@ def __init__(
# Constrain the imaginary part of the sld value for the molecule
constraint_sld_imag = FunctionalConstraint(
- dependent_obj=molecule.isld,
+ dependent_obj=molecule_material.isld,
func=area_per_molecule_to_scattering_length_density,
independent_objs=[_scattering_length_imag, thickness, _area_per_molecule],
)
@@ -118,14 +151,15 @@ def __init__(
_area_per_molecule.user_constraints['iarea_per_molecule'] = constraint_sld_imag
_scattering_length_imag.user_constraints['iarea_per_molecule'] = constraint_sld_imag
- solvated_molecule = MaterialSolvated(
- material=molecule,
+ solvated_molecule_material = MaterialSolvated(
+ material=molecule_material,
solvent=solvent,
solvent_fraction=solvent_fraction,
interface=interface,
+ unique_name=unique_name + 'MaterialSolvated',
)
super().__init__(
- material=solvated_molecule,
+ material=solvated_molecule_material,
thickness=thickness,
roughness=roughness,
name=name,
@@ -149,7 +183,7 @@ def area_per_molecule_parameter(self) -> Parameter:
@property
def area_per_molecule(self) -> float:
"""Get the area per molecule."""
- return self._area_per_molecule.raw_value
+ return self._area_per_molecule.value
@area_per_molecule.setter
def area_per_molecule(self, new_area_per_molecule: float) -> None:
@@ -236,6 +270,8 @@ def as_dict(self, skip: list = None) -> dict[str, str]:
"""
this_dict = super().as_dict(skip=skip)
this_dict['solvent_fraction'] = self.material._fraction.as_dict()
+ this_dict['area_per_molecule'] = self._area_per_molecule.as_dict()
+ this_dict['solvent'] = self.solvent.as_dict()
del this_dict['material']
del this_dict['_scattering_length_real']
del this_dict['_scattering_length_imag']
diff --git a/src/easyreflectometry/sample/elements/layers/layer_collection.py b/src/easyreflectometry/sample/elements/layers/layer_collection.py
index 69490d24..69c481fb 100644
--- a/src/easyreflectometry/sample/elements/layers/layer_collection.py
+++ b/src/easyreflectometry/sample/elements/layers/layer_collection.py
@@ -2,7 +2,6 @@
from typing import Optional
-from ...base_element_collection import SIZE_DEFAULT_COLLECTION
from ...base_element_collection import BaseElementCollection
from .layer import Layer
@@ -14,11 +13,11 @@ class LayerCollection(BaseElementCollection):
def __init__(
self,
*layers: Optional[list[Layer]],
- name: str = 'EasyLayers',
+ name: str = 'EasyLayerCollection',
interface=None,
**kwargs,
):
if not layers:
- layers = [Layer(interface=interface) for _ in range(SIZE_DEFAULT_COLLECTION)]
+ layers = []
super().__init__(name, interface, *layers, **kwargs)
diff --git a/src/easyreflectometry/sample/elements/materials/material.py b/src/easyreflectometry/sample/elements/materials/material.py
index 219a06bc..1485abaa 100644
--- a/src/easyreflectometry/sample/elements/materials/material.py
+++ b/src/easyreflectometry/sample/elements/materials/material.py
@@ -1,10 +1,13 @@
__author__ = 'github.com/arm61'
+from typing import Optional
from typing import Union
import numpy as np
+from easyscience import global_object
+from easyscience.Objects.new_variable import Parameter
+
from easyreflectometry.parameter_utils import get_as_parameter
-from easyscience.Objects.ObjectClasses import Parameter
from ...base_core import BaseCore
@@ -13,7 +16,7 @@
'description': 'The real scattering length density for a material in e-6 per squared angstrom.',
'url': 'https://www.ncnr.nist.gov/resources/activation/',
'value': 4.186,
- 'units': '1 / angstrom ** 2',
+ 'unit': '1 / angstrom^2',
'min': -np.Inf,
'max': np.Inf,
'fixed': True,
@@ -22,7 +25,7 @@
'description': 'The imaginary scattering length density for a material in e-6 per squared angstrom.',
'url': 'https://www.ncnr.nist.gov/resources/activation/',
'value': 0.0,
- 'units': '1 / angstrom ** 2',
+ 'unit': '1 / angstrom^2',
'min': -np.Inf,
'max': np.Inf,
'fixed': True,
@@ -40,6 +43,7 @@ def __init__(
sld: Union[Parameter, float, None] = None,
isld: Union[Parameter, float, None] = None,
name: str = 'EasyMaterial',
+ unique_name: Optional[str] = None,
interface=None,
):
"""Constructor.
@@ -49,8 +53,21 @@ def __init__(
:param name: Name of the material, defaults to 'EasyMaterial'.
:param interface: Calculator interface, defaults to `None`.
"""
- sld = get_as_parameter('sld', sld, DEFAULTS)
- isld = get_as_parameter('isld', isld, DEFAULTS)
+ if unique_name is None:
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
+
+ sld = get_as_parameter(
+ name='sld',
+ value=sld,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Sld',
+ )
+ isld = get_as_parameter(
+ name='isld',
+ value=isld,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Isld',
+ )
super().__init__(name=name, sld=sld, isld=isld, interface=interface)
@@ -60,7 +77,7 @@ def _dict_repr(self) -> dict[str, str]:
"""A simplified dict representation."""
return {
self.name: {
- 'sld': f'{self.sld.raw_value:.3f}e-6 {self.sld.unit}',
- 'isld': f'{self.isld.raw_value:.3f}e-6 {self.isld.unit}',
+ 'sld': f'{self.sld.value:.3f}e-6 {self.sld.unit}',
+ 'isld': f'{self.isld.value:.3f}e-6 {self.isld.unit}',
}
}
diff --git a/src/easyreflectometry/sample/elements/materials/material_density.py b/src/easyreflectometry/sample/elements/materials/material_density.py
index bba2ec3b..fee6168a 100644
--- a/src/easyreflectometry/sample/elements/materials/material_density.py
+++ b/src/easyreflectometry/sample/elements/materials/material_density.py
@@ -1,41 +1,26 @@
+from typing import Optional
from typing import Union
import numpy as np
+from easyscience import global_object
+from easyscience.fitting.Constraints import FunctionalConstraint
+from easyscience.Objects.new_variable import Parameter
+
from easyreflectometry.parameter_utils import get_as_parameter
from easyreflectometry.special.calculations import density_to_sld
from easyreflectometry.special.calculations import molecular_weight
from easyreflectometry.special.calculations import neutron_scattering_length
-from easyscience.Fitting.Constraints import FunctionalConstraint
-from easyscience.Objects.ObjectClasses import Parameter
from .material import DEFAULTS as MATERIAL_DEFAULTS
from .material import Material
DEFAULTS = {
'chemical_structure': 'Si',
- 'sl': {
- 'description': 'The real scattering length for a chemical formula in angstrom.',
- 'url': 'https://www.ncnr.nist.gov/resources/activation/',
- 'value': 4.1491,
- 'units': 'angstrom',
- 'min': -np.Inf,
- 'max': np.Inf,
- 'fixed': True,
- },
- 'isl': {
- 'description': 'The real scattering length for a chemical formula in angstrom.',
- 'url': 'https://www.ncnr.nist.gov/resources/activation/',
- 'value': 0.0,
- 'units': 'angstrom',
- 'min': -np.Inf,
- 'max': np.Inf,
- 'fixed': True,
- },
'density': {
'description': 'The mass density of the material.',
'url': 'https://en.wikipedia.org/wiki/Density',
'value': 2.33,
- 'units': 'gram / centimeter ** 3',
+ 'unit': 'gram / centimeter ** 3',
'min': 0,
'max': np.Inf,
'fixed': True,
@@ -44,7 +29,7 @@
'description': 'The molecular weight of a material.',
'url': 'https://en.wikipedia.org/wiki/Molecular_mass',
'value': 28.02,
- 'units': 'g / mole',
+ 'unit': 'g / mole',
'min': -np.Inf,
'max': np.Inf,
'fixed': True,
@@ -65,6 +50,7 @@ def __init__(
chemical_structure: Union[str, None] = None,
density: Union[Parameter, float, None] = None,
name: str = 'EasyMaterialDensity',
+ unique_name: Optional[str] = None,
interface=None,
):
"""Constructor.
@@ -74,26 +60,50 @@ def __init__(
:param name: Identifier, defaults to `EasyMaterialDensity`.
:param interface: Interface object, defaults to `None`.
"""
+ if unique_name is None:
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
+
if chemical_structure is None:
chemical_structure = DEFAULTS['chemical_structure']
- density = get_as_parameter('density', density, DEFAULTS)
+ density = get_as_parameter(
+ name='density',
+ value=density,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Density',
+ )
scattering_length = neutron_scattering_length(chemical_structure)
- mw = get_as_parameter('molecular_weight', molecular_weight(chemical_structure), DEFAULTS)
+ mw = get_as_parameter(
+ name='molecular_weight',
+ value=molecular_weight(chemical_structure),
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Mw',
+ )
scattering_length_real = get_as_parameter(
name='scattering_length_real',
value=scattering_length.real,
default_dict=DEFAULTS['sld'],
+ unique_name_prefix=f'{unique_name}_ScatteringLengthReal',
+ )
+ scattering_length_imag = get_as_parameter(
+ name='scattering_length_imag',
+ value=scattering_length.imag,
+ default_dict=DEFAULTS['isld'],
+ unique_name_prefix=f'{unique_name}_ScatteringLengthImag',
)
- scattering_length_imag = get_as_parameter('scattering_length_imag', scattering_length.imag, DEFAULTS['isld'])
-
sld = get_as_parameter(
- 'sld', density_to_sld(scattering_length_real.raw_value, mw.raw_value, density.raw_value), DEFAULTS
+ name='sld',
+ value=density_to_sld(scattering_length_real.value, mw.value, density.value),
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Sld',
)
isld = get_as_parameter(
- 'isld', density_to_sld(scattering_length_imag.raw_value, mw.raw_value, density.raw_value), DEFAULTS
+ name='isld',
+ value=density_to_sld(scattering_length_imag.value, mw.value, density.value),
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Isld',
)
constraint = FunctionalConstraint(sld, density_to_sld, [scattering_length_real, mw, density])
@@ -135,7 +145,7 @@ def _dict_repr(self) -> dict[str, str]:
"""Dictionary representation of the instance."""
mat_dict = super()._dict_repr
mat_dict['chemical_structure'] = self._chemical_structure
- mat_dict['density'] = f'{self.density.raw_value:.2e} {self.density.unit}'
+ mat_dict['density'] = f'{self.density.value:.2e} {self.density.unit}'
return mat_dict
def as_dict(self, skip: list = []) -> dict[str, str]:
diff --git a/src/easyreflectometry/sample/elements/materials/material_mixture.py b/src/easyreflectometry/sample/elements/materials/material_mixture.py
index 2a3e0beb..487b64e3 100644
--- a/src/easyreflectometry/sample/elements/materials/material_mixture.py
+++ b/src/easyreflectometry/sample/elements/materials/material_mixture.py
@@ -1,9 +1,12 @@
+from typing import Optional
from typing import Union
+from easyscience import global_object
+from easyscience.fitting.Constraints import FunctionalConstraint
+from easyscience.Objects.new_variable import Parameter
+
from easyreflectometry.parameter_utils import get_as_parameter
from easyreflectometry.special.calculations import weighted_average
-from easyscience.Fitting.Constraints import FunctionalConstraint
-from easyscience.Objects.ObjectClasses import Parameter
from ...base_core import BaseCore
from .material import DEFAULTS as MATERIAL_DEFAULTS
@@ -13,7 +16,7 @@
'fraction': {
'description': 'The fraction of material b in material a',
'value': 0.5,
- 'units': 'dimensionless',
+ 'unit': 'dimensionless',
'min': 0,
'max': 1,
'fixed': True,
@@ -34,6 +37,7 @@ def __init__(
material_b: Union[Material, None] = None,
fraction: Union[Parameter, float, None] = None,
name: Union[str, None] = None,
+ unique_name: Optional[str] = None,
interface=None,
):
"""Constructor.
@@ -44,26 +48,44 @@ def __init__(
:param name: Name of the material, defaults to None that causes the name to be constructed.
:param interface: Calculator interface, defaults to `None`.
"""
+ if unique_name is None:
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
+
if material_a is None:
material_a = Material(interface=interface)
if material_b is None:
material_b = Material(interface=interface)
- fraction = get_as_parameter('fraction', fraction, DEFAULTS)
+ fraction = get_as_parameter(
+ name='fraction',
+ value=fraction,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Fraction',
+ )
sld = weighted_average(
- a=material_a.sld.raw_value,
- b=material_b.sld.raw_value,
- p=fraction.raw_value,
+ a=material_a.sld.value,
+ b=material_b.sld.value,
+ p=fraction.value,
)
isld = weighted_average(
- a=material_a.isld.raw_value,
- b=material_b.isld.raw_value,
- p=fraction.raw_value,
+ a=material_a.isld.value,
+ b=material_b.isld.value,
+ p=fraction.value,
)
- self._sld = get_as_parameter('sld', sld, DEFAULTS)
- self._isld = get_as_parameter('isld', isld, DEFAULTS)
+ self._sld = get_as_parameter(
+ name='sld',
+ value=sld,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Sld',
+ )
+ self._isld = get_as_parameter(
+ name='isld',
+ value=isld,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Isld',
+ )
# To avoid problems when setting the interface
# self._sld and self._isld need to be declared before calling the super constructor
@@ -85,11 +107,11 @@ def _get_linkable_attributes(self):
@property
def sld(self) -> float:
- return self._sld.raw_value
+ return self._sld.value
@property
def isld(self) -> float:
- return self._isld.raw_value
+ return self._isld.value
def _materials_constraints(self):
self._sld.enabled = True
@@ -116,7 +138,7 @@ def _materials_constraints(self):
@property
def fraction(self) -> float:
"""Get the fraction of material_b."""
- return self._fraction.raw_value
+ return self._fraction.value
@fraction.setter
def fraction(self, fraction: float) -> None:
@@ -126,7 +148,7 @@ def fraction(self, fraction: float) -> None:
"""
if not isinstance(fraction, float):
raise ValueError('fraction must be a float')
- self._fraction.raw_value = fraction
+ self._fraction.value = fraction
@property
def material_a(self) -> Material:
@@ -171,9 +193,9 @@ def _dict_repr(self) -> dict[str, str]:
"""A simplified dict representation."""
return {
self.name: {
- 'fraction': f'{self._fraction.raw_value:.3f} {self._fraction.unit}',
- 'sld': f'{self._sld.raw_value:.3f}e-6 {self._sld.unit}',
- 'isld': f'{self._isld.raw_value:.3f}e-6 {self._isld.unit}',
+ 'fraction': f'{self._fraction.value:.3f} {self._fraction.unit}',
+ 'sld': f'{self._sld.value:.3f}e-6 {self._sld.unit}',
+ 'isld': f'{self._isld.value:.3f}e-6 {self._isld.unit}',
'material_a': self._material_a._dict_repr,
'material_b': self._material_b._dict_repr,
}
diff --git a/src/easyreflectometry/sample/elements/materials/material_solvated.py b/src/easyreflectometry/sample/elements/materials/material_solvated.py
index 05ff7780..bef267ed 100644
--- a/src/easyreflectometry/sample/elements/materials/material_solvated.py
+++ b/src/easyreflectometry/sample/elements/materials/material_solvated.py
@@ -1,7 +1,10 @@
+from typing import Optional
from typing import Union
+from easyscience import global_object
+from easyscience.Objects.new_variable import Parameter
+
from easyreflectometry.parameter_utils import get_as_parameter
-from easyscience.Objects.ObjectClasses import Parameter
from .material import Material
from .material_mixture import MaterialMixture
@@ -10,7 +13,7 @@
'solvent_fraction': {
'description': 'Fraction of solvent in layer.',
'value': 0.2,
- 'units': 'dimensionless',
+ 'unit': 'dimensionless',
'min': 0,
'max': 1,
'fixed': True,
@@ -25,6 +28,7 @@ def __init__(
solvent: Union[Material, None] = None,
solvent_fraction: Union[Parameter, float, None] = None,
name=None,
+ unique_name: Optional[str] = None,
interface=None,
):
"""Constructor.
@@ -35,12 +39,20 @@ def __init__(
:param name: Name of the material, defaults to None that causes the name to be constructed.
:param interface: Calculator interface, defaults to `None`.
"""
+ if unique_name is None:
+ unique_name = global_object.generate_unique_name(self.__class__.__name__)
+
if material is None:
material = Material(sld=6.36, isld=0, name='D2O', interface=interface)
if solvent is None:
solvent = Material(sld=-0.561, isld=0, name='H2O', interface=interface)
- solvent_fraction = get_as_parameter('solvent_fraction', solvent_fraction, DEFAULTS)
+ solvent_fraction = get_as_parameter(
+ name='solvent_fraction',
+ value=solvent_fraction,
+ default_dict=DEFAULTS,
+ unique_name_prefix=f'{unique_name}_Fraction',
+ )
# In super class, the fraction is the fraction of material b in material a
super().__init__(
@@ -118,9 +130,9 @@ def _dict_repr(self) -> dict[str, str]:
"""A simplified dict representation."""
return {
self.name: {
- 'solvent_fraction': f'{self._fraction.raw_value:.3f} {self._fraction.unit}',
- 'sld': f'{self._sld.raw_value:.3f}e-6 {self._sld.unit}',
- 'isld': f'{self._isld.raw_value:.3f}e-6 {self._isld.unit}',
+ 'solvent_fraction': f'{self._fraction.value:.3f} {self._fraction.unit}',
+ 'sld': f'{self._sld.value:.3f}e-6 {self._sld.unit}',
+ 'isld': f'{self._isld.value:.3f}e-6 {self._isld.unit}',
'material': self.material._dict_repr,
'solvent': self.solvent._dict_repr,
}
diff --git a/src/easyreflectometry/sample/sample.py b/src/easyreflectometry/sample/sample.py
index 7dec0c94..a613b7d1 100644
--- a/src/easyreflectometry/sample/sample.py
+++ b/src/easyreflectometry/sample/sample.py
@@ -4,9 +4,10 @@
from typing import Union
-import yaml
from easyscience.Objects.Groups import BaseCollection
+from easyreflectometry.parameter_utils import yaml_dump
+
from .assemblies.base_assembly import BaseAssembly
from .assemblies.multilayer import Multilayer
from .elements.layers.layer import Layer
@@ -22,6 +23,7 @@ def __init__(
*list_layer_like: list[Union[Layer, BaseAssembly]],
name: str = 'EasySample',
interface=None,
+ populate_if_none: bool = True,
**kwargs,
):
"""Constructor.
@@ -32,7 +34,13 @@ def __init__(
"""
new_items = []
if not list_layer_like:
- list_layer_like = [Multilayer(interface=interface) for _ in range(NR_DEFAULT_LAYERS)]
+ if populate_if_none:
+ list_layer_like = [Multilayer(interface=interface) for _ in range(NR_DEFAULT_LAYERS)]
+ else:
+ list_layer_like = []
+ # Needed to ensure an empty list is created when saving and instatiating the object as_dict -> from_dict
+ # Else collisions might occur in global_object.map
+ self.populate_if_none = False
for layer_like in list_layer_like:
if issubclass(type(layer_like), Layer):
@@ -44,11 +52,6 @@ def __init__(
super().__init__(name, *new_items, **kwargs)
self.interface = interface
- @property
- def uid(self) -> int:
- """The UID from the borg map."""
- return self._borg.map.convert_id_to_key(self)
-
# Representation
@property
def _dict_repr(self) -> dict:
@@ -57,7 +60,7 @@ def _dict_repr(self) -> dict:
def __repr__(self) -> str:
"""String representation of the sample."""
- return yaml.dump(self._dict_repr, sort_keys=False)
+ return yaml_dump(self._dict_repr)
def as_dict(self, skip: list = None) -> dict:
"""Produces a cleaned dict using a custom as_dict method to skip necessary things.
@@ -70,25 +73,5 @@ def as_dict(self, skip: list = None) -> dict:
this_dict = super().as_dict(skip=skip)
for i, layer in enumerate(self.data):
this_dict['data'][i] = layer.as_dict(skip=skip)
+ this_dict['populate_if_none'] = self.populate_if_none
return this_dict
-
- @classmethod
- def from_dict(cls, data: dict) -> Sample:
- """
- Create a Sample from a dictionary.
-
- :param data: dictionary of the Sample
- :return: Sample
- """
- sample = super().from_dict(data)
-
- # Remove the default multilayers
- for i in range(NR_DEFAULT_LAYERS):
- sample.__delitem__(0)
-
- # Ensure that the data is also converted
- # TODO Should probably be handled in easyscience
- for i in range(len(sample.data)):
- sample[i] = sample[i].__class__.from_dict(data['data'][i])
-
- return sample
diff --git a/src/easyreflectometry/special/calculations.py b/src/easyreflectometry/special/calculations.py
index 18ad2119..f7ea9068 100644
--- a/src/easyreflectometry/special/calculations.py
+++ b/src/easyreflectometry/special/calculations.py
@@ -1,6 +1,7 @@
__author__ = 'github.com/arm61'
import periodictable as pt
+
from easyreflectometry.special.parsing import parse_formula
@@ -59,8 +60,8 @@ def area_per_molecule_to_scattering_length_density(
:param scattering_length: Scattering length of component, in angstrom.
:param thickness: Thickness of component, in angstrom.
- :param area_per_molecule: Area per molecule, in angstrom ** 2.
- :return: Scattering length density of layer in e-6 1/angstrom ** 2.
+ :param area_per_molecule: Area per molecule, in angstrom^2.
+ :return: Scattering length density of layer in e-6 1/angstrom^2.
"""
return scattering_length / (thickness * area_per_molecule) * 1e6
@@ -72,7 +73,7 @@ def density_to_sld(scattering_length: float, molecular_weight: float, density: f
:param scattering_length: Scattering length of component, in angstrom.
:param molecular_weight: Molecular weight of component, in u.
:param density: Mass density of the component, in gram centimeter^-3.
- :return: Scattering length density of layer in e-6 1/angstrom ** 2.
+ :return: Scattering length density of layer in e-6 1/angstrom^2.
"""
# 0.602214076 is avogadros constant times 1e-24
return 0.602214076e6 * density * scattering_length / molecular_weight
diff --git a/tests/calculators/refl1d/test_refl1d_calculator.py b/tests/calculators/refl1d/test_refl1d_calculator.py
index df16c3b7..ba6e39a8 100644
--- a/tests/calculators/refl1d/test_refl1d_calculator.py
+++ b/tests/calculators/refl1d/test_refl1d_calculator.py
@@ -8,10 +8,11 @@
import unittest
import numpy as np
-from easyreflectometry.calculators.refl1d.calculator import Refl1d
from numpy.testing import assert_almost_equal
from numpy.testing import assert_equal
+from easyreflectometry.calculators.refl1d.calculator import Refl1d
+
class TestRefl1d(unittest.TestCase):
def test_init(self):
@@ -108,6 +109,50 @@ def test_calculate2(self):
]
assert_almost_equal(p.fit_func(q, 'MyModel'), expected)
+ def test_calculate_magnetic(self):
+ p = Refl1d()
+ p.include_magnetism = True
+ p._wrapper.create_material('Material1')
+ p._wrapper.update_material('Material1', rho=0.000, irho=0.000)
+ p._wrapper.create_material('Material2')
+ p._wrapper.update_material('Material2', rho=2.000, irho=0.000)
+ p._wrapper.create_material('Material3')
+ p._wrapper.update_material('Material3', rho=4.000, irho=0.000)
+ p._wrapper.create_model('MyModel')
+ p._wrapper.update_model('MyModel', bkg=1e-7)
+ p._wrapper.create_layer('Layer1')
+ p._wrapper.assign_material_to_layer('Material1', 'Layer1')
+ p._wrapper.create_layer('Layer2')
+ p._wrapper.assign_material_to_layer('Material2', 'Layer2')
+ p._wrapper.update_layer('Layer2', thickness=10, interface=1.0)
+ p._wrapper.create_layer('Layer3')
+ p._wrapper.assign_material_to_layer('Material3', 'Layer3')
+ p._wrapper.update_layer('Layer3', interface=1.0)
+ p._wrapper.create_item('Item1')
+ p._wrapper.add_layer_to_item('Layer1', 'Item1')
+ p._wrapper.create_item('Item2')
+ p._wrapper.add_layer_to_item('Layer2', 'Item2')
+ p._wrapper.add_layer_to_item('Layer1', 'Item2')
+ p._wrapper.create_item('Item3')
+ p._wrapper.add_layer_to_item('Layer3', 'Item3')
+ p._wrapper.add_item('Item1', 'MyModel')
+ p._wrapper.add_item('Item2', 'MyModel')
+ p._wrapper.add_item('Item3', 'MyModel')
+ q = np.linspace(0.001, 0.3, 10)
+ expected = [
+ 9.99491251e-01,
+ 1.08413641e-02,
+ 1.46824402e-04,
+ 2.11783999e-05,
+ 5.24616472e-06,
+ 1.61422945e-06,
+ 5.66961121e-07,
+ 2.34269519e-07,
+ 1.30026616e-07,
+ 1.05139655e-07,
+ ]
+ assert_almost_equal(p.fit_func(q, 'MyModel'), expected)
+
def test_sld_profile(self):
p = Refl1d()
p._wrapper.create_material('Material1')
diff --git a/tests/calculators/refl1d/test_refl1d_wrapper.py b/tests/calculators/refl1d/test_refl1d_wrapper.py
index 08f8a618..6753a439 100644
--- a/tests/calculators/refl1d/test_refl1d_wrapper.py
+++ b/tests/calculators/refl1d/test_refl1d_wrapper.py
@@ -10,13 +10,14 @@
from unittest.mock import patch
import numpy as np
+from numpy.testing import assert_almost_equal
+from numpy.testing import assert_equal
+
from easyreflectometry.calculators.refl1d.wrapper import Refl1dWrapper
from easyreflectometry.calculators.refl1d.wrapper import _build_sample
from easyreflectometry.calculators.refl1d.wrapper import _get_oversampling_q
from easyreflectometry.calculators.refl1d.wrapper import _get_polarized_probe
from easyreflectometry.calculators.refl1d.wrapper import _get_probe
-from numpy.testing import assert_almost_equal
-from numpy.testing import assert_equal
class TestRefl1d(unittest.TestCase):
@@ -24,6 +25,12 @@ def test_init(self):
p = Refl1dWrapper()
assert_equal(list(p.storage.keys()), ['material', 'layer', 'item', 'model'])
assert_equal(issubclass(p.storage['material'].__class__, dict), True)
+ assert p._magnetism is False
+
+ def test_set_magnetism(self):
+ p = Refl1dWrapper()
+ p.magnetism = True
+ assert p._magnetism is True
def test_reset_storage(self):
p = Refl1dWrapper()
@@ -70,6 +77,14 @@ def test_update_layer(self):
assert_almost_equal(p.storage['layer']['Si'].thickness.value, 10)
assert_almost_equal(p.storage['layer']['Si'].interface.value, 5)
+ def test_update_magnetic_layer(self):
+ p = Refl1dWrapper()
+ p.magnetism = True
+ p.create_layer('Si')
+ p.update_layer('Si', magnetism_rhoM=5, magnetism_thetaM=10)
+ assert_almost_equal(p.storage['layer']['Si'].magnetism.thetaM.value, 10)
+ assert_almost_equal(p.storage['layer']['Si'].magnetism.rhoM.value, 5)
+
def test_get_layer_value(self):
p = Refl1dWrapper()
p.create_layer('Si')
@@ -77,6 +92,14 @@ def test_get_layer_value(self):
assert_almost_equal(p.get_layer_value('Si', 'thickness'), 10)
assert_almost_equal(p.get_layer_value('Si', 'interface'), 5)
+ def test_magnetic_get_layer_value(self):
+ p = Refl1dWrapper()
+ p.magnetism = True
+ p.create_layer('Si')
+ p.update_layer('Si', magnetism_rhoM=5, magnetism_thetaM=10)
+ assert_almost_equal(p.get_layer_value('Si', 'magnetism_thetaM'), 10)
+ assert_almost_equal(p.get_layer_value('Si', 'magnetism_rhoM'), 5)
+
def test_create_item(self):
p = Refl1dWrapper()
p.create_item('SiNi')
diff --git a/tests/calculators/refnx/test_refnx_calculator.py b/tests/calculators/refnx/test_refnx_calculator.py
index fa0fa923..782df2c0 100644
--- a/tests/calculators/refnx/test_refnx_calculator.py
+++ b/tests/calculators/refnx/test_refnx_calculator.py
@@ -8,10 +8,11 @@
import unittest
import numpy as np
-from easyreflectometry.calculators.refnx.calculator import Refnx
from numpy.testing import assert_almost_equal
from numpy.testing import assert_equal
+from easyreflectometry.calculators.refnx.calculator import Refnx
+
class TestRefnx(unittest.TestCase):
def test_init(self):
diff --git a/tests/calculators/refnx/test_refnx_wrapper.py b/tests/calculators/refnx/test_refnx_wrapper.py
index 3a4bbd04..de2a0027 100644
--- a/tests/calculators/refnx/test_refnx_wrapper.py
+++ b/tests/calculators/refnx/test_refnx_wrapper.py
@@ -9,14 +9,16 @@
import unittest
import numpy as np
-from easyreflectometry.calculators.refnx.wrapper import RefnxWrapper
-from easyreflectometry.experiment import LinearSpline
-from easyreflectometry.experiment import PercentageFhwm
+import pytest
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 LinearSpline
+from easyreflectometry.experiment import PercentageFhwm
+
class TestRefnx(unittest.TestCase):
def test_init(self):
@@ -24,6 +26,11 @@ def test_init(self):
assert_equal(list(p.storage.keys()), ['material', 'layer', 'item', 'model'])
assert_equal(issubclass(p.storage['material'].__class__, dict), True)
+ def test_set_magnetism(self):
+ p = RefnxWrapper()
+ with pytest.raises(NotImplementedError):
+ p.include_magnetism = True
+
def test_reset_storage(self):
p = RefnxWrapper()
p.storage['material']['a'] = 1
diff --git a/tests/experiment/test_model.py b/tests/experiment/test_model.py
index ea99a69a..c1386f8a 100644
--- a/tests/experiment/test_model.py
+++ b/tests/experiment/test_model.py
@@ -5,12 +5,15 @@
__author__ = 'github.com/arm61'
__version__ = '0.0.1'
-
import unittest
from unittest.mock import MagicMock
import numpy as np
import pytest
+from easyscience import global_object
+from numpy.testing import assert_almost_equal
+from numpy.testing import assert_equal
+
from easyreflectometry.calculators import CalculatorFactory
from easyreflectometry.experiment import LinearSpline
from easyreflectometry.experiment import Model
@@ -22,7 +25,6 @@
from easyreflectometry.sample import RepeatingMultilayer
from easyreflectometry.sample import Sample
from easyreflectometry.sample import SurfactantLayer
-from numpy.testing import assert_equal
class TestModel(unittest.TestCase):
@@ -33,13 +35,13 @@ def test_default(self):
assert_equal(p.sample.name, 'EasySample')
assert_equal(p.scale.display_name, 'scale')
assert_equal(str(p.scale.unit), 'dimensionless')
- assert_equal(p.scale.value.value.magnitude, 1.0)
+ assert_equal(p.scale.value, 1.0)
assert_equal(p.scale.min, 0.0)
assert_equal(p.scale.max, np.Inf)
assert_equal(p.scale.fixed, True)
assert_equal(p.background.display_name, 'background')
assert_equal(str(p.background.unit), 'dimensionless')
- assert_equal(p.background.value.value.magnitude, 1.0e-8)
+ assert_equal(p.background.value, 1.0e-8)
assert_equal(p.background.min, 0.0)
assert_equal(p.background.max, np.Inf)
assert_equal(p.background.fixed, True)
@@ -69,13 +71,13 @@ def test_from_pars(self):
assert_equal(mod.sample.name, 'myModel')
assert_equal(mod.scale.display_name, 'scale')
assert_equal(str(mod.scale.unit), 'dimensionless')
- assert_equal(mod.scale.value.value.magnitude, 2.0)
+ assert_equal(mod.scale.value, 2.0)
assert_equal(mod.scale.min, 0.0)
assert_equal(mod.scale.max, np.Inf)
assert_equal(mod.scale.fixed, True)
assert_equal(mod.background.display_name, 'background')
assert_equal(str(mod.background.unit), 'dimensionless')
- assert_equal(mod.background.value.value.magnitude, 1.0e-5)
+ assert_equal(mod.background.value, 1.0e-5)
assert_equal(mod.background.min, 0.0)
assert_equal(mod.background.max, np.Inf)
assert_equal(mod.background.fixed, True)
@@ -335,10 +337,6 @@ def test_remove_item_with_interface_refl1d(self):
# assert_equal(len(mod.interface()._wrapper.storage['item']), 1)
# assert_equal(len(mod.interface()._wrapper.storage['layer']), 2)
- def test_uid(self):
- p = Model()
- assert_equal(p.uid, p._borg.map.convert_id_to_key(p))
-
def test_resolution_function(self):
mock_resolution_function = MagicMock()
interface = CalculatorFactory()
@@ -380,7 +378,7 @@ def test_repr(self):
assert (
model.__repr__()
- == 'EasyModel:\n scale: 1.0\n background: 1.0e-08\n resolution: 5.0 %\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
+ == 'EasyModel:\n scale: 1.0\n background: 1.0e-08\n resolution: 5.0 %\n sample:\n EasySample:\n - EasyMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n' # noqa: E501
)
def test_repr_resolution_function(self):
@@ -389,26 +387,35 @@ def test_repr_resolution_function(self):
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
+ == 'EasyModel:\n scale: 1.0\n background: 1.0e-08\n resolution: function of Q\n sample:\n EasySample:\n - EasyMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n' # noqa: E501
)
- def test_dict_round_trip(self):
- # When
- resolution_function = LinearSpline([0, 10], [0, 10])
- interface = CalculatorFactory()
- model = Model(interface=interface)
- model.resolution_function = resolution_function
- surfactant = SurfactantLayer()
- model.add_item(surfactant)
- multilayer = Multilayer()
- model.add_item(multilayer)
- repeating = RepeatingMultilayer()
- model.add_item(repeating)
- src_dict = model.as_dict()
- # Then
- model_from_dict = Model.from_dict(src_dict)
-
- # Expect
- assert model.as_data_dict(skip=['resolution_function']) == model_from_dict.as_data_dict(skip=['resolution_function'])
- assert model._resolution_function.smearing(5.5) == model_from_dict._resolution_function.smearing(5.5)
+@pytest.mark.parametrize(
+ 'interface',
+ [None, CalculatorFactory()],
+)
+def test_dict_round_trip(interface): # , additional_layer):
+ # When
+ resolution_function = LinearSpline([0, 10], [0, 10])
+ model = Model(interface=interface)
+ model.resolution_function = resolution_function
+ for additional_layer in [SurfactantLayer(), Multilayer(), RepeatingMultilayer()]:
+ model.add_item(additional_layer)
+ src_dict = model.as_dict()
+ global_object.map._clear()
+
+ # Then
+ model_from_dict = Model.from_dict(src_dict)
+
+ # Expect
+ assert sorted(model.as_data_dict(skip=['resolution_function', 'interface'])) == sorted(
+ model_from_dict.as_data_dict(skip=['resolution_function', 'interface'])
+ )
+ assert model._resolution_function.smearing(5.5) == model_from_dict._resolution_function.smearing(5.5)
+ if interface is not None:
+ assert model.interface().name == model_from_dict.interface().name
+ assert_almost_equal(
+ model.interface().fit_func([0.3], model.unique_name),
+ model_from_dict.interface().fit_func([0.3], model_from_dict.unique_name),
+ )
diff --git a/tests/experiment/test_model_collection.py b/tests/experiment/test_model_collection.py
index 11c3ba71..02f0ec4b 100644
--- a/tests/experiment/test_model_collection.py
+++ b/tests/experiment/test_model_collection.py
@@ -1,10 +1,10 @@
-import unittest
+from easyscience import global_object
from easyreflectometry.experiment.model import Model
from easyreflectometry.experiment.model_collection import ModelCollection
-class TestModelCollection(unittest.TestCase):
+class TestModelCollection:
def test_default(self):
# When Then
collection = ModelCollection()
@@ -76,17 +76,16 @@ def test_dict_round_trip(self):
model_1 = Model(name='Model1')
model_2 = Model(name='Model2')
model_3 = Model(name='Model3')
+ p = ModelCollection(model_1, model_2, model_3)
+ p_dict = p.as_dict()
+ global_object.map._clear()
# Then
- collection = ModelCollection(model_1, model_2, model_3)
-
- src_dict = collection.as_dict()
-
- # Then
- collection_from_dict = ModelCollection.from_dict(src_dict)
+ q = ModelCollection.from_dict(p_dict)
# Expect
- assert collection.as_data_dict(skip=['resolution_function', 'interface']) == collection_from_dict.as_data_dict(
- skip=['resolution_function', 'interface']
+ # We have to skip the resolution_function and interface
+ assert sorted(p.as_data_dict(skip=['resolution_function', 'interface'])) == sorted(
+ q.as_data_dict(skip=['resolution_function', 'interface'])
)
- assert collection[0]._resolution_function.smearing(5.5) == collection_from_dict[0]._resolution_function.smearing(5.5)
+ assert p[0]._resolution_function.smearing(5.5) == q[0]._resolution_function.smearing(5.5)
diff --git a/tests/experiment/test_resolution_functions.py b/tests/experiment/test_resolution_functions.py
index a34f95b4..ab8eb614 100644
--- a/tests/experiment/test_resolution_functions.py
+++ b/tests/experiment/test_resolution_functions.py
@@ -1,6 +1,7 @@
import unittest
import numpy as np
+
from easyreflectometry.experiment.resolution_functions import DEFAULT_RESOLUTION_FWHM_PERCENTAGE
from easyreflectometry.experiment.resolution_functions import LinearSpline
from easyreflectometry.experiment.resolution_functions import PercentageFhwm
diff --git a/tests/sample/assemblies/test_base_assembly.py b/tests/sample/assemblies/test_base_assembly.py
index e5c09ebb..acbba9ea 100644
--- a/tests/sample/assemblies/test_base_assembly.py
+++ b/tests/sample/assemblies/test_base_assembly.py
@@ -5,14 +5,18 @@
from typing import Any
from unittest.mock import MagicMock
-import easyreflectometry.sample.assemblies.base_assembly
import pytest
+from easyscience import global_object
+
+import easyreflectometry.sample.assemblies.base_assembly
from easyreflectometry.sample.assemblies.base_assembly import BaseAssembly
class TestBaseAssembly:
@pytest.fixture
def base_assembly(self) -> BaseAssembly:
+ global_object.map._clear()
+
self.mock_layer_0 = MagicMock()
self.mock_layer_1 = MagicMock()
self.mock_layers = [self.mock_layer_0, self.mock_layer_1]
@@ -65,7 +69,7 @@ def test_enable_thickness_constraints(self, base_assembly: BaseAssembly) -> None
# Expect
assert self.mock_layer_0.thickness.user_constraints['thickness_1'].enabled is True
- assert self.mock_layer_0.thickness.value == self.mock_layer_0.thickness.raw_value
+ assert self.mock_layer_0.thickness.value == self.mock_layer_0.thickness.value
assert self.mock_layer_0.thickness.enabled is True
assert self.mock_layer_1.thickness.enabled is True
@@ -116,7 +120,7 @@ def test_enable_roughness_constraints(self, base_assembly):
# Expect
assert self.mock_layer_0.roughness.user_constraints['roughness_1'].enabled is True
- assert self.mock_layer_0.roughness.value == self.mock_layer_0.roughness.raw_value
+ assert self.mock_layer_0.roughness.value == self.mock_layer_0.roughness.value
assert self.mock_layer_0.roughness.enabled is True
assert self.mock_layer_1.roughness.enabled is True
diff --git a/tests/sample/assemblies/test_gradient_layer.py b/tests/sample/assemblies/test_gradient_layer.py
index c506d930..0663e54a 100644
--- a/tests/sample/assemblies/test_gradient_layer.py
+++ b/tests/sample/assemblies/test_gradient_layer.py
@@ -4,18 +4,22 @@
from unittest.mock import MagicMock
-import easyreflectometry.sample.assemblies.gradient_layer
import pytest
+from easyscience import global_object
+from numpy.testing import assert_almost_equal
+
+import easyreflectometry.sample.assemblies.gradient_layer
from easyreflectometry.sample.assemblies.gradient_layer import GradientLayer
from easyreflectometry.sample.assemblies.gradient_layer import _linear_gradient
from easyreflectometry.sample.assemblies.gradient_layer import _prepare_gradient_layers
from easyreflectometry.sample.elements.materials.material import Material
-from numpy.testing import assert_almost_equal
class TestGradientLayer:
@pytest.fixture
def gradient_layer(self) -> GradientLayer:
+ global_object.map._clear()
+
self.front = Material(10.0, -10.0, 'Material_1')
self.back = Material(0.0, 0.0, 'Material_2')
@@ -36,14 +40,14 @@ def test_init(self, gradient_layer: GradientLayer) -> None:
assert gradient_layer._type, 'Gradient-layer'
assert gradient_layer.interface is None
assert gradient_layer.thickness == 1.0
- assert gradient_layer.back_layer.thickness.raw_value == 0.1
+ assert gradient_layer.back_layer.thickness.value == 0.1
- assert gradient_layer.front_layer.material.sld.raw_value == 10.0
- assert gradient_layer.layers[5].material.sld.raw_value == 5.0
- assert gradient_layer.back_layer.material.sld.raw_value == 1.0
- assert gradient_layer.front_layer.material.isld.raw_value == -10.0
- assert gradient_layer.layers[5].material.isld.raw_value == -5.0
- assert gradient_layer.back_layer.material.isld.raw_value == -1.0
+ assert gradient_layer.front_layer.material.sld.value == 10.0
+ assert gradient_layer.layers[5].material.sld.value == 5.0
+ assert gradient_layer.back_layer.material.sld.value == 1.0
+ assert gradient_layer.front_layer.material.isld.value == -10.0
+ assert gradient_layer.layers[5].material.isld.value == -5.0
+ assert gradient_layer.back_layer.material.isld.value == -1.0
def test_default(self) -> None:
# When Then
@@ -78,32 +82,37 @@ def test_from_pars(self) -> None:
def test_repr(self, gradient_layer: GradientLayer) -> None:
# When Then Expect
- expected_str = "thickness: 1.0\ndiscretisation_elements: 10\nback_layer:\n '9':\n material:\n EasyMaterial:\n sld: 1.000e-6 1 / angstrom ** 2\n isld: -1.000e-6 1 / angstrom ** 2\n thickness: 0.100 angstrom\n roughness: 2.000 angstrom\nfront_layer:\n '0':\n material:\n EasyMaterial:\n sld: 10.000e-6 1 / angstrom ** 2\n isld: -10.000e-6 1 / angstrom ** 2\n thickness: 0.100 angstrom\n roughness: 2.000 angstrom\n" # noqa: E501
+ expected_str = "thickness: 1.0\ndiscretisation_elements: 10\nback_layer:\n '9':\n material:\n EasyMaterial:\n sld: 1.000e-6 1/Å^2\n isld: -1.000e-6 1/Å^2\n thickness: 0.100 Å\n roughness: 2.000 Å\nfront_layer:\n '0':\n material:\n EasyMaterial:\n sld: 10.000e-6 1/Å^2\n isld: -10.000e-6 1/Å^2\n thickness: 0.100 Å\n roughness: 2.000 Å\n" # noqa: E501
assert gradient_layer.__repr__() == expected_str
- def test_dict_round_trip(self, gradient_layer: GradientLayer) -> None:
- # When Then
- result = GradientLayer.from_dict(gradient_layer.as_dict())
+ def test_dict_round_trip(self) -> None:
+ # When
+ p = GradientLayer()
+ p_dict = p.as_dict()
+ global_object.map._clear()
- # Expect
- assert result.as_data_dict() == gradient_layer.as_data_dict()
- assert len(gradient_layer.layers) == len(result.layers)
+ # Then
+ q = GradientLayer.from_dict(p_dict)
+
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
+ assert len(p.layers) == len(q.layers)
# Just one layer of the generated layers is checked
- assert gradient_layer.layers[5].__repr__() == result.layers[5].__repr__()
+ assert p.layers[5].__repr__() == q.layers[5].__repr__()
- def test_thickness_setter(self, gradient_layer: GradientLayer) -> None:
+ def test_thickness_setter(self) -> None:
# When
+ gradient_layer = GradientLayer()
gradient_layer.thickness = 10.0
# Then
assert gradient_layer.thickness == 10.0
- assert gradient_layer.front_layer.thickness.raw_value == 1.0
- assert gradient_layer.back_layer.thickness.raw_value == 1.0
+ assert gradient_layer.front_layer.thickness.value == 1.0
+ assert gradient_layer.back_layer.thickness.value == 1.0
def test_thickness_getter(self, gradient_layer: GradientLayer) -> None:
# When
gradient_layer.layers = [MagicMock(), MagicMock()]
- gradient_layer.front_layer.thickness.raw_value = 10.0
+ gradient_layer.front_layer.thickness.value = 10.0
# Then
# discretisation_elements * discrete_layer_thickness
@@ -115,13 +124,13 @@ def test_roughness_setter(self, gradient_layer: GradientLayer) -> None:
# Then
assert gradient_layer.roughness == 10.0
- assert gradient_layer.front_layer.roughness.raw_value == 10.0
- assert gradient_layer.back_layer.roughness.raw_value == 10.0
+ assert gradient_layer.front_layer.roughness.value == 10.0
+ assert gradient_layer.back_layer.roughness.value == 10.0
def test_roughness_getter(self, gradient_layer: GradientLayer) -> None:
# When
gradient_layer.layers = [MagicMock(), MagicMock()]
- gradient_layer.front_layer.roughness.raw_value = 10.0
+ gradient_layer.front_layer.roughness.value = 10.0
# Then
assert gradient_layer.roughness == 10.0
@@ -177,9 +186,3 @@ def test_prepare_gradient_layers(monkeypatch):
assert mock_Layer.call_args_list[0][1]['thickness'] == 0.0
assert mock_Layer.call_args_list[0][1]['name'] == '0'
assert mock_Layer.call_args_list[0][1]['interface'] is None
-
-
-def test_dict_round_trip():
- p = GradientLayer()
- q = GradientLayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
diff --git a/tests/sample/assemblies/test_multilayer.py b/tests/sample/assemblies/test_multilayer.py
index 5d4bd264..c1ee3fd0 100644
--- a/tests/sample/assemblies/test_multilayer.py
+++ b/tests/sample/assemblies/test_multilayer.py
@@ -7,13 +7,15 @@
import unittest
+from easyscience import global_object
+from numpy.testing import assert_equal
+from numpy.testing import assert_raises
+
from easyreflectometry.calculators.factory import CalculatorFactory
from easyreflectometry.sample.assemblies.multilayer import Multilayer
from easyreflectometry.sample.elements.layers.layer import Layer
from easyreflectometry.sample.elements.layers.layer_collection import LayerCollection
from easyreflectometry.sample.elements.materials.material import Material
-from numpy.testing import assert_equal
-from numpy.testing import assert_raises
class TestMultilayer(unittest.TestCase):
@@ -23,7 +25,14 @@ def test_default(self):
assert_equal(p._type, 'Multi-layer')
assert_equal(p.interface, None)
assert_equal(len(p.layers), 2)
- assert_equal(p.layers.name, 'EasyLayers')
+ assert_equal(p.layers.name, 'EasyLayerCollection')
+
+ def test_default_empty(self):
+ p = Multilayer(populate_if_none=False)
+ assert_equal(p.name, 'EasyMultilayer')
+ assert_equal(p._type, 'Multi-layer')
+ assert_equal(p.interface, None)
+ assert_equal(len(p.layers), 0)
def test_from_pars(self):
m = Material(6.908, -0.278, 'Boron')
@@ -74,10 +83,10 @@ def test_add_layer_with_interface_refnx(self):
p = Layer(m, 5.0, 2.0, 'thinBoron', interface=interface)
q = Layer(k, 50.0, 1.0, 'thickPotassium', interface=interface)
o = Multilayer(p, 'twoLayerItem', interface=interface)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
o.add_layer(q)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 2)
- assert_equal(o.interface()._wrapper.storage['item'][o.uid].components[1].thick.value, 50.0)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 2)
+ assert_equal(o.interface()._wrapper.storage['item'][o.unique_name].components[1].thick.value, 50.0)
def test_duplicate_layer(self):
m = Material(6.908, -0.278, 'Boron')
@@ -101,18 +110,18 @@ def test_duplicate_layer_with_interface_refnx(self):
p = Layer(m, 5.0, 2.0, 'thinBoron', interface=interface)
q = Layer(k, 50.0, 1.0, 'thickPotassium', interface=interface)
o = Multilayer(p, 'twoLayerItem', interface=interface)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
o.add_layer(q)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 2)
- assert_equal(o.interface()._wrapper.storage['item'][o.uid].components[1].thick.value, 50.0)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 2)
+ assert_equal(o.interface()._wrapper.storage['item'][o.unique_name].components[1].thick.value, 50.0)
o.duplicate_layer(1)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 3)
- assert_equal(o.interface()._wrapper.storage['item'][o.uid].components[2].thick.value, 50.0)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 3)
+ assert_equal(o.interface()._wrapper.storage['item'][o.unique_name].components[2].thick.value, 50.0)
assert_raises(
AssertionError,
assert_equal,
- o.interface()._wrapper.storage['item'][o.uid].components[1].name,
- o.interface()._wrapper.storage['item'][o.uid].components[2].name,
+ o.interface()._wrapper.storage['item'][o.unique_name].components[1].name,
+ o.interface()._wrapper.storage['item'][o.unique_name].components[2].name,
)
def test_remove_layer(self):
@@ -137,22 +146,25 @@ def test_remove_layer_with_interface_refnx(self):
p = Layer(m, 5.0, 2.0, 'thinBoron', interface=interface)
q = Layer(k, 50.0, 1.0, 'thickPotassium', interface=interface)
o = Multilayer(p, name='twoLayerItem', interface=interface)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
o.add_layer(q)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 2)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 2)
assert_equal(o.layers[1].name, 'thickPotassium')
o.remove_layer(1)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
assert_equal(o.layers[0].name, 'thinBoron')
def test_repr(self):
p = Multilayer()
assert (
p.__repr__()
- == '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
+ == 'EasyMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n' # noqa: E501
)
def test_dict_round_trip(self):
p = Multilayer()
- q = Multilayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ q = Multilayer.from_dict(p_dict)
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/assemblies/test_repeating_multilayer.py b/tests/sample/assemblies/test_repeating_multilayer.py
index 89057926..ce585992 100644
--- a/tests/sample/assemblies/test_repeating_multilayer.py
+++ b/tests/sample/assemblies/test_repeating_multilayer.py
@@ -8,13 +8,15 @@
import unittest
+from easyscience import global_object
+from numpy.testing import assert_equal
+from numpy.testing import assert_raises
+
from easyreflectometry.calculators import CalculatorFactory
from easyreflectometry.sample.assemblies.repeating_multilayer import RepeatingMultilayer
from easyreflectometry.sample.elements.layers.layer import Layer
from easyreflectometry.sample.elements.layers.layer_collection import LayerCollection
from easyreflectometry.sample.elements.materials.material import Material
-from numpy.testing import assert_equal
-from numpy.testing import assert_raises
class TestRepeatingMultilayer(unittest.TestCase):
@@ -26,11 +28,24 @@ def test_default(self):
assert_equal(len(p.layers), 2)
assert_equal(p.repetitions.display_name, 'repetitions')
assert_equal(str(p.repetitions.unit), 'dimensionless')
- assert_equal(p.repetitions.value.value.magnitude, 1.0)
+ assert_equal(p.repetitions.value, 1.0)
assert_equal(p.repetitions.min, 1)
assert_equal(p.repetitions.max, 9999)
assert_equal(p.repetitions.fixed, True)
- assert_equal(p.layers.name, 'EasyLayers')
+ assert_equal(p.layers.name, 'EasyLayerCollection')
+
+ def test_default_empty(self):
+ p = RepeatingMultilayer(populate_if_none=False)
+ assert_equal(p.name, 'EasyRepeatingMultilayer')
+ assert_equal(p._type, 'Repeating Multi-layer')
+ assert_equal(p.interface, None)
+ assert_equal(p.repetitions.display_name, 'repetitions')
+ assert_equal(str(p.repetitions.unit), 'dimensionless')
+ assert_equal(p.repetitions.value, 1.0)
+ assert_equal(p.repetitions.min, 1)
+ assert_equal(p.repetitions.max, 9999)
+ assert_equal(p.repetitions.fixed, True)
+ assert_equal(p.layers.name, 'EasyLayerCollection')
def test_from_pars(self):
m = Material(6.908, -0.278, 'Boron')
@@ -44,7 +59,7 @@ def test_from_pars(self):
assert_equal(o.interface, None)
assert_equal(o.repetitions.display_name, 'repetitions')
assert_equal(str(o.repetitions.unit), 'dimensionless')
- assert_equal(o.repetitions.value.value.magnitude, 2.0)
+ assert_equal(o.repetitions.value, 2.0)
assert_equal(o.repetitions.min, 1)
assert_equal(o.repetitions.max, 9999)
assert_equal(o.repetitions.fixed, True)
@@ -58,7 +73,7 @@ def test_from_pars_layer(self):
assert_equal(o.interface, None)
assert_equal(o.repetitions.display_name, 'repetitions')
assert_equal(str(o.repetitions.unit), 'dimensionless')
- assert_equal(o.repetitions.value.value.magnitude, 2.0)
+ assert_equal(o.repetitions.value, 2.0)
assert_equal(o.repetitions.min, 1)
assert_equal(o.repetitions.max, 9999)
assert_equal(o.repetitions.fixed, True)
@@ -73,7 +88,7 @@ def test_from_pars_layer_list(self):
assert_equal(o.name, 'twoLayerItem')
assert_equal(o.interface, None)
assert_equal(o.layers.name, 'thinBoron/layerPotassium')
- assert_equal(o.repetitions.value.value.magnitude, 10.0)
+ assert_equal(o.repetitions.value, 10.0)
assert_equal(o.repetitions.min, 1)
assert_equal(o.repetitions.max, 9999)
@@ -96,10 +111,10 @@ def test_add_layer_with_interface_refnx(self):
p = Layer(m, 5.0, 2.0, 'thinBoron', interface=interface)
q = Layer(k, 50.0, 1.0, 'thickPotassium', interface=interface)
o = RepeatingMultilayer(p, 2.0, 'twoLayerItem', interface=interface)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
o.add_layer(q)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 2)
- assert_equal(o.interface()._wrapper.storage['item'][o.uid].components[1].thick.value, 50.0)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 2)
+ assert_equal(o.interface()._wrapper.storage['item'][o.unique_name].components[1].thick.value, 50.0)
def test_duplicate_layer(self):
m = Material(6.908, -0.278, 'Boron')
@@ -123,18 +138,18 @@ def test_duplicate_layer_with_interface_refnx(self):
p = Layer(m, 5.0, 2.0, 'thinBoron', interface=interface)
q = Layer(k, 50.0, 1.0, 'thickPotassium', interface=interface)
o = RepeatingMultilayer(p, 2.0, 'twoLayerItem', interface=interface)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
o.add_layer(q)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 2)
- assert_equal(o.interface()._wrapper.storage['item'][o.uid].components[1].thick.value, 50.0)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 2)
+ assert_equal(o.interface()._wrapper.storage['item'][o.unique_name].components[1].thick.value, 50.0)
o.duplicate_layer(1)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 3)
- assert_equal(o.interface()._wrapper.storage['item'][o.uid].components[2].thick.value, 50.0)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 3)
+ assert_equal(o.interface()._wrapper.storage['item'][o.unique_name].components[2].thick.value, 50.0)
assert_raises(
AssertionError,
assert_equal,
- o.interface()._wrapper.storage['item'][o.uid].components[1].name,
- o.interface()._wrapper.storage['item'][o.uid].components[2].name,
+ o.interface()._wrapper.storage['item'][o.unique_name].components[1].name,
+ o.interface()._wrapper.storage['item'][o.unique_name].components[2].name,
)
def test_remove_layer(self):
@@ -159,22 +174,25 @@ def test_remove_layer_with_interface_refnx(self):
p = Layer(m, 5.0, 2.0, 'thinBoron', interface=interface)
q = Layer(k, 50.0, 1.0, 'thickPotassium', interface=interface)
o = RepeatingMultilayer(p, repetitions=2.0, name='twoLayerItem', interface=interface)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
o.add_layer(q)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 2)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 2)
assert_equal(o.layers[1].name, 'thickPotassium')
o.remove_layer(1)
- assert_equal(len(o.interface()._wrapper.storage['item'][o.uid].components), 1)
+ assert_equal(len(o.interface()._wrapper.storage['item'][o.unique_name].components), 1)
assert_equal(o.layers[0].name, 'thinBoron')
def test_repr(self):
- p = RepeatingMultilayer()
+ p = RepeatingMultilayer(populate_if_none=True)
assert (
p.__repr__()
- == 'EasyRepeatingMultilayer:\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 repetitions: 1.0\n' # noqa: E501
+ == 'EasyRepeatingMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n repetitions: 1.0\n' # noqa: E501
)
def test_dict_round_trip(self):
- p = RepeatingMultilayer()
- q = RepeatingMultilayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ p = RepeatingMultilayer(populate_if_none=True)
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ q = RepeatingMultilayer.from_dict(p_dict)
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/assemblies/test_surfactant_layer.py b/tests/sample/assemblies/test_surfactant_layer.py
index c432df32..85672708 100644
--- a/tests/sample/assemblies/test_surfactant_layer.py
+++ b/tests/sample/assemblies/test_surfactant_layer.py
@@ -8,12 +8,15 @@
import unittest
+from easyscience import global_object
+
from easyreflectometry.sample.assemblies.surfactant_layer import SurfactantLayer
from easyreflectometry.sample.elements.layers.layer import Layer
+from easyreflectometry.sample.elements.layers.layer_area_per_molecule import LayerAreaPerMolecule
from easyreflectometry.sample.elements.materials.material import Material
-class TestSurfactantLayer(unittest.TestCase):
+class TestSurfactantLayer:
def test_default(self):
p = SurfactantLayer()
assert p.name == 'EasySurfactantLayer'
@@ -37,15 +40,15 @@ def test_from_pars(self):
assert p.layers[0].name == 'A Test Tail Layer'
assert p.tail_layer.name == 'A Test Tail Layer'
assert p.tail_layer.molecular_formula == 'C8O10H12P'
- assert p.tail_layer.thickness.raw_value == 12
+ assert p.tail_layer.thickness.value == 12
assert p.tail_layer.solvent.as_data_dict() == h2o.as_data_dict()
assert p.tail_layer.solvent_fraction == 0.5
assert p.tail_layer.area_per_molecule == 50
- assert p.tail_layer.roughness.raw_value == 2
+ assert p.tail_layer.roughness.value == 2
assert p.layers[1].name == 'A Test Head Layer'
assert p.head_layer.name == 'A Test Head Layer'
assert p.head_layer.molecular_formula == 'C10H24'
- assert p.head_layer.thickness.raw_value == 10
+ assert p.head_layer.thickness.value == 10
assert p.head_layer.solvent.as_data_dict() == noth2o.as_data_dict()
assert p.head_layer.solvent_fraction == 0.2
assert p.head_layer.area_per_molecule == 40
@@ -68,33 +71,33 @@ def test_constraint_area_per_molecule(self):
def test_conformal_roughness(self):
p = SurfactantLayer()
p.tail_layer.roughness.value = 2
- assert p.tail_layer.roughness.raw_value == 2
- assert p.head_layer.roughness.raw_value == 3
+ assert p.tail_layer.roughness.value == 2
+ assert p.head_layer.roughness.value == 3
p.conformal_roughness = True
- assert p.tail_layer.roughness.raw_value == 2
- assert p.head_layer.roughness.raw_value == 2
+ assert p.tail_layer.roughness.value == 2
+ assert p.head_layer.roughness.value == 2
assert p.conformal_roughness is True
p.tail_layer.roughness.value = 4
- assert p.tail_layer.roughness.raw_value == 4
- assert p.head_layer.roughness.raw_value == 4
+ assert p.tail_layer.roughness.value == 4
+ assert p.head_layer.roughness.value == 4
def test_constain_solvent_roughness(self):
p = SurfactantLayer()
layer = Layer()
p.tail_layer.roughness.value = 2
- assert p.tail_layer.roughness.raw_value == 2
- assert p.head_layer.roughness.raw_value == 3
- assert layer.roughness.raw_value == 3.3
+ assert p.tail_layer.roughness.value == 2
+ assert p.head_layer.roughness.value == 3
+ assert layer.roughness.value == 3.3
p.conformal_roughness = True
p.constrain_solvent_roughness(layer.roughness)
- assert p.tail_layer.roughness.raw_value == 2
- assert p.head_layer.roughness.raw_value == 2
- assert layer.roughness.raw_value == 2
+ assert p.tail_layer.roughness.value == 2
+ assert p.head_layer.roughness.value == 2
+ assert layer.roughness.value == 2
assert p.conformal_roughness is True
p.tail_layer.roughness.value = 4
- assert p.tail_layer.roughness.raw_value == 4
- assert p.head_layer.roughness.raw_value == 4
- assert layer.roughness.raw_value == 4
+ assert p.tail_layer.roughness.value == 4
+ assert p.head_layer.roughness.value == 4
+ assert layer.roughness.value == 4
def test_dict_repr(self):
p = SurfactantLayer()
@@ -105,42 +108,34 @@ def test_dict_repr(self):
'material': {
'C10H18NO8P in D2O': {
'solvent_fraction': '0.200 dimensionless',
- 'sld': '2.269e-6 1 / angstrom ** 2',
- 'isld': '0.000e-6 1 / angstrom ** 2',
- 'material': {
- 'C10H18NO8P': {'sld': '1.246e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}
- },
- 'solvent': {
- 'D2O': {'sld': '6.360e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}
- },
+ 'sld': '2.269e-6 1/Å^2',
+ 'isld': '0.000e-6 1/Å^2',
+ 'material': {'C10H18NO8P': {'sld': '1.246e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
+ 'solvent': {'D2O': {'sld': '6.360e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
}
},
- 'thickness': '10.000 angstrom',
- 'roughness': '3.000 angstrom',
+ 'thickness': '10.000 Å',
+ 'roughness': '3.000 Å',
},
'molecular_formula': 'C10H18NO8P',
- 'area_per_molecule': '48.20 angstrom ** 2',
+ 'area_per_molecule': '48.20 Å^2',
},
'tail_layer': {
'DPPC Tail': {
'material': {
'C32D64 in Air': {
'solvent_fraction': '0.000 dimensionless',
- 'sld': '8.297e-6 1 / angstrom ** 2',
- 'isld': '0.000e-6 1 / angstrom ** 2',
- 'material': {
- 'C32D64': {'sld': '8.297e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}
- },
- 'solvent': {
- 'Air': {'sld': '0.000e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}
- },
+ 'sld': '8.297e-6 1/Å^2',
+ 'isld': '0.000e-6 1/Å^2',
+ 'material': {'C32D64': {'sld': '8.297e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
+ 'solvent': {'Air': {'sld': '0.000e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
}
},
- 'thickness': '16.000 angstrom',
- 'roughness': '3.000 angstrom',
+ 'thickness': '16.000 Å',
+ 'roughness': '3.000 Å',
},
'molecular_formula': 'C32D64',
- 'area_per_molecule': '48.20 angstrom ** 2',
+ 'area_per_molecule': '48.20 Å^2',
},
'area per molecule constrained': False,
'conformal roughness': False,
@@ -189,33 +184,89 @@ def test_set_tail_layer(self):
assert p.front_layer == new_layer
assert p.layers[0] == new_layer
- def test_dict_round_trip(self):
- p = SurfactantLayer()
- q = SurfactantLayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
- def test_dict_round_trip_area_per_molecule_constraint_enabled(self):
- p = SurfactantLayer()
- p.constrain_area_per_molecule = True
- q = SurfactantLayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+def test_dict_round_trip():
+ # When
+ solvent = Material(-0.561, 0, 'H2O')
+ tail_layer = LayerAreaPerMolecule(
+ molecular_formula='CO2',
+ solvent=solvent,
+ solvent_fraction=0.25,
+ area_per_molecule=50,
+ thickness=10,
+ roughness=4,
+ )
+ head_layer = LayerAreaPerMolecule(
+ molecular_formula='CH2',
+ solvent_fraction=0.75,
+ area_per_molecule=50,
+ thickness=5,
+ roughness=2,
+ )
+ p = SurfactantLayer(head_layer=head_layer, tail_layer=tail_layer)
+ p_dict = p.as_dict()
+ global_object.map._clear()
- def test_dict_round_trip_area_per_molecule_constraint_disabled(self):
- p = SurfactantLayer()
- p.constrain_area_per_molecule = True
- p.constrain_area_per_molecule = False
- q = SurfactantLayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ # Then
+ q = SurfactantLayer.from_dict(p_dict)
- def test_dict_round_trip_roughness_constraint_enabled(self):
- p = SurfactantLayer()
- p.conformal_roughness = True
- q = SurfactantLayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ # Expect
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
- def test_dict_round_trip_roughness_constraint_disabled(self):
- p = SurfactantLayer()
- p.conformal_roughness = True
- p.conformal_roughness = False
- q = SurfactantLayer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+
+def test_dict_round_trip_area_per_molecule_constraint_enabled():
+ # When
+ p = SurfactantLayer()
+ p.constrain_area_per_molecule = True
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ # Then
+ q = SurfactantLayer.from_dict(p_dict)
+
+ # Expect
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
+
+
+def test_dict_round_trip_area_per_molecule_constraint_disabled():
+ # When
+ p = SurfactantLayer()
+ p.constrain_area_per_molecule = True
+ p.constrain_area_per_molecule = False
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ # Then
+ q = SurfactantLayer.from_dict(p_dict)
+
+ # Expect
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
+
+
+def test_dict_round_trip_roughness_constraint_enabled():
+ # When
+ p = SurfactantLayer()
+ p.conformal_roughness = True
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ # Then
+ q = SurfactantLayer.from_dict(p_dict)
+
+ # Expect
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
+
+
+def test_dict_round_trip_roughness_constraint_disabled():
+ # When
+ p = SurfactantLayer()
+ p.conformal_roughness = True
+ p.conformal_roughness = False
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ # Then
+ q = SurfactantLayer.from_dict(p_dict)
+
+ # Expect
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/elements/layers/test_layer.py b/tests/sample/elements/layers/test_layer.py
index 93b6a111..2b75e717 100644
--- a/tests/sample/elements/layers/test_layer.py
+++ b/tests/sample/elements/layers/test_layer.py
@@ -8,13 +8,15 @@
import unittest
import numpy as np
+from easyscience import global_object
+from numpy.testing import assert_almost_equal
+from numpy.testing import assert_equal
+
from easyreflectometry.calculators.factory import CalculatorFactory
from easyreflectometry.parameter_utils import get_as_parameter
from easyreflectometry.sample.elements.layers.layer import DEFAULTS
from easyreflectometry.sample.elements.layers.layer import Layer
from easyreflectometry.sample.elements.materials.material import Material
-from numpy.testing import assert_almost_equal
-from numpy.testing import assert_equal
class TestLayer(unittest.TestCase):
@@ -24,14 +26,14 @@ def test_no_arguments(self):
assert_equal(p.interface, None)
assert_equal(p.material.name, 'EasyMaterial')
assert_equal(p.thickness.display_name, 'thickness')
- assert_equal(str(p.thickness.unit), 'angstrom')
- assert_equal(p.thickness.value.value.magnitude, 10.0)
+ assert_equal(str(p.thickness.unit), 'Å')
+ assert_equal(p.thickness.value, 10.0)
assert_equal(p.thickness.min, 0.0)
assert_equal(p.thickness.max, np.Inf)
assert_equal(p.thickness.fixed, True)
assert_equal(p.roughness.display_name, 'roughness')
- assert_equal(str(p.roughness.unit), 'angstrom')
- assert_equal(p.roughness.value.value.magnitude, 3.3)
+ assert_equal(str(p.roughness.unit), 'Å')
+ assert_equal(p.roughness.value, 3.3)
assert_equal(p.roughness.min, 0.0)
assert_equal(p.roughness.max, np.Inf)
assert_equal(p.roughness.fixed, True)
@@ -43,14 +45,14 @@ def test_shuffled_arguments(self):
assert_equal(p.interface, None)
assert_equal(p.material.name, 'Boron')
assert_equal(p.thickness.display_name, 'thickness')
- assert_equal(str(p.thickness.unit), 'angstrom')
- assert_equal(p.thickness.value.value.magnitude, 5.0)
+ assert_equal(str(p.thickness.unit), 'Å')
+ assert_equal(p.thickness.value, 5.0)
assert_equal(p.thickness.min, 0.0)
assert_equal(p.thickness.max, np.Inf)
assert_equal(p.thickness.fixed, True)
assert_equal(p.roughness.display_name, 'roughness')
- assert_equal(str(p.roughness.unit), 'angstrom')
- assert_equal(p.roughness.value.value.magnitude, 2.0)
+ assert_equal(str(p.roughness.unit), 'Å')
+ assert_equal(p.roughness.value, 2.0)
assert_equal(p.roughness.min, 0.0)
assert_equal(p.roughness.max, np.Inf)
assert_equal(p.roughness.fixed, True)
@@ -58,8 +60,8 @@ def test_shuffled_arguments(self):
def test_only_roughness_key(self):
p = Layer(roughness=10.0)
assert_equal(p.roughness.display_name, 'roughness')
- assert_equal(str(p.roughness.unit), 'angstrom')
- assert_equal(p.roughness.value.value.magnitude, 10.0)
+ assert_equal(str(p.roughness.unit), 'Å')
+ assert_equal(p.roughness.value, 10.0)
assert_equal(p.roughness.min, 0.0)
assert_equal(p.roughness.max, np.Inf)
assert_equal(p.roughness.fixed, True)
@@ -68,14 +70,14 @@ def test_only_roughness_key_paramter(self):
roughness = get_as_parameter('roughness', 10, DEFAULTS)
roughness.min = -10.0
p = Layer(roughness=roughness)
- assert_equal(p.roughness.value.value.magnitude, 10.0)
+ assert_equal(p.roughness.value, 10.0)
assert_equal(p.roughness.min, -10.0)
def test_only_thickness_key(self):
p = Layer(thickness=10.0)
assert_equal(p.thickness.display_name, 'thickness')
- assert_equal(str(p.thickness.unit), 'angstrom')
- assert_equal(p.thickness.value.value.magnitude, 10.0)
+ assert_equal(str(p.thickness.unit), 'Å')
+ assert_equal(p.thickness.value, 10.0)
assert_equal(p.thickness.min, 0.0)
assert_equal(p.thickness.max, np.Inf)
assert_equal(p.thickness.fixed, True)
@@ -84,37 +86,37 @@ def test_only_thickness_key_paramter(self):
thickness = get_as_parameter('thickness', 10, DEFAULTS)
thickness.min = -10.0
p = Layer(thickness=thickness)
- assert_equal(p.thickness.value.value.magnitude, 10.0)
+ assert_equal(p.thickness.value, 10.0)
assert_equal(p.thickness.min, -10.0)
def test_assign_material(self):
m = Material(6.908, -0.278, 'Boron')
p = Layer(m, 5.0, 2.0, 'thinBoron')
k = Material(2.074, 0.0, 'Silicon')
- assert_almost_equal(p.material.sld.raw_value, 6.908)
- assert_almost_equal(p.material.isld.raw_value, -0.278)
+ assert_almost_equal(p.material.sld.value, 6.908)
+ assert_almost_equal(p.material.isld.value, -0.278)
p.assign_material(k)
- assert_almost_equal(p.material.sld.raw_value, 2.074)
- assert_almost_equal(p.material.isld.raw_value, 0.0)
+ assert_almost_equal(p.material.sld.value, 2.074)
+ assert_almost_equal(p.material.isld.value, 0.0)
def test_assign_material_with_interface_refnx(self):
interface = CalculatorFactory()
m = Material(6.908, -0.278, 'Boron', interface=interface)
p = Layer(m, 5.0, 2.0, 'thinBoron', interface=interface)
k = Material(2.074, 0.0, 'Silicon', interface=interface)
- assert_almost_equal(p.interface()._wrapper.storage['layer'][p.uid].sld.real.value, 6.908)
- assert_almost_equal(p.interface()._wrapper.storage['layer'][p.uid].sld.imag.value, -0.278)
+ assert_almost_equal(p.interface()._wrapper.storage['layer'][p.unique_name].sld.real.value, 6.908)
+ assert_almost_equal(p.interface()._wrapper.storage['layer'][p.unique_name].sld.imag.value, -0.278)
p.assign_material(k)
- assert_almost_equal(p.interface()._wrapper.storage['layer'][p.uid].sld.real.value, 2.074)
- assert_almost_equal(p.interface()._wrapper.storage['layer'][p.uid].sld.imag.value, 0.0)
+ assert_almost_equal(p.interface()._wrapper.storage['layer'][p.unique_name].sld.real.value, 2.074)
+ assert_almost_equal(p.interface()._wrapper.storage['layer'][p.unique_name].sld.imag.value, 0.0)
def test_dict_repr(self):
p = Layer()
assert p._dict_repr == {
'EasyLayer': {
- 'material': {'EasyMaterial': {'isld': '0.000e-6 1 / angstrom ** 2', 'sld': '4.186e-6 1 / angstrom ** 2'}},
- 'roughness': '3.300 angstrom',
- 'thickness': '10.000 angstrom',
+ 'material': {'EasyMaterial': {'isld': '0.000e-6 1/Å^2', 'sld': '4.186e-6 1/Å^2'}},
+ 'roughness': '3.300 Å',
+ 'thickness': '10.000 Å',
}
}
@@ -122,10 +124,13 @@ def test_repr(self):
p = Layer()
assert (
p.__repr__()
- == '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
+ == 'EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n' # noqa: E501
) # noqa: E501
def test_dict_round_trip(self):
p = Layer()
- q = Layer.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ q = Layer.from_dict(p_dict)
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/elements/layers/test_layer_area_per_molecule.py b/tests/sample/elements/layers/test_layer_area_per_molecule.py
index e9455f7f..acfabd9f 100644
--- a/tests/sample/elements/layers/test_layer_area_per_molecule.py
+++ b/tests/sample/elements/layers/test_layer_area_per_molecule.py
@@ -4,9 +4,11 @@
import unittest
+from easyscience import global_object
+from numpy.testing import assert_almost_equal
+
from easyreflectometry.sample.elements.layers.layer_area_per_molecule import LayerAreaPerMolecule
from easyreflectometry.sample.elements.materials.material import Material
-from numpy.testing import assert_almost_equal
class TestLayerAreaPerMolecule(unittest.TestCase):
@@ -14,19 +16,19 @@ def test_default(self):
p = LayerAreaPerMolecule()
assert p.molecular_formula == 'C10H18NO8P'
assert p.area_per_molecule == 48.2
- assert str(p._area_per_molecule.unit) == 'angstrom ** 2'
+ assert str(p._area_per_molecule.unit) == 'Å^2'
assert p._area_per_molecule.fixed is True
- assert p.thickness.raw_value == 10.0
- assert str(p.thickness.unit) == 'angstrom'
+ assert p.thickness.value == 10.0
+ assert str(p.thickness.unit) == 'Å'
assert p.thickness.fixed is True
- assert p.roughness.raw_value == 3.3
- assert str(p.roughness.unit) == 'angstrom'
+ assert p.roughness.value == 3.3
+ assert str(p.roughness.unit) == 'Å'
assert p.roughness.fixed is True
assert_almost_equal(p.material.sld, 2.2691419)
assert_almost_equal(p.material.isld, 0)
assert p.material.name == 'C10H18NO8P in D2O'
- assert p.solvent.sld.raw_value == 6.36
- assert p.solvent.isld.raw_value == 0
+ assert p.solvent.sld.value == 6.36
+ assert p.solvent.isld.value == 0
assert p.solvent.name == 'D2O'
assert p.solvent_fraction == 0.2
assert str(p.material._fraction.unit) == 'dimensionless'
@@ -45,10 +47,10 @@ def test_from_pars(self):
)
assert p.molecular_formula == 'C8O10H12P'
assert p.area_per_molecule == 50
- assert p.thickness.raw_value == 12
- assert p.roughness.raw_value == 2
- assert p.solvent.sld.raw_value == -0.561
- assert p.solvent.isld.raw_value == 0
+ assert p.thickness.value == 12
+ assert p.roughness.value == 2
+ assert p.solvent.sld.value == -0.561
+ assert p.solvent.isld.value == 0
assert p.solvent_fraction == 0.5
def test_from_pars_constraint(self):
@@ -65,16 +67,16 @@ def test_from_pars_constraint(self):
assert p.molecular_formula == 'C8O10H12P'
assert p.area_per_molecule == 50
assert_almost_equal(p.material.sld, 0.31513666667)
- assert p.thickness.raw_value == 12
- assert p.roughness.raw_value == 2
- assert p.solvent.sld.raw_value == -0.561
- assert p.solvent.isld.raw_value == 0
+ assert p.thickness.value == 12
+ assert p.roughness.value == 2
+ assert p.solvent.sld.value == -0.561
+ assert p.solvent.isld.value == 0
assert p.solvent_fraction == 0.5
p.area_per_molecule = 30
assert p.area_per_molecule == 30
assert_almost_equal(p.material.sld, 0.712227778)
p.thickness.value = 10
- assert p.thickness.raw_value == 10
+ assert p.thickness.value == 10
assert_almost_equal(p.material.sld, 0.910773333)
def test_solvent_change(self):
@@ -92,20 +94,20 @@ def test_solvent_change(self):
assert p.area_per_molecule == 50
print(p.material)
assert_almost_equal(p.material.sld, 0.31513666667)
- assert p.thickness.raw_value == 12
- assert p.roughness.raw_value == 2
- assert p.solvent.sld.raw_value == -0.561
- assert p.solvent.isld.raw_value == 0
+ assert p.thickness.value == 12
+ assert p.roughness.value == 2
+ assert p.solvent.sld.value == -0.561
+ assert p.solvent.isld.value == 0
assert p.solvent_fraction == 0.5
d2o = Material(6.335, 0, 'D2O')
p.solvent = d2o
assert p.molecular_formula == 'C8O10H12P'
assert p.area_per_molecule == 50
assert_almost_equal(p.material.sld, 3.7631366667)
- assert p.thickness.raw_value == 12
- assert p.roughness.raw_value == 2
- assert p.solvent.sld.raw_value == 6.335
- assert p.solvent.isld.raw_value == 0
+ assert p.thickness.value == 12
+ assert p.roughness.value == 2
+ assert p.solvent.sld.value == 6.335
+ assert p.solvent.isld.value == 0
assert p.solvent_fraction == 0.5
def test_molecular_formula_change(self):
@@ -122,21 +124,21 @@ def test_molecular_formula_change(self):
assert p.molecular_formula == 'C8O10H12P'
assert p.area_per_molecule == 50
assert_almost_equal(p.material.sld, 0.31513666667)
- assert p.thickness.raw_value == 12
- assert p.roughness.raw_value == 2
+ assert p.thickness.value == 12
+ assert p.roughness.value == 2
- assert p.solvent.sld.raw_value == -0.561
- assert p.solvent.isld.raw_value == 0
+ assert p.solvent.sld.value == -0.561
+ assert p.solvent.isld.value == 0
assert p.solvent_fraction == 0.5
assert p.material.name == 'C8O10H12P in H2O'
p.molecular_formula = 'C8O10D12P'
assert p.molecular_formula == 'C8O10D12P'
assert p.area_per_molecule == 50
assert_almost_equal(p.material.sld, 1.3566266666666666)
- assert p.thickness.raw_value == 12
- assert p.roughness.raw_value == 2
- assert p.solvent.sld.raw_value == -0.561
- assert p.solvent.isld.raw_value == 0
+ assert p.thickness.value == 12
+ assert p.roughness.value == 2
+ assert p.solvent.sld.value == -0.561
+ assert p.solvent.isld.value == 0
assert p.solvent_fraction == 0.5
assert p.material.name == 'C8O10D12P in H2O'
@@ -147,22 +149,35 @@ def test_dict_repr(self):
'material': {
'C10H18NO8P in D2O': {
'solvent_fraction': '0.200 dimensionless',
- 'sld': '2.269e-6 1 / angstrom ** 2',
- 'isld': '0.000e-6 1 / angstrom ** 2',
- 'material': {
- 'C10H18NO8P': {'sld': '1.246e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}
- },
- 'solvent': {'D2O': {'sld': '6.360e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}},
+ 'sld': '2.269e-6 1/Å^2',
+ 'isld': '0.000e-6 1/Å^2',
+ 'material': {'C10H18NO8P': {'sld': '1.246e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
+ 'solvent': {'D2O': {'sld': '6.360e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
}
},
- 'thickness': '10.000 angstrom',
- 'roughness': '3.300 angstrom',
+ 'thickness': '10.000 Å',
+ 'roughness': '3.300 Å',
},
'molecular_formula': 'C10H18NO8P',
- 'area_per_molecule': '48.20 angstrom ** 2',
+ 'area_per_molecule': '48.20 Å^2',
}
def test_dict_round_trip(self):
- p = LayerAreaPerMolecule()
- q = LayerAreaPerMolecule.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ # When
+ solvent = Material(-0.561, 0, 'H2O')
+ p = LayerAreaPerMolecule(
+ molecular_formula='CO2',
+ solvent=solvent,
+ solvent_fraction=0.5,
+ area_per_molecule=50,
+ thickness=10,
+ roughness=3,
+ )
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ # Then
+ q = LayerAreaPerMolecule.from_dict(p_dict)
+
+ # Expect
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/elements/layers/test_layer_collection.py b/tests/sample/elements/layers/test_layer_collection.py
index 9c91c570..c2c0bec2 100644
--- a/tests/sample/elements/layers/test_layer_collection.py
+++ b/tests/sample/elements/layers/test_layer_collection.py
@@ -7,21 +7,21 @@
import unittest
+from easyscience import global_object
+from numpy.testing import assert_equal
+
from easyreflectometry.sample.assemblies.repeating_multilayer import RepeatingMultilayer
from easyreflectometry.sample.elements.layers.layer import Layer
from easyreflectometry.sample.elements.layers.layer_collection import LayerCollection
from easyreflectometry.sample.elements.materials.material import Material
-from numpy.testing import assert_equal
class TestLayerCollection(unittest.TestCase):
def test_default(self):
p = LayerCollection()
- assert_equal(p.name, 'EasyLayers')
+ assert_equal(p.name, 'EasyLayerCollection')
assert_equal(p.interface, None)
- assert_equal(len(p), 2)
- assert_equal(p[0].name, 'EasyLayer')
- assert_equal(p[1].name, 'EasyLayer')
+ assert_equal(len(p), 0)
def test_from_pars(self):
m = Material(6.908, -0.278, 'Boron')
@@ -44,35 +44,31 @@ def test_from_pars_item(self):
assert_equal(layers.interface, None)
def test_dict_repr(self):
- p = LayerCollection()
+ p = LayerCollection(layers=[Layer(), Layer()])
assert p._dict_repr == {
- 'EasyLayers': [
+ 'EasyLayerCollection': [
{
'EasyLayer': {
- 'material': {
- 'EasyMaterial': {'sld': '4.186e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}
- },
- 'thickness': '10.000 angstrom',
- 'roughness': '3.300 angstrom',
+ 'material': {'EasyMaterial': {'sld': '4.186e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
+ 'thickness': '10.000 Å',
+ 'roughness': '3.300 Å',
}
},
{
'EasyLayer': {
- 'material': {
- 'EasyMaterial': {'sld': '4.186e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}
- },
- 'thickness': '10.000 angstrom',
- 'roughness': '3.300 angstrom',
+ 'material': {'EasyMaterial': {'sld': '4.186e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
+ 'thickness': '10.000 Å',
+ 'roughness': '3.300 Å',
}
},
]
}
def test_repr(self):
- p = LayerCollection()
+ p = LayerCollection([Layer(), Layer()])
assert (
p.__repr__()
- == '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
+ == 'EasyLayerCollection:\n- EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n- EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n' # noqa: E501
)
def test_dict_round_trip(self):
@@ -84,9 +80,11 @@ def test_dict_round_trip(self):
r = LayerCollection()
r.insert(0, p)
r.append(q)
+ r_dict = r.as_dict()
+ global_object.map._clear()
# Then
- s = LayerCollection.from_dict(r.as_dict())
+ s = LayerCollection.from_dict(r_dict)
# Expect
- assert s.as_data_dict() == r.as_data_dict()
+ assert sorted(r.as_data_dict()) == sorted(s.as_data_dict())
diff --git a/tests/sample/elements/materials/test_material.py b/tests/sample/elements/materials/test_material.py
index f5c39967..0d836037 100644
--- a/tests/sample/elements/materials/test_material.py
+++ b/tests/sample/elements/materials/test_material.py
@@ -9,6 +9,8 @@
import unittest
import numpy as np
+from easyscience import global_object
+
from easyreflectometry.parameter_utils import get_as_parameter
from easyreflectometry.sample.elements.materials.material import DEFAULTS
from easyreflectometry.sample.elements.materials.material import Material
@@ -20,14 +22,14 @@ def test_no_arguments(self):
assert p.name == 'EasyMaterial'
assert p.interface is None
assert p.sld.display_name == 'sld'
- assert str(p.sld.unit) == '1 / angstrom ** 2'
- assert p.sld.value.value.magnitude == 4.186
+ assert str(p.sld.unit) == '1/Å^2'
+ assert p.sld.value == 4.186
assert p.sld.min == -np.Inf
assert p.sld.max == np.Inf
assert p.sld.fixed is True
assert p.isld.display_name == 'isld'
- assert str(p.isld.unit) == '1 / angstrom ** 2'
- assert p.isld.value.value.magnitude == 0.0
+ assert str(p.isld.unit) == '1/Å^2'
+ assert p.isld.value == 0.0
assert p.isld.min == -np.Inf
assert p.isld.max == np.Inf
assert p.isld.fixed is True
@@ -37,14 +39,14 @@ def test_shuffled_arguments(self):
assert p.name == 'Boron'
assert p.interface is None
assert p.sld.display_name == 'sld'
- assert str(p.sld.unit) == '1 / angstrom ** 2'
- assert p.sld.value.value.magnitude == 6.908
+ assert str(p.sld.unit) == '1/Å^2'
+ assert p.sld.value == 6.908
assert p.sld.min == -np.Inf
assert p.sld.max == np.Inf
assert p.sld.fixed is True
assert p.isld.display_name == 'isld'
- assert str(p.isld.unit) == '1 / angstrom ** 2'
- assert p.isld.value.value.magnitude == -0.278
+ assert str(p.isld.unit) == '1/Å^2'
+ assert p.isld.value == -0.278
assert p.isld.min == -np.Inf
assert p.isld.max == np.Inf
assert p.isld.fixed is True
@@ -52,8 +54,8 @@ def test_shuffled_arguments(self):
def test_only_sld_key(self):
p = Material(sld=10)
assert p.sld.display_name == 'sld'
- assert str(p.sld.unit) == '1 / angstrom ** 2'
- assert p.sld.value.value.magnitude == 10
+ assert str(p.sld.unit) == '1/Å^2'
+ assert p.sld.value == 10
assert p.sld.min == -np.Inf
assert p.sld.max == np.Inf
assert p.sld.fixed is True
@@ -62,14 +64,14 @@ def test_only_sld_key_parameter(self):
sld = get_as_parameter('sld', 10, DEFAULTS)
sld.min = -10.0
p = Material(sld=sld)
- assert p.sld.value.value.magnitude == 10
+ assert p.sld.value == 10
assert p.sld.min == -10
def test_only_isld_key(self):
p = Material(isld=10)
assert p.isld.display_name == 'isld'
- assert str(p.isld.unit) == '1 / angstrom ** 2'
- assert p.isld.value.value.magnitude == 10
+ assert str(p.isld.unit) == '1/Å^2'
+ assert p.isld.value == 10
assert p.isld.min == -np.Inf
assert p.isld.max == np.Inf
assert p.isld.fixed is True
@@ -78,18 +80,22 @@ def test_only_isld_key_parameter(self):
isld = get_as_parameter('isld', 10, DEFAULTS)
isld.min = -10.0
p = Material(isld=isld)
- assert p.isld.value.value.magnitude == 10
+ assert p.isld.value == 10
assert p.isld.min == -10
def test_dict_repr(self):
p = Material()
- assert p._dict_repr == {'EasyMaterial': {'sld': '4.186e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}}
+ assert p._dict_repr == {'EasyMaterial': {'sld': '4.186e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}}
def test_repr(self):
p = Material()
- assert p.__repr__() == 'EasyMaterial:\n sld: 4.186e-6 1 / angstrom ** 2\n isld: 0.000e-6 1 / angstrom ** 2\n'
+ assert p.__repr__() == 'EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n'
def test_dict_round_trip(self):
p = Material()
- q = Material.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ q = Material.from_dict(p_dict)
+
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/elements/materials/test_material_collection.py b/tests/sample/elements/materials/test_material_collection.py
index 1374dd6e..cdfc47b0 100644
--- a/tests/sample/elements/materials/test_material_collection.py
+++ b/tests/sample/elements/materials/test_material_collection.py
@@ -7,11 +7,13 @@
import unittest
+from easyscience import global_object
+
from easyreflectometry.sample.elements.materials.material import Material
from easyreflectometry.sample.elements.materials.material_collection import MaterialCollection
-class TestLayerCollection(unittest.TestCase):
+class TestMaterialCollection(unittest.TestCase):
def test_default(self):
p = MaterialCollection()
assert p.name == 'EasyMaterials'
@@ -40,16 +42,17 @@ def test_dict_repr(self):
p = MaterialCollection()
assert p._dict_repr == {
'EasyMaterials': [
- {'EasyMaterial': {'isld': '0.000e-6 1 / angstrom ** 2', 'sld': '4.186e-6 1 / angstrom ** 2'}},
- {'EasyMaterial': {'isld': '0.000e-6 1 / angstrom ** 2', 'sld': '4.186e-6 1 / angstrom ** 2'}},
+ {'EasyMaterial': {'isld': '0.000e-6 1/Å^2', 'sld': '4.186e-6 1/Å^2'}},
+ {'EasyMaterial': {'isld': '0.000e-6 1/Å^2', 'sld': '4.186e-6 1/Å^2'}},
]
}
def test_repr(self):
p = MaterialCollection()
+ p.__repr__()
assert (
p.__repr__()
- == 'EasyMaterials:\n- EasyMaterial:\n sld: 4.186e-6 1 / angstrom ** 2\n isld: 0.000e-6 1 / angstrom ** 2\n- EasyMaterial:\n sld: 4.186e-6 1 / angstrom ** 2\n isld: 0.000e-6 1 / angstrom ** 2\n' # noqa: E501
+ == 'EasyMaterials:\n- EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n- EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n' # noqa: E501
)
def test_dict_round_trip(self):
@@ -59,9 +62,11 @@ def test_dict_round_trip(self):
p = MaterialCollection()
p.insert(0, m)
p.append(k)
+ p_dict = p.as_dict()
+ global_object.map._clear()
# Then
- q = MaterialCollection.from_dict(p.as_dict())
+ q = MaterialCollection.from_dict(p_dict)
# Expect
- assert p.as_data_dict() == q.as_data_dict()
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/elements/materials/test_material_density.py b/tests/sample/elements/materials/test_material_density.py
index 864d094a..cde67369 100644
--- a/tests/sample/elements/materials/test_material_density.py
+++ b/tests/sample/elements/materials/test_material_density.py
@@ -1,9 +1,11 @@
import unittest
import numpy as np
-from easyreflectometry.sample.elements.materials.material_density import MaterialDensity
+from easyscience import global_object
from numpy.testing import assert_almost_equal
+from easyreflectometry.sample.elements.materials.material_density import MaterialDensity
+
class TestMaterialDensity(unittest.TestCase):
def test_default(self):
@@ -11,47 +13,51 @@ def test_default(self):
assert p.name == 'EasyMaterialDensity'
assert p.interface is None
assert p.density.display_name == 'density'
- assert str(p.density.unit) == 'gram / centimeter ** 3'
- assert p.density.value.value.magnitude == 2.33
+ assert str(p.density.unit) == 'kg/L'
+ assert p.density.value == 2.33
assert p.density.min == 0
assert p.density.max == np.Inf
assert p.density.fixed is True
def test_default_constraint(self):
p = MaterialDensity()
- assert p.density.value.value.magnitude == 2.33
- assert_almost_equal(p.sld.value.value.magnitude, 2.073705382)
+ assert p.density.value == 2.33
+ assert_almost_equal(p.sld.value, 2.073705382)
p.density.value = 2
- assert_almost_equal(p.sld.value.value.magnitude, 1.780004619)
+ assert_almost_equal(p.sld.value, 1.780004619)
def test_from_pars(self):
p = MaterialDensity('Co', 8.9, 'Cobalt')
- assert p.density.value.value.magnitude == 8.9
- assert_almost_equal(p.sld.value.value.magnitude, 2.2645412328256)
+ assert p.density.value == 8.9
+ assert_almost_equal(p.sld.value, 2.2645412328256)
assert p.chemical_structure == 'Co'
def test_chemical_structure_change(self):
p = MaterialDensity('Co', 8.9, 'Cobolt')
- assert p.density.value.value.magnitude == 8.9
- assert_almost_equal(p.sld.value.value.magnitude, 2.2645412328256)
- assert_almost_equal(p.isld.value.value.magnitude, 0.0)
+ assert p.density.value == 8.9
+ assert_almost_equal(p.sld.value, 2.2645412328256)
+ assert_almost_equal(p.isld.value, 0.0)
assert p.chemical_structure == 'Co'
p.chemical_structure = 'B'
- assert p.density.value.value.magnitude == 8.9
- assert_almost_equal(p.sld.value.value.magnitude, 4.820107844970)
- assert_almost_equal(p.isld.value.value.magnitude, -0.19098540517806603)
+ assert p.density.value == 8.9
+ assert_almost_equal(p.sld.value, 4.820107844970)
+ assert_almost_equal(p.isld.value, -0.19098540517806603)
assert p.chemical_structure == 'B'
def test_dict_repr(self):
p = MaterialDensity()
print(p._dict_repr)
assert p._dict_repr == {
- 'EasyMaterialDensity': {'sld': '2.074e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'},
+ 'EasyMaterialDensity': {'sld': '2.074e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'},
'chemical_structure': 'Si',
- 'density': '2.33e+00 gram / centimeter ** 3',
+ 'density': '2.33e+00 kg/L',
}
def test_dict_round_trip(self):
p = MaterialDensity()
- q = MaterialDensity.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ q = MaterialDensity.from_dict(p_dict)
+
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/sample/elements/materials/test_material_mixture.py b/tests/sample/elements/materials/test_material_mixture.py
index 18f8bb7f..9a8db8e2 100644
--- a/tests/sample/elements/materials/test_material_mixture.py
+++ b/tests/sample/elements/materials/test_material_mixture.py
@@ -1,133 +1,141 @@
-import unittest
from unittest.mock import MagicMock
+from easyscience import global_object
+from numpy.testing import assert_almost_equal
+
from easyreflectometry.sample.elements.materials.material import Material
from easyreflectometry.sample.elements.materials.material_mixture import MaterialMixture
-from numpy.testing import assert_almost_equal
-class TestMaterialMixture(unittest.TestCase):
- def test_default(self):
- p = MaterialMixture()
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert p.sld == Material().sld.raw_value
- assert p.isld == Material().isld.raw_value
- assert str(p._sld.unit) == '1 / angstrom ** 2'
- assert str(p._isld.unit) == '1 / angstrom ** 2'
-
- def test_default_constraint(self):
- p = MaterialMixture()
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert p.sld == Material().sld.raw_value
- assert p.isld == Material().isld.raw_value
- p.material_a.sld.value = 0
- p.material_b.isld.value = -1
- assert_almost_equal(p.sld, 2.093)
- assert_almost_equal(p.isld, -0.5)
- assert str(p._sld.unit) == '1 / angstrom ** 2'
- assert str(p._isld.unit) == '1 / angstrom ** 2'
+class TestMaterialMixture:
+ def test_default(self) -> None:
+ material_mixture = MaterialMixture()
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 4.186)
+ assert_almost_equal(material_mixture.isld, 0)
+ assert str(material_mixture._sld.unit) == '1/Å^2'
+ assert str(material_mixture._isld.unit) == '1/Å^2'
+
+ def test_default_constraint(self) -> None:
+ material_mixture = MaterialMixture()
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 4.186)
+ assert_almost_equal(material_mixture.isld, 0)
+ material_mixture.material_a.sld.value = 0
+ material_mixture.material_b.isld.value = -1
+ assert_almost_equal(material_mixture.sld, 2.093)
+ assert_almost_equal(material_mixture.isld, -0.5)
+ assert str(material_mixture._sld.unit) == '1/Å^2'
+ assert str(material_mixture._isld.unit) == '1/Å^2'
def test_fraction_constraint(self):
p = Material()
q = Material(6.908, -0.278, 'Boron')
- r = MaterialMixture(p, q, 0.2)
- assert r.fraction == 0.2
- assert_almost_equal(r.sld, 4.7304)
- assert_almost_equal(r.isld, -0.0556)
- r._fraction.value = 0.5
- assert r.fraction == 0.5
- assert_almost_equal(r.sld, 5.54700)
- assert_almost_equal(r.isld, -0.1390)
-
- def test_material_a_change(self):
- p = MaterialMixture()
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert p.sld == Material().sld.raw_value
- assert p.isld == Material().isld.raw_value
+ material_mixture = MaterialMixture(p, q, 0.2)
+ assert material_mixture.fraction == 0.2
+ assert_almost_equal(material_mixture.sld, 4.7304)
+ assert_almost_equal(material_mixture.isld, -0.0556)
+ material_mixture._fraction.value = 0.5
+ assert material_mixture.fraction == 0.5
+ assert_almost_equal(material_mixture.sld, 5.54700)
+ assert_almost_equal(material_mixture.isld, -0.1390)
+
+ def test_material_a_change(self) -> None:
+ material_mixture = MaterialMixture()
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 4.186)
+ assert_almost_equal(material_mixture.isld, 0)
q = Material(6.908, -0.278, 'Boron')
- p.material_a = q
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert_almost_equal(p.sld, 5.54700)
- assert_almost_equal(p.isld, -0.1390)
+ material_mixture.material_a = q
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 5.54700)
+ assert_almost_equal(material_mixture.isld, -0.1390)
- def test_material_b_change(self):
- p = MaterialMixture()
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert p.sld == Material().sld.raw_value
- assert p.isld == Material().isld.raw_value
+ def test_material_b_change(self) -> None:
+ material_mixture = MaterialMixture()
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 4.186)
+ assert_almost_equal(material_mixture.isld, 0)
q = Material(6.908, -0.278, 'Boron')
- p.material_b = q
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert_almost_equal(p.sld, 5.54700)
- assert_almost_equal(p.isld, -0.1390)
+ material_mixture.material_b = q
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 5.54700)
+ assert_almost_equal(material_mixture.isld, -0.1390)
- def test_material_b_change_double(self):
- p = MaterialMixture()
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert p.sld == Material().sld.raw_value
- assert p.isld == Material().isld.raw_value
+ def test_material_b_change_double(self) -> None:
+ material_mixture = MaterialMixture()
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 4.186)
+ assert_almost_equal(material_mixture.isld, 0)
q = Material(6.908, -0.278, 'Boron')
- p.material_b = q
- assert p.name == 'EasyMaterial/Boron'
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert_almost_equal(p.sld, 5.54700)
- assert_almost_equal(p.isld, -0.1390)
+ material_mixture.material_b = q
+ assert material_mixture.name == 'EasyMaterial/Boron'
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 5.54700)
+ assert_almost_equal(material_mixture.isld, -0.1390)
r = Material(0.00, 0.00, 'ACMW')
- p.material_b = r
- assert p.name == 'EasyMaterial/ACMW'
- assert p.fraction == 0.5
- assert str(p._fraction.unit) == 'dimensionless'
- assert_almost_equal(p.sld, 2.0930)
- assert_almost_equal(p.isld, 0.0000)
+ material_mixture.material_b = r
+ assert material_mixture.name == 'EasyMaterial/ACMW'
+ assert material_mixture.fraction == 0.5
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 2.0930)
+ assert_almost_equal(material_mixture.isld, 0.0000)
def test_from_pars(self):
p = Material()
q = Material(6.908, -0.278, 'Boron')
- r = MaterialMixture(p, q, 0.2)
- assert r.fraction == 0.2
- assert str(r._fraction.unit) == 'dimensionless'
- assert_almost_equal(r.sld, 4.7304)
- assert_almost_equal(r.isld, -0.0556)
- assert str(r._sld.unit) == '1 / angstrom ** 2'
- assert str(r._isld.unit) == '1 / angstrom ** 2'
-
- def test_dict_repr(self):
- p = MaterialMixture()
- assert p._dict_repr == {
+ material_mixture = MaterialMixture(p, q, 0.2)
+ assert material_mixture.fraction == 0.2
+ assert str(material_mixture._fraction.unit) == 'dimensionless'
+ assert_almost_equal(material_mixture.sld, 4.7304)
+ assert_almost_equal(material_mixture.isld, -0.0556)
+ assert str(material_mixture._sld.unit) == '1/Å^2'
+ assert str(material_mixture._isld.unit) == '1/Å^2'
+
+ def test_dict_repr(self) -> None:
+ material_mixture = MaterialMixture()
+ assert material_mixture._dict_repr == {
'EasyMaterial/EasyMaterial': {
'fraction': '0.500 dimensionless',
- 'sld': '4.186e-6 1 / angstrom ** 2',
- 'isld': '0.000e-6 1 / angstrom ** 2',
- 'material_a': {'EasyMaterial': {'sld': '4.186e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}},
- 'material_b': {'EasyMaterial': {'sld': '4.186e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}},
+ 'sld': '4.186e-6 1/Å^2',
+ 'isld': '0.000e-6 1/Å^2',
+ 'material_a': {'EasyMaterial': {'sld': '4.186e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
+ 'material_b': {'EasyMaterial': {'sld': '4.186e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
}
}
- def test_dict_round_trip(self):
+ def test_dict_round_trip(self) -> None:
+ # When
p = MaterialMixture()
- q = MaterialMixture.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ p_dict = p.as_dict()
+ global_object.map._clear()
- def test_update_name(self):
+ # Then
+ q = MaterialMixture.from_dict(p_dict)
+
+ # Expect
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
+
+ def test_update_name(self) -> None:
# When
- p = MaterialMixture()
+ material_mixture = MaterialMixture()
mock_material_a = MagicMock()
mock_material_a.name = 'name_a'
- p._material_a = mock_material_a
+ material_mixture._material_a = mock_material_a
mock_material_b = MagicMock()
mock_material_b.name = 'name_b'
- p._material_b = mock_material_b
+ material_mixture._material_b = mock_material_b
# Then
- p._update_name()
+ material_mixture._update_name()
# Expect
- assert p.name == 'name_a/name_b'
+ assert material_mixture.name == 'name_a/name_b'
diff --git a/tests/sample/elements/materials/test_material_solvated.py b/tests/sample/elements/materials/test_material_solvated.py
index 15795660..4fe90cd7 100644
--- a/tests/sample/elements/materials/test_material_solvated.py
+++ b/tests/sample/elements/materials/test_material_solvated.py
@@ -1,11 +1,13 @@
from unittest.mock import MagicMock
+import pytest
+from easyscience import global_object
+from easyscience.Objects.new_variable import Parameter
+
import easyreflectometry.sample.elements.materials.material_mixture
import easyreflectometry.sample.elements.materials.material_solvated
-import pytest
from easyreflectometry.sample.elements.materials.material import Material
from easyreflectometry.sample.elements.materials.material_solvated import MaterialSolvated
-from easyscience.Objects.ObjectClasses import Parameter
class TestMaterialSolvated:
@@ -14,7 +16,7 @@ def material_solvated(self, monkeypatch) -> MaterialSolvated:
self.material = Material(sld=1.0, isld=0, name='material')
self.solvent = Material(sld=2.0, isld=0, name='solvent')
self.mock_solvent_fraction = MagicMock(spec=Parameter)
- self.mock_solvent_fraction.raw_value = 0.1
+ self.mock_solvent_fraction.value = 0.1
self.mock_interface = MagicMock()
self.mock_Parameter = MagicMock()
self.mock_FunctionalConstraint = MagicMock()
@@ -109,17 +111,21 @@ def test_dict_repr(self) -> None:
assert p._dict_repr == {
'D2O in H2O': {
'solvent_fraction': '0.200 dimensionless',
- 'sld': '4.976e-6 1 / angstrom ** 2',
- 'isld': '0.000e-6 1 / angstrom ** 2',
- 'material': {'D2O': {'sld': '6.360e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}},
- 'solvent': {'H2O': {'sld': '-0.561e-6 1 / angstrom ** 2', 'isld': '0.000e-6 1 / angstrom ** 2'}},
+ 'sld': '4.976e-6 1/Å^2',
+ 'isld': '0.000e-6 1/Å^2',
+ 'material': {'D2O': {'sld': '6.360e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
+ 'solvent': {'H2O': {'sld': '-0.561e-6 1/Å^2', 'isld': '0.000e-6 1/Å^2'}},
}
}
def test_dict_round_trip(self):
p = MaterialSolvated()
- q = MaterialSolvated.from_dict(p.as_dict())
- assert p.as_data_dict() == q.as_data_dict()
+ p_dict = p.as_dict()
+ global_object.map._clear()
+
+ q = MaterialSolvated.from_dict(p_dict)
+
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
def test_update_name(self, material_solvated: MaterialSolvated) -> None:
# When
diff --git a/tests/sample/test_sample.py b/tests/sample/test_sample.py
index a2c83213..0a916173 100644
--- a/tests/sample/test_sample.py
+++ b/tests/sample/test_sample.py
@@ -7,6 +7,9 @@
import unittest
+from easyscience import global_object
+from numpy.testing import assert_equal
+
from easyreflectometry.sample import Layer
from easyreflectometry.sample import LayerCollection
from easyreflectometry.sample import Material
@@ -14,7 +17,6 @@
from easyreflectometry.sample import RepeatingMultilayer
from easyreflectometry.sample import Sample
from easyreflectometry.sample import SurfactantLayer
-from numpy.testing import assert_equal
class TestSample(unittest.TestCase):
@@ -60,7 +62,7 @@ def test_repr(self):
p = Sample()
assert (
p.__repr__()
- == '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
+ == 'EasySample:\n- EasyMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n- EasyMultilayer:\n EasyLayerCollection:\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n - EasyLayer:\n material:\n EasyMaterial:\n sld: 4.186e-6 1/Å^2\n isld: 0.000e-6 1/Å^2\n thickness: 10.000 Å\n roughness: 3.300 Å\n' # noqa: E501
)
def test_dict_round_trip(self):
@@ -72,9 +74,10 @@ def test_dict_round_trip(self):
p.append(multilayer)
repeating = RepeatingMultilayer()
p.append(repeating)
+ p_dict = p.as_dict()
+ global_object.map._clear()
# Then
- q = Sample.from_dict(p.as_dict())
+ q = Sample.from_dict(p_dict)
- # Expect
- assert p.as_data_dict() == q.as_data_dict()
+ assert sorted(p.as_data_dict()) == sorted(q.as_data_dict())
diff --git a/tests/special/test_calculations.py b/tests/special/test_calculations.py
index 45f9d0bf..3e3211a2 100644
--- a/tests/special/test_calculations.py
+++ b/tests/special/test_calculations.py
@@ -2,11 +2,12 @@
import unittest
+from numpy.testing import assert_almost_equal
+
from easyreflectometry.special.calculations import area_per_molecule_to_scattering_length_density
from easyreflectometry.special.calculations import molecular_weight
from easyreflectometry.special.calculations import neutron_scattering_length
from easyreflectometry.special.calculations import weighted_average
-from numpy.testing import assert_almost_equal
class TestMaterialMixture(unittest.TestCase):
diff --git a/tests/test_data.py b/tests/test_data.py
index eda39985..ded2107e 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -4,15 +4,16 @@
import os
import unittest
-import easyreflectometry
import numpy as np
-from easyreflectometry.data import _load_orso
-from easyreflectometry.data import _load_txt
-from easyreflectometry.data import load
from numpy.testing import assert_almost_equal
from orsopy.fileio import Header
from orsopy.fileio import load_orso
+import easyreflectometry
+from easyreflectometry.data import _load_orso
+from easyreflectometry.data import _load_txt
+from easyreflectometry.data import load
+
PATH_STATIC = os.path.join(os.path.dirname(easyreflectometry.__file__), '..', '..', 'tests' , '_static')
diff --git a/tests/test_fitting.py b/tests/test_fitting.py
index d92de5fd..42948feb 100644
--- a/tests/test_fitting.py
+++ b/tests/test_fitting.py
@@ -1,7 +1,9 @@
__author__ = 'github.com/arm61'
import os
-import unittest
+
+import pytest
+from easyscience.fitting.minimizers.factory import AvailableMinimizers
import easyreflectometry
from easyreflectometry.calculators import CalculatorFactory
@@ -16,43 +18,44 @@
PATH_STATIC = os.path.join(os.path.dirname(easyreflectometry.__file__), '..', '..', 'tests', '_static')
-class TestFitting(unittest.TestCase):
- def test_fitting(self):
- fpath = os.path.join(PATH_STATIC, 'example.ort')
- data = load(fpath)
- si = Material(2.07, 0, 'Si')
- sio2 = Material(3.47, 0, 'SiO2')
- film = Material(2.0, 0, 'Film')
- d2o = Material(6.36, 0, 'D2O')
- si_layer = Layer(si, 0, 0, 'Si layer')
- sio2_layer = Layer(sio2, 30, 3, 'SiO2 layer')
- film_layer = Layer(film, 250, 3, 'Film Layer')
- superphase = Layer(d2o, 0, 3, 'D2O Subphase')
- sample = Sample(
- si_layer,
- sio2_layer,
- film_layer,
- superphase,
- name='Film Structure',
- )
- resolution_function = PercentageFhwm(0.02)
- model = Model(sample, 1, 1e-6, resolution_function, 'Film Model')
- # Thicknesses
- sio2_layer.thickness.bounds = (15, 50)
- film_layer.thickness.bounds = (200, 300)
- # Roughnesses
- sio2_layer.roughness.bounds = (1, 15)
- film_layer.roughness.bounds = (1, 15)
- superphase.roughness.bounds = (1, 15)
- # Scattering length density
- film.sld.bounds = (0.1, 3)
- # Background
- model.background.bounds = (1e-7, 1e-5)
- # Scale
- model.scale.bounds = (0.5, 1.5)
- interface = CalculatorFactory()
- model.interface = interface
- fitter = Fitter(model)
- analysed = fitter.fit(data)
- assert 'R_0_model' in analysed.keys()
- assert 'SLD_0' in analysed.keys()
+@pytest.mark.parametrize('minimizer', [AvailableMinimizers.Bumps, AvailableMinimizers.DFO, AvailableMinimizers.LMFit])
+def test_fitting(minimizer):
+ fpath = os.path.join(PATH_STATIC, 'example.ort')
+ data = load(fpath)
+ si = Material(2.07, 0, 'Si')
+ sio2 = Material(3.47, 0, 'SiO2')
+ film = Material(2.0, 0, 'Film')
+ d2o = Material(6.36, 0, 'D2O')
+ si_layer = Layer(si, 0, 0, 'Si layer')
+ sio2_layer = Layer(sio2, 30, 3, 'SiO2 layer')
+ film_layer = Layer(film, 250, 3, 'Film Layer')
+ superphase = Layer(d2o, 0, 3, 'D2O Subphase')
+ sample = Sample(
+ si_layer,
+ sio2_layer,
+ film_layer,
+ superphase,
+ name='Film Structure',
+ )
+ resolution_function = PercentageFhwm(0.02)
+ model = Model(sample, 1, 1e-6, resolution_function, 'Film Model')
+ # Thicknesses
+ sio2_layer.thickness.bounds = (15, 50)
+ film_layer.thickness.bounds = (200, 300)
+ # Roughnesses
+ sio2_layer.roughness.bounds = (1, 15)
+ film_layer.roughness.bounds = (1, 15)
+ superphase.roughness.bounds = (1, 15)
+ # Scattering length density
+ film.sld.bounds = (0.1, 3)
+ # Background
+ model.background.bounds = (1e-7, 1e-5)
+ # Scale
+ model.scale.bounds = (0.5, 1.5)
+ interface = CalculatorFactory()
+ model.interface = interface
+ fitter = Fitter(model)
+ fitter.easy_f.switch_minimizer(minimizer)
+ analysed = fitter.fit(data)
+ assert 'R_0_model' in analysed.keys()
+ assert 'SLD_0' in analysed.keys()
diff --git a/tests/test_parameter_utils.py b/tests/test_parameter_utils.py
index 174a350a..910f4b4b 100644
--- a/tests/test_parameter_utils.py
+++ b/tests/test_parameter_utils.py
@@ -1,8 +1,9 @@
import numpy as np
import pytest
-from easyreflectometry.parameter_utils import get_as_parameter
from numpy.testing import assert_equal
+from easyreflectometry.parameter_utils import get_as_parameter
+
PARAMETER_DETAILS = {
'test_parameter': {
'description': 'Test parameter',
@@ -33,7 +34,7 @@ def test_get_as_parameter():
# Expected
test_parameter.name == 'test_parameter'
assert_equal(str(test_parameter.unit), 'dimensionless')
- assert_equal(test_parameter.raw_value, 1.0)
+ assert_equal(test_parameter.value, 1.0)
assert_equal(test_parameter.min, 0.0)
assert_equal(test_parameter.max, np.Inf)
assert_equal(test_parameter.fixed, True)
@@ -48,7 +49,7 @@ def test_get_as_parameter_from_float():
test_parameter = get_as_parameter('test_parameter', float(test_parameter), PARAMETER_DETAILS)
# Expected
- assert_equal(test_parameter.raw_value, 2.0)
+ assert_equal(test_parameter.value, 2.0)
def test_get_as_parameter_from_int():
@@ -59,7 +60,7 @@ def test_get_as_parameter_from_int():
test_parameter = get_as_parameter('test_parameter', int(test_parameter), PARAMETER_DETAILS)
# Expected
- assert_equal(test_parameter.raw_value, 2.0)
+ assert_equal(test_parameter.value, 2.0)
def test_get_as_parameter_from_parameter():
@@ -72,7 +73,7 @@ def test_get_as_parameter_from_parameter():
# Expected
test_parameter.name == 'test_parameter'
assert_equal(str(test_parameter.unit), 'dimensionless')
- assert_equal(test_parameter.raw_value, 10.0)
+ assert_equal(test_parameter.value, 10.0)
assert_equal(test_parameter.min, -10.0)
assert_equal(test_parameter.max, 10.0)
assert_equal(test_parameter.fixed, False)