diff --git a/RATapi/events.py b/RATapi/events.py index e6c7334e..1f62264f 100644 --- a/RATapi/events.py +++ b/RATapi/events.py @@ -57,11 +57,26 @@ def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventDat __event_callbacks[event_type].add(callback) -def clear() -> None: - """Clears all event callbacks.""" - __event_impl.clear() - for key in __event_callbacks: - __event_callbacks[key] = set() +def clear(key=None, callback=None) -> None: + """Clears all event callbacks or specific callback. + + Parameters + ---------- + callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None] + The callback for when the event is triggered. + + """ + if key is None and callback is None: + for key in __event_callbacks: + __event_callbacks[key] = set() + elif key is not None and callback is not None: + __event_callbacks[key].remove(callback) + + for value in __event_callbacks.values(): + if value: + break + else: + __event_impl.clear() dir_path = os.path.dirname(os.path.realpath(__file__)) diff --git a/RATapi/utils/plotting.py b/RATapi/utils/plotting.py index 946ab6df..84adf1b0 100644 --- a/RATapi/utils/plotting.py +++ b/RATapi/utils/plotting.py @@ -12,45 +12,6 @@ from RATapi.rat_core import PlotEventData, makeSLDProfileXY -class Figure: - """Creates a plotting figure.""" - - def __init__(self, row: int = 1, col: int = 1): - """Initializes the figure and the subplots. - - Parameters - ---------- - row : int, default: 1 - The number of rows in subplot - col : int, default: 1 - The number of columns in subplot - - """ - self._fig, self._ax = plt.subplots(row, col, num="Reflectivity Algorithms Toolbox (RAT)") - plt.show(block=False) - self._esc_pressed = False - self._close_clicked = False - self._fig.canvas.mpl_connect("key_press_event", self._process_button_press) - self._fig.canvas.mpl_connect("close_event", self._close) - - def wait_for_close(self): - """Waits for the user to close the figure - using the esc key. - """ - while not (self._esc_pressed or self._close_clicked): - plt.waitforbuttonpress(timeout=0.005) - plt.close(self._fig) - - def _process_button_press(self, event): - """Process the key_press_event.""" - if event.key == "escape": - self._esc_pressed = True - - def _close(self, _): - """Process the close_event.""" - self._close_clicked = True - - def plot_errorbars(ax: Axes, x: np.ndarray, y: np.ndarray, err: np.ndarray, one_sided: bool, color: str): """Plots the error bars. @@ -75,7 +36,7 @@ def plot_errorbars(ax: Axes, x: np.ndarray, y: np.ndarray, err: np.ndarray, one_ ax.scatter(x=x, y=y, s=3, marker="o", color=color) -def plot_ref_sld_helper(data: PlotEventData, fig: Optional[Figure] = None, delay: bool = True): +def plot_ref_sld_helper(data: PlotEventData, fig: Optional[plt.figure] = None, delay: bool = True): """Clears the previous plots and updates the ref and SLD plots. Parameters @@ -83,25 +44,31 @@ def plot_ref_sld_helper(data: PlotEventData, fig: Optional[Figure] = None, delay data : PlotEventData The plot event data that contains all the information to generate the ref and sld plots - fig : Figure, optional + fig : matplotlib.pyplot.figure, optional The figure class that has two subplots delay : bool, default: True Controls whether to delay 0.005s after plot is created Returns ------- - fig : Figure + fig : matplotlib.pyplot.figure The figure class that has two subplots """ - if fig is None: - fig = Figure(1, 2) - elif fig._ax.shape != (2,): - fig._fig.clf() - fig._ax = fig._fig.subplots(1, 2) + preserve_zoom = False - ref_plot = fig._ax[0] - sld_plot = fig._ax[1] + if fig is None: + fig = plt.subplots(1, 2)[0] + elif len(fig.axes) != 2: + fig.clf() + fig.subplots(1, 2) + fig.subplots_adjust(wspace=0.3) + + ref_plot = fig.axes[0] + sld_plot = fig.axes[1] + if ref_plot.lines and fig.canvas.toolbar is not None: + preserve_zoom = True + fig.canvas.toolbar.push_current() # Clears the previous plots ref_plot.cla() @@ -160,16 +127,18 @@ def plot_ref_sld_helper(data: PlotEventData, fig: Optional[Figure] = None, delay # Format the axis ref_plot.set_yscale("log") ref_plot.set_xscale("log") - ref_plot.set_xlabel("Qz") - ref_plot.set_ylabel("Ref") + ref_plot.set_xlabel("$Q_{z} (\u00c5^{-1})$") + ref_plot.set_ylabel("Reflectivity") ref_plot.legend() ref_plot.grid() - sld_plot.set_xlabel("Z") - sld_plot.set_ylabel("SLD") + sld_plot.set_xlabel("$Z (\u00c5)$") + sld_plot.set_ylabel("$SLD (\u00c5^{-2})$") sld_plot.legend() sld_plot.grid() + if preserve_zoom: + fig.canvas.toolbar.back() if delay: plt.pause(0.005) @@ -204,8 +173,52 @@ def plot_ref_sld( data.subRoughs = results.contrastParams.subRoughs data.resample = RATapi.inputs.make_resample(project) - figure = Figure(1, 2) + figure = plt.subplots(1, 2)[0] plot_ref_sld_helper(data, figure) - if block: - figure.wait_for_close() + + plt.show(block=block) + + +class LivePlot: + """Creates a plot that gets updates from the plot event during a + calculation + + Parameters + ---------- + block : bool, default: False + Indicates the plot should block until it is closed + + """ + + def __init__(self, block=False): + self.block = block + self.closed = False + + def __enter__(self): + self.figure = plt.subplots(1, 2)[0] + self.figure.canvas.mpl_connect("close_event", self._setCloseState) + self.figure.show() + RATapi.events.register(RATapi.events.EventTypes.Plot, self.plotEvent) + + return self.figure + + def _setCloseState(self, _): + """Close event handler""" + self.closed = True + + def plotEvent(self, event): + """Callback for the plot event. + + Parameters + ---------- + event: PlotEventData + The plot event data. + """ + if not self.closed and self.figure.number in plt.get_fignums(): + plot_ref_sld_helper(event, self.figure) + + def __exit__(self, _exc_type, _exc_val, _traceback): + RATapi.events.clear(RATapi.events.EventTypes.Plot, self.plotEvent) + if not self.closed and self.figure.number in plt.get_fignums(): + plt.show(block=self.block) diff --git a/cpp/RAT b/cpp/RAT index a3efb07c..3f2462a8 160000 --- a/cpp/RAT +++ b/cpp/RAT @@ -1 +1 @@ -Subproject commit a3efb07c442f917b166392b569fdcac55201e4c8 +Subproject commit 3f2462a80471a2daa896553cb3ec673ed0777fee diff --git a/cpp/rat.cpp b/cpp/rat.cpp index 8a633056..9a135861 100644 --- a/cpp/rat.cpp +++ b/cpp/rat.cpp @@ -192,19 +192,25 @@ class EventBridge }; py::list unpackDataToCell(int rows, int cols, double* data, double* nData, - double* data2, double* nData2, int dataCol) + double* data2, double* nData2, bool isOutput2D=false) { py::list allResults; - int dims[2] = {0, dataCol}; + int dims[2] = {0, 0}; int offset = 0; for (int i = 0; i < rows; i++){ - py::list rowList; - dims[0] = (int)nData[i] / dataCol; + dims[0] = (int)nData[2*i]; + dims[1] = (int)nData[2*i+1]; auto result = py::array_t({dims[0], dims[1]}); std::memcpy(result.request().ptr, data + offset, result.nbytes()); offset += result.size(); - rowList.append(result); - allResults.append(rowList); + if (isOutput2D){ + py::list rowList; + rowList.append(result); + allResults.append(rowList); + } + else{ + allResults.append(result); + } } if (data2 != NULL && nData2 != NULL) @@ -212,7 +218,8 @@ class EventBridge // This is used to unpack the domains data into the second column offset = 0; for ( int i = 0; i < rows; i++){ - dims[0] = (int)nData2[i] / dataCol; + dims[0] = (int)nData2[2*i]; + dims[1] = (int)nData2[2*i+1]; auto result = py::array_t({dims[0], dims[1]}); std::memcpy(result.request().ptr, data2 + offset, result.nbytes()); offset += result.size(); @@ -252,18 +259,18 @@ class EventBridge std::memcpy(eventData.dataPresent.request().ptr, pEvent->data->dataPresent, eventData.dataPresent.nbytes()); eventData.reflectivity = unpackDataToCell(pEvent->data->nContrast, 1, - pEvent->data->reflect, pEvent->data->nReflect, NULL, NULL, 2); + pEvent->data->reflect, pEvent->data->nReflect, NULL, NULL); eventData.shiftedData = unpackDataToCell(pEvent->data->nContrast, 1, - pEvent->data->shiftedData, pEvent->data->nShiftedData, NULL, NULL, 3); + pEvent->data->shiftedData, pEvent->data->nShiftedData, NULL, NULL); eventData.sldProfiles = unpackDataToCell(pEvent->data->nContrast, (pEvent->data->nSldProfiles2 == NULL) ? 1 : 2, pEvent->data->sldProfiles, pEvent->data->nSldProfiles, - pEvent->data->sldProfiles2, pEvent->data->nSldProfiles2, 2); - + pEvent->data->sldProfiles2, pEvent->data->nSldProfiles2, true); + eventData.resampledLayers = unpackDataToCell(pEvent->data->nContrast, (pEvent->data->nLayers2 == NULL) ? 1 : 2, - pEvent->data->layers, pEvent->data->nLayers, - pEvent->data->layers2, pEvent->data->nLayers, 2); + pEvent->data->layers, pEvent->data->nLayers, + pEvent->data->layers2, pEvent->data->nLayers2, true); this->callback(event.type, eventData); } }; diff --git a/tests/conftest.py b/tests/conftest.py index ca6f4b48..8d2ceb1f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,6 +6,254 @@ import RATapi.rat_core +@pytest.fixture +def input_project(): + """A cut-down version of the input Project object for a reflectivity calculation set out in + "DSPC_standard_layers.py". + """ + project = RATapi.Project( + name="original_dspc_bilayer", + calculation="non polarised", + model="standard layers", + geometry="substrate/liquid", + absorption=False, + ) + + # Set up the relevant parameters + project.parameters.append( + name="Oxide Thickness", + min=5.0, + value=19.54, + max=60.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="Oxide SLD", + min=3.39e-06, + value=3.39e-06, + max=3.41e-06, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="SAM Tails Thickness", + min=15.0, + value=22.66, + max=40.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="SAM Tails SLD", + min=-5e-07, + value=-4.01e-07, + max=-3e-07, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="SAM Tails Hydration", + min=1.0, + value=5.252, + max=50.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="SAM Roughness", + min=1.0, + value=5.64, + max=15.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="CW Thickness", + min=10.0, + value=17.12, + max=28.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="CW SLD", + min=0.0, + value=0.0, + max=1e-09, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="SAM Heads Thickness", + min=5.0, + value=8.56, + max=17.0, + fit=True, + prior_type="gaussian", + mu=10.0, + sigma=2.0, + ) + project.parameters.append( + name="SAM Heads SLD", + min=1.0e-07, + value=1.75e-06, + max=2.0e-06, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="SAM Heads Hydration", + min=10.0, + value=45.45, + max=50.0, + fit=True, + prior_type="uniform", + mu=30.0, + sigma=3.0, + ) + project.parameters.append( + name="Bilayer Heads Thickness", + min=7.0, + value=10.7, + max=17.0, + fit=True, + prior_type="gaussian", + mu=10.0, + sigma=2.0, + ) + project.parameters.append( + name="Bilayer Heads SLD", + min=5.0e-07, + value=1.47e-06, + max=1.5e-06, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="Bilayer Roughness", + min=2.0, + value=6.014, + max=15.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="Bilayer Tails Thickness", + min=14.0, + value=17.82, + max=22.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="Bilayer Tails SLD", + min=-5.0e-07, + value=-4.61e-07, + max=0.0, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="Bilayer Tails Hydration", + min=10.0, + value=17.64, + max=50.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="Bilayer Heads Hydration", + min=10.0, + value=36.15, + max=50.0, + fit=True, + prior_type="gaussian", + mu=30.0, + sigma=3.0, + ) + project.parameters.append( + name="CW Hydration", + min=99.9, + value=100.0, + max=100.0, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + project.parameters.append( + name="Oxide Hydration", + min=0.0, + value=23.61, + max=60.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + + project.parameters.set_fields(0, max=10) + + del project.bulk_in[0] + project.bulk_in.append(name="Silicon", min=2.0e-06, value=2.073e-06, max=2.1e-06, fit=False) + + del project.bulk_out[0] + project.bulk_out.append(name="D2O", min=5.50e-06, value=5.98e-06, max=6.4e-06, fit=True) + project.bulk_out.append(name="SMW", min=1.0e-06, value=2.21e-06, max=4.99e-06, fit=True) + + del project.scalefactors[0] + project.scalefactors.append(name="Scalefactor 1", min=0.05, value=0.10, max=0.2, fit=False) + project.scalefactors.append(name="Scalefactor 2", min=0.05, value=0.15, max=0.2, fit=False) + + del project.backgrounds[0] + del project.background_parameters[0] + project.background_parameters.append( + name="Background parameter D2O", + min=5.0e-10, + value=2.23e-06, + max=7.0e-06, + fit=True, + ) + project.background_parameters.append( + name="Background parameter SMW", + min=1.0e-10, + value=3.38e-06, + max=4.99e-06, + fit=True, + ) + + return project + + @pytest.fixture def reflectivity_calculation_output_results(): """The C++ results object for a reflectivity calculation of the project set out in "DSPC_standard_layers.py".""" diff --git a/tests/test_events.py b/tests/test_events.py index 99719ba3..185f7800 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -25,6 +25,11 @@ def test_event_register() -> None: [first_callback, second_callback] ) + RATapi.events.clear(RATapi.events.EventTypes.Message, second_callback) + result = RATapi.events.get_event_callback(RATapi.events.EventTypes.Message) + assert result == [first_callback] + result = RATapi.events.get_event_callback(RATapi.events.EventTypes.Plot) + assert result == [second_callback] RATapi.events.clear() assert RATapi.events.get_event_callback(RATapi.events.EventTypes.Plot) == [] assert RATapi.events.get_event_callback(RATapi.events.EventTypes.Message) == [] diff --git a/tests/test_plotting.py b/tests/test_plotting.py index 51939837..c21b634f 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -1,13 +1,13 @@ import os import pickle -import re from unittest.mock import MagicMock, patch import matplotlib.pyplot as plt import pytest -from RATapi.rat_core import PlotEventData -from RATapi.utils.plotting import Figure, plot_ref_sld_helper +from RATapi.events import notify +from RATapi.rat_core import EventTypes, PlotEventData +from RATapi.utils.plotting import LivePlot, plot_ref_sld, plot_ref_sld_helper TEST_DIR_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data") @@ -31,39 +31,38 @@ def data() -> PlotEventData: @pytest.fixture -def fig() -> Figure: +def fig() -> plt.figure: """Creates the fixture for the tests.""" plt.close("all") - figure = Figure(1, 3) - fig = plot_ref_sld_helper(fig=figure, data=data()) - return fig + figure = plt.subplots(1, 3)[0] + return plot_ref_sld_helper(fig=figure, data=data()) -def test_figure_axis_formating(fig: Figure) -> None: +def test_figure_axis_formating(fig: plt.figure) -> None: """Tests the axis formating of the figure.""" - ref_plot = fig._ax[0] - sld_plot = fig._ax[1] + ref_plot = fig.axes[0] + sld_plot = fig.axes[1] - assert fig._fig.axes[0].get_subplotspec().get_gridspec().get_geometry() == (1, 2) - assert fig._ax.shape == (2,) + assert fig.axes[0].get_subplotspec().get_gridspec().get_geometry() == (1, 2) + assert len(fig.axes) == 2 - assert ref_plot.get_xlabel() == "Qz" + assert ref_plot.get_xlabel() == "$Q_{z} (\u00c5^{-1})$" assert ref_plot.get_xscale() == "log" - assert ref_plot.get_ylabel() == "Ref" + assert ref_plot.get_ylabel() == "Reflectivity" assert ref_plot.get_yscale() == "log" assert [label._text for label in ref_plot.get_legend().texts] == ["ref 1", "ref 2", "ref 3"] - assert sld_plot.get_xlabel() == "Z" + assert sld_plot.get_xlabel() == "$Z (\u00c5)$" assert sld_plot.get_xscale() == "linear" - assert sld_plot.get_ylabel() == "SLD" + assert sld_plot.get_ylabel() == "$SLD (\u00c5^{-2})$" assert sld_plot.get_yscale() == "linear" assert [label._text for label in sld_plot.get_legend().texts] == ["sld 1", "sld 2", "sld 3"] -def test_figure_color_formating(fig: Figure) -> None: +def test_figure_color_formating(fig: plt.figure) -> None: """Tests the color formating of the figure.""" - ref_plot = fig._ax[0] - sld_plot = fig._ax[1] + ref_plot = fig.axes[0] + sld_plot = fig.axes[1] assert len(ref_plot.get_lines()) == 3 assert len(sld_plot.get_lines()) == 6 @@ -83,69 +82,42 @@ def test_figure_color_formating(fig: Figure) -> None: assert sld_plot.get_lines()[ax1].get_color() == sld_plot.get_lines()[ax2].get_color() -def test_eventhandlers_linked_to_figure(fig: Figure) -> None: - """Tests whether the eventhandlers for close_event - and key_press_event in the figure are linked to the - class methods. - """ - pattern = r"\(([^\]]+)\)" - index = 0 - - for ix, val in fig._fig.canvas.callbacks.callbacks["close_event"].items(): - if str(type(val)) == "": - index = ix - break - canvas_close_event_callback = fig._fig.canvas.callbacks.callbacks["close_event"][index]._func_ref.__repr__() - close_event_callback = re.findall(pattern, canvas_close_event_callback)[0] - assert close_event_callback == "_close" - assert hasattr(Figure, "_close") - - for ix, val in fig._fig.canvas.callbacks.callbacks["key_press_event"].items(): - if str(type(val)) == "": - index = ix - break - canvas_key_press_event_callback = fig._fig.canvas.callbacks.callbacks["key_press_event"][index]._func_ref.__repr__() - key_press_event_callback = re.findall(pattern, canvas_key_press_event_callback)[0] - assert key_press_event_callback == "_process_button_press" - assert hasattr(Figure, "_process_button_press") - - -def test_eventhandler_variable_update(fig: Figure) -> None: - """Tests whether the eventhandlers for close_event - and key_press_event update variables that stop - while loop in wait_for_close. +@patch("RATapi.utils.plotting.makeSLDProfileXY") +def test_sld_profile_function_call(mock: MagicMock) -> None: + """Tests the makeSLDProfileXY function called with + correct args. """ - assert not fig._esc_pressed - on_key_mock_event = type("MockEvent", (object,), {"key": "escape"}) - fig._process_button_press(on_key_mock_event) - assert fig._esc_pressed - - assert not fig._close_clicked - fig._close("test") - assert fig._close_clicked - + plot_ref_sld_helper(data()) -@patch("RATapi.utils.plotting.plt.waitforbuttonpress") -def test_wait_for_close(mock: MagicMock, fig: Figure) -> None: - """Tests the _wait_for_close method stops the - while loop when _esc_pressed is True. - """ + assert mock.call_count == 3 + assert mock.call_args_list[0].args[0] == 2.07e-06 + assert mock.call_args_list[0].args[1] == 6.28e-06 + assert mock.call_args_list[0].args[2] == 0.0 + assert mock.call_args_list[0].args[4] == 82 + assert mock.call_args_list[0].args[5] == 1.0 - def mock_wait_for_button_press(timeout): - fig._esc_pressed = True + assert mock.call_args_list[1].args[0] == 2.07e-06 + assert mock.call_args_list[1].args[1] == 1.83e-06 + assert mock.call_args_list[1].args[2] == 0.0 + assert mock.call_args_list[1].args[4] == 128 + assert mock.call_args_list[1].args[5] == 1.0 - mock.side_effect = mock_wait_for_button_press - assert not fig._esc_pressed - fig.wait_for_close() - assert fig._esc_pressed + assert mock.call_args_list[2].args[0] == 2.07e-06 + assert mock.call_args_list[2].args[1] == -5.87e-07 + assert mock.call_args_list[2].args[2] == 0.0 + assert mock.call_args_list[2].args[4] == 153 + assert mock.call_args_list[2].args[5] == 1.0 @patch("RATapi.utils.plotting.makeSLDProfileXY") -def test_sld_profile_function_call(mock: MagicMock) -> None: - """Tests the makeSLDProfileXY function called with - correct args. - """ - plot_ref_sld_helper(data()) +def test_live_plot(mock: MagicMock) -> None: + plot_data = data() + + with LivePlot() as figure: + assert len(figure.axes) == 2 + notify(EventTypes.Plot, plot_data) + plt.close(figure) + notify(EventTypes.Plot, plot_data) assert mock.call_count == 3 assert mock.call_args_list[0].args[0] == 2.07e-06 @@ -165,3 +137,23 @@ def test_sld_profile_function_call(mock: MagicMock) -> None: assert mock.call_args_list[2].args[2] == 0.0 assert mock.call_args_list[2].args[4] == 153 assert mock.call_args_list[2].args[5] == 1.0 + + +@patch("RATapi.utils.plotting.plot_ref_sld_helper") +def test_plot_ref_sld(mock: MagicMock, input_project, reflectivity_calculation_results) -> None: + plot_ref_sld(input_project, reflectivity_calculation_results) + mock.assert_called_once() + data = mock.call_args[0][0] + figure = mock.call_args[0][1] + + assert figure.axes[0].get_subplotspec().get_gridspec().get_geometry() == (1, 2) + assert len(figure.axes) == 2 + + assert data.modelType == input_project.model + assert data.reflectivity == reflectivity_calculation_results.reflectivity + assert data.shiftedData == reflectivity_calculation_results.shiftedData + assert data.sldProfiles == reflectivity_calculation_results.sldProfiles + assert data.resampledLayers == reflectivity_calculation_results.resampledLayers + assert data.dataPresent.size == 0 + assert (data.subRoughs == reflectivity_calculation_results.contrastParams.subRoughs).all() + assert data.resample.size == 0 diff --git a/tests/test_run.py b/tests/test_run.py index ff0194e0..56e4354e 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -15,254 +15,6 @@ from tests.utils import check_results_equal -@pytest.fixture -def input_project(): - """A cut-down version of the input Project object for a reflectivity calculation set out in - "DSPC_standard_layers.py". - """ - project = RATapi.Project( - name="original_dspc_bilayer", - calculation="non polarised", - model="standard layers", - geometry="substrate/liquid", - absorption=False, - ) - - # Set up the relevant parameters - project.parameters.append( - name="Oxide Thickness", - min=5.0, - value=19.54, - max=60.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="Oxide SLD", - min=3.39e-06, - value=3.39e-06, - max=3.41e-06, - fit=False, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="SAM Tails Thickness", - min=15.0, - value=22.66, - max=40.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="SAM Tails SLD", - min=-5e-07, - value=-4.01e-07, - max=-3e-07, - fit=False, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="SAM Tails Hydration", - min=1.0, - value=5.252, - max=50.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="SAM Roughness", - min=1.0, - value=5.64, - max=15.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="CW Thickness", - min=10.0, - value=17.12, - max=28.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="CW SLD", - min=0.0, - value=0.0, - max=1e-09, - fit=False, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="SAM Heads Thickness", - min=5.0, - value=8.56, - max=17.0, - fit=True, - prior_type="gaussian", - mu=10.0, - sigma=2.0, - ) - project.parameters.append( - name="SAM Heads SLD", - min=1.0e-07, - value=1.75e-06, - max=2.0e-06, - fit=False, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="SAM Heads Hydration", - min=10.0, - value=45.45, - max=50.0, - fit=True, - prior_type="uniform", - mu=30.0, - sigma=3.0, - ) - project.parameters.append( - name="Bilayer Heads Thickness", - min=7.0, - value=10.7, - max=17.0, - fit=True, - prior_type="gaussian", - mu=10.0, - sigma=2.0, - ) - project.parameters.append( - name="Bilayer Heads SLD", - min=5.0e-07, - value=1.47e-06, - max=1.5e-06, - fit=False, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="Bilayer Roughness", - min=2.0, - value=6.014, - max=15.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="Bilayer Tails Thickness", - min=14.0, - value=17.82, - max=22.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="Bilayer Tails SLD", - min=-5.0e-07, - value=-4.61e-07, - max=0.0, - fit=False, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="Bilayer Tails Hydration", - min=10.0, - value=17.64, - max=50.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="Bilayer Heads Hydration", - min=10.0, - value=36.15, - max=50.0, - fit=True, - prior_type="gaussian", - mu=30.0, - sigma=3.0, - ) - project.parameters.append( - name="CW Hydration", - min=99.9, - value=100.0, - max=100.0, - fit=False, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - project.parameters.append( - name="Oxide Hydration", - min=0.0, - value=23.61, - max=60.0, - fit=True, - prior_type="uniform", - mu=0.0, - sigma=np.inf, - ) - - project.parameters.set_fields(0, max=10) - - del project.bulk_in[0] - project.bulk_in.append(name="Silicon", min=2.0e-06, value=2.073e-06, max=2.1e-06, fit=False) - - del project.bulk_out[0] - project.bulk_out.append(name="D2O", min=5.50e-06, value=5.98e-06, max=6.4e-06, fit=True) - project.bulk_out.append(name="SMW", min=1.0e-06, value=2.21e-06, max=4.99e-06, fit=True) - - del project.scalefactors[0] - project.scalefactors.append(name="Scalefactor 1", min=0.05, value=0.10, max=0.2, fit=False) - project.scalefactors.append(name="Scalefactor 2", min=0.05, value=0.15, max=0.2, fit=False) - - del project.backgrounds[0] - del project.background_parameters[0] - project.background_parameters.append( - name="Background parameter D2O", - min=5.0e-10, - value=2.23e-06, - max=7.0e-06, - fit=True, - ) - project.background_parameters.append( - name="Background parameter SMW", - min=1.0e-10, - value=3.38e-06, - max=4.99e-06, - fit=True, - ) - - return project - - @pytest.fixture def reflectivity_calculation_problem(): """The output C++ ProblemDefinition object for a reflectivity calculation of the project set out in