diff --git a/.github/workflows/run_ruff.yml b/.github/workflows/run_ruff.yml new file mode 100644 index 00000000..41b9e1ac --- /dev/null +++ b/.github/workflows/run_ruff.yml @@ -0,0 +1,18 @@ +name: Ruff + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + - uses: chartboost/ruff-action@v1 + with: + args: 'format --check' + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1f0386ae..5cab62d3 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,6 @@ docs/*.inv build/* dist/* *.whl + +# Local pre-commit hooks +.pre-commit-config.yaml diff --git a/RAT/__init__.py b/RAT/__init__.py index fe0d597d..98d87986 100644 --- a/RAT/__init__.py +++ b/RAT/__init__.py @@ -1,9 +1,12 @@ import os + +from RAT import models from RAT.classlist import ClassList -from RAT.project import Project from RAT.controls import set_controls +from RAT.project import Project from RAT.run import run -import RAT.models + +__all__ = ["ClassList", "Project", "run", "set_controls", "models"] dir_path = os.path.dirname(os.path.realpath(__file__)) -os.environ["RAT_PATH"] = os.path.join(dir_path, '') +os.environ["RAT_PATH"] = os.path.join(dir_path, "") diff --git a/RAT/classlist.py b/RAT/classlist.py index a1eb7dcd..7ec821dc 100644 --- a/RAT/classlist.py +++ b/RAT/classlist.py @@ -1,12 +1,14 @@ -"""The classlist module. Contains the ClassList class, which defines a list containing instances of a particular class. +"""The classlist module. Contains the ClassList class, which defines a list containing instances of a particular +class. """ import collections -from collections.abc import Iterable, Sequence import contextlib -import prettytable -from typing import Any, Union import warnings +from collections.abc import Iterable, Sequence +from typing import Any, Union + +import prettytable class ClassList(collections.UserList): @@ -31,7 +33,9 @@ class ClassList(collections.UserList): An instance, or list of instance(s), of the class to be used in this ClassList. name_field : str, optional The field used to define unique objects in the ClassList (default is "name"). + """ + def __init__(self, init_list: Union[Sequence[object], object] = None, name_field: str = "name") -> None: self.name_field = name_field @@ -56,7 +60,7 @@ def __repr__(self): else: if any(model.__dict__ for model in self.data): table = prettytable.PrettyTable() - table.field_names = ['index'] + [key.replace('_', ' ') for key in self.data[0].__dict__.keys()] + table.field_names = ["index"] + [key.replace("_", " ") for key in self.data[0].__dict__] table.add_rows([[index] + list(model.__dict__.values()) for index, model in enumerate(self.data)]) output = table.get_string() else: @@ -81,15 +85,15 @@ def _delitem(self, index: int) -> None: """Auxiliary routine of "__delitem__" used to enable wrapping.""" del self.data[index] - def __iadd__(self, other: Sequence[object]) -> 'ClassList': + def __iadd__(self, other: Sequence[object]) -> "ClassList": """Define in-place addition using the "+=" operator.""" return self._iadd(other) - def _iadd(self, other: Sequence[object]) -> 'ClassList': + def _iadd(self, other: Sequence[object]) -> "ClassList": """Auxiliary routine of "__iadd__" used to enable wrapping.""" if other and not (isinstance(other, Sequence) and not isinstance(other, str)): other = [other] - if not hasattr(self, '_class_handle'): + if not hasattr(self, "_class_handle"): self._class_handle = self._determine_class_handle(self + other) self._check_classes(self + other) self._check_unique_name_fields(self + other) @@ -129,20 +133,27 @@ def append(self, obj: object = None, **kwargs) -> None: SyntaxWarning Raised if the input arguments contain BOTH an object and keyword arguments. In this situation the object is appended to the ClassList and the keyword arguments are discarded. + """ if obj and kwargs: - warnings.warn('ClassList.append() called with both an object and keyword arguments. ' - 'The keyword arguments will be ignored.', SyntaxWarning) + warnings.warn( + "ClassList.append() called with both an object and keyword arguments. " + "The keyword arguments will be ignored.", + SyntaxWarning, + stacklevel=2, + ) if obj: - if not hasattr(self, '_class_handle'): + if not hasattr(self, "_class_handle"): self._class_handle = type(obj) self._check_classes(self + [obj]) self._check_unique_name_fields(self + [obj]) self.data.append(obj) else: - if not hasattr(self, '_class_handle'): - raise TypeError('ClassList.append() called with keyword arguments for a ClassList without a class ' - 'defined. Call ClassList.append() with an object to define the class.') + if not hasattr(self, "_class_handle"): + raise TypeError( + "ClassList.append() called with keyword arguments for a ClassList without a class " + "defined. Call ClassList.append() with an object to define the class.", + ) self._validate_name_field(kwargs) self.data.append(self._class_handle(**kwargs)) @@ -169,20 +180,27 @@ def insert(self, index: int, obj: object = None, **kwargs) -> None: SyntaxWarning Raised if the input arguments contain both an object and keyword arguments. In this situation the object is inserted into the ClassList and the keyword arguments are discarded. + """ if obj and kwargs: - warnings.warn('ClassList.insert() called with both an object and keyword arguments. ' - 'The keyword arguments will be ignored.', SyntaxWarning) + warnings.warn( + "ClassList.insert() called with both an object and keyword arguments. " + "The keyword arguments will be ignored.", + SyntaxWarning, + stacklevel=2, + ) if obj: - if not hasattr(self, '_class_handle'): + if not hasattr(self, "_class_handle"): self._class_handle = type(obj) self._check_classes(self + [obj]) self._check_unique_name_fields(self + [obj]) self.data.insert(index, obj) else: - if not hasattr(self, '_class_handle'): - raise TypeError('ClassList.insert() called with keyword arguments for a ClassList without a class ' - 'defined. Call ClassList.insert() with an object to define the class.') + if not hasattr(self, "_class_handle"): + raise TypeError( + "ClassList.insert() called with keyword arguments for a ClassList without a class " + "defined. Call ClassList.insert() with an object to define the class.", + ) self._validate_name_field(kwargs) self.data.insert(index, self._class_handle(**kwargs)) @@ -209,7 +227,7 @@ def extend(self, other: Sequence[object]) -> None: """Extend the ClassList by adding another sequence.""" if other and not (isinstance(other, Sequence) and not isinstance(other, str)): other = [other] - if not hasattr(self, '_class_handle'): + if not hasattr(self, "_class_handle"): self._class_handle = self._determine_class_handle(self + other) self._check_classes(self + other) self._check_unique_name_fields(self + other) @@ -229,6 +247,7 @@ def get_names(self) -> list[str]: ------- names : list [str] The value of the name_field attribute of each object in the ClassList. + """ return [getattr(model, self.name_field) for model in self.data if hasattr(model, self.name_field)] @@ -244,9 +263,14 @@ def get_all_matches(self, value: Any) -> list[tuple]: ------- : list [tuple] A list of (index, field) tuples matching the given value. + """ - return [(index, field) for index, element in enumerate(self.data) for field in vars(element) - if getattr(element, field) == value] + return [ + (index, field) + for index, element in enumerate(self.data) + for field in vars(element) + if getattr(element, field) == value + ] def _validate_name_field(self, input_args: dict[str, Any]) -> None: """Raise a ValueError if the name_field attribute is passed as an object parameter, and its value is already @@ -261,12 +285,15 @@ def _validate_name_field(self, input_args: dict[str, Any]) -> None: ------ ValueError Raised if the input arguments contain a name_field value already defined in the ClassList. + """ names = self.get_names() with contextlib.suppress(KeyError): if input_args[self.name_field] in names: - raise ValueError(f"Input arguments contain the {self.name_field} '{input_args[self.name_field]}', " - f"which is already specified in the ClassList") + raise ValueError( + f"Input arguments contain the {self.name_field} '{input_args[self.name_field]}', " + f"which is already specified in the ClassList", + ) def _check_unique_name_fields(self, input_list: Iterable[object]) -> None: """Raise a ValueError if any value of the name_field attribute is used more than once in a list of class @@ -281,6 +308,7 @@ def _check_unique_name_fields(self, input_list: Iterable[object]) -> None: ------ ValueError Raised if the input list defines more than one object with the same value of name_field. + """ names = [getattr(model, self.name_field) for model in input_list if hasattr(model, self.name_field)] if len(set(names)) != len(names): @@ -298,6 +326,7 @@ def _check_classes(self, input_list: Iterable[object]) -> None: ------ ValueError Raised if the input list defines objects of different types. + """ if not (all(isinstance(element, self._class_handle) for element in input_list)): raise ValueError(f"Input list contains elements of type other than '{self._class_handle.__name__}'") @@ -315,6 +344,7 @@ def _get_item_from_name_field(self, value: Union[object, str]) -> Union[object, instance : object or str Either the object with the value of the name_field attribute given by value, or the input value if an object with that value of the name_field attribute cannot be found. + """ return next((model for model in self.data if getattr(model, self.name_field) == value), value) @@ -333,6 +363,7 @@ def _determine_class_handle(input_list: Sequence[object]): class_handle : type The type object of the element fulfilling the condition of satisfying "issubclass" for all of the other elements. + """ for this_element in input_list: if all([issubclass(type(instance), type(this_element)) for instance in input_list]): diff --git a/RAT/controls.py b/RAT/controls.py index bc4c0bad..093687d5 100644 --- a/RAT/controls.py +++ b/RAT/controls.py @@ -1,15 +1,17 @@ from dataclasses import dataclass, field -import prettytable -from pydantic import BaseModel, Field, field_validator, ValidationError from typing import Literal, Union -from RAT.utils.enums import Parallel, Procedures, Display, BoundHandling, Strategies +import prettytable +from pydantic import BaseModel, Field, ValidationError, field_validator + from RAT.utils.custom_errors import custom_pydantic_validation_error +from RAT.utils.enums import BoundHandling, Display, Parallel, Procedures, Strategies @dataclass(frozen=True) class Controls: """The full set of controls parameters required for the compiled RAT code.""" + # All Procedures procedure: Procedures = Procedures.Calculate parallel: Parallel = Parallel.Single @@ -44,8 +46,9 @@ class Controls: adaptPCR: bool = False -class Calculate(BaseModel, validate_assignment=True, extra='forbid'): +class Calculate(BaseModel, validate_assignment=True, extra="forbid"): """Defines the class for the calculate procedure, which includes the properties used in all five procedures.""" + procedure: Literal[Procedures.Calculate] = Procedures.Calculate parallel: Parallel = Parallel.Single calcSldDuringFit: bool = False @@ -56,20 +59,21 @@ class Calculate(BaseModel, validate_assignment=True, extra='forbid'): @classmethod def check_resample_params(cls, resampleParams): if not 0 < resampleParams[0] < 1: - raise ValueError('resampleParams[0] must be between 0 and 1') + raise ValueError("resampleParams[0] must be between 0 and 1") if resampleParams[1] < 0: - raise ValueError('resampleParams[1] must be greater than or equal to 0') + raise ValueError("resampleParams[1] must be greater than or equal to 0") return resampleParams def __repr__(self) -> str: table = prettytable.PrettyTable() - table.field_names = ['Property', 'Value'] + table.field_names = ["Property", "Value"] table.add_rows([[k, v] for k, v in self.__dict__.items()]) return table.get_string() class Simplex(Calculate): """Defines the additional fields for the simplex procedure.""" + procedure: Literal[Procedures.Simplex] = Procedures.Simplex xTolerance: float = Field(1.0e-6, gt=0.0) funcTolerance: float = Field(1.0e-6, gt=0.0) @@ -81,6 +85,7 @@ class Simplex(Calculate): class DE(Calculate): """Defines the additional fields for the Differential Evolution procedure.""" + procedure: Literal[Procedures.DE] = Procedures.DE populationSize: int = Field(20, ge=1) fWeight: float = 0.5 @@ -92,6 +97,7 @@ class DE(Calculate): class NS(Calculate): """Defines the additional fields for the Nested Sampler procedure.""" + procedure: Literal[Procedures.NS] = Procedures.NS nLive: int = Field(150, ge=1) nMCMC: float = Field(0.0, ge=0.0) @@ -101,6 +107,7 @@ class NS(Calculate): class Dream(Calculate): """Defines the additional fields for the Dream procedure.""" + procedure: Literal[Procedures.Dream] = Procedures.Dream nSamples: int = Field(50000, ge=0) nChains: int = Field(10, gt=0) @@ -110,15 +117,17 @@ class Dream(Calculate): adaptPCR: bool = False -def set_controls(procedure: Procedures = Procedures.Calculate, **properties)\ - -> Union[Calculate, Simplex, DE, NS, Dream]: +def set_controls( + procedure: Procedures = Procedures.Calculate, + **properties, +) -> Union[Calculate, Simplex, DE, NS, Dream]: """Returns the appropriate controls model given the specified procedure.""" controls = { Procedures.Calculate: Calculate, Procedures.Simplex: Simplex, Procedures.DE: DE, Procedures.NS: NS, - Procedures.Dream: Dream + Procedures.Dream: Dream, } try: @@ -126,12 +135,13 @@ def set_controls(procedure: Procedures = Procedures.Calculate, **properties)\ except KeyError: members = list(Procedures.__members__.values()) allowed_values = f'{", ".join([repr(member.value) for member in members[:-1]])} or {members[-1].value!r}' - raise ValueError(f'The controls procedure must be one of: {allowed_values}') from None + raise ValueError(f"The controls procedure must be one of: {allowed_values}") from None except ValidationError as exc: - custom_error_msgs = {'extra_forbidden': f'Extra inputs are not permitted. The fields for the {procedure}' - f' controls procedure are:\n ' - f'{", ".join(controls[procedure].model_fields.keys())}\n' - } + custom_error_msgs = { + "extra_forbidden": f'Extra inputs are not permitted. The fields for the {procedure}' + f' controls procedure are:\n ' + f'{", ".join(controls[procedure].model_fields.keys())}\n', + } custom_error_list = custom_pydantic_validation_error(exc.errors(), custom_error_msgs) raise ValidationError.from_exception_data(exc.title, custom_error_list) from None diff --git a/RAT/events.py b/RAT/events.py index c4bc84f6..d5679984 100644 --- a/RAT/events.py +++ b/RAT/events.py @@ -1,9 +1,10 @@ -from typing import Callable, Union, List +from typing import Callable, List, Union + from RAT.rat_core import EventBridge, EventTypes, PlotEventData, ProgressEventData def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEventData]) -> None: - """Calls registered callbacks with the data when event type has + """Calls registered callbacks with the data when event type has been triggered. Parameters @@ -12,6 +13,7 @@ def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEvent The event type that was triggered. data : str or PlotEventData or ProgressEventData The data sent by the event. The message event data is a string. + """ callbacks = __event_callbacks[event_type] for callback in callbacks: @@ -30,6 +32,7 @@ def get_event_callback(event_type: EventTypes) -> List[Callable[[Union[str, Plot ------- callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None] The callback for the event type. + """ return list(__event_callbacks[event_type]) @@ -43,10 +46,11 @@ def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventDat The event type to register. callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None] The callback for when the event is triggered. + """ if not isinstance(event_type, EventTypes): raise ValueError("event_type must be a events.EventTypes enum") - + if len(__event_callbacks[event_type]) == 0: __event_impl.register(event_type) __event_callbacks[event_type].add(callback) @@ -55,7 +59,7 @@ def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventDat def clear() -> None: """Clears all event callbacks.""" __event_impl.clear() - for key in __event_callbacks.keys(): + for key in __event_callbacks: __event_callbacks[key] = set() diff --git a/RAT/examples/absorption/absorption.py b/RAT/examples/absorption/absorption.py index 5e44e363..35f9a057 100644 --- a/RAT/examples/absorption/absorption.py +++ b/RAT/examples/absorption/absorption.py @@ -1,14 +1,20 @@ """Custom layers model including absorption""" -import numpy as np import os import pathlib +import numpy as np + import RAT import RAT.utils.plotting -problem = RAT.Project(name="Absorption example", calculation="non polarised", model="custom layers", - geometry="substrate/liquid", absorption=True) +problem = RAT.Project( + name="Absorption example", + calculation="non polarised", + model="custom layers", + geometry="substrate/liquid", + absorption=True, +) # Add the required parameters (substrate roughness is already there by default) problem.parameters.append(name="Alloy Thickness", min=100.0, value=135.6, max=200.0, fit=True) @@ -79,25 +85,61 @@ problem.data.append(name="H2O_up", data=data_4) # Add the custom file -problem.custom_files.append(name="DPPC absorption", filename="volume_thiol_bilayer.py", language="python", - path=pathlib.Path(__file__).parent.resolve()) +problem.custom_files.append( + name="DPPC absorption", + filename="volume_thiol_bilayer.py", + language="python", + path=pathlib.Path(__file__).parent.resolve(), +) # Finally add the contrasts -problem.contrasts.append(name="D2O Down", data="D2O_dn", background="Background 1", bulk_in="Silicon", - bulk_out="D2O", scalefactor="Scalefactor 1", resolution="Resolution 1", resample=True, - model=["DPPC absorption"]) - -problem.contrasts.append(name="D2O Up", data="D2O_up", background="Background 2", bulk_in="Silicon", - bulk_out="D2O", scalefactor="Scalefactor 2", resolution="Resolution 1", resample=True, - model=["DPPC absorption"]) - -problem.contrasts.append(name="H2O Down", data="H2O_dn", background="Background 3", bulk_in="Silicon", - bulk_out="H2O", scalefactor="Scalefactor 3", resolution="Resolution 1", resample=True, - model=["DPPC absorption"]) - -problem.contrasts.append(name="H2O Up", data="H2O_up", background="Background 4", bulk_in="Silicon", - bulk_out="H2O", scalefactor="Scalefactor 4", resolution="Resolution 1", resample=True, - model=["DPPC absorption"]) +problem.contrasts.append( + name="D2O Down", + data="D2O_dn", + background="Background 1", + bulk_in="Silicon", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=True, + model=["DPPC absorption"], +) + +problem.contrasts.append( + name="D2O Up", + data="D2O_up", + background="Background 2", + bulk_in="Silicon", + bulk_out="D2O", + scalefactor="Scalefactor 2", + resolution="Resolution 1", + resample=True, + model=["DPPC absorption"], +) + +problem.contrasts.append( + name="H2O Down", + data="H2O_dn", + background="Background 3", + bulk_in="Silicon", + bulk_out="H2O", + scalefactor="Scalefactor 3", + resolution="Resolution 1", + resample=True, + model=["DPPC absorption"], +) + +problem.contrasts.append( + name="H2O Up", + data="H2O_up", + background="Background 4", + bulk_in="Silicon", + bulk_out="H2O", + scalefactor="Scalefactor 4", + resolution="Resolution 1", + resample=True, + model=["DPPC absorption"], +) # Now make a controls block controls = RAT.set_controls(parallel="contrasts", resampleParams=[0.9, 150.0]) diff --git a/RAT/examples/absorption/volume_thiol_bilayer.py b/RAT/examples/absorption/volume_thiol_bilayer.py index 754454ca..f5ac1bbc 100644 --- a/RAT/examples/absorption/volume_thiol_bilayer.py +++ b/RAT/examples/absorption/volume_thiol_bilayer.py @@ -1,6 +1,5 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): - """ - volumeThiolBilayer RAT Custom Layer Model File. + """VolumeThiolBilayer RAT Custom Layer Model File. This file accepts 3 vectors containing the values for params, bulk in and bulk out. The final parameter is an index of the contrast being calculated @@ -48,25 +47,22 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): # Neutron b's.. # define all the neutron b's. - bc = 0.6646e-4 # Carbon - bo = 0.5843e-4 # Oxygen + bc = 0.6646e-4 # Carbon + bo = 0.5843e-4 # Oxygen bh = -0.3739e-4 # Hydrogen - bp = 0.513e-4 # Phosphorus - bn = 0.936e-4 # Nitrogen - bd = 0.6671e-4 # Deuterium + bp = 0.513e-4 # Phosphorus + bn = 0.936e-4 # Nitrogen # Work out the total scattering length in each fragment # Define scattering lengths # Hydrogenated version - COO = (2*bo) + (bc) - GLYC = (3*bc) + (5*bh) - CH3 = (1*bc) + (3*bh) - PO4 = (1*bp) + (4*bo) - CH2 = (1*bc) + (2*bh) - CH = (1*bc) + (1*bh) - CHOL = (5*bc) + (12*bh) + (1*bn) - H2O = (2*bh) + (1*bo) - D2O = (2*bd) + (1*bo) + COO = (2 * bo) + (bc) + GLYC = (3 * bc) + (5 * bh) + CH3 = (1 * bc) + (3 * bh) + PO4 = (1 * bp) + (4 * bo) + CH2 = (1 * bc) + (2 * bh) + CH = (1 * bc) + (1 * bh) + CHOL = (5 * bc) + (12 * bh) + (1 * bn) # And also volumes vCH3 = 52.7 # CH3 volume in the paper appears to be for 2 * CH3's @@ -75,57 +71,56 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): vGLYC = 68.8 vPO4 = 53.7 vCHOL = 120.4 - vWAT = 30.4 vCHCH = 42.14 - vHead = vCHOL + vPO4 + vGLYC + 2*vCOO - vTail = (28*vCH2) + (1*vCHCH) + (2*vCH3) # Tail volume + vHead = vCHOL + vPO4 + vGLYC + 2 * vCOO + vTail = (28 * vCH2) + (1 * vCHCH) + (2 * vCH3) # Tail volume # Calculate sum_b's for other fragments - sumbHead = CHOL + PO4 + GLYC + 2*COO - sumbTail = (28*CH2) + (2*CH) + 2*CH3 + sumbHead = CHOL + PO4 + GLYC + 2 * COO + sumbTail = (28 * CH2) + (2 * CH) + 2 * CH3 # Calculate SLDs and Thickness - sldHead = sumbHead/vHead - thickHead = vHead/thiolAPM + sldHead = sumbHead / vHead + thickHead = vHead / thiolAPM - sldTail = sumbTail/vTail - thickTail = vTail/thiolAPM + sldTail = sumbTail / vTail + thickTail = vTail / thiolAPM # Correct head SLD based on hydration - thiolHeadHydr = thiolHeadHydr/100 - sldHead = (sldHead * (1 - thiolHeadHydr) + (thiolHeadHydr * bulk_out[contrast])) + thiolHeadHydr = thiolHeadHydr / 100 + sldHead = sldHead * (1 - thiolHeadHydr) + (thiolHeadHydr * bulk_out[contrast]) # Now correct both the SLDs for the coverage parameter - sldTail = (thiolCoverage*sldTail) + ((1-thiolCoverage) * bulk_out[contrast]) - sldHead = (thiolCoverage*sldHead) + ((1-thiolCoverage) * bulk_out[contrast]) + sldTail = (thiolCoverage * sldTail) + ((1 - thiolCoverage) * bulk_out[contrast]) + sldHead = (thiolCoverage * sldHead) + ((1 - thiolCoverage) * bulk_out[contrast]) SAMTAILS = [thickTail, sldTail, 0, goldRough] SAMHEAD = [thickHead, sldHead, 0, goldRough] # Now do the same for the bilayer - vHead = vCHOL + vPO4 + vGLYC + 2*vCOO - vTail = (28*vCH2) # Tail volume - vMe = (2*vCH3) + vHead = vCHOL + vPO4 + vGLYC + 2 * vCOO + vTail = 28 * vCH2 # Tail volume + vMe = 2 * vCH3 - sumbHead = CHOL + PO4 + GLYC + 2*COO - sumbTail = (28*CH2) - sumbMe = 2*CH3 + sumbHead = CHOL + PO4 + GLYC + 2 * COO + sumbTail = 28 * CH2 + sumbMe = 2 * CH3 - sldHead = sumbHead/vHead - thickHead = vHead/bilayerAPM + sldHead = sumbHead / vHead + thickHead = vHead / bilayerAPM bilHeadHydr = bilHeadHydr / 100 - sldHead = (sldHead * (1 - bilHeadHydr) + (bilHeadHydr * bulk_out[contrast])) + sldHead = sldHead * (1 - bilHeadHydr) + (bilHeadHydr * bulk_out[contrast]) - sldTail = sumbTail/vTail - thickTail = vTail/bilayerAPM + sldTail = sumbTail / vTail + thickTail = vTail / bilayerAPM - sldMe = sumbMe/vMe - thickMe = vMe/bilayerAPM + sldMe = sumbMe / vMe + thickMe = vMe / bilayerAPM - sldTail = (bilayerCoverage * sldTail) + ((1-bilayerCoverage) * bulk_out[contrast]) - sldHead = (bilayerCoverage * sldHead) + ((1-bilayerCoverage) * bulk_out[contrast]) - sldMe = (bilayerCoverage * sldMe) + ((1-bilayerCoverage) * bulk_out[contrast]) + sldTail = (bilayerCoverage * sldTail) + ((1 - bilayerCoverage) * bulk_out[contrast]) + sldHead = (bilayerCoverage * sldHead) + ((1 - bilayerCoverage) * bulk_out[contrast]) + sldMe = (bilayerCoverage * sldMe) + ((1 - bilayerCoverage) * bulk_out[contrast]) BILTAILS = [thickTail, sldTail, 0, bilayerRough] BILHEAD = [thickHead, sldHead, 0, bilayerRough] diff --git a/RAT/examples/domains/alloy_domains.py b/RAT/examples/domains/alloy_domains.py index eb919a62..73aec375 100644 --- a/RAT/examples/domains/alloy_domains.py +++ b/RAT/examples/domains/alloy_domains.py @@ -1,9 +1,7 @@ - def alloy_domains(params, bulkIn, bulkOut, contrast, domain): """Simple custom model for testing incoherent summing. Simple two layer of permalloy / gold, with up/down domains. """ - # Split up the parameters subRough = params[0] alloyThick = params[1] diff --git a/RAT/examples/domains/domains_XY_model.py b/RAT/examples/domains/domains_XY_model.py index 059d1112..cde8c299 100644 --- a/RAT/examples/domains/domains_XY_model.py +++ b/RAT/examples/domains/domains_XY_model.py @@ -1,9 +1,9 @@ import math + import numpy as np def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): - # Split up the parameters for convenience subRough = params[0] oxideThick = params[1] @@ -51,22 +51,20 @@ def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): def makeLayer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): - """ This produces a layer, with a defined thickness, height and roughness. + """This produces a layer, with a defined thickness, height and roughness. Each side of the layer has its own roughness value. """ # Find the edges - l = prevLaySurf - r = prevLaySurf + thickness + left = prevLaySurf + right = prevLaySurf + thickness # Make our heaviside - a = (z-l) / ((2**0.5) * Sigma_L) - b = (z-r) / ((2**0.5) * Sigma_R) + a = (z - left) / ((2**0.5) * Sigma_L) + b = (z - right) / ((2**0.5) * Sigma_R) erf_a = np.array([math.erf(value) for value in a]) erf_b = np.array([math.erf(value) for value in b]) VF = np.array((height / 2) * (erf_a - erf_b)) - thisLaySurf = r - - return VF, thisLaySurf + return VF, right diff --git a/RAT/examples/domains/domains_custom_XY.py b/RAT/examples/domains/domains_custom_XY.py index 80ff4f9f..75665898 100644 --- a/RAT/examples/domains/domains_custom_XY.py +++ b/RAT/examples/domains/domains_custom_XY.py @@ -20,21 +20,49 @@ problem.bulk_out.append(name="SLD H2O", min=-0.6e-6, value=-0.56e-6, max=-0.5e-6) # Add the custom file -problem.custom_files.append(name="Domain Layer", filename="domains_XY_model.py", language="python", - path=pathlib.Path(__file__).parent.resolve()) +problem.custom_files.append( + name="Domain Layer", + filename="domains_XY_model.py", + language="python", + path=pathlib.Path(__file__).parent.resolve(), +) # Make contrasts -problem.contrasts.append(name="D2O", background="Background 1", resolution="Resolution 1", scalefactor="Scalefactor 1", - bulk_in="Silicon", bulk_out="SLD D2O", domain_ratio="Domain Ratio 1", data="Simulation", - model=["Domain Layer"]) +problem.contrasts.append( + name="D2O", + background="Background 1", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_in="Silicon", + bulk_out="SLD D2O", + domain_ratio="Domain Ratio 1", + data="Simulation", + model=["Domain Layer"], +) -problem.contrasts.append(name="SMW", background="Background 1", resolution="Resolution 1", scalefactor="Scalefactor 1", - bulk_in="Silicon", bulk_out="SLD SMW", domain_ratio="Domain Ratio 1", data="Simulation", - model=["Domain Layer"]) +problem.contrasts.append( + name="SMW", + background="Background 1", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_in="Silicon", + bulk_out="SLD SMW", + domain_ratio="Domain Ratio 1", + data="Simulation", + model=["Domain Layer"], +) -problem.contrasts.append(name="H2O", background="Background 1", resolution="Resolution 1", scalefactor="Scalefactor 1", - bulk_in="Silicon", bulk_out="SLD H2O", domain_ratio="Domain Ratio 1", data="Simulation", - model=["Domain Layer"]) +problem.contrasts.append( + name="H2O", + background="Background 1", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_in="Silicon", + bulk_out="SLD H2O", + domain_ratio="Domain Ratio 1", + data="Simulation", + model=["Domain Layer"], +) controls = RAT.set_controls() problem, results = RAT.run(problem, controls) diff --git a/RAT/examples/domains/domains_custom_layers.py b/RAT/examples/domains/domains_custom_layers.py index bb48c19f..eff1b7ba 100644 --- a/RAT/examples/domains/domains_custom_layers.py +++ b/RAT/examples/domains/domains_custom_layers.py @@ -20,13 +20,26 @@ problem.bulk_in.set_fields(0, name="Silicon", value=2.073e-6, max=1.0) # Add the custom file -problem.custom_files.append(name="Alloy domains", filename="alloy_domains.py", language="python", - path=pathlib.Path(__file__).parent.resolve()) +problem.custom_files.append( + name="Alloy domains", + filename="alloy_domains.py", + language="python", + path=pathlib.Path(__file__).parent.resolve(), +) # Make a contrast -problem.contrasts.append(name="D2O Contrast", data="Simulation", background="Background 1", bulk_in="Silicon", - bulk_out="SLD D2O", scalefactor="Scalefactor 1", resolution="Resolution 1", resample=False, - domain_ratio="Domain Ratio 1", model=["Alloy domains"]) +problem.contrasts.append( + name="D2O Contrast", + data="Simulation", + background="Background 1", + bulk_in="Silicon", + bulk_out="SLD D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + domain_ratio="Domain Ratio 1", + model=["Alloy domains"], +) controls = RAT.set_controls() diff --git a/RAT/examples/domains/domains_standard_layers.py b/RAT/examples/domains/domains_standard_layers.py index fe2f3a21..3ec4fd55 100644 --- a/RAT/examples/domains/domains_standard_layers.py +++ b/RAT/examples/domains/domains_standard_layers.py @@ -21,14 +21,32 @@ # Now group these parameters into layers -problem.layers.append(name="Layer 1", thickness="L1 Thickness", SLD="L1 SLD", roughness="L1 Roughness", - hydration="L1 Hydration", hydrate_with="bulk out") +problem.layers.append( + name="Layer 1", + thickness="L1 Thickness", + SLD="L1 SLD", + roughness="L1 Roughness", + hydration="L1 Hydration", + hydrate_with="bulk out", +) -problem.layers.append(name="Layer 2", thickness="L2 Thickness", SLD="L2 SLD", roughness="L2 Roughness", - hydration="L2 Hydration", hydrate_with="bulk out") +problem.layers.append( + name="Layer 2", + thickness="L2 Thickness", + SLD="L2 SLD", + roughness="L2 Roughness", + hydration="L2 Hydration", + hydrate_with="bulk out", +) -problem.layers.append(name="Layer 3", thickness="L3 Thickness", SLD="L3 SLD", roughness="L3 Roughness", - hydration="L3 Hydration", hydrate_with="bulk out") +problem.layers.append( + name="Layer 3", + thickness="L3 Thickness", + SLD="L3 SLD", + roughness="L3 Roughness", + hydration="L3 Hydration", + hydrate_with="bulk out", +) # If we look at the project, there are two extra groups as compared to a normal standard layers calculation: @@ -37,9 +55,18 @@ problem.domain_contrasts.append(name="Domain 2", model=["Layer 2", "Layer 3"]) # Now make a contrast as with standard models, but this time also including the default domain ratio ("Domain Ratio 1") -problem.contrasts.append(name="Domain Test", background="Background 1", resolution="Resolution 1", - scalefactor="Scalefactor 1", resample=False, bulk_in="SLD Air", bulk_out="SLD D2O", - domain_ratio="Domain Ratio 1", data="Simulation", model=["Domain 1", "Domain 2"]) +problem.contrasts.append( + name="Domain Test", + background="Background 1", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + resample=False, + bulk_in="SLD Air", + bulk_out="SLD D2O", + domain_ratio="Domain Ratio 1", + data="Simulation", + model=["Domain 1", "Domain 2"], +) # Now we can run our simulation as usual, and plot the results diff --git a/RAT/examples/languages/custom_bilayer.py b/RAT/examples/languages/custom_bilayer.py index 4f61454c..dc978e31 100644 --- a/RAT/examples/languages/custom_bilayer.py +++ b/RAT/examples/languages/custom_bilayer.py @@ -2,7 +2,6 @@ def custom_bilayer(params, bulk_in, bulk_out, contrast): - sub_rough = params[0] oxide_thick = params[1] oxide_hydration = params[2] @@ -14,30 +13,29 @@ def custom_bilayer(params, bulk_in, bulk_out, contrast): # We have a constant SLD for the bilayer oxide_SLD = 3.41e-6 - + # Now make the lipid layers # Use known lipid volume and compositions # to make the layers # define all the neutron b's. - bc = 0.6646e-4 # Carbon - bo = 0.5843e-4 # Oxygen - bh = -0.3739e-4 # Hydrogen - bp = 0.513e-4 # Phosphorus - bn = 0.936e-4 # Nitrogen - bd = 0.6671e-4 # Deuterium + bc = 0.6646e-4 # Carbon + bo = 0.5843e-4 # Oxygen + bh = -0.3739e-4 # Hydrogen + bp = 0.513e-4 # Phosphorus + bn = 0.936e-4 # Nitrogen # Now make the lipid groups - COO = (4*bo) + (2*bc) - GLYC = (3*bc) + (5*bh) - CH3 = (2*bc) + (6*bh) - PO4 = (1*bp) + (4*bo) - CH2 = (1*bc) + (2*bh) - CHOL = (5*bc) + (12*bh) + (1*bn) + COO = (4 * bo) + (2 * bc) + GLYC = (3 * bc) + (5 * bh) + CH3 = (2 * bc) + (6 * bh) + PO4 = (1 * bp) + (4 * bo) + CH2 = (1 * bc) + (2 * bh) + CHOL = (5 * bc) + (12 * bh) + (1 * bn) # Group these into heads and tails: Head = CHOL + PO4 + GLYC + COO - Tails = (34*CH2) + (2*CH3) + Tails = (34 * CH2) + (2 * CH3) # We need volumes for each. # Use literature values: @@ -55,14 +53,14 @@ def custom_bilayer(params, bulk_in, bulk_out, contrast): # Manually deal with hydration for layers in this example. oxSLD = (oxide_hydration * bulk_out[contrast]) + ((1 - oxide_hydration) * oxide_SLD) headSLD = (headHydration * bulk_out[contrast]) + ((1 - headHydration) * SLDhead) - tailSLD = (bilayerHydration * bulk_out[contrast]) + ((1 - bilayerHydration) * SLDtail) + tailSLD = (bilayerHydration * bulk_out[contrast]) + ((1 - bilayerHydration) * SLDtail) # Make the layers oxide = [oxide_thick, oxSLD, sub_rough] water = [waterThick, bulk_out[contrast], bilayerRough] head = [headThick, headSLD, bilayerRough] tail = [tailThick, tailSLD, bilayerRough] - + output = np.array([oxide, water, head, tail, tail, head]) return output, sub_rough diff --git a/RAT/examples/languages/run_custom_file_languages.py b/RAT/examples/languages/run_custom_file_languages.py index 54c51c71..c1b37e3b 100644 --- a/RAT/examples/languages/run_custom_file_languages.py +++ b/RAT/examples/languages/run_custom_file_languages.py @@ -1,10 +1,12 @@ """Test custom function languages.""" -import RAT.utils.plotting import pathlib -import setup_problem import time +import setup_problem + +import RAT.utils.plotting + path = pathlib.Path(__file__).parent.resolve() project = setup_problem.make_example_problem() @@ -19,7 +21,7 @@ RAT.utils.plotting.plot_ref_sld(project, results) # Matlab -project.custom_files.set_fields(0, filename='custom_bilayer.m', language='matlab', path=path) +project.custom_files.set_fields(0, filename="custom_bilayer.m", language="matlab", path=path) start = time.time() project, results = RAT.run(project, controls) @@ -29,7 +31,7 @@ RAT.utils.plotting.plot_ref_sld(project, results) # C++ -project.custom_files.set_fields(0, filename='custom_bilayer.dll', language='cpp', path=path) +project.custom_files.set_fields(0, filename="custom_bilayer.dll", language="cpp", path=path) start = time.time() project, results = RAT.run(project, controls) diff --git a/RAT/examples/languages/setup_problem.py b/RAT/examples/languages/setup_problem.py index 91d18e10..a7ed17f8 100644 --- a/RAT/examples/languages/setup_problem.py +++ b/RAT/examples/languages/setup_problem.py @@ -1,17 +1,17 @@ -""" -Custom Layers example for Supported DSPC layer. +"""Custom Layers example for Supported DSPC layer. Example of using custom layers to model a DSPC supported bilayer. """ -import numpy as np import os import pathlib +import numpy as np + import RAT -def make_example_problem(): +def make_example_problem(): problem = RAT.Project(name="Orso lipid example - custom layers", model="custom layers", geometry="substrate/liquid") # First we need to set up a parameters group. We will be using a pre-prepared custom model file, so we need to add @@ -27,7 +27,8 @@ def make_example_problem(): problem.parameters.set_fields(0, min=1.0, max=10.0) - # Need to add the relevant Bulk SLDs. Change the bulk in from air to silicon, and add two additional water contrasts: + # Need to add the relevant Bulk SLDs. + # Change the bulk in from air to silicon, and add two additional water contrasts: problem.bulk_in.set_fields(0, name="Silicon", min=2.07e-6, value=2.073e-6, max=2.08e-6, fit=False) problem.bulk_out.append(name="SLD SMW", min=1.0e-6, value=2.073e-6, max=3.0e-6, fit=True) @@ -50,17 +51,37 @@ def make_example_problem(): problem.data.append(name="Bilayer / H2O", data=H2O_data) # Add the custom file to the project - problem.custom_files.append(name="DSPC Model", filename="custom_bilayer.py", language="python", - path=pathlib.Path(__file__).parent.resolve()) + problem.custom_files.append( + name="DSPC Model", + filename="custom_bilayer.py", + language="python", + path=pathlib.Path(__file__).parent.resolve(), + ) # Also, add the relevant background parameters - one each for each contrast: - problem.background_parameters.set_fields(0, name="Background parameter D2O", fit=True, min=1.0e-10, max=1.0e-5, - value=1.0e-07) - - problem.background_parameters.append(name="Background parameter SMW", min=1.0e-10, value=1.0e-7, max=1.0e-5, - fit=True) - problem.background_parameters.append(name="Background parameter H2O", min=1.0e-10, value=1.0e-7, max=1.0e-5, - fit=True) + problem.background_parameters.set_fields( + 0, + name="Background parameter D2O", + fit=True, + min=1.0e-10, + max=1.0e-5, + value=1.0e-07, + ) + + problem.background_parameters.append( + name="Background parameter SMW", + min=1.0e-10, + value=1.0e-7, + max=1.0e-5, + fit=True, + ) + problem.background_parameters.append( + name="Background parameter H2O", + min=1.0e-10, + value=1.0e-7, + max=1.0e-5, + fit=True, + ) # And add the two new constant backgrounds problem.backgrounds.append(name="Background SMW", type="constant", value_1="Background parameter SMW") @@ -73,16 +94,37 @@ def make_example_problem(): problem.scalefactors.set_fields(0, value=1.0, min=0.5, max=2.0, fit=True) # Now add the three contrasts - problem.contrasts.append(name="Bilayer / D2O", background="Background D2O", resolution="Resolution 1", - scalefactor="Scalefactor 1", bulk_out="SLD D2O", bulk_in="Silicon", data="Bilayer / D2O", - model=["DSPC Model"]) - - problem.contrasts.append(name="Bilayer / SMW", background="Background SMW", resolution="Resolution 1", - scalefactor="Scalefactor 1", bulk_out="SLD SMW", bulk_in="Silicon", data="Bilayer / SMW", - model=["DSPC Model"]) - - problem.contrasts.append(name="Bilayer / H2O", background="Background H2O", resolution="Resolution 1", - scalefactor="Scalefactor 1", bulk_out="SLD H2O", bulk_in="Silicon", data="Bilayer / H2O", - model=["DSPC Model"]) + problem.contrasts.append( + name="Bilayer / D2O", + background="Background D2O", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_out="SLD D2O", + bulk_in="Silicon", + data="Bilayer / D2O", + model=["DSPC Model"], + ) + + problem.contrasts.append( + name="Bilayer / SMW", + background="Background SMW", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_out="SLD SMW", + bulk_in="Silicon", + data="Bilayer / SMW", + model=["DSPC Model"], + ) + + problem.contrasts.append( + name="Bilayer / H2O", + background="Background H2O", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_out="SLD H2O", + bulk_in="Silicon", + data="Bilayer / H2O", + model=["DSPC Model"], + ) return problem diff --git a/RAT/examples/non_polarised/DSPC_custom_XY.py b/RAT/examples/non_polarised/DSPC_custom_XY.py index 51c42b7f..feb87688 100644 --- a/RAT/examples/non_polarised/DSPC_custom_XY.py +++ b/RAT/examples/non_polarised/DSPC_custom_XY.py @@ -1,5 +1,4 @@ -""" -Custom XY Example for Supported DSPC layer. +"""Custom XY Example for Supported DSPC layer. In this example, we model the same data (DSPC supported bilayer) as the Custom Layers example, but this time we will use continuous distributions of the volume fractions of each component to build up the SLD profiles (as described in @@ -19,15 +18,16 @@ does not permit any hydration, so to deal with this, we can simply scale the (full occupation) Heaviside functions by relevant coverage parameters. When this is correctly done, we can obtain the remaining water distribution as -$${\textrm{VF}}_{\textrm{wat}} =1-\sum_n {\textrm{VF}}_n$$ +$${\textrm{VF}}_{\textrm{wat}} =1-\\sum_n {\textrm{VF}}_n$$ where VFn is the Volume Fraction of the n'th layer. """ -import numpy as np import os import pathlib +import numpy as np + import RAT import RAT.utils.plotting @@ -68,12 +68,22 @@ problem.data.append(name="Bilayer / H2O", data=H2O_data) # Add the custom file to the project -problem.custom_files.append(name="DSPC Model", filename="custom_XY_DSPC.py", language="python", - path=pathlib.Path(__file__).parent.resolve()) +problem.custom_files.append( + name="DSPC Model", + filename="custom_XY_DSPC.py", + language="python", + path=pathlib.Path(__file__).parent.resolve(), +) # Also, add the relevant background parameters - one each for each contrast: -problem.background_parameters.set_fields(0, name="Background parameter D2O", fit=True, min=1.0e-10, max=1.0e-5, - value=1.0e-07) +problem.background_parameters.set_fields( + 0, + name="Background parameter D2O", + fit=True, + min=1.0e-10, + max=1.0e-5, + value=1.0e-07, +) problem.background_parameters.append(name="Background parameter SMW", min=0.0, value=1.0e-7, max=1.0e-5, fit=True) problem.background_parameters.append(name="Background parameter H2O", min=0.0, value=1.0e-7, max=1.0e-5, fit=True) @@ -92,17 +102,38 @@ problem.resolutions.append(name="Data Resolution", type="data") # Now add the three contrasts -problem.contrasts.append(name="Bilayer / D2O", background="Background D2O", resolution="Data Resolution", - scalefactor="Scalefactor 1", bulk_out="SLD D2O", bulk_in="Silicon", data="Bilayer / D2O", - model=["DSPC Model"]) - -problem.contrasts.append(name="Bilayer / SMW", background="Background SMW", resolution="Data Resolution", - scalefactor="Scalefactor 1", bulk_out="SLD SMW", bulk_in="Silicon", data="Bilayer / SMW", - model=["DSPC Model"]) - -problem.contrasts.append(name="Bilayer / H2O", background="Background H2O", resolution="Data Resolution", - scalefactor="Scalefactor 1", bulk_out="SLD H2O", bulk_in="Silicon", data="Bilayer / H2O", - model=["DSPC Model"]) +problem.contrasts.append( + name="Bilayer / D2O", + background="Background D2O", + resolution="Data Resolution", + scalefactor="Scalefactor 1", + bulk_out="SLD D2O", + bulk_in="Silicon", + data="Bilayer / D2O", + model=["DSPC Model"], +) + +problem.contrasts.append( + name="Bilayer / SMW", + background="Background SMW", + resolution="Data Resolution", + scalefactor="Scalefactor 1", + bulk_out="SLD SMW", + bulk_in="Silicon", + data="Bilayer / SMW", + model=["DSPC Model"], +) + +problem.contrasts.append( + name="Bilayer / H2O", + background="Background H2O", + resolution="Data Resolution", + scalefactor="Scalefactor 1", + bulk_out="SLD H2O", + bulk_in="Silicon", + data="Bilayer / H2O", + model=["DSPC Model"], +) controls = RAT.set_controls() diff --git a/RAT/examples/non_polarised/DSPC_custom_layers.py b/RAT/examples/non_polarised/DSPC_custom_layers.py index 508de14f..13cc9cca 100644 --- a/RAT/examples/non_polarised/DSPC_custom_layers.py +++ b/RAT/examples/non_polarised/DSPC_custom_layers.py @@ -1,12 +1,13 @@ -""" -Custom Layers example for Supported DSPC layer. +"""Custom Layers example for Supported DSPC layer. Example of using custom layers to model a DSPC supported bilayer. """ -import numpy as np + import os import pathlib +import numpy as np + import RAT import RAT.utils.plotting @@ -48,11 +49,22 @@ problem.data.append(name="Bilayer / H2O", data=H2O_data, data_range=[0.013, 0.33048]) # Add the custom file to the project -problem.custom_files.append(name="DSPC Model", filename="custom_bilayer_DSPC.py", language="python", - path=pathlib.Path(__file__).parent.resolve()) +problem.custom_files.append( + name="DSPC Model", + filename="custom_bilayer_DSPC.py", + language="python", + path=pathlib.Path(__file__).parent.resolve(), +) # Also, add the relevant background parameters - one each for each contrast: -problem.background_parameters.set_fields(0, name="Background parameter D2O", fit=True, min=1.0e-10, max=1.0e-5, value=1.0e-07) +problem.background_parameters.set_fields( + 0, + name="Background parameter D2O", + min=1.0e-10, + max=1.0e-5, + value=1.0e-07, + fit=True, +) problem.background_parameters.append(name="Background parameter SMW", min=1.0e-10, value=1.0e-7, max=1.0e-5, fit=True) problem.background_parameters.append(name="Background parameter H2O", min=1.0e-10, value=1.0e-7, max=1.0e-5, fit=True) @@ -71,17 +83,38 @@ problem.resolutions.append(name="Data Resolution", type="data") # Now add the three contrasts -problem.contrasts.append(name="Bilayer / D2O", background="Background D2O", resolution="Data Resolution", - scalefactor="Scalefactor 1", bulk_out="SLD D2O", bulk_in="Silicon", data="Bilayer / D2O", - model=["DSPC Model"]) - -problem.contrasts.append(name="Bilayer / SMW", background="Background SMW", resolution="Data Resolution", - scalefactor="Scalefactor 1", bulk_out="SLD SMW", bulk_in="Silicon", data="Bilayer / SMW", - model=["DSPC Model"]) - -problem.contrasts.append(name="Bilayer / H2O", background="Background H2O", resolution="Data Resolution", - scalefactor="Scalefactor 1", bulk_out="SLD H2O", bulk_in="Silicon", data="Bilayer / H2O", - model=["DSPC Model"]) +problem.contrasts.append( + name="Bilayer / D2O", + background="Background D2O", + resolution="Data Resolution", + scalefactor="Scalefactor 1", + bulk_out="SLD D2O", + bulk_in="Silicon", + data="Bilayer / D2O", + model=["DSPC Model"], +) + +problem.contrasts.append( + name="Bilayer / SMW", + background="Background SMW", + resolution="Data Resolution", + scalefactor="Scalefactor 1", + bulk_out="SLD SMW", + bulk_in="Silicon", + data="Bilayer / SMW", + model=["DSPC Model"], +) + +problem.contrasts.append( + name="Bilayer / H2O", + background="Background H2O", + resolution="Data Resolution", + scalefactor="Scalefactor 1", + bulk_out="SLD H2O", + bulk_in="Silicon", + data="Bilayer / H2O", + model=["DSPC Model"], +) controls = RAT.set_controls() diff --git a/RAT/examples/non_polarised/DSPC_standard_layers.py b/RAT/examples/non_polarised/DSPC_standard_layers.py index 07d91fcc..8799710b 100644 --- a/RAT/examples/non_polarised/DSPC_standard_layers.py +++ b/RAT/examples/non_polarised/DSPC_standard_layers.py @@ -1,57 +1,279 @@ """Standard Layers fit of a DSPC floating bilayer""" -import numpy as np import os import pathlib +import numpy as np + import RAT import RAT.utils.plotting -problem = RAT.Project(name="original_dspc_bilayer", calculation="non polarised", model="standard layers", - geometry="substrate/liquid", absorption=False) +problem = RAT.Project( + name="original_dspc_bilayer", + calculation="non polarised", + model="standard layers", + geometry="substrate/liquid", + absorption=False, +) # Set up the relevant parameters -problem.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) -problem.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) -problem.parameters.append(name="SAM Tails Thickness", min=15.0, value=22.66, max=35.0, fit=True, prior_type="uniform", mu=0.0, sigma=np.inf) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) -problem.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) +problem.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, +) +problem.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, +) +problem.parameters.append( + name="SAM Tails Thickness", + min=15.0, + value=22.66, + max=35.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) +problem.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, +) problem.parameters.set_fields(0, max=10) # Group these into layers -problem.layers.append(name="Oxide", thickness="Oxide Thickness", SLD="Oxide SLD", roughness="Substrate Roughness", - hydration="Oxide Hydration", hydrate_with="bulk out") +problem.layers.append( + name="Oxide", + thickness="Oxide Thickness", + SLD="Oxide SLD", + roughness="Substrate Roughness", + hydration="Oxide Hydration", + hydrate_with="bulk out", +) -problem.layers.append(name="SAM Tails", thickness="SAM Tails Thickness", SLD="SAM Tails SLD", roughness="SAM Roughness", - hydration="SAM Tails Hydration", hydrate_with="bulk out") +problem.layers.append( + name="SAM Tails", + thickness="SAM Tails Thickness", + SLD="SAM Tails SLD", + roughness="SAM Roughness", + hydration="SAM Tails Hydration", + hydrate_with="bulk out", +) -problem.layers.append(name="SAM Heads", thickness="SAM Heads Thickness", SLD="SAM Heads SLD", roughness="SAM Roughness", - hydration="SAM Heads Hydration", hydrate_with="bulk out") +problem.layers.append( + name="SAM Heads", + thickness="SAM Heads Thickness", + SLD="SAM Heads SLD", + roughness="SAM Roughness", + hydration="SAM Heads Hydration", + hydrate_with="bulk out", +) -problem.layers.append(name="Central Water", thickness="CW Thickness", SLD="CW SLD", roughness="Bilayer Roughness", - hydration="CW Hydration", hydrate_with="bulk out") +problem.layers.append( + name="Central Water", + thickness="CW Thickness", + SLD="CW SLD", + roughness="Bilayer Roughness", + hydration="CW Hydration", + hydrate_with="bulk out", +) -problem.layers.append(name="Bilayer Heads", thickness="Bilayer Heads Thickness", SLD="Bilayer Heads SLD", - roughness="Bilayer Roughness", hydration="Bilayer Heads Hydration", hydrate_with="bulk out") +problem.layers.append( + name="Bilayer Heads", + thickness="Bilayer Heads Thickness", + SLD="Bilayer Heads SLD", + roughness="Bilayer Roughness", + hydration="Bilayer Heads Hydration", + hydrate_with="bulk out", +) -problem.layers.append(name="Bilayer Tails", thickness="Bilayer Tails Thickness", SLD="Bilayer Tails SLD", - roughness="Bilayer Roughness", hydration="Bilayer Tails Hydration", hydrate_with="bulk out") +problem.layers.append( + name="Bilayer Tails", + thickness="Bilayer Tails Thickness", + SLD="Bilayer Tails SLD", + roughness="Bilayer Roughness", + hydration="Bilayer Tails Hydration", + hydrate_with="bulk out", +) # Make the bulk SLDs del problem.bulk_in[0] @@ -69,8 +291,20 @@ # Now deal with the backgrounds del problem.backgrounds[0] del problem.background_parameters[0] -problem.background_parameters.append(name="Background parameter D2O", min=5.0e-10, value=2.23e-06, max=7.0e-06, fit=True) -problem.background_parameters.append(name="Background parameter SMW", min=1.0e-10, value=3.38e-06, max=4.99e-06, fit=True) +problem.background_parameters.append( + name="Background parameter D2O", + min=5.0e-10, + value=2.23e-06, + max=7.0e-06, + fit=True, +) +problem.background_parameters.append( + name="Background parameter SMW", + min=1.0e-10, + value=3.38e-06, + max=4.99e-06, + fit=True, +) problem.backgrounds.append(name="D2O Background", type="constant", value_1="Background parameter D2O") problem.backgrounds.append(name="SMW Background", type="constant", value_1="Background parameter SMW") @@ -85,15 +319,39 @@ problem.data.append(name="dspc_bil_smw", data=smw_dat) # Set the model -stack = ["Oxide", "SAM Tails", "SAM Heads", "Central Water", "Bilayer Heads", "Bilayer Tails", "Bilayer Tails", - "Bilayer Heads"] +stack = [ + "Oxide", + "SAM Tails", + "SAM Heads", + "Central Water", + "Bilayer Heads", + "Bilayer Tails", + "Bilayer Tails", + "Bilayer Heads", +] # Then make the two contrasts -problem.contrasts.append(name="D2O", bulk_in="Silicon", bulk_out="D2O", background="D2O Background", - resolution="Resolution 1", scalefactor="Scalefactor 1", data="dspc_bil_D2O", model=stack) +problem.contrasts.append( + name="D2O", + bulk_in="Silicon", + bulk_out="D2O", + background="D2O Background", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + data="dspc_bil_D2O", + model=stack, +) -problem.contrasts.append(name="SMW", bulk_in="Silicon", bulk_out="SMW", background="SMW Background", - resolution="Resolution 1", scalefactor="Scalefactor 2", data="dspc_bil_smw", model=stack) +problem.contrasts.append( + name="SMW", + bulk_in="Silicon", + bulk_out="SMW", + background="SMW Background", + resolution="Resolution 1", + scalefactor="Scalefactor 2", + data="dspc_bil_smw", + model=stack, +) controls = RAT.set_controls() diff --git a/RAT/examples/non_polarised/custom_XY_DSPC.py b/RAT/examples/non_polarised/custom_XY_DSPC.py index ebcf31d8..0a8c1167 100644 --- a/RAT/examples/non_polarised/custom_XY_DSPC.py +++ b/RAT/examples/non_polarised/custom_XY_DSPC.py @@ -1,10 +1,10 @@ import math + import numpy as np def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): """This function makes a model of a supported DSPC bilayer using volume restricted distribution functions.""" - # Split up the parameters subRough = params[0] oxideThick = params[1] @@ -19,24 +19,23 @@ def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): # Define these first # define all the neutron b's. - bc = 0.6646e-4 # Carbon - bo = 0.5843e-4 # Oxygen + bc = 0.6646e-4 # Carbon + bo = 0.5843e-4 # Oxygen bh = -0.3739e-4 # Hydrogen - bp = 0.513e-4 # Phosphorus - bn = 0.936e-4 # Nitrogen - bd = 0.6671e-4 # Deuterium + bp = 0.513e-4 # Phosphorus + bn = 0.936e-4 # Nitrogen # Now make the lipid groups - COO = (4*bo) + (2*bc) - GLYC = (3*bc) + (5*bh) - CH3 = (2*bc) + (6*bh) - PO4 = (1*bp) + (4*bo) - CH2 = (1*bc) + (2*bh) - CHOL = (5*bc) + (12*bh) + (1*bn) + COO = (4 * bo) + (2 * bc) + GLYC = (3 * bc) + (5 * bh) + CH3 = (2 * bc) + (6 * bh) + PO4 = (1 * bp) + (4 * bo) + CH2 = (1 * bc) + (2 * bh) + CHOL = (5 * bc) + (12 * bh) + (1 * bn) # Group these into heads and tails heads = CHOL + PO4 + GLYC + COO - tails = (34*CH2) + (2*CH3) + tails = (34 * CH2) + (2 * CH3) # We need volumes for each. Use literature values vHead = 319 @@ -119,21 +118,20 @@ def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): def layer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): - """ - This produces a layer, with a defined thickness, height and roughness. + """This produces a layer, with a defined thickness, height and roughness. Each side of the layer has its own roughness value. """ # Find the edges - l = prevLaySurf - r = prevLaySurf + thickness + left = prevLaySurf + right = prevLaySurf + thickness # Make our heaviside - a = (z-l) / ((2**0.5) * Sigma_L) - b = (z-r) / ((2**0.5) * Sigma_R) + a = (z - left) / ((2**0.5) * Sigma_L) + b = (z - right) / ((2**0.5) * Sigma_R) erf_a = np.array([math.erf(value) for value in a]) erf_b = np.array([math.erf(value) for value in b]) VF = np.array((height / 2) * (erf_a - erf_b)) - return VF, r + return VF, right diff --git a/RAT/examples/non_polarised/custom_bilayer_DSPC.py b/RAT/examples/non_polarised/custom_bilayer_DSPC.py index 2aa3eb91..c97cde4e 100644 --- a/RAT/examples/non_polarised/custom_bilayer_DSPC.py +++ b/RAT/examples/non_polarised/custom_bilayer_DSPC.py @@ -1,8 +1,8 @@ import numpy as np + def custom_bilayer_DSPC(params, bulk_in, bulk_out, contrast): - """ - CUSTOMBILAYER RAT Custom Layer Model File. + """CUSTOMBILAYER RAT Custom Layer Model File. This file accepts 3 vectors containing the values for params, bulk in and bulk out. The final parameter is an index of the contrast being calculated. @@ -23,7 +23,6 @@ def custom_bilayer_DSPC(params, bulk_in, bulk_out, contrast): The second output parameter should be the substrate roughness. """ - sub_rough = params[0] oxide_thick = params[1] oxide_hydration = params[2] @@ -40,24 +39,23 @@ def custom_bilayer_DSPC(params, bulk_in, bulk_out, contrast): # Use known lipid volume and compositions to make the layers # define all the neutron b's. - bc = 0.6646e-4 # Carbon - bo = 0.5843e-4 # Oxygen + bc = 0.6646e-4 # Carbon + bo = 0.5843e-4 # Oxygen bh = -0.3739e-4 # Hydrogen - bp = 0.513e-4 # Phosphorus - bn = 0.936e-4 # Nitrogen - bd = 0.6671e-4 # Deuterium + bp = 0.513e-4 # Phosphorus + bn = 0.936e-4 # Nitrogen # Now make the lipid groups - COO = (4*bo) + (2*bc) - GLYC = (3*bc) + (5*bh) - CH3 = (2*bc) + (6*bh) - PO4 = (1*bp) + (4*bo) - CH2 = (1*bc) + (2*bh) - CHOL = (5*bc) + (12*bh) + (1*bn) + COO = (4 * bo) + (2 * bc) + GLYC = (3 * bc) + (5 * bh) + CH3 = (2 * bc) + (6 * bh) + PO4 = (1 * bp) + (4 * bo) + CH2 = (1 * bc) + (2 * bh) + CHOL = (5 * bc) + (12 * bh) + (1 * bn) # Group these into heads and tails: Head = CHOL + PO4 + GLYC + COO - Tails = (34*CH2) + (2*CH3) + Tails = (34 * CH2) + (2 * CH3) # We need volumes for each. Use literature values: vHead = 319 diff --git a/RAT/inputs.py b/RAT/inputs.py index b19c6898..3c64ceef 100644 --- a/RAT/inputs.py +++ b/RAT/inputs.py @@ -1,4 +1,5 @@ """Converts python models to the necessary inputs for the compiled RAT code""" + import importlib import os import pathlib @@ -6,16 +7,17 @@ import RAT import RAT.controls -from RAT.utils.enums import Calculations, Languages, LayerModels, TypeOptions import RAT.wrappers - from RAT.rat_core import Cells, Checks, Control, Limits, Priors, ProblemDefinition +from RAT.utils.enums import Calculations, Languages, LayerModels, TypeOptions -def make_input(project: RAT.Project, controls: Union[RAT.controls.Calculate, RAT.controls.Simplex, RAT.controls.DE, - RAT.controls.NS, RAT.controls.Dream] - ) -> tuple[ProblemDefinition, Cells, Limits, Priors, Control]: - """Constructs the inputs required for the compiled RAT code using the data defined in the input project and controls. +def make_input( + project: RAT.Project, + controls: Union[RAT.controls.Calculate, RAT.controls.Simplex, RAT.controls.DE, RAT.controls.NS, RAT.controls.Dream], +) -> tuple[ProblemDefinition, Cells, Limits, Priors, Control]: + """Constructs the inputs required for the compiled RAT code using the data defined in the input project and + controls. Parameters ---------- @@ -36,26 +38,28 @@ def make_input(project: RAT.Project, controls: Union[RAT.controls.Calculate, RAT The priors defined for each parameter in the project. cpp_controls : RAT.rat_core.Control The controls object used in the compiled RAT code. - """ - parameter_field = {'parameters': 'param', - 'bulk_in': 'bulkIn', - 'bulk_out': 'bulkOut', - 'scalefactors': 'scalefactor', - 'domain_ratios': 'domainRatio', - 'background_parameters': 'backgroundParam', - 'resolution_parameters': 'resolutionParam', - } - checks_field = {'parameters': 'fitParam', - 'bulk_in': 'fitBulkIn', - 'bulk_out': 'fitBulkOut', - 'scalefactors': 'fitScalefactor', - 'domain_ratios': 'fitDomainRatio', - 'background_parameters': 'fitBackgroundParam', - 'resolution_parameters': 'fitResolutionParam', - } - - prior_id = {'uniform': 1, 'gaussian': 2, 'jeffreys': 3} + """ + parameter_field = { + "parameters": "param", + "bulk_in": "bulkIn", + "bulk_out": "bulkOut", + "scalefactors": "scalefactor", + "domain_ratios": "domainRatio", + "background_parameters": "backgroundParam", + "resolution_parameters": "resolutionParam", + } + checks_field = { + "parameters": "fitParam", + "bulk_in": "fitBulkIn", + "bulk_out": "fitBulkOut", + "scalefactors": "fitScalefactor", + "domain_ratios": "fitDomainRatio", + "background_parameters": "fitBackgroundParam", + "resolution_parameters": "fitResolutionParam", + } + + prior_id = {"uniform": 1, "gaussian": 2, "jeffreys": 3} problem = make_problem(project) cells = make_cells(project) @@ -66,21 +70,30 @@ def make_input(project: RAT.Project, controls: Union[RAT.controls.Calculate, RAT for class_list in RAT.project.parameter_class_lists: setattr(checks, checks_field[class_list], [int(element.fit) for element in getattr(project, class_list)]) - setattr(limits, parameter_field[class_list], [[element.min, element.max] - for element in getattr(project, class_list)]) - setattr(priors, parameter_field[class_list], [[element.name, element.prior_type, element.mu, element.sigma] - for element in getattr(project, class_list)]) + setattr( + limits, + parameter_field[class_list], + [[element.min, element.max] for element in getattr(project, class_list)], + ) + setattr( + priors, + parameter_field[class_list], + [[element.name, element.prior_type, element.mu, element.sigma] for element in getattr(project, class_list)], + ) # Use dummy values for qzshifts checks.fitQzshift = [] limits.qzshift = [] priors.qzshift = [] - priors.priorNames = [param.name for class_list in RAT.project.parameter_class_lists - for param in getattr(project, class_list)] - priors.priorValues = [[prior_id[param.prior_type], param.mu, param.sigma] - for class_list in RAT.project.parameter_class_lists - for param in getattr(project, class_list)] + priors.priorNames = [ + param.name for class_list in RAT.project.parameter_class_lists for param in getattr(project, class_list) + ] + priors.priorValues = [ + [prior_id[param.prior_type], param.mu, param.sigma] + for class_list in RAT.project.parameter_class_lists + for param in getattr(project, class_list) + ] if project.model == LayerModels.CustomXY: controls.calcSldDuringFit = True @@ -102,12 +115,13 @@ def make_problem(project: RAT.Project) -> ProblemDefinition: ------- problem : RAT.rat_core.ProblemDefinition The problem input used in the compiled RAT code. + """ - action_id = {'add': 1, 'subtract': 2} + action_id = {"add": 1, "subtract": 2} # Set contrast parameters according to model type if project.model == LayerModels.StandardLayers: - contrast_custom_files = [float('NaN')] * len(project.contrasts) + contrast_custom_files = [float("NaN")] * len(project.contrasts) else: contrast_custom_files = [project.custom_files.index(contrast.model[0], True) for contrast in project.contrasts] @@ -148,9 +162,13 @@ def make_problem(project: RAT.Project) -> ProblemDefinition: problem.contrastBulkIns = [project.bulk_in.index(contrast.bulk_in, True) for contrast in project.contrasts] problem.contrastBulkOuts = [project.bulk_out.index(contrast.bulk_out, True) for contrast in project.contrasts] problem.contrastQzshifts = [0] * len(project.contrasts) # This is marked as "to do" in RAT - problem.contrastScalefactors = [project.scalefactors.index(contrast.scalefactor, True) for contrast in project.contrasts] - problem.contrastDomainRatios = [project.domain_ratios.index(contrast.domain_ratio, True) - if hasattr(contrast, 'domain_ratio') else 0 for contrast in project.contrasts] + problem.contrastScalefactors = [ + project.scalefactors.index(contrast.scalefactor, True) for contrast in project.contrasts + ] + problem.contrastDomainRatios = [ + project.domain_ratios.index(contrast.domain_ratio, True) if hasattr(contrast, "domain_ratio") else 0 + for contrast in project.contrasts + ] problem.contrastBackgroundParams = contrast_background_params problem.contrastBackgroundActions = [action_id[contrast.background_action] for contrast in project.contrasts] problem.contrastResolutionParams = contrast_resolution_params @@ -161,14 +179,30 @@ def make_problem(project: RAT.Project) -> ProblemDefinition: problem.numberOfContrasts = len(project.contrasts) problem.numberOfLayers = len(project.layers) problem.numberOfDomainContrasts = len(project.domain_contrasts) - problem.fitParams = [param.value for class_list in RAT.project.parameter_class_lists - for param in getattr(project, class_list) if param.fit] - problem.fitLimits = [[param.min, param.max] for class_list in RAT.project.parameter_class_lists - for param in getattr(project, class_list) if param.fit] - problem.otherParams = [param.value for class_list in RAT.project.parameter_class_lists - for param in getattr(project, class_list) if not param.fit] - problem.otherLimits = [[param.min, param.max] for class_list in RAT.project.parameter_class_lists - for param in getattr(project, class_list) if not param.fit] + problem.fitParams = [ + param.value + for class_list in RAT.project.parameter_class_lists + for param in getattr(project, class_list) + if param.fit + ] + problem.fitLimits = [ + [param.min, param.max] + for class_list in RAT.project.parameter_class_lists + for param in getattr(project, class_list) + if param.fit + ] + problem.otherParams = [ + param.value + for class_list in RAT.project.parameter_class_lists + for param in getattr(project, class_list) + if not param.fit + ] + problem.otherLimits = [ + [param.min, param.max] + for class_list in RAT.project.parameter_class_lists + for param in getattr(project, class_list) + if not param.fit + ] check_indices(problem) @@ -187,6 +221,7 @@ def make_resample(project: RAT.Project) -> list[int]: ------- : list[int] The "resample" field of the problem input used in the compiled RAT code. + """ return [contrast.resample for contrast in project.contrasts] @@ -203,8 +238,11 @@ def make_data_present(project: RAT.Project) -> list[int]: ------- : list[int] The "dataPresent" field of the problem input used in the compiled RAT code. + """ - return [1 if project.data[project.data.index(contrast.data)].data.size != 0 else 0 for contrast in project.contrasts] + return [ + 1 if project.data[project.data.index(contrast.data)].data.size != 0 else 0 for contrast in project.contrasts + ] def check_indices(problem: ProblemDefinition) -> None: @@ -215,26 +253,33 @@ def check_indices(problem: ProblemDefinition) -> None: ---------- problem : RAT.rat_core.ProblemDefinition The problem input used in the compiled RAT code. + """ - index_list = {'bulkIn': 'contrastBulkIns', - 'bulkOut': 'contrastBulkOuts', - 'scalefactors': 'contrastScalefactors', - 'domainRatio': 'contrastDomainRatios', - 'backgroundParams': 'contrastBackgroundParams', - 'resolutionParams': 'contrastResolutionParams', - } + index_list = { + "bulkIn": "contrastBulkIns", + "bulkOut": "contrastBulkOuts", + "scalefactors": "contrastScalefactors", + "domainRatio": "contrastDomainRatios", + "backgroundParams": "contrastBackgroundParams", + "resolutionParams": "contrastResolutionParams", + } # Check the indices -- note we have switched to 1-based indexing at this point - for params in index_list.keys(): + for params in index_list: param_list = getattr(problem, params) - if len(param_list) > 0 and not all((element > 0 or element == -1) and element <= len(param_list) - for element in getattr(problem, index_list[params])): - elements = [element for element in getattr(problem, index_list[params]) - if not ((element > 0 or element == -1) and element <= len(param_list))] - raise IndexError(f'The problem field "{index_list[params]}" contains: {", ".join(str(i) for i in elements)}' - f', which lie outside of the range of "{params}"') - - return None + if len(param_list) > 0 and not all( + (element > 0 or element == -1) and element <= len(param_list) + for element in getattr(problem, index_list[params]) + ): + elements = [ + element + for element in getattr(problem, index_list[params]) + if not ((element > 0 or element == -1) and element <= len(param_list)) + ] + raise IndexError( + f'The problem field "{index_list[params]}" contains: {", ".join(str(i) for i in elements)}' + f', which lie outside of the range of "{params}"', + ) def make_cells(project: RAT.Project) -> Cells: @@ -251,28 +296,32 @@ def make_cells(project: RAT.Project) -> Cells: ------- cells : RAT.rat_core.Cells The set of inputs that are defined in MATLAB as cell arrays. - """ - hydrate_id = {'bulk in': 1, 'bulk out': 2} + """ + hydrate_id = {"bulk in": 1, "bulk out": 2} # Set contrast parameters according to model type if project.model == LayerModels.StandardLayers: if project.calculation == Calculations.Domains: - contrast_models = [[project.domain_contrasts.index(domain_contrast, True) for domain_contrast in contrast.model] - for contrast in project.contrasts] + contrast_models = [ + [project.domain_contrasts.index(domain_contrast, True) for domain_contrast in contrast.model] + for contrast in project.contrasts + ] else: - contrast_models = [[project.layers.index(layer, True) for layer in contrast.model] - for contrast in project.contrasts] + contrast_models = [ + [project.layers.index(layer, True) for layer in contrast.model] for contrast in project.contrasts + ] else: contrast_models = [[]] * len(project.contrasts) # Get details of defined layers layer_details = [] for layer in project.layers: - - layer_params = [project.parameters.index(getattr(layer, attribute), True) - for attribute in list(layer.model_fields.keys())[1:-2]] - layer_params.append(project.parameters.index(layer.hydration, True) if layer.hydration else float('NaN')) + layer_params = [ + project.parameters.index(getattr(layer, attribute), True) + for attribute in list(layer.model_fields.keys())[1:-2] + ] + layer_params.append(project.parameters.index(layer.hydration, True) if layer.hydration else float("NaN")) layer_params.append(hydrate_id[layer.hydrate_with]) layer_details.append(layer_params) @@ -283,7 +332,6 @@ def make_cells(project: RAT.Project) -> Cells: simulation_limits = [] for contrast in project.contrasts: - data_index = project.data.index(contrast.data) all_data.append(project.data[data_index].data) data_range = project.data[data_index].data_range @@ -331,10 +379,13 @@ def make_cells(project: RAT.Project) -> Cells: cells.f17 = [[[]]] * len(project.contrasts) # Placeholder for oil chi data cells.f18 = [[0, 1]] * len(project.domain_contrasts) # This is marked as "to do" in RAT - domain_contrast_models = [[project.layers.index(layer, True) for layer in domain_contrast.model] - for domain_contrast in project.domain_contrasts] - cells.f19 = [domain_contrast_model if domain_contrast_model else 0 - for domain_contrast_model in domain_contrast_models] + domain_contrast_models = [ + [project.layers.index(layer, True) for layer in domain_contrast.model] + for domain_contrast in project.domain_contrasts + ] + cells.f19 = [ + domain_contrast_model if domain_contrast_model else 0 for domain_contrast_model in domain_contrast_models + ] cells.f20 = [param.name for param in project.domain_ratios] @@ -357,6 +408,7 @@ def get_python_handle(file_name: str, function_name: str, path: Union[str, pathl ------- handle : Callable The handle of the function defined in the python module file. + """ spec = importlib.util.spec_from_file_location(pathlib.Path(file_name).stem, os.path.join(path, file_name)) custom_module = importlib.util.module_from_spec(spec) @@ -365,8 +417,10 @@ def get_python_handle(file_name: str, function_name: str, path: Union[str, pathl return handle -def make_controls(controls: Union[RAT.controls.Calculate, RAT.controls.Simplex, RAT.controls.DE, RAT.controls.NS, - RAT.controls.Dream], checks: Checks) -> Control: +def make_controls( + controls: Union[RAT.controls.Calculate, RAT.controls.Simplex, RAT.controls.DE, RAT.controls.NS, RAT.controls.Dream], + checks: Checks, +) -> Control: """Converts the controls object to the format required by the compiled RAT code. Parameters @@ -380,8 +434,8 @@ def make_controls(controls: Union[RAT.controls.Calculate, RAT.controls.Simplex, ------- controls : RAT.rat_core.Control The controls object used in the compiled RAT code. - """ + """ full_controls = RAT.controls.Controls(**controls.model_dump()) cpp_controls = Control() diff --git a/RAT/models.py b/RAT/models.py index 7970363b..2ec9aa21 100644 --- a/RAT/models.py +++ b/RAT/models.py @@ -1,10 +1,11 @@ """The models module. Contains the pydantic models used by RAT to store project parameters.""" -import numpy as np -from pydantic import BaseModel, Field, ValidationInfo, field_validator, model_validator import pathlib from typing import Any, Union +import numpy as np +from pydantic import BaseModel, Field, ValidationInfo, field_validator, model_validator + from RAT.utils.enums import BackgroundActions, Hydration, Languages, Priors, TypeOptions try: @@ -32,105 +33,109 @@ def int_sequence(): resolution_number = int_sequence() -class RATModel(BaseModel, validate_assignment=True, extra='forbid'): +class RATModel(BaseModel, validate_assignment=True, extra="forbid"): """A BaseModel where enums are represented by their value.""" + def __repr__(self): - fields_repr = (', '.join(repr(v) if a is None else - f'{a}={v.value!r}' if isinstance(v, StrEnum) else - f'{a}={v!r}' - for a, v in self.__repr_args__() - ) - ) - return f'{self.__repr_name__()}({fields_repr})' + fields_repr = ", ".join( + repr(v) if a is None else f"{a}={v.value!r}" if isinstance(v, StrEnum) else f"{a}={v!r}" + for a, v in self.__repr_args__() + ) + return f"{self.__repr_name__()}({fields_repr})" class Background(RATModel): """Defines the Backgrounds in RAT.""" - name: str = Field(default_factory=lambda: 'New Background ' + next(background_number), min_length=1) + + name: str = Field(default_factory=lambda: "New Background " + next(background_number), min_length=1) type: TypeOptions = TypeOptions.Constant - value_1: str = '' - value_2: str = '' - value_3: str = '' - value_4: str = '' - value_5: str = '' + value_1: str = "" + value_2: str = "" + value_3: str = "" + value_4: str = "" + value_5: str = "" class Contrast(RATModel): """Groups together all of the components of the model.""" - name: str = Field(default_factory=lambda: 'New Contrast ' + next(contrast_number), min_length=1) - data: str = '' - background: str = '' + + name: str = Field(default_factory=lambda: "New Contrast " + next(contrast_number), min_length=1) + data: str = "" + background: str = "" background_action: BackgroundActions = BackgroundActions.Add - bulk_in: str = '' - bulk_out: str = '' - scalefactor: str = '' - resolution: str = '' + bulk_in: str = "" + bulk_out: str = "" + scalefactor: str = "" + resolution: str = "" resample: bool = False model: list[str] = [] class ContrastWithRatio(RATModel): """Groups together all of the components of the model including domain terms.""" - name: str = Field(default_factory=lambda: 'New Contrast ' + next(contrast_number), min_length=1) - data: str = '' - background: str = '' + + name: str = Field(default_factory=lambda: "New Contrast " + next(contrast_number), min_length=1) + data: str = "" + background: str = "" background_action: BackgroundActions = BackgroundActions.Add - bulk_in: str = '' - bulk_out: str = '' - scalefactor: str = '' - resolution: str = '' + bulk_in: str = "" + bulk_out: str = "" + scalefactor: str = "" + resolution: str = "" resample: bool = False - domain_ratio: str = '' + domain_ratio: str = "" model: list[str] = [] class CustomFile(RATModel): """Defines the files containing functions to run when using custom models.""" - name: str = Field(default_factory=lambda: 'New Custom File ' + next(custom_file_number), min_length=1) - filename: str = '' - function_name: str = '' + + name: str = Field(default_factory=lambda: "New Custom File " + next(custom_file_number), min_length=1) + filename: str = "" + function_name: str = "" language: Languages = Languages.Python - path: Union[str, pathlib.Path] = '' + path: Union[str, pathlib.Path] = "" def model_post_init(self, __context: Any) -> None: """If a "filename" is supplied but the "function_name" field is not set, the "function_name" should be set to the file name without the extension. """ - if "filename" in self.model_fields_set and "function_name" not in self.model_fields_set: self.function_name = pathlib.Path(self.filename).stem - @model_validator(mode='after') + @model_validator(mode="after") def set_matlab_function_name(self): - """If we have a matlab custom function, the "function_name" should be set to the filename without the extension. + """If we have a matlab custom function, the "function_name" should be set to the filename without the + extension. """ if self.language == Languages.Matlab and self.function_name != pathlib.Path(self.filename).stem: self.function_name = pathlib.Path(self.filename).stem return self - + class Data(RATModel, arbitrary_types_allowed=True): """Defines the dataset required for each contrast.""" - name: str = Field(default_factory=lambda: 'New Data ' + next(data_number), min_length=1) + + name: str = Field(default_factory=lambda: "New Data " + next(data_number), min_length=1) data: np.ndarray[np.float64] = np.empty([0, 3]) data_range: list[float] = Field(default=[], min_length=2, max_length=2) simulation_range: list[float] = Field(default=[], min_length=2, max_length=2) - @field_validator('data') + @field_validator("data") @classmethod def check_data_dimension(cls, data: np.ndarray[float]) -> np.ndarray[float]: """The data must be a two-dimensional array containing at least three columns.""" try: data.shape[1] except IndexError: - raise ValueError('"data" must have at least two dimensions') + raise ValueError('"data" must have at least two dimensions') from None else: if data.shape[1] < 3: - raise ValueError('"data" must have at least three columns') + raise ValueError('"data" must have at least three columns') from None return data - @field_validator('data_range', 'simulation_range') + @field_validator("data_range", "simulation_range") @classmethod def check_min_max(cls, limits: list[float], info: ValidationInfo) -> list[float]: """The data range and simulation range maximum must be greater than the minimum.""" @@ -149,85 +154,94 @@ def model_post_init(self, __context: Any) -> None: if field not in self.model_fields_set: getattr(self, field).extend([data_min, data_max]) - @model_validator(mode='after') - def check_ranges(self) -> 'Data': + @model_validator(mode="after") + def check_ranges(self) -> "Data": """The limits of the "data_range" field must lie within the range of the supplied data, whilst the limits of the "simulation_range" field must lie outside the range of the supplied data. """ if self.data.shape[0] > 0: data_min = np.min(self.data[:, 0]) data_max = np.max(self.data[:, 0]) - if "data_range" in self.model_fields_set and (self.data_range[0] < data_min or - self.data_range[1] > data_max): - raise ValueError(f'The data_range value of: {self.data_range} must lie within the min/max values of ' - f'the data: [{data_min}, {data_max}]') - if "simulation_range" in self.model_fields_set and (self.simulation_range[0] > data_min or - self.simulation_range[1] < data_max): - raise ValueError(f'The simulation_range value of: {self.simulation_range} must lie outside of the ' - f'min/max values of the data: [{data_min}, {data_max}]') + if "data_range" in self.model_fields_set and ( + self.data_range[0] < data_min or self.data_range[1] > data_max + ): + raise ValueError( + f"The data_range value of: {self.data_range} must lie within the min/max values of " + f"the data: [{data_min}, {data_max}]", + ) + if "simulation_range" in self.model_fields_set and ( + self.simulation_range[0] > data_min or self.simulation_range[1] < data_max + ): + raise ValueError( + f"The simulation_range value of: {self.simulation_range} must lie outside of the " + f"min/max values of the data: [{data_min}, {data_max}]", + ) return self - def __eq__(self, other: Any) -> bool: + def __eq__(self, other: object) -> bool: if isinstance(other, BaseModel): # When comparing instances of generic types for equality, as long as all field values are equal, # only require their generic origin types to be equal, rather than exact type equality. # This prevents headaches like MyGeneric(x=1) != MyGeneric[Any](x=1). - self_type = self.__pydantic_generic_metadata__['origin'] or self.__class__ - other_type = other.__pydantic_generic_metadata__['origin'] or other.__class__ + self_type = self.__pydantic_generic_metadata__["origin"] or self.__class__ + other_type = other.__pydantic_generic_metadata__["origin"] or other.__class__ return ( - self_type == other_type - and self.name == other.name - and (self.data == other.data).all() - and self.data_range == other.data_range - and self.simulation_range == other.simulation_range - and self.__pydantic_private__ == other.__pydantic_private__ - and self.__pydantic_extra__ == other.__pydantic_extra__ + self_type == other_type + and self.name == other.name + and (self.data == other.data).all() + and self.data_range == other.data_range + and self.simulation_range == other.simulation_range + and self.__pydantic_private__ == other.__pydantic_private__ + and self.__pydantic_extra__ == other.__pydantic_extra__ ) else: return NotImplemented # delegate to the other item in the comparison def __repr__(self): """Only include the name if the data is empty.""" - fields_repr = (f"name={self.name!r}" if self.data.size == 0 else - ", ".join(repr(v) if a is None else - f"{a}={v!r}" - for a, v in self.__repr_args__() - ) - ) - return f'{self.__repr_name__()}({fields_repr})' + fields_repr = ( + f"name={self.name!r}" + if self.data.size == 0 + else ", ".join(repr(v) if a is None else f"{a}={v!r}" for a, v in self.__repr_args__()) + ) + return f"{self.__repr_name__()}({fields_repr})" class DomainContrast(RATModel): """Groups together the layers required for each domain.""" - name: str = Field(default_factory=lambda: 'New Domain Contrast ' + next(domain_contrast_number), min_length=1) + + name: str = Field(default_factory=lambda: "New Domain Contrast " + next(domain_contrast_number), min_length=1) model: list[str] = [] class Layer(RATModel, populate_by_name=True): """Combines parameters into defined layers.""" - name: str = Field(default_factory=lambda: 'New Layer ' + next(layer_number), min_length=1) + + name: str = Field(default_factory=lambda: "New Layer " + next(layer_number), min_length=1) thickness: str - SLD: str = Field(validation_alias='SLD_real') + SLD: str = Field(validation_alias="SLD_real") roughness: str - hydration: str = '' + hydration: str = "" hydrate_with: Hydration = Hydration.BulkOut class AbsorptionLayer(RATModel, populate_by_name=True): """Combines parameters into defined layers including absorption terms.""" - name: str = Field(default_factory=lambda: 'New Layer ' + next(layer_number), min_length=1) + + name: str = Field(default_factory=lambda: "New Layer " + next(layer_number), min_length=1) thickness: str - SLD_real: str = Field(validation_alias='SLD') - SLD_imaginary: str = '' + SLD_real: str = Field(validation_alias="SLD") + SLD_imaginary: str = "" roughness: str - hydration: str = '' + hydration: str = "" hydrate_with: Hydration = Hydration.BulkOut class Parameter(RATModel): """Defines parameters needed to specify the model.""" - name: str = Field(default_factory=lambda: 'New Parameter ' + next(parameter_number), min_length=1) + + name: str = Field(default_factory=lambda: "New Parameter " + next(parameter_number), min_length=1) min: float = 0.0 value: float = 0.0 max: float = 0.0 @@ -236,32 +250,34 @@ class Parameter(RATModel): mu: float = 0.0 sigma: float = np.inf - @model_validator(mode='after') - def check_min_max(self) -> 'Parameter': + @model_validator(mode="after") + def check_min_max(self) -> "Parameter": """The maximum value of a parameter must be greater than the minimum.""" if self.min > self.max: - raise ValueError(f'The maximum value {self.max} must be greater than the minimum value {self.min}') + raise ValueError(f"The maximum value {self.max} must be greater than the minimum value {self.min}") return self - @model_validator(mode='after') - def check_value_in_range(self) -> 'Parameter': + @model_validator(mode="after") + def check_value_in_range(self) -> "Parameter": """The value of a parameter must lie within its defined bounds.""" if self.value < self.min or self.value > self.max: - raise ValueError(f'value {self.value} is not within the defined range: {self.min} <= value <= {self.max}') + raise ValueError(f"value {self.value} is not within the defined range: {self.min} <= value <= {self.max}") return self class ProtectedParameter(Parameter): """A Parameter with a fixed name.""" + name: str = Field(frozen=True, min_length=1) class Resolution(RATModel): """Defines Resolutions in RAT.""" - name: str = Field(default_factory=lambda: 'New Resolution ' + next(resolution_number), min_length=1) + + name: str = Field(default_factory=lambda: "New Resolution " + next(resolution_number), min_length=1) type: TypeOptions = TypeOptions.Constant - value_1: str = '' - value_2: str = '' - value_3: str = '' - value_4: str = '' - value_5: str = '' + value_1: str = "" + value_2: str = "" + value_3: str = "" + value_4: str = "" + value_5: str = "" diff --git a/RAT/outputs.py b/RAT/outputs.py index fee942a8..6ed51bc2 100644 --- a/RAT/outputs.py +++ b/RAT/outputs.py @@ -1,10 +1,12 @@ """Converts outputs from the compiled RAT code to python dataclasses""" from dataclasses import dataclass -import numpy as np from typing import Optional, Union -from RAT.utils.enums import Procedures + +import numpy as np + import RAT.rat_core +from RAT.utils.enums import Procedures @dataclass @@ -106,13 +108,16 @@ class BayesResults(Results): chain: np.ndarray -def make_results(procedure: Procedures, output_results: RAT.rat_core.OutputResult, - bayes_results: Optional[RAT.rat_core.BayesResults] = None) -> Union[Results, BayesResults]: +def make_results( + procedure: Procedures, + output_results: RAT.rat_core.OutputResult, + bayes_results: Optional[RAT.rat_core.BayesResults] = None, +) -> Union[Results, BayesResults]: """Initialise a python Results or BayesResults object using the outputs from a RAT calculation.""" - - calculation_results = CalculationResults(chiValues=output_results.calculationResults.chiValues, - sumChi=output_results.calculationResults.sumChi - ) + calculation_results = CalculationResults( + chiValues=output_results.calculationResults.chiValues, + sumChi=output_results.calculationResults.sumChi, + ) contrast_params = ContrastParams( backgroundParams=output_results.contrastParams.backgroundParams, scalefactors=output_results.contrastParams.scalefactors, @@ -120,23 +125,22 @@ def make_results(procedure: Procedures, output_results: RAT.rat_core.OutputResul bulkOut=output_results.contrastParams.bulkOut, resolutionParams=output_results.contrastParams.resolutionParams, subRoughs=output_results.contrastParams.subRoughs, - resample=output_results.contrastParams.resample + resample=output_results.contrastParams.resample, ) if procedure in [Procedures.NS, Procedures.Dream]: - prediction_intervals = PredictionIntervals( reflectivity=bayes_results.predictionIntervals.reflectivity, sld=bayes_results.predictionIntervals.sld, reflectivityXData=bayes_results.predictionIntervals.reflectivityXData, sldXData=bayes_results.predictionIntervals.sldXData, - sampleChi=bayes_results.predictionIntervals.sampleChi + sampleChi=bayes_results.predictionIntervals.sampleChi, ) confidence_intervals = ConfidenceIntervals( percentile95=bayes_results.confidenceIntervals.percentile95, percentile65=bayes_results.confidenceIntervals.percentile65, - mean=bayes_results.confidenceIntervals.mean + mean=bayes_results.confidenceIntervals.mean, ) dream_params = DreamParams( @@ -158,7 +162,7 @@ def make_results(procedure: Procedures, output_results: RAT.rat_core.OutputResul ABC=bool(bayes_results.dreamParams.ABC), IO=bool(bayes_results.dreamParams.IO), storeOutput=bool(bayes_results.dreamParams.storeOutput), - R=bayes_results.dreamParams.R + R=bayes_results.dreamParams.R, ) dream_output = DreamOutput( @@ -169,13 +173,13 @@ def make_results(procedure: Procedures, output_results: RAT.rat_core.OutputResul modelOutput=bayes_results.dreamOutput.modelOutput, AR=bayes_results.dreamOutput.AR, R_stat=bayes_results.dreamOutput.R_stat, - CR=bayes_results.dreamOutput.CR + CR=bayes_results.dreamOutput.CR, ) nested_sampler_output = NestedSamplerOutput( logZ=bayes_results.nestedSamplerOutput.logZ, nestSamples=bayes_results.nestedSamplerOutput.nestSamples, - postSamples=bayes_results.nestedSamplerOutput.postSamples + postSamples=bayes_results.nestedSamplerOutput.postSamples, ) results = BayesResults( @@ -194,11 +198,10 @@ def make_results(procedure: Procedures, output_results: RAT.rat_core.OutputResul dreamParams=dream_params, dreamOutput=dream_output, nestedSamplerOutput=nested_sampler_output, - chain=bayes_results.chain + chain=bayes_results.chain, ) else: - results = Results( reflectivity=output_results.reflectivity, simulation=output_results.simulation, @@ -209,7 +212,7 @@ def make_results(procedure: Procedures, output_results: RAT.rat_core.OutputResul calculationResults=calculation_results, contrastParams=contrast_params, fitParams=output_results.fitParams, - fitNames=output_results.fitNames + fitNames=output_results.fitNames, ) return results diff --git a/RAT/project.py b/RAT/project.py index 8166419f..46b2b224 100644 --- a/RAT/project.py +++ b/RAT/project.py @@ -3,88 +3,104 @@ import collections import copy import functools -import numpy as np import os -from pydantic import BaseModel, ValidationInfo, field_validator, model_validator, ValidationError from typing import Any, Callable -from RAT.classlist import ClassList +import numpy as np +from pydantic import BaseModel, ValidationError, ValidationInfo, field_validator, model_validator + import RAT.models +from RAT.classlist import ClassList from RAT.utils.custom_errors import custom_pydantic_validation_error from RAT.utils.enums import Calculations, Geometries, LayerModels, Priors, TypeOptions - # Map project fields to pydantic models -model_in_classlist = {'parameters': 'Parameter', - 'bulk_in': 'Parameter', - 'bulk_out': 'Parameter', - 'scalefactors': 'Parameter', - 'domain_ratios': 'Parameter', - 'background_parameters': 'Parameter', - 'resolution_parameters': 'Parameter', - 'backgrounds': 'Background', - 'resolutions': 'Resolution', - 'custom_files': 'CustomFile', - 'data': 'Data', - 'layers': 'Layer', - 'domain_contrasts': 'DomainContrast', - 'contrasts': 'Contrast', - } - -values_defined_in = {'backgrounds.value_1': 'background_parameters', - 'backgrounds.value_2': 'background_parameters', - 'backgrounds.value_3': 'background_parameters', - 'backgrounds.value_4': 'background_parameters', - 'backgrounds.value_5': 'background_parameters', - 'resolutions.value_1': 'resolution_parameters', - 'resolutions.value_2': 'resolution_parameters', - 'resolutions.value_3': 'resolution_parameters', - 'resolutions.value_4': 'resolution_parameters', - 'resolutions.value_5': 'resolution_parameters', - 'layers.thickness': 'parameters', - 'layers.SLD': 'parameters', - 'layers.SLD_real': 'parameters', - 'layers.SLD_imaginary': 'parameters', - 'layers.roughness': 'parameters', - 'contrasts.data': 'data', - 'contrasts.background': 'backgrounds', - 'contrasts.bulk_in': 'bulk_in', - 'contrasts.bulk_out': 'bulk_out', - 'contrasts.scalefactor': 'scalefactors', - 'contrasts.resolution': 'resolutions', - 'contrasts.domain_ratio': 'domain_ratios', - } - -AllFields = collections.namedtuple('AllFields', ['attribute', 'fields']) -model_names_used_in = {'background_parameters': AllFields('backgrounds', ['value_1', 'value_2', 'value_3', 'value_4', - 'value_5']), - 'resolution_parameters': AllFields('resolutions', ['value_1', 'value_2', 'value_3', 'value_4', - 'value_5']), - 'parameters': AllFields('layers', ['thickness', 'SLD', 'SLD_real', 'SLD_imaginary', - 'roughness', 'hydration']), - 'data': AllFields('contrasts', ['data']), - 'backgrounds': AllFields('contrasts', ['background']), - 'bulk_in': AllFields('contrasts', ['bulk_in']), - 'bulk_out': AllFields('contrasts', ['bulk_out']), - 'scalefactors': AllFields('contrasts', ['scalefactor']), - 'domain_ratios': AllFields('contrasts', ['domain_ratio']), - 'resolutions': AllFields('contrasts', ['resolution']), - } +model_in_classlist = { + "parameters": "Parameter", + "bulk_in": "Parameter", + "bulk_out": "Parameter", + "scalefactors": "Parameter", + "domain_ratios": "Parameter", + "background_parameters": "Parameter", + "resolution_parameters": "Parameter", + "backgrounds": "Background", + "resolutions": "Resolution", + "custom_files": "CustomFile", + "data": "Data", + "layers": "Layer", + "domain_contrasts": "DomainContrast", + "contrasts": "Contrast", +} + +values_defined_in = { + "backgrounds.value_1": "background_parameters", + "backgrounds.value_2": "background_parameters", + "backgrounds.value_3": "background_parameters", + "backgrounds.value_4": "background_parameters", + "backgrounds.value_5": "background_parameters", + "resolutions.value_1": "resolution_parameters", + "resolutions.value_2": "resolution_parameters", + "resolutions.value_3": "resolution_parameters", + "resolutions.value_4": "resolution_parameters", + "resolutions.value_5": "resolution_parameters", + "layers.thickness": "parameters", + "layers.SLD": "parameters", + "layers.SLD_real": "parameters", + "layers.SLD_imaginary": "parameters", + "layers.roughness": "parameters", + "contrasts.data": "data", + "contrasts.background": "backgrounds", + "contrasts.bulk_in": "bulk_in", + "contrasts.bulk_out": "bulk_out", + "contrasts.scalefactor": "scalefactors", + "contrasts.resolution": "resolutions", + "contrasts.domain_ratio": "domain_ratios", +} + +AllFields = collections.namedtuple("AllFields", ["attribute", "fields"]) +model_names_used_in = { + "background_parameters": AllFields("backgrounds", ["value_1", "value_2", "value_3", "value_4", "value_5"]), + "resolution_parameters": AllFields("resolutions", ["value_1", "value_2", "value_3", "value_4", "value_5"]), + "parameters": AllFields("layers", ["thickness", "SLD", "SLD_real", "SLD_imaginary", "roughness", "hydration"]), + "data": AllFields("contrasts", ["data"]), + "backgrounds": AllFields("contrasts", ["background"]), + "bulk_in": AllFields("contrasts", ["bulk_in"]), + "bulk_out": AllFields("contrasts", ["bulk_out"]), + "scalefactors": AllFields("contrasts", ["scalefactor"]), + "domain_ratios": AllFields("contrasts", ["domain_ratio"]), + "resolutions": AllFields("contrasts", ["resolution"]), +} # Note that the order of these parameters is hard-coded into RAT -parameter_class_lists = ['parameters', 'background_parameters', 'scalefactors', 'bulk_in', 'bulk_out', - 'resolution_parameters', 'domain_ratios'] -class_lists = [*parameter_class_lists, 'backgrounds', 'resolutions', 'custom_files', 'data', 'layers', - 'domain_contrasts', 'contrasts'] - - -class Project(BaseModel, validate_assignment=True, extra='forbid', arbitrary_types_allowed=True): +parameter_class_lists = [ + "parameters", + "background_parameters", + "scalefactors", + "bulk_in", + "bulk_out", + "resolution_parameters", + "domain_ratios", +] +class_lists = [ + *parameter_class_lists, + "backgrounds", + "resolutions", + "custom_files", + "data", + "layers", + "domain_contrasts", + "contrasts", +] + + +class Project(BaseModel, validate_assignment=True, extra="forbid", arbitrary_types_allowed=True): """Defines the input data for a reflectivity calculation in RAT. This class combines the data defined in each of the pydantic models included in "models.py" into the full set of inputs required for a reflectivity calculation. """ - name: str = '' + + name: str = "" calculation: Calculations = Calculations.NonPolarised model: LayerModels = LayerModels.StandardLayers geometry: Geometries = Geometries.AirSubstrate @@ -92,36 +108,91 @@ class Project(BaseModel, validate_assignment=True, extra='forbid', arbitrary_typ parameters: ClassList = ClassList() - bulk_in: ClassList = ClassList(RAT.models.Parameter(name='SLD Air', min=0.0, value=0.0, max=0.0, fit=False, - prior_type=Priors.Uniform, mu=0.0, sigma=np.inf)) - - bulk_out: ClassList = ClassList(RAT.models.Parameter(name='SLD D2O', min=6.2e-6, value=6.35e-6, max=6.35e-6, - fit=False, prior_type=Priors.Uniform, mu=0.0, - sigma=np.inf)) - - scalefactors: ClassList = ClassList(RAT.models.Parameter(name='Scalefactor 1', min=0.02, value=0.23, max=0.25, - fit=False, prior_type=Priors.Uniform, mu=0.0, - sigma=np.inf)) - - domain_ratios: ClassList = ClassList(RAT.models.Parameter(name='Domain Ratio 1', min=0.4, value=0.5, max=0.6, - fit=False, prior_type=Priors.Uniform, mu=0.0, - sigma=np.inf)) - - background_parameters: ClassList = ClassList(RAT.models.Parameter(name='Background Param 1', min=1e-7, value=1e-6, - max=1e-5, fit=False, - prior_type=Priors.Uniform, mu=0.0, - sigma=np.inf)) - - backgrounds: ClassList = ClassList(RAT.models.Background(name='Background 1', type=TypeOptions.Constant, - value_1='Background Param 1')) - - resolution_parameters: ClassList = ClassList(RAT.models.Parameter(name='Resolution Param 1', min=0.01, value=0.03, - max=0.05, fit=False, - prior_type=Priors.Uniform, mu=0.0, - sigma=np.inf)) - - resolutions: ClassList = ClassList(RAT.models.Resolution(name='Resolution 1', type=TypeOptions.Constant, - value_1='Resolution Param 1')) + bulk_in: ClassList = ClassList( + RAT.models.Parameter( + name="SLD Air", + min=0.0, + value=0.0, + max=0.0, + fit=False, + prior_type=Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + + bulk_out: ClassList = ClassList( + RAT.models.Parameter( + name="SLD D2O", + min=6.2e-6, + value=6.35e-6, + max=6.35e-6, + fit=False, + prior_type=Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + + scalefactors: ClassList = ClassList( + RAT.models.Parameter( + name="Scalefactor 1", + min=0.02, + value=0.23, + max=0.25, + fit=False, + prior_type=Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + + domain_ratios: ClassList = ClassList( + RAT.models.Parameter( + name="Domain Ratio 1", + min=0.4, + value=0.5, + max=0.6, + fit=False, + prior_type=Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + + background_parameters: ClassList = ClassList( + RAT.models.Parameter( + name="Background Param 1", + min=1e-7, + value=1e-6, + max=1e-5, + fit=False, + prior_type=Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + + backgrounds: ClassList = ClassList( + RAT.models.Background(name="Background 1", type=TypeOptions.Constant, value_1="Background Param 1"), + ) + + resolution_parameters: ClassList = ClassList( + RAT.models.Parameter( + name="Resolution Param 1", + min=0.01, + value=0.03, + max=0.05, + fit=False, + prior_type=Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + + resolutions: ClassList = ClassList( + RAT.models.Resolution(name="Resolution 1", type=TypeOptions.Constant, value_1="Resolution Param 1"), + ) custom_files: ClassList = ClassList() data: ClassList = ClassList() @@ -133,18 +204,30 @@ class Project(BaseModel, validate_assignment=True, extra='forbid', arbitrary_typ _contrast_model_field: str _protected_parameters: dict - @field_validator('parameters', 'bulk_in', 'bulk_out', 'scalefactors', 'background_parameters', - 'backgrounds', 'resolution_parameters', 'resolutions', 'custom_files', 'data', 'layers', - 'domain_contrasts', 'contrasts') + @field_validator( + "parameters", + "bulk_in", + "bulk_out", + "scalefactors", + "background_parameters", + "backgrounds", + "resolution_parameters", + "resolutions", + "custom_files", + "data", + "layers", + "domain_contrasts", + "contrasts", + ) @classmethod def check_class(cls, value: ClassList, info: ValidationInfo) -> ClassList: """Each of the data fields should be a ClassList of the appropriate model.""" model_name = model_in_classlist[info.field_name] # Correct model name if necessary - if info.field_name == 'layers' and info.data['absorption']: - model_name = 'AbsorptionLayer' - if info.field_name == 'contrasts' and info.data['calculation'] == Calculations.Domains: - model_name = 'ContrastWithRatio' + if info.field_name == "layers" and info.data["absorption"]: + model_name = "AbsorptionLayer" + if info.field_name == "contrasts" and info.data["calculation"] == Calculations.Domains: + model_name = "ContrastWithRatio" model = getattr(RAT.models, model_name) if not all(isinstance(element, model) for element in value): @@ -157,38 +240,47 @@ def model_post_init(self, __context: Any) -> None: control revalidation. """ # Ensure all ClassLists have the correct _class_handle defined - layer_field = getattr(self, 'layers') + layer_field = self.layers if not hasattr(layer_field, "_class_handle"): if self.absorption: - setattr(layer_field, "_class_handle", getattr(RAT.models, 'AbsorptionLayer')) + layer_field._class_handle = RAT.models.AbsorptionLayer else: - setattr(layer_field, "_class_handle", getattr(RAT.models, 'Layer')) + layer_field._class_handle = RAT.models.Layer - contrast_field = getattr(self, 'contrasts') + contrast_field = self.contrasts if not hasattr(contrast_field, "_class_handle"): if self.calculation == Calculations.Domains: - setattr(contrast_field, "_class_handle", getattr(RAT.models, 'ContrastWithRatio')) + contrast_field._class_handle = RAT.models.ContrastWithRatio else: - setattr(contrast_field, "_class_handle", getattr(RAT.models, 'Contrast')) + contrast_field._class_handle = RAT.models.Contrast for field_name, model in model_in_classlist.items(): field = getattr(self, field_name) if not hasattr(field, "_class_handle"): - setattr(field, "_class_handle", getattr(RAT.models, model)) - - if 'Substrate Roughness' not in self.parameters.get_names(): - self.parameters.insert(0, RAT.models.ProtectedParameter(name='Substrate Roughness', min=1.0, value=3.0, - max=5.0, fit=True, - prior_type=RAT.models.Priors.Uniform, mu=0.0, - sigma=np.inf)) - elif 'Substrate Roughness' not in self.get_all_protected_parameters().values(): + field._class_handle = getattr(RAT.models, model) + + if "Substrate Roughness" not in self.parameters.get_names(): + self.parameters.insert( + 0, + RAT.models.ProtectedParameter( + name="Substrate Roughness", + min=1.0, + value=3.0, + max=5.0, + fit=True, + prior_type=RAT.models.Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + elif "Substrate Roughness" not in self.get_all_protected_parameters().values(): # If substrate roughness is included as a standard parameter replace it with a protected parameter - substrate_roughness_values = self.parameters[self.parameters.index('Substrate Roughness')].model_dump() - self.parameters.remove('Substrate Roughness') + substrate_roughness_values = self.parameters[self.parameters.index("Substrate Roughness")].model_dump() + self.parameters.remove("Substrate Roughness") self.parameters.insert(0, RAT.models.ProtectedParameter(**substrate_roughness_values)) - if 'Simulation' not in self.data.get_names(): - self.data.insert(0, RAT.models.Data(name='Simulation', simulation_range=[0.005, 0.7])) + if "Simulation" not in self.data.get_names(): + self.data.insert(0, RAT.models.Data(name="Simulation", simulation_range=[0.005, 0.7])) self._all_names = self.get_all_names() self._contrast_model_field = self.get_contrast_model_field() @@ -196,23 +288,33 @@ def model_post_init(self, __context: Any) -> None: # Wrap ClassList routines - when any of these routines are called, the wrapper will force revalidation of the # model, handle errors and reset previous values if necessary. - methods_to_wrap = ['_setitem', '_delitem', '_iadd', 'append', 'insert', 'pop', 'remove', 'clear', 'extend', - 'set_fields'] + methods_to_wrap = [ + "_setitem", + "_delitem", + "_iadd", + "append", + "insert", + "pop", + "remove", + "clear", + "extend", + "set_fields", + ] for class_list in class_lists: attribute = getattr(self, class_list) for methodName in methods_to_wrap: setattr(attribute, methodName, self._classlist_wrapper(attribute, getattr(attribute, methodName))) - @model_validator(mode='after') - def set_domain_ratios(self) -> 'Project': + @model_validator(mode="after") + def set_domain_ratios(self) -> "Project": """If we are not running a domains calculation, ensure the domain_ratios component of the model is empty.""" if self.calculation != Calculations.Domains: self.domain_ratios.data = [] return self - @model_validator(mode='after') - def set_domain_contrasts(self) -> 'Project': + @model_validator(mode="after") + def set_domain_contrasts(self) -> "Project": """If we are not running a domains calculation with standard layers, ensure the domain_contrasts component of the model is empty. """ @@ -220,37 +322,46 @@ def set_domain_contrasts(self) -> 'Project': self.domain_contrasts.data = [] return self - @model_validator(mode='after') - def set_layers(self) -> 'Project': + @model_validator(mode="after") + def set_layers(self) -> "Project": """If we are not using a standard layers model, ensure the layers component of the model is empty.""" if self.model != LayerModels.StandardLayers: self.layers.data = [] return self - @model_validator(mode='after') - def set_calculation(self) -> 'Project': + @model_validator(mode="after") + def set_calculation(self) -> "Project": """Apply the calc setting to the project.""" contrast_list = [] - handle = getattr(self.contrasts, '_class_handle').__name__ - if self.calculation == Calculations.Domains and handle == 'Contrast': + handle = self.contrasts._class_handle.__name__ + if self.calculation == Calculations.Domains and handle == "Contrast": for contrast in self.contrasts: contrast_list.append(RAT.models.ContrastWithRatio(**contrast.model_dump())) self.contrasts.data = contrast_list - self.domain_ratios.data = [RAT.models.Parameter(name='Domain Ratio 1', min=0.4, value=0.5, max=0.6, - fit=False, prior_type=RAT.models.Priors.Uniform, mu=0.0, - sigma=np.inf)] - setattr(self.contrasts, '_class_handle', getattr(RAT.models, 'ContrastWithRatio')) - elif self.calculation != Calculations.Domains and handle == 'ContrastWithRatio': + self.domain_ratios.data = [ + RAT.models.Parameter( + name="Domain Ratio 1", + min=0.4, + value=0.5, + max=0.6, + fit=False, + prior_type=RAT.models.Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ] + self.contrasts._class_handle = RAT.models.ContrastWithRatio + elif self.calculation != Calculations.Domains and handle == "ContrastWithRatio": for contrast in self.contrasts: contrast_params = contrast.model_dump() - del contrast_params['domain_ratio'] + del contrast_params["domain_ratio"] contrast_list.append(RAT.models.Contrast(**contrast_params)) self.contrasts.data = contrast_list - setattr(self.contrasts, '_class_handle', getattr(RAT.models, 'Contrast')) + self.contrasts._class_handle = RAT.models.Contrast return self - @model_validator(mode='after') - def set_contrast_model_field(self) -> 'Project': + @model_validator(mode="after") + def set_contrast_model_field(self) -> "Project": """The contents of the "model" field of "contrasts" depend on the values of the "calculation" and "model_type" defined in the project. If they have changed, clear the contrast models. """ @@ -261,107 +372,117 @@ def set_contrast_model_field(self) -> 'Project': self._contrast_model_field = model_field return self - @model_validator(mode='after') - def check_contrast_model_length(self) -> 'Project': - """Given certain values of the "calculation" and "model" defined in the project, the "model" field of "contrasts" - may be constrained in its length. + @model_validator(mode="after") + def check_contrast_model_length(self) -> "Project": + """Given certain values of the "calculation" and "model" defined in the project, the "model" field of + "contrasts" may be constrained in its length. """ if self.model == LayerModels.StandardLayers and self.calculation == Calculations.Domains: for contrast in self.contrasts: if contrast.model and len(contrast.model) != 2: - raise ValueError('For a standard layers domains calculation the "model" field of "contrasts" must ' - 'contain exactly two values.') + raise ValueError( + 'For a standard layers domains calculation the "model" field of "contrasts" must ' + "contain exactly two values.", + ) elif self.model != LayerModels.StandardLayers: for contrast in self.contrasts: if len(contrast.model) > 1: - raise ValueError('For a custom model calculation the "model" field of "contrasts" cannot contain ' - 'more than one value.') + raise ValueError( + 'For a custom model calculation the "model" field of "contrasts" cannot contain ' + "more than one value.", + ) return self - @model_validator(mode='after') - def set_absorption(self) -> 'Project': + @model_validator(mode="after") + def set_absorption(self) -> "Project": """Apply the absorption setting to the project.""" layer_list = [] - handle = getattr(self.layers, '_class_handle').__name__ - if self.absorption and handle == 'Layer': + handle = self.layers._class_handle.__name__ + if self.absorption and handle == "Layer": for layer in self.layers: layer_list.append(RAT.models.AbsorptionLayer(**layer.model_dump())) self.layers.data = layer_list - setattr(self.layers, '_class_handle', getattr(RAT.models, 'AbsorptionLayer')) - elif not self.absorption and handle == 'AbsorptionLayer': + self.layers._class_handle = RAT.models.AbsorptionLayer + elif not self.absorption and handle == "AbsorptionLayer": for layer in self.layers: layer_params = layer.model_dump() - del layer_params['SLD_imaginary'] + del layer_params["SLD_imaginary"] layer_list.append(RAT.models.Layer(**layer_params)) self.layers.data = layer_list - setattr(self.layers, '_class_handle', getattr(RAT.models, 'Layer')) + self.layers._class_handle = RAT.models.Layer return self - @model_validator(mode='after') - def update_renamed_models(self) -> 'Project': + @model_validator(mode="after") + def update_renamed_models(self) -> "Project": """When models defined in the ClassLists are renamed, we need to update that name elsewhere in the project.""" - for class_list in model_names_used_in.keys(): + for class_list in model_names_used_in: old_names = self._all_names[class_list] new_names = getattr(self, class_list).get_names() if len(old_names) == len(new_names): name_diff = [(old, new) for (old, new) in zip(old_names, new_names) if old != new] - for (old_name, new_name) in name_diff: + for old_name, new_name in name_diff: model_names_list = getattr(self, model_names_used_in[class_list].attribute) all_matches = model_names_list.get_all_matches(old_name) fields = model_names_used_in[class_list].fields - for (index, field) in all_matches: + for index, field in all_matches: if field in fields: setattr(model_names_list[index], field, new_name) self._all_names = self.get_all_names() return self - @model_validator(mode='after') - def cross_check_model_values(self) -> 'Project': + @model_validator(mode="after") + def cross_check_model_values(self) -> "Project": """Certain model fields should contain values defined elsewhere in the project.""" - value_fields = ['value_1', 'value_2', 'value_3', 'value_4', 'value_5'] - self.check_allowed_values('backgrounds', value_fields, self.background_parameters.get_names()) - self.check_allowed_values('resolutions', value_fields, self.resolution_parameters.get_names()) - self.check_allowed_values('layers', ['thickness', 'SLD', 'SLD_real', 'SLD_imaginary', 'roughness'], - self.parameters.get_names()) - - self.check_allowed_values('contrasts', ['data'], self.data.get_names()) - self.check_allowed_values('contrasts', ['background'], self.backgrounds.get_names()) - self.check_allowed_values('contrasts', ['bulk_in'], self.bulk_in.get_names()) - self.check_allowed_values('contrasts', ['bulk_out'], self.bulk_out.get_names()) - self.check_allowed_values('contrasts', ['scalefactor'], self.scalefactors.get_names()) - self.check_allowed_values('contrasts', ['resolution'], self.resolutions.get_names()) - self.check_allowed_values('contrasts', ['domain_ratio'], self.domain_ratios.get_names()) - - self.check_contrast_model_allowed_values('contrasts', getattr(self, self._contrast_model_field).get_names(), - self._contrast_model_field) - self.check_contrast_model_allowed_values('domain_contrasts', self.layers.get_names(), 'layers') + value_fields = ["value_1", "value_2", "value_3", "value_4", "value_5"] + self.check_allowed_values("backgrounds", value_fields, self.background_parameters.get_names()) + self.check_allowed_values("resolutions", value_fields, self.resolution_parameters.get_names()) + self.check_allowed_values( + "layers", + ["thickness", "SLD", "SLD_real", "SLD_imaginary", "roughness"], + self.parameters.get_names(), + ) + + self.check_allowed_values("contrasts", ["data"], self.data.get_names()) + self.check_allowed_values("contrasts", ["background"], self.backgrounds.get_names()) + self.check_allowed_values("contrasts", ["bulk_in"], self.bulk_in.get_names()) + self.check_allowed_values("contrasts", ["bulk_out"], self.bulk_out.get_names()) + self.check_allowed_values("contrasts", ["scalefactor"], self.scalefactors.get_names()) + self.check_allowed_values("contrasts", ["resolution"], self.resolutions.get_names()) + self.check_allowed_values("contrasts", ["domain_ratio"], self.domain_ratios.get_names()) + + self.check_contrast_model_allowed_values( + "contrasts", + getattr(self, self._contrast_model_field).get_names(), + self._contrast_model_field, + ) + self.check_contrast_model_allowed_values("domain_contrasts", self.layers.get_names(), "layers") return self - @model_validator(mode='after') - def check_protected_parameters(self) -> 'Project': + @model_validator(mode="after") + def check_protected_parameters(self) -> "Project": """Protected parameters should not be deleted. If this is attempted, raise an error.""" for class_list in parameter_class_lists: - protected_parameters = [param.name for param in getattr(self, class_list) - if isinstance(param, RAT.models.ProtectedParameter)] + protected_parameters = [ + param.name for param in getattr(self, class_list) if isinstance(param, RAT.models.ProtectedParameter) + ] # All previously existing protected parameters should be present in new list if not all(element in protected_parameters for element in self._protected_parameters[class_list]): - removed_params = [param for param in self._protected_parameters[class_list] - if param not in protected_parameters] + removed_params = [ + param for param in self._protected_parameters[class_list] if param not in protected_parameters + ] raise ValueError(f'Can\'t delete the protected parameters: {", ".join(str(i) for i in removed_params)}') self._protected_parameters = self.get_all_protected_parameters() return self def __repr__(self): - output = '' + output = "" for key, value in self.__dict__.items(): if value: output += f'{key.replace("_", " ").title() + ": " :-<100}\n\n' try: - value.value # For enums + output += value.value + "\n\n" # For enums except AttributeError: - output += repr(value) + '\n\n' - else: - output += value.value + '\n\n' + output += repr(value) + "\n\n" return output def get_all_names(self): @@ -370,9 +491,12 @@ def get_all_names(self): def get_all_protected_parameters(self): """Record the protected parameters defined in the project.""" - return {class_list: [param.name for param in getattr(self, class_list) - if isinstance(param, RAT.models.ProtectedParameter)] - for class_list in parameter_class_lists} + return { + class_list: [ + param.name for param in getattr(self, class_list) if isinstance(param, RAT.models.ProtectedParameter) + ] + for class_list in parameter_class_lists + } def check_allowed_values(self, attribute: str, field_list: list[str], allowed_values: list[str]) -> None: """Check the values of the given fields in the given model are in the supplied list of allowed values. @@ -390,17 +514,24 @@ def check_allowed_values(self, attribute: str, field_list: list[str], allowed_va ------ ValueError Raised if any field in field_list has a value not specified in allowed_values. + """ class_list = getattr(self, attribute) for model in class_list: for field in field_list: - value = getattr(model, field, '') + value = getattr(model, field, "") if value and value not in allowed_values: - raise ValueError(f'The value "{value}" in the "{field}" field of "{attribute}" must be defined in ' - f'"{values_defined_in[f"{attribute}.{field}"]}".') - - def check_contrast_model_allowed_values(self, contrast_attribute: str, allowed_values: list[str], - allowed_field: str) -> None: + raise ValueError( + f'The value "{value}" in the "{field}" field of "{attribute}" must be defined in ' + f'"{values_defined_in[f"{attribute}.{field}"]}".', + ) + + def check_contrast_model_allowed_values( + self, + contrast_attribute: str, + allowed_values: list[str], + allowed_field: str, + ) -> None: """The contents of the "model" field of "contrasts" and "domain_contrasts" must be defined elsewhere in the project. @@ -417,13 +548,16 @@ def check_contrast_model_allowed_values(self, contrast_attribute: str, allowed_v ------ ValueError Raised if any model in contrast_attribute has a value not specified in allowed_values. + """ class_list = getattr(self, contrast_attribute) for contrast in class_list: - model_values = getattr(contrast, 'model') + model_values = contrast.model if model_values and not all(value in allowed_values for value in model_values): - raise ValueError(f'The values: "{", ".join(str(i) for i in model_values)}" in the "model" field of ' - f'"{contrast_attribute}" must be defined in "{allowed_field}".') + raise ValueError( + f'The values: "{", ".join(str(i) for i in model_values)}" in the "model" field of ' + f'"{contrast_attribute}" must be defined in "{allowed_field}".', + ) def get_contrast_model_field(self): """Get the field used to define the contents of the "model" field in contrasts. @@ -432,17 +566,18 @@ def get_contrast_model_field(self): ------- model_field : str The name of the field used to define the contrasts' model field. + """ if self.model == LayerModels.StandardLayers: if self.calculation == Calculations.Domains: - model_field = 'domain_contrasts' + model_field = "domain_contrasts" else: - model_field = 'layers' + model_field = "layers" else: - model_field = 'custom_files' + model_field = "custom_files" return model_field - def write_script(self, obj_name: str = 'problem', script: str = 'project_script.py'): + def write_script(self, obj_name: str = "problem", script: str = "project_script.py"): """Write a python script that can be run to reproduce this project object. Parameters @@ -451,33 +586,37 @@ def write_script(self, obj_name: str = 'problem', script: str = 'project_script. The name given to the project object under construction (default is "problem"). script : str, optional The filepath of the generated script (default is "project_script.py"). + """ # Need to ensure correct format for script name file_parts = os.path.splitext(script) if not file_parts[1]: - script += '.py' - elif file_parts[1] != '.py': + script += ".py" + elif file_parts[1] != ".py": raise ValueError('The script name provided to "write_script" must use the ".py" format') indent = 4 * " " - with open(script, 'w') as f: - - f.write('# THIS FILE IS GENERATED FROM RAT VIA THE "WRITE_SCRIPT" ROUTINE. IT IS NOT PART OF THE RAT CODE.' - '\n\n') + with open(script, "w") as f: + f.write( + '# THIS FILE IS GENERATED FROM RAT VIA THE "WRITE_SCRIPT" ROUTINE. IT IS NOT PART OF THE RAT CODE.' + "\n\n", + ) # Need imports - f.write('import RAT\nfrom RAT.models import *\nfrom numpy import array, inf\n\n') + f.write("import RAT\nfrom RAT.models import *\nfrom numpy import array, inf\n\n") - f.write(f"{obj_name} = RAT.Project(\n{indent}name='{self.name}', calculation='{self.calculation}'," - f" model='{self.model}', geometry='{self.geometry}', absorption={self.absorption},\n") + f.write( + f"{obj_name} = RAT.Project(\n{indent}name='{self.name}', calculation='{self.calculation}'," + f" model='{self.model}', geometry='{self.geometry}', absorption={self.absorption},\n", + ) for class_list in class_lists: contents = getattr(self, class_list).data if contents: - f.write(f'{indent}{class_list}=RAT.ClassList({contents}),\n') - f.write(f'{indent})\n') + f.write(f"{indent}{class_list}=RAT.ClassList({contents}),\n") + f.write(f"{indent})\n") def _classlist_wrapper(self, class_list: ClassList, func: Callable): """Defines the function used to wrap around ClassList routines to force revalidation. @@ -493,25 +632,28 @@ def _classlist_wrapper(self, class_list: ClassList, func: Callable): ------- wrapped_func : Callable The wrapped routine. + """ + @functools.wraps(func) def wrapped_func(*args, **kwargs): """Run the given function and then revalidate the "Project" model. If any exception is raised, restore the previous state of the given ClassList and report details of the exception. """ - previous_state = copy.deepcopy(getattr(class_list, 'data')) + previous_state = copy.deepcopy(class_list.data) return_value = None try: return_value = func(*args, **kwargs) Project.model_validate(self) except ValidationError as exc: - setattr(class_list, 'data', previous_state) + class_list.data = previous_state custom_error_list = custom_pydantic_validation_error(exc.errors()) raise ValidationError.from_exception_data(exc.title, custom_error_list) from None except (TypeError, ValueError): - setattr(class_list, 'data', previous_state) + class_list.data = previous_state raise finally: del previous_state return return_value + return wrapped_func diff --git a/RAT/run.py b/RAT/run.py index 52c0d82c..f654420e 100644 --- a/RAT/run.py +++ b/RAT/run.py @@ -1,30 +1,35 @@ +import RAT.rat_core from RAT.inputs import make_input from RAT.outputs import make_results -import RAT.rat_core def run(project, controls): """Run RAT for the given project and controls inputs.""" - - parameter_field = {'parameters': 'params', - 'bulk_in': 'bulkIn', - 'bulk_out': 'bulkOut', - 'scalefactors': 'scalefactors', - 'domain_ratios': 'domainRatio', - 'background_parameters': 'backgroundParams', - 'resolution_parameters': 'resolutionParams', - } + parameter_field = { + "parameters": "params", + "bulk_in": "bulkIn", + "bulk_out": "bulkOut", + "scalefactors": "scalefactors", + "domain_ratios": "domainRatio", + "background_parameters": "backgroundParams", + "resolution_parameters": "resolutionParams", + } problem_definition, cells, limits, priors, cpp_controls = make_input(project, controls) - problem_definition, output_results, bayes_results = RAT.rat_core.RATMain(problem_definition, cells, limits, - cpp_controls, priors) + problem_definition, output_results, bayes_results = RAT.rat_core.RATMain( + problem_definition, + cells, + limits, + cpp_controls, + priors, + ) results = make_results(controls.procedure, output_results, bayes_results) # Update parameter values in project for class_list in RAT.project.parameter_class_lists: - for (index, value) in enumerate(getattr(problem_definition, parameter_field[class_list])): - setattr(getattr(project, class_list)[index], 'value', value) + for index, value in enumerate(getattr(problem_definition, parameter_field[class_list])): + getattr(project, class_list)[index].value = value return project, results diff --git a/RAT/utils/custom_errors.py b/RAT/utils/custom_errors.py index 22a4f3b8..1778841a 100644 --- a/RAT/utils/custom_errors.py +++ b/RAT/utils/custom_errors.py @@ -1,10 +1,14 @@ """Defines routines for custom error handling in RAT.""" + +from typing import Optional + import pydantic_core -def custom_pydantic_validation_error(error_list: list[pydantic_core.ErrorDetails], - custom_error_msgs: dict[str, str] = None - ) -> list[pydantic_core.ErrorDetails]: +def custom_pydantic_validation_error( + error_list: list[pydantic_core.ErrorDetails], + custom_error_msgs: Optional[dict[str, str]] = None, +) -> list[pydantic_core.ErrorDetails]: """Run through the list of errors generated from a pydantic ValidationError, substituting the standard error for a PydanticCustomError for a given set of error types. @@ -22,16 +26,17 @@ def custom_pydantic_validation_error(error_list: list[pydantic_core.ErrorDetails ------- new_error : list[pydantic_core.ErrorDetails] A list of errors including PydanticCustomErrors in place of the error types in custom_errors. + """ if custom_error_msgs is None: custom_error_msgs = {} custom_error_list = [] for error in error_list: - if error['type'] in custom_error_msgs: - custom_error = pydantic_core.PydanticCustomError(error['type'], custom_error_msgs[error['type']]) + if error["type"] in custom_error_msgs: + custom_error = pydantic_core.PydanticCustomError(error["type"], custom_error_msgs[error["type"]]) else: - custom_error = pydantic_core.PydanticCustomError(error['type'], error['msg']) - error['type'] = custom_error + custom_error = pydantic_core.PydanticCustomError(error["type"], error["msg"]) + error["type"] = custom_error custom_error_list.append(error) return custom_error_list diff --git a/RAT/utils/enums.py b/RAT/utils/enums.py index c1f8e395..9e22b380 100644 --- a/RAT/utils/enums.py +++ b/RAT/utils/enums.py @@ -1,4 +1,5 @@ from enum import Enum + try: from enum import StrEnum except ImportError: @@ -8,38 +9,43 @@ # Controls class Parallel(StrEnum): """Defines the available options for parallelization""" - Single = 'single' - Points = 'points' - Contrasts = 'contrasts' + + Single = "single" + Points = "points" + Contrasts = "contrasts" class Procedures(StrEnum): """Defines the available options for procedures""" - Calculate = 'calculate' - Simplex = 'simplex' - DE = 'de' - NS = 'ns' - Dream = 'dream' + + Calculate = "calculate" + Simplex = "simplex" + DE = "de" + NS = "ns" + Dream = "dream" class Display(StrEnum): """Defines the available options for display""" - Off = 'off' - Iter = 'iter' - Notify = 'notify' - Final = 'final' + + Off = "off" + Iter = "iter" + Notify = "notify" + Final = "final" class BoundHandling(StrEnum): """Defines the available options for bound handling""" - Off = 'off' - Reflect = 'reflect' - Bound = 'bound' - Fold = 'fold' + + Off = "off" + Reflect = "reflect" + Bound = "bound" + Fold = "fold" class Strategies(Enum): """Defines the available options for strategies""" + Random = 1 LocalToBest = 2 BestWithJitter = 3 @@ -50,46 +56,46 @@ class Strategies(Enum): # Models class Hydration(StrEnum): - None_ = 'none' - BulkIn = 'bulk in' - BulkOut = 'bulk out' - Oil = 'oil' + None_ = "none" + BulkIn = "bulk in" + BulkOut = "bulk out" + Oil = "oil" class Languages(StrEnum): - Cpp = 'cpp' - Python = 'python' - Matlab = 'matlab' + Cpp = "cpp" + Python = "python" + Matlab = "matlab" class Priors(StrEnum): - Uniform = 'uniform' - Gaussian = 'gaussian' + Uniform = "uniform" + Gaussian = "gaussian" class TypeOptions(StrEnum): - Constant = 'constant' - Data = 'data' - Function = 'function' + Constant = "constant" + Data = "data" + Function = "function" class BackgroundActions(StrEnum): - Add = 'add' - Subtract = 'subtract' + Add = "add" + Subtract = "subtract" # Project class Calculations(StrEnum): - NonPolarised = 'non polarised' - Domains = 'domains' + NonPolarised = "non polarised" + Domains = "domains" class Geometries(StrEnum): - AirSubstrate = 'air/substrate' - SubstrateLiquid = 'substrate/liquid' + AirSubstrate = "air/substrate" + SubstrateLiquid = "substrate/liquid" class LayerModels(StrEnum): - CustomLayers = 'custom layers' - CustomXY = 'custom xy' - StandardLayers = 'standard layers' + CustomLayers = "custom layers" + CustomXY = "custom xy" + StandardLayers = "standard layers" diff --git a/RAT/utils/plotting.py b/RAT/utils/plotting.py index e79bac38..99748f27 100644 --- a/RAT/utils/plotting.py +++ b/RAT/utils/plotting.py @@ -1,24 +1,22 @@ -""" -Plots using the matplotlib library -""" +"""Plots using the matplotlib library""" + from typing import Optional, Union + import matplotlib.pyplot as plt import numpy as np -from RAT.rat_core import PlotEventData, makeSLDProfileXY +from matplotlib.axes._axes import Axes import RAT import RAT.inputs import RAT.outputs +from RAT.rat_core import PlotEventData, makeSLDProfileXY class Figure: - """ - Creates a plotting figure. - """ + """Creates a plotting figure.""" def __init__(self, row: int = 1, col: int = 1): - """ - Initializes the figure and the subplots. + """Initializes the figure and the subplots. Parameters ---------- @@ -26,20 +24,17 @@ def __init__(self, row: int = 1, col: int = 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)") + 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) + 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 + """Waits for the user to close the figure using the esc key. """ while not (self._esc_pressed or self._close_clicked): @@ -47,23 +42,17 @@ def wait_for_close(self): plt.close(self._fig) def _process_button_press(self, event): - """ - Process the key_press_event. - """ - if event.key == 'escape': + """Process the key_press_event.""" + if event.key == "escape": self._esc_pressed = True def _close(self, _): - """ - Process the close_event. - """ + """Process the close_event.""" self._close_clicked = True -def plot_errorbars(ax: 'matplotlib.axes._axes.Axes', x: np.ndarray, y: np.ndarray, err: np.ndarray, - one_sided: bool, color: str): - """ - Plots the error bars. +def plot_errorbars(ax: Axes, x: np.ndarray, y: np.ndarray, err: np.ndarray, one_sided: bool, color: str): + """Plots the error bars. Parameters ---------- @@ -79,28 +68,22 @@ def plot_errorbars(ax: 'matplotlib.axes._axes.Axes', x: np.ndarray, y: np.ndarra A boolean to indicate whether to draw one sided errorbars color : str The hex representing the color of the errorbars + """ - y_error = [[0]*len(err), err] if one_sided else err - ax.errorbar(x=x, - y=y, - yerr=y_error, - fmt='none', - ecolor=color, - elinewidth=1, - capsize=0) + y_error = [[0] * len(err), err] if one_sided else err + ax.errorbar(x=x, y=y, yerr=y_error, fmt="none", ecolor=color, elinewidth=1, capsize=0) 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): - """ - Clears the previous plots and updates the ref and SLD plots. + """Clears the previous plots and updates the ref and SLD plots. Parameters ---------- data : PlotEventData The plot event data that contains all the information to generate the ref and sld plots - fig : Figure, optional + fig : Figure, optional The figure class that has two subplots delay : bool, default: True Controls whether to delay 0.005s after plot is created @@ -109,6 +92,7 @@ def plot_ref_sld_helper(data: PlotEventData, fig: Optional[Figure] = None, delay ------- fig : Figure The figure class that has two subplots + """ if fig is None: fig = Figure(1, 2) @@ -123,86 +107,81 @@ def plot_ref_sld_helper(data: PlotEventData, fig: Optional[Figure] = None, delay ref_plot.cla() sld_plot.cla() - for i, (r, sd, sld, layer) in enumerate(zip(data.reflectivity, - data.shiftedData, - data.sldProfiles, - data.resampledLayers)): + for i, (r, sd, sld, layer) in enumerate( + zip(data.reflectivity, data.shiftedData, data.sldProfiles, data.resampledLayers), + ): # Calculate the divisor - div = 1 if i == 0 else 2**(4*(i+1)) + div = 1 if i == 0 else 2 ** (4 * (i + 1)) # Plot the reflectivity on plot (1,1) - ref_plot.plot(r[:, 0], - r[:, 1]/div, - label=f'ref {i+1}', - linewidth=2) + ref_plot.plot(r[:, 0], r[:, 1] / div, label=f"ref {i+1}", linewidth=2) color = ref_plot.get_lines()[-1].get_color() if data.dataPresent[i]: sd_x = sd[:, 0] - sd_y, sd_e = map(lambda x: x/div, (sd[:, 1], sd[:, 2])) + sd_y, sd_e = map(lambda x: x / div, (sd[:, 1], sd[:, 2])) # Plot the errorbars indices_removed = np.flip(np.nonzero(sd_y - sd_e < 0)[0]) - sd_x_r, sd_y_r, sd_e_r = map(lambda x: - np.delete(x, indices_removed), - (sd_x, sd_y, sd_e)) + sd_x_r, sd_y_r, sd_e_r = map(lambda x: np.delete(x, indices_removed), (sd_x, sd_y, sd_e)) plot_errorbars(ref_plot, sd_x_r, sd_y_r, sd_e_r, False, color) # Plot one sided errorbars - indices_selected = [x for x in indices_removed - if x not in np.nonzero(sd_y < 0)[0]] - sd_x_s, sd_y_s, sd_e_s = map(lambda x: - [x[i] for i in indices_selected], - (sd_x, sd_y, sd_e)) + indices_selected = [x for x in indices_removed if x not in np.nonzero(sd_y < 0)[0]] + sd_x_s, sd_y_s, sd_e_s = map(lambda x: [x[i] for i in indices_selected], (sd_x, sd_y, sd_e)) plot_errorbars(ref_plot, sd_x_s, sd_y_s, sd_e_s, True, color) # Plot the slds on plot (1,2) for j in range(len(sld)): - sld_plot.plot(sld[j][:, 0], - sld[j][:, 1], - label=f'sld {i+1}', - linewidth=1) + sld_plot.plot(sld[j][:, 0], sld[j][:, 1], label=f"sld {i+1}", linewidth=1) - if data.resample[i] == 1 or data.modelType == 'custom xy': + if data.resample[i] == 1 or data.modelType == "custom xy": layers = data.resampledLayers[i][0] for j in range(len(data.resampledLayers[i])): layer = data.resampledLayers[i][j] if layers.shape[1] == 4: layer = np.delete(layer, 2, 1) - new_profile = makeSLDProfileXY(layers[0, 1], # Bulk In - layers[-1, 1], # Bulk Out - data.subRoughs[i], # roughness - layer, - len(layer), - 1.0) - - sld_plot.plot([row[0]-49 for row in new_profile], - [row[1] for row in new_profile], - color=color, - linewidth=1) + new_profile = makeSLDProfileXY( + layers[0, 1], # Bulk In + layers[-1, 1], # Bulk Out + data.subRoughs[i], # roughness + layer, + len(layer), + 1.0, + ) + + sld_plot.plot( + [row[0] - 49 for row in new_profile], + [row[1] for row in new_profile], + color=color, + linewidth=1, + ) # 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_yscale("log") + ref_plot.set_xscale("log") + ref_plot.set_xlabel("Qz") + ref_plot.set_ylabel("Ref") ref_plot.legend() ref_plot.grid() - sld_plot.set_xlabel('Z') - sld_plot.set_ylabel('SLD') + sld_plot.set_xlabel("Z") + sld_plot.set_ylabel("SLD") sld_plot.legend() sld_plot.grid() if delay: plt.pause(0.005) - + return fig -def plot_ref_sld(project: RAT.Project, results: Union[RAT.outputs.Results, RAT.outputs.BayesResults], block: bool = False): - """ - Plots the reflectivity and SLD profiles. +def plot_ref_sld( + project: RAT.Project, + results: Union[RAT.outputs.Results, RAT.outputs.BayesResults], + block: bool = False, +): + """Plots the reflectivity and SLD profiles. Parameters ---------- @@ -212,6 +191,7 @@ def plot_ref_sld(project: RAT.Project, results: Union[RAT.outputs.Results, RAT.o The result from the calculation block : bool, default: False Indicates the plot should block until it is closed + """ data = PlotEventData() diff --git a/RAT/wrappers.py b/RAT/wrappers.py index 87404efa..3a7b72e9 100644 --- a/RAT/wrappers.py +++ b/RAT/wrappers.py @@ -1,7 +1,9 @@ import pathlib from typing import Callable, Tuple + import numpy as np from numpy.typing import ArrayLike + import RAT.rat_core @@ -12,13 +14,15 @@ class MatlabWrapper: ---------- filename : string The path of the file containing MATLAB function + """ + def __init__(self, filename: str) -> None: self.engine = None try: import matlab.engine except ImportError: - raise ImportError('matlabengine is required to use MatlabWrapper') + raise ImportError("matlabengine is required to use MatlabWrapper") from None self.engine = matlab.engine.start_matlab() path = pathlib.Path(filename) self.engine.cd(str(path.parent), nargout=0) @@ -35,21 +39,30 @@ def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tup ------- wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]] The wrapper function for the MATLAB callback + """ + def handle(params, bulk_in, bulk_out, contrast, domain=-1): - if domain == -1: - output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'), - np.array(bulk_in, 'float'), - np.array(bulk_out, 'float'), - float(contrast + 1), nargout=2) + if domain == -1: + output, sub_rough = getattr(self.engine, self.function_name)( + np.array(params, "float"), + np.array(bulk_in, "float"), + np.array(bulk_out, "float"), + float(contrast + 1), + nargout=2, + ) else: - output, sub_rough = getattr(self.engine, self.function_name)(np.array(params, 'float'), - np.array(bulk_in, 'float'), - np.array(bulk_out, 'float'), - float(contrast + 1), float(domain + 1), - nargout=2) - return output, sub_rough - return handle + output, sub_rough = getattr(self.engine, self.function_name)( + np.array(params, "float"), + np.array(bulk_in, "float"), + np.array(bulk_out, "float"), + float(contrast + 1), + float(domain + 1), + nargout=2, + ) + return output, sub_rough + + return handle class DylibWrapper: @@ -61,10 +74,12 @@ class DylibWrapper: The path of the dynamic library function_name : str The name of the function to call + """ + def __init__(self, filename, function_name) -> None: self.engine = RAT.rat_core.DylibEngine(filename, function_name) - + def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]: """Returns a wrapper for the custom dynamic library function @@ -72,11 +87,14 @@ def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tup ------- wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]] The wrapper function for the dynamic library callback + """ + def handle(params, bulk_in, bulk_out, contrast, domain=-1): - if domain == -1: + if domain == -1: output, sub_rough = self.engine.invoke(params, bulk_in, bulk_out, contrast) else: output, sub_rough = self.engine.invoke(params, bulk_in, bulk_out, contrast, domain) - return output, sub_rough + return output, sub_rough + return handle diff --git a/pyproject.toml b/pyproject.toml index b91bf7dc..4216b6e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,3 +6,13 @@ requires = [ ] build-backend = 'setuptools.build_meta' +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +select = ["E", "F", "UP", "B", "SIM", "I"] +ignore = ["SIM108"] + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 00000000..4899358b --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1 @@ +ruff >= 0.4.10 diff --git a/setup.py b/setup.py index af559726..3eedf681 100644 --- a/setup.py +++ b/setup.py @@ -1,31 +1,30 @@ -from glob import glob -from pathlib import Path import platform import sys +from glob import glob +from pathlib import Path + import pybind11 -from setuptools import setup, Extension, find_packages -from setuptools.command.build_ext import build_ext +from setuptools import Extension, find_packages, setup from setuptools.command.build_clib import build_clib +from setuptools.command.build_ext import build_ext - -__version__ = '0.0.0' +__version__ = "0.0.0" -libevent = ('eventManager', {'sources': ['cpp/RAT/events/eventManager.cpp'], - 'include_dirs': ['cpp/RAT/events/']}) +libevent = ("eventManager", {"sources": ["cpp/RAT/events/eventManager.cpp"], "include_dirs": ["cpp/RAT/events/"]}) ext_modules = [ Extension( - 'RAT.rat_core', - sources=['cpp/rat.cpp', *glob('cpp/RAT/*.c*')], + "RAT.rat_core", + sources=["cpp/rat.cpp", *glob("cpp/RAT/*.c*")], include_dirs=[ # Path to pybind11 headers pybind11.get_include(), pybind11.get_include(True), - 'cpp/RAT/', + "cpp/RAT/", ], - language='c++' + language="c++", ), ] @@ -33,9 +32,11 @@ # check whether compiler supports a flag def has_flag(compiler, flagname): import tempfile + from setuptools.errors import CompileError - with tempfile.NamedTemporaryFile('w', suffix='.cpp') as f: - f.write('int main (int argc, char **argv) { return 0; }') + + with tempfile.NamedTemporaryFile("w", suffix=".cpp") as f: + f.write("int main (int argc, char **argv) { return 0; }") try: compiler.compile([f.name], extra_postargs=[flagname]) except CompileError: @@ -44,59 +45,60 @@ def has_flag(compiler, flagname): def get_shared_object_name(lib_name): - if platform.system() == 'Windows': - return f'{lib_name}.dll' - elif platform.system() == 'Darwin': - return f'{lib_name}.dylib' + if platform.system() == "Windows": + return f"{lib_name}.dll" + elif platform.system() == "Darwin": + return f"{lib_name}.dylib" else: - return f'{lib_name}.so' + return f"{lib_name}.so" class BuildExt(build_ext): """A custom build extension for adding compiler-specific options.""" + c_opts = { - 'msvc': ['/EHsc'], - 'unix': ['-fopenmp', '-std=c++11'], + "msvc": ["/EHsc"], + "unix": ["-fopenmp", "-std=c++11"], } l_opts = { - 'msvc': [], - 'unix': ['-fopenmp'], + "msvc": [], + "unix": ["-fopenmp"], } - if sys.platform == 'darwin': - darwin_opts = ['-stdlib=libc++', '-mmacosx-version-min=10.9'] - c_opts['unix'] = [*darwin_opts, '-fopenmp'] - l_opts['unix'] = [*darwin_opts, '-lomp'] + if sys.platform == "darwin": + darwin_opts = ["-stdlib=libc++", "-mmacosx-version-min=10.9"] + c_opts["unix"] = [*darwin_opts, "-fopenmp"] + l_opts["unix"] = [*darwin_opts, "-lomp"] def build_extensions(self): ct = self.compiler.compiler_type opts = self.c_opts.get(ct, []) link_opts = self.l_opts.get(ct, []) - if ct == 'unix': - if '-Wstrict-prototypes' in self.compiler.compiler_so: - self.compiler.compiler_so.remove('-Wstrict-prototypes') - - opts.append('-DVERSION_INFO="%s"' % self.distribution.get_version()) - if has_flag(self.compiler, '-fvisibility=hidden'): - opts.append('-fvisibility=hidden') - elif ct == 'msvc': - opts.append('/DVERSION_INFO=\\"%s\\"' % self.distribution.get_version()) + if ct == "unix": + if "-Wstrict-prototypes" in self.compiler.compiler_so: + self.compiler.compiler_so.remove("-Wstrict-prototypes") + + opts.append(f'-DVERSION_INFO="{self.distribution.get_version()}"') + if has_flag(self.compiler, "-fvisibility=hidden"): + opts.append("-fvisibility=hidden") + elif ct == "msvc": + opts.append(f'/DVERSION_INFO=\\"{self.distribution.get_version()}\\"') for ext in self.extensions: ext.extra_compile_args = opts ext.extra_link_args = link_opts build_ext.build_extensions(self) - + def run(self): super().run() - build_py = self.get_finalized_command('build_py') - package_dir = f'{build_py.build_lib}/RAT/' + build_py = self.get_finalized_command("build_py") + package_dir = f"{build_py.build_lib}/RAT/" for p in Path(package_dir).glob("**/*"): if p.suffix in {".exp", ".a", ".lib"}: - p.unlink() - + p.unlink() + if self.inplace: obj_name = get_shared_object_name(libevent[0]) - src = f'{build_py.build_lib}/RAT/{obj_name}' + src = f"{build_py.build_lib}/RAT/{obj_name}" dest = f'{build_py.get_package_dir("RAT")}/{obj_name}' build_py.copy_file(src, dest) @@ -104,72 +106,73 @@ def run(self): class BuildClib(build_clib): def initialize_options(self): super().initialize_options() - build_py = self.get_finalized_command('build_py') - self.build_clib = f'{build_py.build_lib}/RAT' + build_py = self.get_finalized_command("build_py") + self.build_clib = f"{build_py.build_lib}/RAT" def build_libraries(self, libraries): # bug in distutils: flag not valid for c++ - flag = '-Wstrict-prototypes' - if (hasattr(self.compiler, 'compiler_so') - and flag in self.compiler.compiler_so): + flag = "-Wstrict-prototypes" + if hasattr(self.compiler, "compiler_so") and flag in self.compiler.compiler_so: self.compiler.compiler_so.remove(flag) compiler_type = self.compiler.compiler_type - if compiler_type == 'msvc': - compile_args = ['/EHsc', '/LD'] + if compiler_type == "msvc": + compile_args = ["/EHsc", "/LD"] else: - compile_args = ['-std=c++11', '-fPIC'] - - for (lib_name, build_info) in libraries: - build_info['cflags'] = compile_args - macros = build_info.get('macros') - include_dirs = build_info.get('include_dirs') - cflags = build_info.get('cflags') - sources = list(build_info.get('sources')) + compile_args = ["-std=c++11", "-fPIC"] + + for lib_name, build_info in libraries: + build_info["cflags"] = compile_args + macros = build_info.get("macros") + include_dirs = build_info.get("include_dirs") + cflags = build_info.get("cflags") + sources = list(build_info.get("sources")) objects = self.compiler.compile( - sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=include_dirs, - extra_postargs=cflags, - debug=self.debug - ) + sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + extra_postargs=cflags, + debug=self.debug, + ) language = self.compiler.detect_language(sources) self.compiler.link_shared_object( - objects, + objects, get_shared_object_name(lib_name), - output_dir=self.build_clib, - target_lang=language - ) + output_dir=self.build_clib, + target_lang=language, + ) super().build_libraries(libraries) - + setup( - name='RAT', + name="RAT", version=__version__, - author='', - author_email='', - url='https://github.com/RascalSoftware/python-RAT', - description='Python extension for the Reflectivity Analysis Toolbox (RAT)', - long_description=open('README.md').read(), - long_description_content_type='text/markdown', + author="", + author_email="", + url="https://github.com/RascalSoftware/python-RAT", + description="Python extension for the Reflectivity Analysis Toolbox (RAT)", + long_description=open("README.md").read(), # noqa: SIM115 + long_description_content_type="text/markdown", packages=find_packages(), include_package_data=True, - package_data={'': [get_shared_object_name(libevent[0])], 'RAT.examples': ["data/*.dat"]}, - cmdclass={'build_clib': BuildClib, 'build_ext': BuildExt}, + package_data={"": [get_shared_object_name(libevent[0])], "RAT.examples": ["data/*.dat"]}, + cmdclass={"build_clib": BuildClib, "build_ext": BuildExt}, libraries=[libevent], ext_modules=ext_modules, - python_requires='>=3.9', - install_requires=['numpy >= 1.20', 'prettytable >= 3.9.0', 'pydantic >= 2.7.2', 'matplotlib >= 3.8.3'], - extras_require={':python_version < "3.11"': ['StrEnum >= 0.4.15'], - 'Dev': ['pytest>=7.4.0', 'pytest-cov>=4.1.0'], - 'Matlab_latest': ['matlabengine'], - 'Matlab_2023b': ['matlabengine == 23.2.1'], - 'Matlab_2023a': ['matlabengine == 9.14.3'], - 'Matlab-2022b': ['matlabengine == 9.13.9'], - 'Matlab_2022a': ['matlabengine == 9.12.19'], - 'Matlab_2021b': ['matlabengine == 9.11.21'], - 'Matlab_2021a': ['matlabengine == 9.10.3']}, + python_requires=">=3.9", + install_requires=["numpy >= 1.20", "prettytable >= 3.9.0", "pydantic >= 2.7.2", "matplotlib >= 3.8.3"], + extras_require={ + ':python_version < "3.11"': ["StrEnum >= 0.4.15"], + "Dev": ["pytest>=7.4.0", "pytest-cov>=4.1.0", "ruff>=0.4.10"], + "Matlab_latest": ["matlabengine"], + "Matlab_2023b": ["matlabengine == 23.2.1"], + "Matlab_2023a": ["matlabengine == 9.14.3"], + "Matlab_2022b": ["matlabengine == 9.13.9"], + "Matlab_2022a": ["matlabengine == 9.12.19"], + "Matlab_2021b": ["matlabengine == 9.11.21"], + "Matlab_2021a": ["matlabengine == 9.10.3"], + }, zip_safe=False, ) diff --git a/tests/conftest.py b/tests/conftest.py index 3c162486..60dad927 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,198 +10,254 @@ def reflectivity_calculation_output_results(): """The C++ results object for a reflectivity calculation of the project set out in "DSPC_standard_layers.py".""" results = RAT.rat_core.OutputResult() - results.reflectivity = [np.array([[1.14030000e-02, 1.00000223e+00], - [1.38610000e-02, 1.00000223e+00], - [1.68480000e-02, 6.42692703e-02], - [2.04790000e-02, 1.69530247e-02], - [2.48920000e-02, 6.18815370e-03], - [3.02560000e-02, 2.99474163e-03], - [3.67770000e-02, 1.73558265e-03], - [4.47020000e-02, 1.03290554e-03], - [5.43360000e-02, 6.45645642e-04], - [6.60450000e-02, 5.57949197e-04], - [8.02790000e-02, 5.58974858e-04], - [9.75790000e-02, 3.49803750e-04], - [1.18610000e-01, 8.89485853e-05], - [1.44170000e-01, 4.04713900e-05], - [1.75240000e-01, 6.98590391e-06], - [2.13000000e-01, 3.60410795e-06], - [2.58910000e-01, 2.41835671e-06], - [3.14700000e-01, 2.26496635e-06], - [3.82520000e-01, 2.26396064e-06], - [4.64960000e-01, 2.24609517e-06], - [5.65160000e-01, 2.23162115e-06]]), - np.array([[1.14030000e-02, 1.53247324e-02], - [1.38610000e-02, 9.89602164e-03], - [1.68480000e-02, 6.26868663e-03], - [2.04790000e-02, 3.83918877e-03], - [2.48920000e-02, 2.21818017e-03], - [3.02560000e-02, 1.15473774e-03], - [3.67770000e-02, 4.92469653e-04], - [4.47020000e-02, 1.37287345e-04], - [5.43360000e-02, 2.28561535e-05], - [6.60450000e-02, 6.63620782e-05], - [8.02790000e-02, 1.36790069e-04], - [9.75790000e-02, 1.15354200e-04], - [1.18610000e-01, 3.73063683e-05], - [1.44170000e-01, 1.21263573e-05], - [1.75240000e-01, 6.59103452e-06], - [2.13000000e-01, 4.38321947e-06], - [2.58910000e-01, 3.40797246e-06], - [3.14700000e-01, 3.41625063e-06], - [3.82520000e-01, 3.40076933e-06], - [4.64960000e-01, 3.38892224e-06], - [5.65160000e-01, 3.38103236e-06]])] - results.simulation = [np.array([[1.14030000e-02, 1.00000223e+00], - [1.38610000e-02, 1.00000223e+00], - [1.68480000e-02, 6.42692703e-02], - [2.04790000e-02, 1.69530247e-02], - [2.48920000e-02, 6.18815370e-03], - [3.02560000e-02, 2.99474163e-03], - [3.67770000e-02, 1.73558265e-03], - [4.47020000e-02, 1.03290554e-03], - [5.43360000e-02, 6.45645642e-04], - [6.60450000e-02, 5.57949197e-04], - [8.02790000e-02, 5.58974858e-04], - [9.75790000e-02, 3.49803750e-04], - [1.18610000e-01, 8.89485853e-05], - [1.44170000e-01, 4.04713900e-05], - [1.75240000e-01, 6.98590391e-06], - [2.13000000e-01, 3.60410795e-06], - [2.58910000e-01, 2.41835671e-06], - [3.14700000e-01, 2.26496635e-06], - [3.82520000e-01, 2.26396064e-06], - [4.64960000e-01, 2.24609517e-06], - [5.65160000e-01, 2.23162115e-06]]), - np.array([[1.14030000e-02, 1.53247324e-02], - [1.38610000e-02, 9.89602164e-03], - [1.68480000e-02, 6.26868663e-03], - [2.04790000e-02, 3.83918877e-03], - [2.48920000e-02, 2.21818017e-03], - [3.02560000e-02, 1.15473774e-03], - [3.67770000e-02, 4.92469653e-04], - [4.47020000e-02, 1.37287345e-04], - [5.43360000e-02, 2.28561535e-05], - [6.60450000e-02, 6.63620782e-05], - [8.02790000e-02, 1.36790069e-04], - [9.75790000e-02, 1.15354200e-04], - [1.18610000e-01, 3.73063683e-05], - [1.44170000e-01, 1.21263573e-05], - [1.75240000e-01, 6.59103452e-06], - [2.13000000e-01, 4.38321947e-06], - [2.58910000e-01, 3.40797246e-06], - [3.14700000e-01, 3.41625063e-06], - [3.82520000e-01, 3.40076933e-06], - [4.64960000e-01, 3.38892224e-06], - [5.65160000e-01, 3.38103236e-06]])] - results.shiftedData = [np.array([[1.1403e-02, 1.0063e+00, 1.9003e-02], - [1.3861e-02, 9.0118e-01, 1.1774e-02], - [1.6848e-02, 7.0455e-02, 1.3083e-03], - [2.0479e-02, 1.7544e-02, 5.1254e-04], - [2.4892e-02, 6.4257e-03, 2.6236e-04], - [3.0256e-02, 2.7746e-03, 8.5758e-05], - [3.6777e-02, 1.8591e-03, 4.9391e-05], - [4.4702e-02, 1.1002e-03, 3.2644e-05], - [5.4336e-02, 6.6691e-04, 2.1365e-05], - [6.6045e-02, 6.0729e-04, 1.1791e-05], - [8.0279e-02, 5.8755e-04, 1.5569e-05], - [9.7579e-02, 3.2700e-04, 6.5280e-06], - [1.1861e-01, 7.8205e-05, 2.5881e-06], - [1.4417e-01, 3.3455e-05, 1.5143e-06], - [1.7524e-01, 4.9313e-06, 5.6663e-07], - [2.1300e-01, 4.1948e-06, 6.8549e-07], - [2.5891e-01, 3.9863e-06, 8.2061e-07], - [3.1470e-01, 2.0861e-06, 6.1379e-07], - [3.8252e-01, 2.1154e-06, 6.3084e-07], - [4.6496e-01, 1.9906e-06, 6.0793e-07], - [5.6516e-01, 2.3816e-06, 7.0610e-07]]), - np.array([[1.14030000e-02, 1.20493333e-02, 7.32200000e-04], - [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], - [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], - [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], - [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], - [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], - [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], - [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], - [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], - [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], - [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], - [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], - [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], - [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], - [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], - [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], - [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], - [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], - [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], - [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], - [5.65160000e-01, 2.17460000e-06, 5.31346667e-07]])] - results.layerSlds = [[np.array([[1.954000e+01, 4.001499e-06, 3.000000e+00], - [2.266000e+01, -6.586988e-08, 3.000000e+00], - [8.560000e+00, 3.672535e-06, 5.640000e+00], - [1.712000e+01, 5.980000e-06, 5.640000e+00], - [1.070000e+01, 3.100365e-06, 6.014000e+00], - [1.782000e+01, 6.751924e-07, 6.014000e+00], - [1.782000e+01, 6.751924e-07, 6.014000e+00], - [1.070000e+01, 3.100365e-06, 6.014000e+00]])], - [np.array([[1.9540000e+01, 3.1114020e-06, 3.0000000e+00], - [2.2660000e+01, -2.6387028e-07, 3.0000000e+00], - [8.5600000e+00, 1.9590700e-06, 5.6400000e+00], - [1.7120000e+01, 2.2100000e-06, 5.6400000e+00], - [1.0700000e+01, 1.7375100e-06, 6.0140000e+00], - [1.7820000e+01, 1.0164400e-08, 6.0140000e+00], - [1.7820000e+01, 1.0164400e-08, 6.0140000e+00], - [1.0700000e+01, 1.7375100e-06, 6.0140000e+00]])]] - results.sldProfiles = [[np.array([[0.00000000e+00, 2.07300000e-06], - [1.10000000e+01, 2.07300000e-06], - [2.20000000e+01, 2.07300000e-06], - [3.30000000e+01, 2.07300001e-06], - [4.40000000e+01, 2.11687361e-06], - [5.50000000e+01, 3.90933280e-06], - [6.60000000e+01, 3.51748792e-06], - [7.70000000e+01, -2.64615370e-08], - [8.80000000e+01, 8.14665196e-07], - [9.90000000e+01, 4.11508879e-06], - [1.10000000e+02, 5.58392432e-06], - [1.21000000e+02, 3.71785214e-06], - [1.32000000e+02, 1.39304140e-06], - [1.43000000e+02, 6.95745588e-07], - [1.54000000e+02, 7.84170141e-07], - [1.65000000e+02, 2.15552213e-06], - [1.76000000e+02, 4.68458332e-06], - [1.87000000e+02, 5.91563638e-06], - [1.98000000e+02, 5.97982117e-06], - [2.09000000e+02, 5.97999998e-06], - [2.20000000e+02, 5.98000000e-06], - [2.31000000e+02, 5.98000000e-06], - [2.42000000e+02, 5.98000000e-06], - [2.53000000e+02, 5.98000000e-06], - [2.64000000e+02, 5.98000000e-06]]), - np.array([[0.00000000e+00, 2.07300000e-06], - [1.10000000e+01, 2.07300000e-06], - [2.20000000e+01, 2.07300000e-06], - [3.30000000e+01, 2.07300001e-06], - [4.40000000e+01, 2.09662378e-06], - [5.50000000e+01, 3.06177428e-06], - [6.60000000e+01, 2.70974796e-06], - [7.70000000e+01, -2.34283042e-07], - [8.80000000e+01, 2.46446429e-07], - [9.90000000e+01, 1.80004279e-06], - [1.10000000e+02, 2.14886270e-06], - [1.21000000e+02, 1.70090192e-06], - [1.32000000e+02, 5.06554250e-07], - [1.43000000e+02, 2.47801381e-08], - [1.54000000e+02, 8.73866316e-08], - [1.65000000e+02, 9.86362863e-07], - [1.76000000e+02, 1.96411923e-06], - [1.87000000e+02, 2.19933821e-06], - [1.98000000e+02, 2.20997064e-06], - [2.09000000e+02, 2.21000000e-06], - [2.20000000e+02, 2.21000000e-06], - [2.31000000e+02, 2.21000000e-06], - [2.42000000e+02, 2.21000000e-06], - [2.53000000e+02, 2.21000000e-06], - [2.64000000e+02, 2.21000000e-06]])]] + results.reflectivity = [ + np.array( + [ + [1.14030000e-02, 1.00000223e00], + [1.38610000e-02, 1.00000223e00], + [1.68480000e-02, 6.42692703e-02], + [2.04790000e-02, 1.69530247e-02], + [2.48920000e-02, 6.18815370e-03], + [3.02560000e-02, 2.99474163e-03], + [3.67770000e-02, 1.73558265e-03], + [4.47020000e-02, 1.03290554e-03], + [5.43360000e-02, 6.45645642e-04], + [6.60450000e-02, 5.57949197e-04], + [8.02790000e-02, 5.58974858e-04], + [9.75790000e-02, 3.49803750e-04], + [1.18610000e-01, 8.89485853e-05], + [1.44170000e-01, 4.04713900e-05], + [1.75240000e-01, 6.98590391e-06], + [2.13000000e-01, 3.60410795e-06], + [2.58910000e-01, 2.41835671e-06], + [3.14700000e-01, 2.26496635e-06], + [3.82520000e-01, 2.26396064e-06], + [4.64960000e-01, 2.24609517e-06], + [5.65160000e-01, 2.23162115e-06], + ], + ), + np.array( + [ + [1.14030000e-02, 1.53247324e-02], + [1.38610000e-02, 9.89602164e-03], + [1.68480000e-02, 6.26868663e-03], + [2.04790000e-02, 3.83918877e-03], + [2.48920000e-02, 2.21818017e-03], + [3.02560000e-02, 1.15473774e-03], + [3.67770000e-02, 4.92469653e-04], + [4.47020000e-02, 1.37287345e-04], + [5.43360000e-02, 2.28561535e-05], + [6.60450000e-02, 6.63620782e-05], + [8.02790000e-02, 1.36790069e-04], + [9.75790000e-02, 1.15354200e-04], + [1.18610000e-01, 3.73063683e-05], + [1.44170000e-01, 1.21263573e-05], + [1.75240000e-01, 6.59103452e-06], + [2.13000000e-01, 4.38321947e-06], + [2.58910000e-01, 3.40797246e-06], + [3.14700000e-01, 3.41625063e-06], + [3.82520000e-01, 3.40076933e-06], + [4.64960000e-01, 3.38892224e-06], + [5.65160000e-01, 3.38103236e-06], + ], + ), + ] + results.simulation = [ + np.array( + [ + [1.14030000e-02, 1.00000223e00], + [1.38610000e-02, 1.00000223e00], + [1.68480000e-02, 6.42692703e-02], + [2.04790000e-02, 1.69530247e-02], + [2.48920000e-02, 6.18815370e-03], + [3.02560000e-02, 2.99474163e-03], + [3.67770000e-02, 1.73558265e-03], + [4.47020000e-02, 1.03290554e-03], + [5.43360000e-02, 6.45645642e-04], + [6.60450000e-02, 5.57949197e-04], + [8.02790000e-02, 5.58974858e-04], + [9.75790000e-02, 3.49803750e-04], + [1.18610000e-01, 8.89485853e-05], + [1.44170000e-01, 4.04713900e-05], + [1.75240000e-01, 6.98590391e-06], + [2.13000000e-01, 3.60410795e-06], + [2.58910000e-01, 2.41835671e-06], + [3.14700000e-01, 2.26496635e-06], + [3.82520000e-01, 2.26396064e-06], + [4.64960000e-01, 2.24609517e-06], + [5.65160000e-01, 2.23162115e-06], + ], + ), + np.array( + [ + [1.14030000e-02, 1.53247324e-02], + [1.38610000e-02, 9.89602164e-03], + [1.68480000e-02, 6.26868663e-03], + [2.04790000e-02, 3.83918877e-03], + [2.48920000e-02, 2.21818017e-03], + [3.02560000e-02, 1.15473774e-03], + [3.67770000e-02, 4.92469653e-04], + [4.47020000e-02, 1.37287345e-04], + [5.43360000e-02, 2.28561535e-05], + [6.60450000e-02, 6.63620782e-05], + [8.02790000e-02, 1.36790069e-04], + [9.75790000e-02, 1.15354200e-04], + [1.18610000e-01, 3.73063683e-05], + [1.44170000e-01, 1.21263573e-05], + [1.75240000e-01, 6.59103452e-06], + [2.13000000e-01, 4.38321947e-06], + [2.58910000e-01, 3.40797246e-06], + [3.14700000e-01, 3.41625063e-06], + [3.82520000e-01, 3.40076933e-06], + [4.64960000e-01, 3.38892224e-06], + [5.65160000e-01, 3.38103236e-06], + ], + ), + ] + results.shiftedData = [ + np.array( + [ + [1.1403e-02, 1.0063e00, 1.9003e-02], + [1.3861e-02, 9.0118e-01, 1.1774e-02], + [1.6848e-02, 7.0455e-02, 1.3083e-03], + [2.0479e-02, 1.7544e-02, 5.1254e-04], + [2.4892e-02, 6.4257e-03, 2.6236e-04], + [3.0256e-02, 2.7746e-03, 8.5758e-05], + [3.6777e-02, 1.8591e-03, 4.9391e-05], + [4.4702e-02, 1.1002e-03, 3.2644e-05], + [5.4336e-02, 6.6691e-04, 2.1365e-05], + [6.6045e-02, 6.0729e-04, 1.1791e-05], + [8.0279e-02, 5.8755e-04, 1.5569e-05], + [9.7579e-02, 3.2700e-04, 6.5280e-06], + [1.1861e-01, 7.8205e-05, 2.5881e-06], + [1.4417e-01, 3.3455e-05, 1.5143e-06], + [1.7524e-01, 4.9313e-06, 5.6663e-07], + [2.1300e-01, 4.1948e-06, 6.8549e-07], + [2.5891e-01, 3.9863e-06, 8.2061e-07], + [3.1470e-01, 2.0861e-06, 6.1379e-07], + [3.8252e-01, 2.1154e-06, 6.3084e-07], + [4.6496e-01, 1.9906e-06, 6.0793e-07], + [5.6516e-01, 2.3816e-06, 7.0610e-07], + ], + ), + np.array( + [ + [1.14030000e-02, 1.20493333e-02, 7.32200000e-04], + [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], + [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], + [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], + [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], + [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], + [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], + [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], + [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], + [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], + [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], + [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], + [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], + [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], + [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], + [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], + [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], + [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], + [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], + [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], + [5.65160000e-01, 2.17460000e-06, 5.31346667e-07], + ], + ), + ] + results.layerSlds = [ + [ + np.array( + [ + [1.954000e01, 4.001499e-06, 3.000000e00], + [2.266000e01, -6.586988e-08, 3.000000e00], + [8.560000e00, 3.672535e-06, 5.640000e00], + [1.712000e01, 5.980000e-06, 5.640000e00], + [1.070000e01, 3.100365e-06, 6.014000e00], + [1.782000e01, 6.751924e-07, 6.014000e00], + [1.782000e01, 6.751924e-07, 6.014000e00], + [1.070000e01, 3.100365e-06, 6.014000e00], + ], + ), + ], + [ + np.array( + [ + [1.9540000e01, 3.1114020e-06, 3.0000000e00], + [2.2660000e01, -2.6387028e-07, 3.0000000e00], + [8.5600000e00, 1.9590700e-06, 5.6400000e00], + [1.7120000e01, 2.2100000e-06, 5.6400000e00], + [1.0700000e01, 1.7375100e-06, 6.0140000e00], + [1.7820000e01, 1.0164400e-08, 6.0140000e00], + [1.7820000e01, 1.0164400e-08, 6.0140000e00], + [1.0700000e01, 1.7375100e-06, 6.0140000e00], + ], + ), + ], + ] + results.sldProfiles = [ + [ + np.array( + [ + [0.00000000e00, 2.07300000e-06], + [1.10000000e01, 2.07300000e-06], + [2.20000000e01, 2.07300000e-06], + [3.30000000e01, 2.07300001e-06], + [4.40000000e01, 2.11687361e-06], + [5.50000000e01, 3.90933280e-06], + [6.60000000e01, 3.51748792e-06], + [7.70000000e01, -2.64615370e-08], + [8.80000000e01, 8.14665196e-07], + [9.90000000e01, 4.11508879e-06], + [1.10000000e02, 5.58392432e-06], + [1.21000000e02, 3.71785214e-06], + [1.32000000e02, 1.39304140e-06], + [1.43000000e02, 6.95745588e-07], + [1.54000000e02, 7.84170141e-07], + [1.65000000e02, 2.15552213e-06], + [1.76000000e02, 4.68458332e-06], + [1.87000000e02, 5.91563638e-06], + [1.98000000e02, 5.97982117e-06], + [2.09000000e02, 5.97999998e-06], + [2.20000000e02, 5.98000000e-06], + [2.31000000e02, 5.98000000e-06], + [2.42000000e02, 5.98000000e-06], + [2.53000000e02, 5.98000000e-06], + [2.64000000e02, 5.98000000e-06], + ], + ), + np.array( + [ + [0.00000000e00, 2.07300000e-06], + [1.10000000e01, 2.07300000e-06], + [2.20000000e01, 2.07300000e-06], + [3.30000000e01, 2.07300001e-06], + [4.40000000e01, 2.09662378e-06], + [5.50000000e01, 3.06177428e-06], + [6.60000000e01, 2.70974796e-06], + [7.70000000e01, -2.34283042e-07], + [8.80000000e01, 2.46446429e-07], + [9.90000000e01, 1.80004279e-06], + [1.10000000e02, 2.14886270e-06], + [1.21000000e02, 1.70090192e-06], + [1.32000000e02, 5.06554250e-07], + [1.43000000e02, 2.47801381e-08], + [1.54000000e02, 8.73866316e-08], + [1.65000000e02, 9.86362863e-07], + [1.76000000e02, 1.96411923e-06], + [1.87000000e02, 2.19933821e-06], + [1.98000000e02, 2.20997064e-06], + [2.09000000e02, 2.21000000e-06], + [2.20000000e02, 2.21000000e-06], + [2.31000000e02, 2.21000000e-06], + [2.42000000e02, 2.21000000e-06], + [2.53000000e02, 2.21000000e-06], + [2.64000000e02, 2.21000000e-06], + ], + ), + ], + ] results.resampledLayers = [[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]] results.calculationResults = RAT.rat_core.Calculation() results.calculationResults.chiValues = np.array([202.83057377, 1641.4024969]) @@ -214,14 +270,48 @@ def reflectivity_calculation_output_results(): results.contrastParams.resolutionParams = np.array([0.03, 0.03]) results.contrastParams.subRoughs = np.array([3.0, 3.0]) results.contrastParams.resample = np.array([0.0, 0.0]) - results.fitParams = np.array([3.000e+00, 1.954e+01, 2.266e+01, 5.252e+00, 5.640e+00, 1.712e+01, 8.560e+00, - 4.545e+01, 1.070e+01, 6.014e+00, 1.782e+01, 1.764e+01, 3.615e+01, 2.361e+01, - 2.230e-06, 3.380e-06, 5.980e-06, 2.210e-06]) - results.fitNames = ['Substrate Roughness', 'Oxide Thickness', 'SAM Tails Thickness', 'SAM Tails Hydration', - 'SAM Roughness', 'CW Thickness', 'SAM Heads Thickness', 'SAM Heads Hydration', - 'Bilayer Heads Thickness', 'Bilayer Roughness', 'Bilayer Tails Thickness', - 'Bilayer Tails Hydration', 'Bilayer Heads Hydration', 'Oxide Hydration', - 'Background parameter D2O', 'Background parameter SMW', 'D2O', 'SMW'] + results.fitParams = np.array( + [ + 3.000e00, + 1.954e01, + 2.266e01, + 5.252e00, + 5.640e00, + 1.712e01, + 8.560e00, + 4.545e01, + 1.070e01, + 6.014e00, + 1.782e01, + 1.764e01, + 3.615e01, + 2.361e01, + 2.230e-06, + 3.380e-06, + 5.980e-06, + 2.210e-06, + ], + ) + results.fitNames = [ + "Substrate Roughness", + "Oxide Thickness", + "SAM Tails Thickness", + "SAM Tails Hydration", + "SAM Roughness", + "CW Thickness", + "SAM Heads Thickness", + "SAM Heads Hydration", + "Bilayer Heads Thickness", + "Bilayer Roughness", + "Bilayer Tails Thickness", + "Bilayer Tails Hydration", + "Bilayer Heads Hydration", + "Oxide Hydration", + "Background parameter D2O", + "Background parameter SMW", + "D2O", + "SMW", + ] return results @@ -230,216 +320,310 @@ def reflectivity_calculation_output_results(): def reflectivity_calculation_results(): """The python results object for a reflectivity calculation of the project set out in "DSPC_standard_layers.py".""" return RAT.outputs.Results( - reflectivity=[np.array([[1.14030000e-02, 1.00000223e+00], - [1.38610000e-02, 1.00000223e+00], - [1.68480000e-02, 6.42692703e-02], - [2.04790000e-02, 1.69530247e-02], - [2.48920000e-02, 6.18815370e-03], - [3.02560000e-02, 2.99474163e-03], - [3.67770000e-02, 1.73558265e-03], - [4.47020000e-02, 1.03290554e-03], - [5.43360000e-02, 6.45645642e-04], - [6.60450000e-02, 5.57949197e-04], - [8.02790000e-02, 5.58974858e-04], - [9.75790000e-02, 3.49803750e-04], - [1.18610000e-01, 8.89485853e-05], - [1.44170000e-01, 4.04713900e-05], - [1.75240000e-01, 6.98590391e-06], - [2.13000000e-01, 3.60410795e-06], - [2.58910000e-01, 2.41835671e-06], - [3.14700000e-01, 2.26496635e-06], - [3.82520000e-01, 2.26396064e-06], - [4.64960000e-01, 2.24609517e-06], - [5.65160000e-01, 2.23162115e-06]]), - np.array([[1.14030000e-02, 1.53247324e-02], - [1.38610000e-02, 9.89602164e-03], - [1.68480000e-02, 6.26868663e-03], - [2.04790000e-02, 3.83918877e-03], - [2.48920000e-02, 2.21818017e-03], - [3.02560000e-02, 1.15473774e-03], - [3.67770000e-02, 4.92469653e-04], - [4.47020000e-02, 1.37287345e-04], - [5.43360000e-02, 2.28561535e-05], - [6.60450000e-02, 6.63620782e-05], - [8.02790000e-02, 1.36790069e-04], - [9.75790000e-02, 1.15354200e-04], - [1.18610000e-01, 3.73063683e-05], - [1.44170000e-01, 1.21263573e-05], - [1.75240000e-01, 6.59103452e-06], - [2.13000000e-01, 4.38321947e-06], - [2.58910000e-01, 3.40797246e-06], - [3.14700000e-01, 3.41625063e-06], - [3.82520000e-01, 3.40076933e-06], - [4.64960000e-01, 3.38892224e-06], - [5.65160000e-01, 3.38103236e-06]])], - simulation=[np.array([[1.14030000e-02, 1.00000223e+00], - [1.38610000e-02, 1.00000223e+00], - [1.68480000e-02, 6.42692703e-02], - [2.04790000e-02, 1.69530247e-02], - [2.48920000e-02, 6.18815370e-03], - [3.02560000e-02, 2.99474163e-03], - [3.67770000e-02, 1.73558265e-03], - [4.47020000e-02, 1.03290554e-03], - [5.43360000e-02, 6.45645642e-04], - [6.60450000e-02, 5.57949197e-04], - [8.02790000e-02, 5.58974858e-04], - [9.75790000e-02, 3.49803750e-04], - [1.18610000e-01, 8.89485853e-05], - [1.44170000e-01, 4.04713900e-05], - [1.75240000e-01, 6.98590391e-06], - [2.13000000e-01, 3.60410795e-06], - [2.58910000e-01, 2.41835671e-06], - [3.14700000e-01, 2.26496635e-06], - [3.82520000e-01, 2.26396064e-06], - [4.64960000e-01, 2.24609517e-06], - [5.65160000e-01, 2.23162115e-06]]), - np.array([[1.14030000e-02, 1.53247324e-02], - [1.38610000e-02, 9.89602164e-03], - [1.68480000e-02, 6.26868663e-03], - [2.04790000e-02, 3.83918877e-03], - [2.48920000e-02, 2.21818017e-03], - [3.02560000e-02, 1.15473774e-03], - [3.67770000e-02, 4.92469653e-04], - [4.47020000e-02, 1.37287345e-04], - [5.43360000e-02, 2.28561535e-05], - [6.60450000e-02, 6.63620782e-05], - [8.02790000e-02, 1.36790069e-04], - [9.75790000e-02, 1.15354200e-04], - [1.18610000e-01, 3.73063683e-05], - [1.44170000e-01, 1.21263573e-05], - [1.75240000e-01, 6.59103452e-06], - [2.13000000e-01, 4.38321947e-06], - [2.58910000e-01, 3.40797246e-06], - [3.14700000e-01, 3.41625063e-06], - [3.82520000e-01, 3.40076933e-06], - [4.64960000e-01, 3.38892224e-06], - [5.65160000e-01, 3.38103236e-06]])], - shiftedData=[np.array([[1.1403e-02, 1.0063e+00, 1.9003e-02], - [1.3861e-02, 9.0118e-01, 1.1774e-02], - [1.6848e-02, 7.0455e-02, 1.3083e-03], - [2.0479e-02, 1.7544e-02, 5.1254e-04], - [2.4892e-02, 6.4257e-03, 2.6236e-04], - [3.0256e-02, 2.7746e-03, 8.5758e-05], - [3.6777e-02, 1.8591e-03, 4.9391e-05], - [4.4702e-02, 1.1002e-03, 3.2644e-05], - [5.4336e-02, 6.6691e-04, 2.1365e-05], - [6.6045e-02, 6.0729e-04, 1.1791e-05], - [8.0279e-02, 5.8755e-04, 1.5569e-05], - [9.7579e-02, 3.2700e-04, 6.5280e-06], - [1.1861e-01, 7.8205e-05, 2.5881e-06], - [1.4417e-01, 3.3455e-05, 1.5143e-06], - [1.7524e-01, 4.9313e-06, 5.6663e-07], - [2.1300e-01, 4.1948e-06, 6.8549e-07], - [2.5891e-01, 3.9863e-06, 8.2061e-07], - [3.1470e-01, 2.0861e-06, 6.1379e-07], - [3.8252e-01, 2.1154e-06, 6.3084e-07], - [4.6496e-01, 1.9906e-06, 6.0793e-07], - [5.6516e-01, 2.3816e-06, 7.0610e-07]]), - np.array([[1.14030000e-02, 1.20493333e-02, 7.32200000e-04], - [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], - [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], - [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], - [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], - [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], - [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], - [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], - [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], - [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], - [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], - [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], - [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], - [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], - [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], - [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], - [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], - [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], - [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], - [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], - [5.65160000e-01, 2.17460000e-06, 5.31346667e-07]])], - layerSlds=[[np.array([[1.954000e+01, 4.001499e-06, 3.000000e+00], - [2.266000e+01, -6.586988e-08, 3.000000e+00], - [8.560000e+00, 3.672535e-06, 5.640000e+00], - [1.712000e+01, 5.980000e-06, 5.640000e+00], - [1.070000e+01, 3.100365e-06, 6.014000e+00], - [1.782000e+01, 6.751924e-07, 6.014000e+00], - [1.782000e+01, 6.751924e-07, 6.014000e+00], - [1.070000e+01, 3.100365e-06, 6.014000e+00]])], - [np.array([[1.9540000e+01, 3.1114020e-06, 3.0000000e+00], - [2.2660000e+01, -2.6387028e-07, 3.0000000e+00], - [8.5600000e+00, 1.9590700e-06, 5.6400000e+00], - [1.7120000e+01, 2.2100000e-06, 5.6400000e+00], - [1.0700000e+01, 1.7375100e-06, 6.0140000e+00], - [1.7820000e+01, 1.0164400e-08, 6.0140000e+00], - [1.7820000e+01, 1.0164400e-08, 6.0140000e+00], - [1.0700000e+01, 1.7375100e-06, 6.0140000e+00]])]], - sldProfiles=[[np.array([[0.00000000e+00, 2.07300000e-06], - [1.10000000e+01, 2.07300000e-06], - [2.20000000e+01, 2.07300000e-06], - [3.30000000e+01, 2.07300001e-06], - [4.40000000e+01, 2.11687361e-06], - [5.50000000e+01, 3.90933280e-06], - [6.60000000e+01, 3.51748792e-06], - [7.70000000e+01, -2.64615370e-08], - [8.80000000e+01, 8.14665196e-07], - [9.90000000e+01, 4.11508879e-06], - [1.10000000e+02, 5.58392432e-06], - [1.21000000e+02, 3.71785214e-06], - [1.32000000e+02, 1.39304140e-06], - [1.43000000e+02, 6.95745588e-07], - [1.54000000e+02, 7.84170141e-07], - [1.65000000e+02, 2.15552213e-06], - [1.76000000e+02, 4.68458332e-06], - [1.87000000e+02, 5.91563638e-06], - [1.98000000e+02, 5.97982117e-06], - [2.09000000e+02, 5.97999998e-06], - [2.20000000e+02, 5.98000000e-06], - [2.31000000e+02, 5.98000000e-06], - [2.42000000e+02, 5.98000000e-06], - [2.53000000e+02, 5.98000000e-06], - [2.64000000e+02, 5.98000000e-06]]), - np.array([[0.00000000e+00, 2.07300000e-06], - [1.10000000e+01, 2.07300000e-06], - [2.20000000e+01, 2.07300000e-06], - [3.30000000e+01, 2.07300001e-06], - [4.40000000e+01, 2.09662378e-06], - [5.50000000e+01, 3.06177428e-06], - [6.60000000e+01, 2.70974796e-06], - [7.70000000e+01, -2.34283042e-07], - [8.80000000e+01, 2.46446429e-07], - [9.90000000e+01, 1.80004279e-06], - [1.10000000e+02, 2.14886270e-06], - [1.21000000e+02, 1.70090192e-06], - [1.32000000e+02, 5.06554250e-07], - [1.43000000e+02, 2.47801381e-08], - [1.54000000e+02, 8.73866316e-08], - [1.65000000e+02, 9.86362863e-07], - [1.76000000e+02, 1.96411923e-06], - [1.87000000e+02, 2.19933821e-06], - [1.98000000e+02, 2.20997064e-06], - [2.09000000e+02, 2.21000000e-06], - [2.20000000e+02, 2.21000000e-06], - [2.31000000e+02, 2.21000000e-06], - [2.42000000e+02, 2.21000000e-06], - [2.53000000e+02, 2.21000000e-06], - [2.64000000e+02, 2.21000000e-06]])]], + reflectivity=[ + np.array( + [ + [1.14030000e-02, 1.00000223e00], + [1.38610000e-02, 1.00000223e00], + [1.68480000e-02, 6.42692703e-02], + [2.04790000e-02, 1.69530247e-02], + [2.48920000e-02, 6.18815370e-03], + [3.02560000e-02, 2.99474163e-03], + [3.67770000e-02, 1.73558265e-03], + [4.47020000e-02, 1.03290554e-03], + [5.43360000e-02, 6.45645642e-04], + [6.60450000e-02, 5.57949197e-04], + [8.02790000e-02, 5.58974858e-04], + [9.75790000e-02, 3.49803750e-04], + [1.18610000e-01, 8.89485853e-05], + [1.44170000e-01, 4.04713900e-05], + [1.75240000e-01, 6.98590391e-06], + [2.13000000e-01, 3.60410795e-06], + [2.58910000e-01, 2.41835671e-06], + [3.14700000e-01, 2.26496635e-06], + [3.82520000e-01, 2.26396064e-06], + [4.64960000e-01, 2.24609517e-06], + [5.65160000e-01, 2.23162115e-06], + ], + ), + np.array( + [ + [1.14030000e-02, 1.53247324e-02], + [1.38610000e-02, 9.89602164e-03], + [1.68480000e-02, 6.26868663e-03], + [2.04790000e-02, 3.83918877e-03], + [2.48920000e-02, 2.21818017e-03], + [3.02560000e-02, 1.15473774e-03], + [3.67770000e-02, 4.92469653e-04], + [4.47020000e-02, 1.37287345e-04], + [5.43360000e-02, 2.28561535e-05], + [6.60450000e-02, 6.63620782e-05], + [8.02790000e-02, 1.36790069e-04], + [9.75790000e-02, 1.15354200e-04], + [1.18610000e-01, 3.73063683e-05], + [1.44170000e-01, 1.21263573e-05], + [1.75240000e-01, 6.59103452e-06], + [2.13000000e-01, 4.38321947e-06], + [2.58910000e-01, 3.40797246e-06], + [3.14700000e-01, 3.41625063e-06], + [3.82520000e-01, 3.40076933e-06], + [4.64960000e-01, 3.38892224e-06], + [5.65160000e-01, 3.38103236e-06], + ], + ), + ], + simulation=[ + np.array( + [ + [1.14030000e-02, 1.00000223e00], + [1.38610000e-02, 1.00000223e00], + [1.68480000e-02, 6.42692703e-02], + [2.04790000e-02, 1.69530247e-02], + [2.48920000e-02, 6.18815370e-03], + [3.02560000e-02, 2.99474163e-03], + [3.67770000e-02, 1.73558265e-03], + [4.47020000e-02, 1.03290554e-03], + [5.43360000e-02, 6.45645642e-04], + [6.60450000e-02, 5.57949197e-04], + [8.02790000e-02, 5.58974858e-04], + [9.75790000e-02, 3.49803750e-04], + [1.18610000e-01, 8.89485853e-05], + [1.44170000e-01, 4.04713900e-05], + [1.75240000e-01, 6.98590391e-06], + [2.13000000e-01, 3.60410795e-06], + [2.58910000e-01, 2.41835671e-06], + [3.14700000e-01, 2.26496635e-06], + [3.82520000e-01, 2.26396064e-06], + [4.64960000e-01, 2.24609517e-06], + [5.65160000e-01, 2.23162115e-06], + ], + ), + np.array( + [ + [1.14030000e-02, 1.53247324e-02], + [1.38610000e-02, 9.89602164e-03], + [1.68480000e-02, 6.26868663e-03], + [2.04790000e-02, 3.83918877e-03], + [2.48920000e-02, 2.21818017e-03], + [3.02560000e-02, 1.15473774e-03], + [3.67770000e-02, 4.92469653e-04], + [4.47020000e-02, 1.37287345e-04], + [5.43360000e-02, 2.28561535e-05], + [6.60450000e-02, 6.63620782e-05], + [8.02790000e-02, 1.36790069e-04], + [9.75790000e-02, 1.15354200e-04], + [1.18610000e-01, 3.73063683e-05], + [1.44170000e-01, 1.21263573e-05], + [1.75240000e-01, 6.59103452e-06], + [2.13000000e-01, 4.38321947e-06], + [2.58910000e-01, 3.40797246e-06], + [3.14700000e-01, 3.41625063e-06], + [3.82520000e-01, 3.40076933e-06], + [4.64960000e-01, 3.38892224e-06], + [5.65160000e-01, 3.38103236e-06], + ], + ), + ], + shiftedData=[ + np.array( + [ + [1.1403e-02, 1.0063e00, 1.9003e-02], + [1.3861e-02, 9.0118e-01, 1.1774e-02], + [1.6848e-02, 7.0455e-02, 1.3083e-03], + [2.0479e-02, 1.7544e-02, 5.1254e-04], + [2.4892e-02, 6.4257e-03, 2.6236e-04], + [3.0256e-02, 2.7746e-03, 8.5758e-05], + [3.6777e-02, 1.8591e-03, 4.9391e-05], + [4.4702e-02, 1.1002e-03, 3.2644e-05], + [5.4336e-02, 6.6691e-04, 2.1365e-05], + [6.6045e-02, 6.0729e-04, 1.1791e-05], + [8.0279e-02, 5.8755e-04, 1.5569e-05], + [9.7579e-02, 3.2700e-04, 6.5280e-06], + [1.1861e-01, 7.8205e-05, 2.5881e-06], + [1.4417e-01, 3.3455e-05, 1.5143e-06], + [1.7524e-01, 4.9313e-06, 5.6663e-07], + [2.1300e-01, 4.1948e-06, 6.8549e-07], + [2.5891e-01, 3.9863e-06, 8.2061e-07], + [3.1470e-01, 2.0861e-06, 6.1379e-07], + [3.8252e-01, 2.1154e-06, 6.3084e-07], + [4.6496e-01, 1.9906e-06, 6.0793e-07], + [5.6516e-01, 2.3816e-06, 7.0610e-07], + ], + ), + np.array( + [ + [1.14030000e-02, 1.20493333e-02, 7.32200000e-04], + [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], + [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], + [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], + [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], + [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], + [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], + [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], + [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], + [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], + [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], + [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], + [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], + [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], + [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], + [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], + [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], + [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], + [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], + [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], + [5.65160000e-01, 2.17460000e-06, 5.31346667e-07], + ], + ), + ], + layerSlds=[ + [ + np.array( + [ + [1.954000e01, 4.001499e-06, 3.000000e00], + [2.266000e01, -6.586988e-08, 3.000000e00], + [8.560000e00, 3.672535e-06, 5.640000e00], + [1.712000e01, 5.980000e-06, 5.640000e00], + [1.070000e01, 3.100365e-06, 6.014000e00], + [1.782000e01, 6.751924e-07, 6.014000e00], + [1.782000e01, 6.751924e-07, 6.014000e00], + [1.070000e01, 3.100365e-06, 6.014000e00], + ], + ), + ], + [ + np.array( + [ + [1.9540000e01, 3.1114020e-06, 3.0000000e00], + [2.2660000e01, -2.6387028e-07, 3.0000000e00], + [8.5600000e00, 1.9590700e-06, 5.6400000e00], + [1.7120000e01, 2.2100000e-06, 5.6400000e00], + [1.0700000e01, 1.7375100e-06, 6.0140000e00], + [1.7820000e01, 1.0164400e-08, 6.0140000e00], + [1.7820000e01, 1.0164400e-08, 6.0140000e00], + [1.0700000e01, 1.7375100e-06, 6.0140000e00], + ], + ), + ], + ], + sldProfiles=[ + [ + np.array( + [ + [0.00000000e00, 2.07300000e-06], + [1.10000000e01, 2.07300000e-06], + [2.20000000e01, 2.07300000e-06], + [3.30000000e01, 2.07300001e-06], + [4.40000000e01, 2.11687361e-06], + [5.50000000e01, 3.90933280e-06], + [6.60000000e01, 3.51748792e-06], + [7.70000000e01, -2.64615370e-08], + [8.80000000e01, 8.14665196e-07], + [9.90000000e01, 4.11508879e-06], + [1.10000000e02, 5.58392432e-06], + [1.21000000e02, 3.71785214e-06], + [1.32000000e02, 1.39304140e-06], + [1.43000000e02, 6.95745588e-07], + [1.54000000e02, 7.84170141e-07], + [1.65000000e02, 2.15552213e-06], + [1.76000000e02, 4.68458332e-06], + [1.87000000e02, 5.91563638e-06], + [1.98000000e02, 5.97982117e-06], + [2.09000000e02, 5.97999998e-06], + [2.20000000e02, 5.98000000e-06], + [2.31000000e02, 5.98000000e-06], + [2.42000000e02, 5.98000000e-06], + [2.53000000e02, 5.98000000e-06], + [2.64000000e02, 5.98000000e-06], + ], + ), + np.array( + [ + [0.00000000e00, 2.07300000e-06], + [1.10000000e01, 2.07300000e-06], + [2.20000000e01, 2.07300000e-06], + [3.30000000e01, 2.07300001e-06], + [4.40000000e01, 2.09662378e-06], + [5.50000000e01, 3.06177428e-06], + [6.60000000e01, 2.70974796e-06], + [7.70000000e01, -2.34283042e-07], + [8.80000000e01, 2.46446429e-07], + [9.90000000e01, 1.80004279e-06], + [1.10000000e02, 2.14886270e-06], + [1.21000000e02, 1.70090192e-06], + [1.32000000e02, 5.06554250e-07], + [1.43000000e02, 2.47801381e-08], + [1.54000000e02, 8.73866316e-08], + [1.65000000e02, 9.86362863e-07], + [1.76000000e02, 1.96411923e-06], + [1.87000000e02, 2.19933821e-06], + [1.98000000e02, 2.20997064e-06], + [2.09000000e02, 2.21000000e-06], + [2.20000000e02, 2.21000000e-06], + [2.31000000e02, 2.21000000e-06], + [2.42000000e02, 2.21000000e-06], + [2.53000000e02, 2.21000000e-06], + [2.64000000e02, 2.21000000e-06], + ], + ), + ], + ], resampledLayers=[[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]], - calculationResults=RAT.outputs.CalculationResults(chiValues=np.array([202.83057377, 1641.4024969]), - sumChi=1844.2330706690975), - contrastParams=RAT.outputs.ContrastParams(backgroundParams=np.array([2.23e-06, 3.38e-06]), - scalefactors=np.array([0.1, 0.15]), - bulkIn=np.array([2.073e-06, 2.073e-06]), - bulkOut=np.array([5.98e-06, 2.21e-06]), - resolutionParams=np.array([0.03, 0.03]), - subRoughs=np.array([3.0, 3.0]), - resample=np.array([0.0, 0.0])), - fitParams=np.array([3.000e+00, 1.954e+01, 2.266e+01, 5.252e+00, 5.640e+00, 1.712e+01, 8.560e+00, 4.545e+01, - 1.070e+01, 6.014e+00, 1.782e+01, 1.764e+01, 3.615e+01, 2.361e+01, 2.230e-06, 3.380e-06, - 5.980e-06, 2.210e-06]), - fitNames=['Substrate Roughness', 'Oxide Thickness', 'SAM Tails Thickness', 'SAM Tails Hydration', - 'SAM Roughness', 'CW Thickness', 'SAM Heads Thickness', 'SAM Heads Hydration', - 'Bilayer Heads Thickness', 'Bilayer Roughness', 'Bilayer Tails Thickness', - 'Bilayer Tails Hydration', 'Bilayer Heads Hydration', 'Oxide Hydration', - 'Background parameter D2O', 'Background parameter SMW', 'D2O', 'SMW'] + calculationResults=RAT.outputs.CalculationResults( + chiValues=np.array([202.83057377, 1641.4024969]), + sumChi=1844.2330706690975, + ), + contrastParams=RAT.outputs.ContrastParams( + backgroundParams=np.array([2.23e-06, 3.38e-06]), + scalefactors=np.array([0.1, 0.15]), + bulkIn=np.array([2.073e-06, 2.073e-06]), + bulkOut=np.array([5.98e-06, 2.21e-06]), + resolutionParams=np.array([0.03, 0.03]), + subRoughs=np.array([3.0, 3.0]), + resample=np.array([0.0, 0.0]), + ), + fitParams=np.array( + [ + 3.000e00, + 1.954e01, + 2.266e01, + 5.252e00, + 5.640e00, + 1.712e01, + 8.560e00, + 4.545e01, + 1.070e01, + 6.014e00, + 1.782e01, + 1.764e01, + 3.615e01, + 2.361e01, + 2.230e-06, + 3.380e-06, + 5.980e-06, + 2.210e-06, + ], + ), + fitNames=[ + "Substrate Roughness", + "Oxide Thickness", + "SAM Tails Thickness", + "SAM Tails Hydration", + "SAM Roughness", + "CW Thickness", + "SAM Heads Thickness", + "SAM Heads Hydration", + "Bilayer Heads Thickness", + "Bilayer Roughness", + "Bilayer Tails Thickness", + "Bilayer Tails Hydration", + "Bilayer Heads Hydration", + "Oxide Hydration", + "Background parameter D2O", + "Background parameter SMW", + "D2O", + "SMW", + ], ) @@ -451,209 +635,265 @@ def dream_output_results(): and fitParams are taken from an optimisation with the parameters: nSamples=50000, nChains=10. """ results = RAT.rat_core.OutputResult() - results.reflectivity = [np.array([[1.14030000e-02, 1.45891447e+01], - [1.38610000e-02, 1.45739839e+01], - [1.68480000e-02, 1.45684725e+01], - [2.04790000e-02, 1.45658452e+01], - [2.48920000e-02, 1.45641513e+01], - [3.02560000e-02, 1.45628311e+01], - [3.67770000e-02, 1.45618510e+01], - [4.47020000e-02, 1.45613427e+01], - [5.43360000e-02, 1.45612940e+01], - [6.60450000e-02, 1.45613971e+01], - [8.02790000e-02, 1.45613678e+01], - [9.75790000e-02, 1.45612960e+01], - [1.18610000e-01, 1.45612799e+01], - [1.44170000e-01, 1.45612749e+01], - [1.75240000e-01, 1.45612726e+01], - [2.13000000e-01, 1.45612723e+01], - [2.58910000e-01, 1.45612724e+01], - [3.14700000e-01, 1.45612723e+01], - [3.82520000e-01, 1.45612723e+01], - [4.64960000e-01, 1.45612723e+01], - [5.65160000e-01, 1.45612723e+01]]), - np.array([[1.14030000e-02, 1.00000316e+00], - [1.38610000e-02, 1.21238320e-01], - [1.68480000e-02, 2.13433068e-02], - [2.04790000e-02, 8.71162144e-03], - [2.48920000e-02, 5.72807902e-03], - [3.02560000e-02, 3.71827525e-03], - [3.67770000e-02, 1.72067772e-03], - [4.47020000e-02, 3.51471141e-04], - [5.43360000e-02, 2.03975460e-05], - [6.60450000e-02, 1.89221181e-04], - [8.02790000e-02, 1.49280488e-04], - [9.75790000e-02, 3.86439083e-05], - [1.18610000e-01, 1.63612094e-05], - [1.44170000e-01, 6.75770325e-06], - [1.75240000e-01, 3.45955607e-06], - [2.13000000e-01, 3.20880782e-06], - [2.58910000e-01, 3.32068345e-06], - [3.14700000e-01, 3.21671807e-06], - [3.82520000e-01, 3.15612021e-06], - [4.64960000e-01, 3.15645546e-06], - [5.65160000e-01, 3.15511510e-06]])] - results.simulation = [np.array([[1.14030000e-02, 1.45891447e+01], - [1.38610000e-02, 1.45739839e+01], - [1.68480000e-02, 1.45684725e+01], - [2.04790000e-02, 1.45658452e+01], - [2.48920000e-02, 1.45641513e+01], - [3.02560000e-02, 1.45628311e+01], - [3.67770000e-02, 1.45618510e+01], - [4.47020000e-02, 1.45613427e+01], - [5.43360000e-02, 1.45612940e+01], - [6.60450000e-02, 1.45613971e+01], - [8.02790000e-02, 1.45613678e+01], - [9.75790000e-02, 1.45612960e+01], - [1.18610000e-01, 1.45612799e+01], - [1.44170000e-01, 1.45612749e+01], - [1.75240000e-01, 1.45612726e+01], - [2.13000000e-01, 1.45612723e+01], - [2.58910000e-01, 1.45612724e+01], - [3.14700000e-01, 1.45612723e+01], - [3.82520000e-01, 1.45612723e+01], - [4.64960000e-01, 1.45612723e+01], - [5.65160000e-01, 1.45612723e+01]]), - np.array([[1.14030000e-02, 1.00000316e+00], - [1.38610000e-02, 1.21238320e-01], - [1.68480000e-02, 2.13433068e-02], - [2.04790000e-02, 8.71162144e-03], - [2.48920000e-02, 5.72807902e-03], - [3.02560000e-02, 3.71827525e-03], - [3.67770000e-02, 1.72067772e-03], - [4.47020000e-02, 3.51471141e-04], - [5.43360000e-02, 2.03975460e-05], - [6.60450000e-02, 1.89221181e-04], - [8.02790000e-02, 1.49280488e-04], - [9.75790000e-02, 3.86439083e-05], - [1.18610000e-01, 1.63612094e-05], - [1.44170000e-01, 6.75770325e-06], - [1.75240000e-01, 3.45955607e-06], - [2.13000000e-01, 3.20880782e-06], - [2.58910000e-01, 3.32068345e-06], - [3.14700000e-01, 3.21671807e-06], - [3.82520000e-01, 3.15612021e-06], - [4.64960000e-01, 3.15645546e-06], - [5.65160000e-01, 3.15511510e-06]])] - results.shiftedData = [np.array([[1.1403e-02, 1.0063e+00, 1.9003e-02], - [1.3861e-02, 9.0118e-01, 1.1774e-02], - [1.6848e-02, 7.0455e-02, 1.3083e-03], - [2.0479e-02, 1.7544e-02, 5.1254e-04], - [2.4892e-02, 6.4257e-03, 2.6236e-04], - [3.0256e-02, 2.7746e-03, 8.5758e-05], - [3.6777e-02, 1.8591e-03, 4.9391e-05], - [4.4702e-02, 1.1002e-03, 3.2644e-05], - [5.4336e-02, 6.6691e-04, 2.1365e-05], - [6.6045e-02, 6.0729e-04, 1.1791e-05], - [8.0279e-02, 5.8755e-04, 1.5569e-05], - [9.7579e-02, 3.2700e-04, 6.5280e-06], - [1.1861e-01, 7.8205e-05, 2.5881e-06], - [1.4417e-01, 3.3455e-05, 1.5143e-06], - [1.7524e-01, 4.9313e-06, 5.6663e-07], - [2.1300e-01, 4.1948e-06, 6.8549e-07], - [2.5891e-01, 3.9863e-06, 8.2061e-07], - [3.1470e-01, 2.0861e-06, 6.1379e-07], - [3.8252e-01, 2.1154e-06, 6.3084e-07], - [4.6496e-01, 1.9906e-06, 6.0793e-07], - [5.6516e-01, 2.3816e-06, 7.0610e-07]]), - np.array([[1.14030000e-02, 1.20493333e-02, 7.32200000e-04], - [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], - [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], - [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], - [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], - [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], - [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], - [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], - [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], - [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], - [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], - [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], - [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], - [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], - [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], - [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], - [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], - [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], - [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], - [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], - [5.65160000e-01, 2.17460000e-06, 5.31346667e-07]])] - results.layerSlds = [[np.array([[3.15755349e+01, 3.35278238e-06, 4.16625659e+00], - [3.61791464e+01, 7.68327921e-07, 4.16625659e+00], - [1.00488530e+01, 2.06044530e-06, 2.78042232e+01], - [1.08043784e+01, 3.29384190e-06, 2.78042232e+01], - [2.42251646e+01, 2.35556998e-06, 1.55593097e+01], - [1.49022278e+01, 7.42138004e-07, 1.55593097e+01], - [1.49022278e+01, 7.42138004e-07, 1.55593097e+01], - [2.42251646e+01, 2.35556998e-06, 1.55593097e+01]])], - [np.array([[3.15755349e+01, 4.11636356e-06, 4.16625659e+00], - [3.61791464e+01, 1.39268494e-06, 4.16625659e+00], - [1.00488530e+01, 2.45715680e-06, 2.78042232e+01], - [1.08043784e+01, 5.26668495e-06, 2.78042232e+01], - [2.42251646e+01, 3.31348777e-06, 1.55593097e+01], - [1.49022278e+01, 1.37428245e-06, 1.55593097e+01], - [1.49022278e+01, 1.37428245e-06, 1.55593097e+01], - [2.42251646e+01, 3.31348777e-06, 1.55593097e+01]])]] - results.sldProfiles = [[np.array([[0.00000000e+00, 2.07301741e-06], - [1.10000000e+01, 2.07309604e-06], - [2.20000000e+01, 2.07345780e-06], - [3.30000000e+01, 2.07491687e-06], - [4.40000000e+01, 2.17562259e-06], - [5.50000000e+01, 3.22650495e-06], - [6.60000000e+01, 3.40913848e-06], - [7.70000000e+01, 3.13506253e-06], - [8.80000000e+01, 1.20456289e-06], - [9.90000000e+01, 1.27138002e-06], - [1.10000000e+02, 1.56285495e-06], - [1.21000000e+02, 1.84518709e-06], - [1.32000000e+02, 2.00498449e-06], - [1.43000000e+02, 1.96260665e-06], - [1.54000000e+02, 1.71966879e-06], - [1.65000000e+02, 1.39383267e-06], - [1.76000000e+02, 1.22970195e-06], - [1.87000000e+02, 1.41565526e-06], - [1.98000000e+02, 1.88172657e-06], - [2.09000000e+02, 2.40655867e-06], - [2.20000000e+02, 2.83570420e-06], - [2.31000000e+02, 3.11210082e-06], - [2.42000000e+02, 3.24277802e-06], - [2.53000000e+02, 3.28427452e-06], - [2.64000000e+02, 3.29268847e-06], - [2.75000000e+02, 3.29375418e-06], - [2.86000000e+02, 3.29383773e-06], - [2.97000000e+02, 3.29384178e-06], - [3.08000000e+02, 3.29384190e-06]]), - np.array([[0.00000000e+00, 2.07301819e-06], - [1.10000000e+01, 2.07310296e-06], - [2.20000000e+01, 2.07350415e-06], - [3.30000000e+01, 2.07518460e-06], - [4.40000000e+01, 2.23394767e-06], - [5.50000000e+01, 3.90646736e-06], - [6.60000000e+01, 4.18619279e-06], - [7.70000000e+01, 3.91675004e-06], - [8.80000000e+01, 1.92451547e-06], - [9.90000000e+01, 2.06988861e-06], - [1.10000000e+02, 2.47614934e-06], - [1.21000000e+02, 2.84889288e-06], - [1.32000000e+02, 3.00529286e-06], - [1.43000000e+02, 2.86310144e-06], - [1.54000000e+02, 2.49967205e-06], - [1.65000000e+02, 2.09673058e-06], - [1.76000000e+02, 1.92431424e-06], - [1.87000000e+02, 2.18829605e-06], - [1.98000000e+02, 2.83032190e-06], - [2.09000000e+02, 3.62584708e-06], - [2.20000000e+02, 4.36871153e-06], - [2.31000000e+02, 4.89806866e-06], - [2.42000000e+02, 5.16145928e-06], - [2.53000000e+02, 5.24684298e-06], - [2.64000000e+02, 5.26428707e-06], - [2.75000000e+02, 5.26650242e-06], - [2.86000000e+02, 5.26667628e-06], - [2.97000000e+02, 5.26668469e-06], - [3.08000000e+02, 5.26668495e-06]])]] - results.resampledLayers = [[np.array([[0., 0., 0.]])], [np.array([[0., 0., 0.]])]] + results.reflectivity = [ + np.array( + [ + [1.14030000e-02, 1.45891447e01], + [1.38610000e-02, 1.45739839e01], + [1.68480000e-02, 1.45684725e01], + [2.04790000e-02, 1.45658452e01], + [2.48920000e-02, 1.45641513e01], + [3.02560000e-02, 1.45628311e01], + [3.67770000e-02, 1.45618510e01], + [4.47020000e-02, 1.45613427e01], + [5.43360000e-02, 1.45612940e01], + [6.60450000e-02, 1.45613971e01], + [8.02790000e-02, 1.45613678e01], + [9.75790000e-02, 1.45612960e01], + [1.18610000e-01, 1.45612799e01], + [1.44170000e-01, 1.45612749e01], + [1.75240000e-01, 1.45612726e01], + [2.13000000e-01, 1.45612723e01], + [2.58910000e-01, 1.45612724e01], + [3.14700000e-01, 1.45612723e01], + [3.82520000e-01, 1.45612723e01], + [4.64960000e-01, 1.45612723e01], + [5.65160000e-01, 1.45612723e01], + ], + ), + np.array( + [ + [1.14030000e-02, 1.00000316e00], + [1.38610000e-02, 1.21238320e-01], + [1.68480000e-02, 2.13433068e-02], + [2.04790000e-02, 8.71162144e-03], + [2.48920000e-02, 5.72807902e-03], + [3.02560000e-02, 3.71827525e-03], + [3.67770000e-02, 1.72067772e-03], + [4.47020000e-02, 3.51471141e-04], + [5.43360000e-02, 2.03975460e-05], + [6.60450000e-02, 1.89221181e-04], + [8.02790000e-02, 1.49280488e-04], + [9.75790000e-02, 3.86439083e-05], + [1.18610000e-01, 1.63612094e-05], + [1.44170000e-01, 6.75770325e-06], + [1.75240000e-01, 3.45955607e-06], + [2.13000000e-01, 3.20880782e-06], + [2.58910000e-01, 3.32068345e-06], + [3.14700000e-01, 3.21671807e-06], + [3.82520000e-01, 3.15612021e-06], + [4.64960000e-01, 3.15645546e-06], + [5.65160000e-01, 3.15511510e-06], + ], + ), + ] + results.simulation = [ + np.array( + [ + [1.14030000e-02, 1.45891447e01], + [1.38610000e-02, 1.45739839e01], + [1.68480000e-02, 1.45684725e01], + [2.04790000e-02, 1.45658452e01], + [2.48920000e-02, 1.45641513e01], + [3.02560000e-02, 1.45628311e01], + [3.67770000e-02, 1.45618510e01], + [4.47020000e-02, 1.45613427e01], + [5.43360000e-02, 1.45612940e01], + [6.60450000e-02, 1.45613971e01], + [8.02790000e-02, 1.45613678e01], + [9.75790000e-02, 1.45612960e01], + [1.18610000e-01, 1.45612799e01], + [1.44170000e-01, 1.45612749e01], + [1.75240000e-01, 1.45612726e01], + [2.13000000e-01, 1.45612723e01], + [2.58910000e-01, 1.45612724e01], + [3.14700000e-01, 1.45612723e01], + [3.82520000e-01, 1.45612723e01], + [4.64960000e-01, 1.45612723e01], + [5.65160000e-01, 1.45612723e01], + ], + ), + np.array( + [ + [1.14030000e-02, 1.00000316e00], + [1.38610000e-02, 1.21238320e-01], + [1.68480000e-02, 2.13433068e-02], + [2.04790000e-02, 8.71162144e-03], + [2.48920000e-02, 5.72807902e-03], + [3.02560000e-02, 3.71827525e-03], + [3.67770000e-02, 1.72067772e-03], + [4.47020000e-02, 3.51471141e-04], + [5.43360000e-02, 2.03975460e-05], + [6.60450000e-02, 1.89221181e-04], + [8.02790000e-02, 1.49280488e-04], + [9.75790000e-02, 3.86439083e-05], + [1.18610000e-01, 1.63612094e-05], + [1.44170000e-01, 6.75770325e-06], + [1.75240000e-01, 3.45955607e-06], + [2.13000000e-01, 3.20880782e-06], + [2.58910000e-01, 3.32068345e-06], + [3.14700000e-01, 3.21671807e-06], + [3.82520000e-01, 3.15612021e-06], + [4.64960000e-01, 3.15645546e-06], + [5.65160000e-01, 3.15511510e-06], + ], + ), + ] + results.shiftedData = [ + np.array( + [ + [1.1403e-02, 1.0063e00, 1.9003e-02], + [1.3861e-02, 9.0118e-01, 1.1774e-02], + [1.6848e-02, 7.0455e-02, 1.3083e-03], + [2.0479e-02, 1.7544e-02, 5.1254e-04], + [2.4892e-02, 6.4257e-03, 2.6236e-04], + [3.0256e-02, 2.7746e-03, 8.5758e-05], + [3.6777e-02, 1.8591e-03, 4.9391e-05], + [4.4702e-02, 1.1002e-03, 3.2644e-05], + [5.4336e-02, 6.6691e-04, 2.1365e-05], + [6.6045e-02, 6.0729e-04, 1.1791e-05], + [8.0279e-02, 5.8755e-04, 1.5569e-05], + [9.7579e-02, 3.2700e-04, 6.5280e-06], + [1.1861e-01, 7.8205e-05, 2.5881e-06], + [1.4417e-01, 3.3455e-05, 1.5143e-06], + [1.7524e-01, 4.9313e-06, 5.6663e-07], + [2.1300e-01, 4.1948e-06, 6.8549e-07], + [2.5891e-01, 3.9863e-06, 8.2061e-07], + [3.1470e-01, 2.0861e-06, 6.1379e-07], + [3.8252e-01, 2.1154e-06, 6.3084e-07], + [4.6496e-01, 1.9906e-06, 6.0793e-07], + [5.6516e-01, 2.3816e-06, 7.0610e-07], + ], + ), + np.array( + [ + [1.14030000e-02, 1.20493333e-02, 7.32200000e-04], + [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], + [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], + [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], + [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], + [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], + [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], + [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], + [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], + [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], + [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], + [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], + [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], + [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], + [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], + [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], + [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], + [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], + [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], + [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], + [5.65160000e-01, 2.17460000e-06, 5.31346667e-07], + ], + ), + ] + results.layerSlds = [ + [ + np.array( + [ + [3.15755349e01, 3.35278238e-06, 4.16625659e00], + [3.61791464e01, 7.68327921e-07, 4.16625659e00], + [1.00488530e01, 2.06044530e-06, 2.78042232e01], + [1.08043784e01, 3.29384190e-06, 2.78042232e01], + [2.42251646e01, 2.35556998e-06, 1.55593097e01], + [1.49022278e01, 7.42138004e-07, 1.55593097e01], + [1.49022278e01, 7.42138004e-07, 1.55593097e01], + [2.42251646e01, 2.35556998e-06, 1.55593097e01], + ], + ), + ], + [ + np.array( + [ + [3.15755349e01, 4.11636356e-06, 4.16625659e00], + [3.61791464e01, 1.39268494e-06, 4.16625659e00], + [1.00488530e01, 2.45715680e-06, 2.78042232e01], + [1.08043784e01, 5.26668495e-06, 2.78042232e01], + [2.42251646e01, 3.31348777e-06, 1.55593097e01], + [1.49022278e01, 1.37428245e-06, 1.55593097e01], + [1.49022278e01, 1.37428245e-06, 1.55593097e01], + [2.42251646e01, 3.31348777e-06, 1.55593097e01], + ], + ), + ], + ] + results.sldProfiles = [ + [ + np.array( + [ + [0.00000000e00, 2.07301741e-06], + [1.10000000e01, 2.07309604e-06], + [2.20000000e01, 2.07345780e-06], + [3.30000000e01, 2.07491687e-06], + [4.40000000e01, 2.17562259e-06], + [5.50000000e01, 3.22650495e-06], + [6.60000000e01, 3.40913848e-06], + [7.70000000e01, 3.13506253e-06], + [8.80000000e01, 1.20456289e-06], + [9.90000000e01, 1.27138002e-06], + [1.10000000e02, 1.56285495e-06], + [1.21000000e02, 1.84518709e-06], + [1.32000000e02, 2.00498449e-06], + [1.43000000e02, 1.96260665e-06], + [1.54000000e02, 1.71966879e-06], + [1.65000000e02, 1.39383267e-06], + [1.76000000e02, 1.22970195e-06], + [1.87000000e02, 1.41565526e-06], + [1.98000000e02, 1.88172657e-06], + [2.09000000e02, 2.40655867e-06], + [2.20000000e02, 2.83570420e-06], + [2.31000000e02, 3.11210082e-06], + [2.42000000e02, 3.24277802e-06], + [2.53000000e02, 3.28427452e-06], + [2.64000000e02, 3.29268847e-06], + [2.75000000e02, 3.29375418e-06], + [2.86000000e02, 3.29383773e-06], + [2.97000000e02, 3.29384178e-06], + [3.08000000e02, 3.29384190e-06], + ], + ), + np.array( + [ + [0.00000000e00, 2.07301819e-06], + [1.10000000e01, 2.07310296e-06], + [2.20000000e01, 2.07350415e-06], + [3.30000000e01, 2.07518460e-06], + [4.40000000e01, 2.23394767e-06], + [5.50000000e01, 3.90646736e-06], + [6.60000000e01, 4.18619279e-06], + [7.70000000e01, 3.91675004e-06], + [8.80000000e01, 1.92451547e-06], + [9.90000000e01, 2.06988861e-06], + [1.10000000e02, 2.47614934e-06], + [1.21000000e02, 2.84889288e-06], + [1.32000000e02, 3.00529286e-06], + [1.43000000e02, 2.86310144e-06], + [1.54000000e02, 2.49967205e-06], + [1.65000000e02, 2.09673058e-06], + [1.76000000e02, 1.92431424e-06], + [1.87000000e02, 2.18829605e-06], + [1.98000000e02, 2.83032190e-06], + [2.09000000e02, 3.62584708e-06], + [2.20000000e02, 4.36871153e-06], + [2.31000000e02, 4.89806866e-06], + [2.42000000e02, 5.16145928e-06], + [2.53000000e02, 5.24684298e-06], + [2.64000000e02, 5.26428707e-06], + [2.75000000e02, 5.26650242e-06], + [2.86000000e02, 5.26667628e-06], + [2.97000000e02, 5.26668469e-06], + [3.08000000e02, 5.26668495e-06], + ], + ), + ], + ] + results.resampledLayers = [[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]] results.calculationResults = RAT.rat_core.Calculation() - results.calculationResults.chiValues = np.array([4.6077885, 7.00028098]), + results.calculationResults.chiValues = (np.array([4.6077885, 7.00028098]),) results.calculationResults.sumChi = 11.608069475997699 results.contrastParams = RAT.rat_core.ContrastParams() results.contrastParams.backgroundParams = np.array([2.37113128e-06, 1.99006694e-06]) @@ -663,16 +903,48 @@ def dream_output_results(): results.contrastParams.resolutionParams = np.array([0.03, 0.03]) results.contrastParams.subRoughs = np.array([6.19503045, 6.19503045]) results.contrastParams.resample = np.array([0.0, 0.0]) - results.fitParams = np.array([6.19503045e+00, 1.84420960e+01, 2.11039621e+01, 8.75538121e+00, - 3.72292994e+00, 1.84624551e+01, 1.02316734e+01, 2.31156093e+01, - 1.09906265e+01, 5.71005361e+00, 1.67933822e+01, 1.72009856e+01, - 3.00260126e+01, 2.94448999e+01, 2.37113128e-06, 1.99006694e-06, - 6.01489149e-06, 1.59371685e-06]) - results.fitNames = ['Substrate Roughness', 'Oxide Thickness', 'SAM Tails Thickness', 'SAM Tails Hydration', - 'SAM Roughness', 'CW Thickness', 'SAM Heads Thickness', 'SAM Heads Hydration', - 'Bilayer Heads Thickness', 'Bilayer Roughness', 'Bilayer Tails Thickness', - 'Bilayer Tails Hydration', 'Bilayer Heads Hydration', 'Oxide Hydration', - 'Background parameter D2O', 'Background parameter SMW', 'D2O', 'SMW'] + results.fitParams = np.array( + [ + 6.19503045e00, + 1.84420960e01, + 2.11039621e01, + 8.75538121e00, + 3.72292994e00, + 1.84624551e01, + 1.02316734e01, + 2.31156093e01, + 1.09906265e01, + 5.71005361e00, + 1.67933822e01, + 1.72009856e01, + 3.00260126e01, + 2.94448999e01, + 2.37113128e-06, + 1.99006694e-06, + 6.01489149e-06, + 1.59371685e-06, + ], + ) + results.fitNames = [ + "Substrate Roughness", + "Oxide Thickness", + "SAM Tails Thickness", + "SAM Tails Hydration", + "SAM Roughness", + "CW Thickness", + "SAM Heads Thickness", + "SAM Heads Hydration", + "Bilayer Heads Thickness", + "Bilayer Roughness", + "Bilayer Tails Thickness", + "Bilayer Tails Hydration", + "Bilayer Heads Hydration", + "Oxide Hydration", + "Background parameter D2O", + "Background parameter SMW", + "D2O", + "SMW", + ] return results @@ -685,376 +957,1599 @@ def dream_bayes(): """ bayes = RAT.rat_core.BayesResults() bayes.predictionIntervals = RAT.rat_core.PredictionIntervals() - bayes.predictionIntervals.reflectivity = [np.array([[1.00000560e+00, 7.07687612e-01, 2.08315160e-02, 2.40787966e-03, - 2.17627660e-03, 2.54301700e-03, 1.76309827e-03, 6.15269679e-04, - 3.43679710e-05, 7.93625275e-05, 1.27760549e-04, 3.35799941e-05, - 6.75048751e-06, 7.64258431e-06, 6.05800395e-06, 5.60288298e-06, - 5.60333677e-06, 5.60223341e-06, 5.60206667e-06, 5.60206314e-06, - 5.60206314e-06], - [1.00000560e+00, 7.07687612e-01, 2.08315160e-02, 2.40787966e-03, - 2.17627660e-03, 2.54301700e-03, 1.76309827e-03, 6.15269679e-04, - 3.43679710e-05, 7.93625275e-05, 1.27760549e-04, 3.35799941e-05, - 6.75048751e-06, 7.64258431e-06, 6.05800395e-06, 5.60288298e-06, - 5.60333677e-06, 5.60223341e-06, 5.60206667e-06, 5.60206314e-06, - 5.60206314e-06], - [1.55201098e+01, 1.53748894e+01, 1.50402011e+01, 1.50299478e+01, - 1.50290525e+01, 1.50287935e+01, 1.50282126e+01, 1.50276044e+01, - 1.50273248e+01, 1.50273185e+01, 1.50272997e+01, 1.50272498e+01, - 1.50272364e+01, 1.50272347e+01, 1.50272335e+01, 1.50272330e+01, - 1.50272329e+01, 1.50272328e+01, 1.50272328e+01, 1.50272328e+01, - 1.50272328e+01], - [2.91397425e+01, 2.91324974e+01, 2.91281368e+01, 2.91255472e+01, - 2.91240295e+01, 2.91231836e+01, 2.91227893e+01, 2.91226872e+01, - 2.91226902e+01, 2.91226359e+01, 2.91225541e+01, 2.91225457e+01, - 2.91225448e+01, 2.91225407e+01, 2.91225398e+01, 2.91225393e+01, - 2.91225391e+01, 2.91225390e+01, 2.91225390e+01, 2.91225389e+01, - 2.91225389e+01], - [2.91397425e+01, 2.91324974e+01, 2.91281368e+01, 2.91255472e+01, - 2.91240295e+01, 2.91231836e+01, 2.91227893e+01, 2.91226872e+01, - 2.91226902e+01, 2.91226359e+01, 2.91225541e+01, 2.91225457e+01, - 2.91225448e+01, 2.91225407e+01, 2.91225398e+01, 2.91225393e+01, - 2.91225391e+01, 2.91225390e+01, 2.91225390e+01, 2.91225389e+01, - 2.91225389e+01]]), - np.array([[7.82198834e-01, 2.84434275e-02, 3.42472318e-03, 1.45801296e-03, - 2.02213149e-03, 2.00826891e-03, 1.27577246e-03, 4.27099544e-04, - 2.07304219e-05, 4.88683542e-05, 4.14000873e-05, 1.57801531e-05, - 2.08705254e-06, 2.27936213e-06, 1.09950377e-06, 7.09021331e-07, - 7.09539552e-07, 7.08228574e-07, 7.08101644e-07, 7.08098642e-07, - 7.08098641e-07], - [7.82198834e-01, 2.84434275e-02, 3.42472318e-03, 1.45801296e-03, - 2.02213149e-03, 2.00826891e-03, 1.27577246e-03, 4.27099544e-04, - 2.07304219e-05, 4.88683542e-05, 4.14000873e-05, 1.57801531e-05, - 2.08705254e-06, 2.27936213e-06, 1.09950377e-06, 7.09021331e-07, - 7.09539552e-07, 7.08228574e-07, 7.08101644e-07, 7.08098642e-07, - 7.08098641e-07], - [8.94587126e-01, 4.07514176e-01, 3.66355642e-02, 1.22207690e-02, - 5.91350591e-03, 3.17495745e-03, 1.50593011e-03, 5.80889579e-04, - 2.44654124e-04, 1.40925782e-04, 6.26965047e-05, 1.91064075e-05, - 9.45189755e-06, 6.16421495e-06, 5.17046678e-06, 4.24101973e-06, - 3.82067554e-06, 3.55352666e-06, 3.38981154e-06, 3.29631224e-06, - 3.25061722e-06], - [1.00000560e+00, 7.63076662e-01, 6.77868181e-02, 2.23160672e-02, - 9.56355479e-03, 4.26929321e-03, 1.72181442e-03, 7.25142247e-04, - 4.54691084e-04, 2.27274223e-04, 8.54009496e-05, 2.26525796e-05, - 1.63600080e-05, 9.80814666e-06, 8.98896697e-06, 7.55397947e-06, - 6.73887287e-06, 6.22237216e-06, 5.90521384e-06, 5.72401646e-06, - 5.63546023e-06], - [1.00000560e+00, 7.63076662e-01, 6.77868181e-02, 2.23160672e-02, - 9.56355479e-03, 4.26929321e-03, 1.72181442e-03, 7.25142247e-04, - 4.54691084e-04, 2.27274223e-04, 8.54009496e-05, 2.26525796e-05, - 1.63600080e-05, 9.80814666e-06, 8.98896697e-06, 7.55397947e-06, - 6.73887287e-06, 6.22237216e-06, 5.90521384e-06, 5.72401646e-06, - 5.63546023e-06]])] - bayes.predictionIntervals.sld = [[np.array([[-2.26996619e-06, -2.26938579e-06, -2.26877469e-06, ..., - 9.14568096e-07, 9.14567880e-07, 9.14567682e-07], - [-2.26996619e-06, -2.26938579e-06, -2.26877469e-06, ..., - 9.14568096e-07, 9.14567880e-07, 9.14567682e-07], - [-1.67970553e-07, -1.67671068e-07, -1.67355735e-07, ..., - 3.31763635e-06, 3.31763624e-06, 3.31763614e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.87958515e-06, 5.87958515e-06, 5.87958515e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.87958515e-06, 5.87958515e-06, 5.87958515e-06]])], - [np.array([[-1.35107208e-06, -1.34966627e-06, -1.34817823e-06, ..., - 4.65378475e-06, 4.65378475e-06, 4.65378475e-06], - [-1.35107208e-06, -1.34966627e-06, -1.34817823e-06, ..., - 4.65378475e-06, 4.65378475e-06, 4.65378475e-06], - [3.06178804e-07, 3.06904206e-07, 3.07672036e-07, ..., - 4.92477587e-06, 4.92477714e-06, 4.92477830e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.17896134e-06, 5.17896381e-06, 5.17896605e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.17896134e-06, 5.17896381e-06, 5.17896605e-06]])]] - bayes.predictionIntervals.reflectivityXData = [np.array([[0.011403, 0.013861, 0.016848, 0.020479, 0.024892, 0.030256, - 0.036777, 0.044702, 0.054336, 0.066045, 0.080279, 0.097579, - 0.11861, 0.14417, 0.17524, 0.213, 0.25891, 0.3147, - 0.38252, 0.46496, 0.56516]]), - np.array([[0.011403, 0.013861, 0.016848, 0.020479, 0.024892, 0.030256, - 0.036777, 0.044702, 0.054336, 0.066045, 0.080279, 0.097579, - 0.11861, 0.14417, 0.17524, 0.213, 0.25891, 0.3147, - 0.38252, 0.46496, 0.56516]])] - bayes.predictionIntervals.sldXData = [[np.array([[0., 11., 22., 33., 44., 55., 66., 77., 88., 99., 110., - 121., 132., 143., 154., 165., 176., 187., 198., 209., 220., 231., - 242., 253., 264., 275., 286., 297., 308., 319.]]), - np.array([[0., 11., 22., 33., 44., 55., 66., 77., 88., 99., 110., - 121., 132., 143., 154., 165., 176., 187., 198., 209., 220., 231., - 242., 253., 264., 275., 286., 297., 308., 319.]])]] - bayes.predictionIntervals.sampleChi = np.array([1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16]) + bayes.predictionIntervals.reflectivity = [ + np.array( + [ + [ + 1.00000560e00, + 7.07687612e-01, + 2.08315160e-02, + 2.40787966e-03, + 2.17627660e-03, + 2.54301700e-03, + 1.76309827e-03, + 6.15269679e-04, + 3.43679710e-05, + 7.93625275e-05, + 1.27760549e-04, + 3.35799941e-05, + 6.75048751e-06, + 7.64258431e-06, + 6.05800395e-06, + 5.60288298e-06, + 5.60333677e-06, + 5.60223341e-06, + 5.60206667e-06, + 5.60206314e-06, + 5.60206314e-06, + ], + [ + 1.00000560e00, + 7.07687612e-01, + 2.08315160e-02, + 2.40787966e-03, + 2.17627660e-03, + 2.54301700e-03, + 1.76309827e-03, + 6.15269679e-04, + 3.43679710e-05, + 7.93625275e-05, + 1.27760549e-04, + 3.35799941e-05, + 6.75048751e-06, + 7.64258431e-06, + 6.05800395e-06, + 5.60288298e-06, + 5.60333677e-06, + 5.60223341e-06, + 5.60206667e-06, + 5.60206314e-06, + 5.60206314e-06, + ], + [ + 1.55201098e01, + 1.53748894e01, + 1.50402011e01, + 1.50299478e01, + 1.50290525e01, + 1.50287935e01, + 1.50282126e01, + 1.50276044e01, + 1.50273248e01, + 1.50273185e01, + 1.50272997e01, + 1.50272498e01, + 1.50272364e01, + 1.50272347e01, + 1.50272335e01, + 1.50272330e01, + 1.50272329e01, + 1.50272328e01, + 1.50272328e01, + 1.50272328e01, + 1.50272328e01, + ], + [ + 2.91397425e01, + 2.91324974e01, + 2.91281368e01, + 2.91255472e01, + 2.91240295e01, + 2.91231836e01, + 2.91227893e01, + 2.91226872e01, + 2.91226902e01, + 2.91226359e01, + 2.91225541e01, + 2.91225457e01, + 2.91225448e01, + 2.91225407e01, + 2.91225398e01, + 2.91225393e01, + 2.91225391e01, + 2.91225390e01, + 2.91225390e01, + 2.91225389e01, + 2.91225389e01, + ], + [ + 2.91397425e01, + 2.91324974e01, + 2.91281368e01, + 2.91255472e01, + 2.91240295e01, + 2.91231836e01, + 2.91227893e01, + 2.91226872e01, + 2.91226902e01, + 2.91226359e01, + 2.91225541e01, + 2.91225457e01, + 2.91225448e01, + 2.91225407e01, + 2.91225398e01, + 2.91225393e01, + 2.91225391e01, + 2.91225390e01, + 2.91225390e01, + 2.91225389e01, + 2.91225389e01, + ], + ], + ), + np.array( + [ + [ + 7.82198834e-01, + 2.84434275e-02, + 3.42472318e-03, + 1.45801296e-03, + 2.02213149e-03, + 2.00826891e-03, + 1.27577246e-03, + 4.27099544e-04, + 2.07304219e-05, + 4.88683542e-05, + 4.14000873e-05, + 1.57801531e-05, + 2.08705254e-06, + 2.27936213e-06, + 1.09950377e-06, + 7.09021331e-07, + 7.09539552e-07, + 7.08228574e-07, + 7.08101644e-07, + 7.08098642e-07, + 7.08098641e-07, + ], + [ + 7.82198834e-01, + 2.84434275e-02, + 3.42472318e-03, + 1.45801296e-03, + 2.02213149e-03, + 2.00826891e-03, + 1.27577246e-03, + 4.27099544e-04, + 2.07304219e-05, + 4.88683542e-05, + 4.14000873e-05, + 1.57801531e-05, + 2.08705254e-06, + 2.27936213e-06, + 1.09950377e-06, + 7.09021331e-07, + 7.09539552e-07, + 7.08228574e-07, + 7.08101644e-07, + 7.08098642e-07, + 7.08098641e-07, + ], + [ + 8.94587126e-01, + 4.07514176e-01, + 3.66355642e-02, + 1.22207690e-02, + 5.91350591e-03, + 3.17495745e-03, + 1.50593011e-03, + 5.80889579e-04, + 2.44654124e-04, + 1.40925782e-04, + 6.26965047e-05, + 1.91064075e-05, + 9.45189755e-06, + 6.16421495e-06, + 5.17046678e-06, + 4.24101973e-06, + 3.82067554e-06, + 3.55352666e-06, + 3.38981154e-06, + 3.29631224e-06, + 3.25061722e-06, + ], + [ + 1.00000560e00, + 7.63076662e-01, + 6.77868181e-02, + 2.23160672e-02, + 9.56355479e-03, + 4.26929321e-03, + 1.72181442e-03, + 7.25142247e-04, + 4.54691084e-04, + 2.27274223e-04, + 8.54009496e-05, + 2.26525796e-05, + 1.63600080e-05, + 9.80814666e-06, + 8.98896697e-06, + 7.55397947e-06, + 6.73887287e-06, + 6.22237216e-06, + 5.90521384e-06, + 5.72401646e-06, + 5.63546023e-06, + ], + [ + 1.00000560e00, + 7.63076662e-01, + 6.77868181e-02, + 2.23160672e-02, + 9.56355479e-03, + 4.26929321e-03, + 1.72181442e-03, + 7.25142247e-04, + 4.54691084e-04, + 2.27274223e-04, + 8.54009496e-05, + 2.26525796e-05, + 1.63600080e-05, + 9.80814666e-06, + 8.98896697e-06, + 7.55397947e-06, + 6.73887287e-06, + 6.22237216e-06, + 5.90521384e-06, + 5.72401646e-06, + 5.63546023e-06, + ], + ], + ), + ] + bayes.predictionIntervals.sld = [ + [ + np.array( + [ + [ + -2.26996619e-06, + -2.26938579e-06, + -2.26877469e-06, + ..., + 9.14568096e-07, + 9.14567880e-07, + 9.14567682e-07, + ], + [ + -2.26996619e-06, + -2.26938579e-06, + -2.26877469e-06, + ..., + 9.14568096e-07, + 9.14567880e-07, + 9.14567682e-07, + ], + [ + -1.67970553e-07, + -1.67671068e-07, + -1.67355735e-07, + ..., + 3.31763635e-06, + 3.31763624e-06, + 3.31763614e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.87958515e-06, + 5.87958515e-06, + 5.87958515e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.87958515e-06, + 5.87958515e-06, + 5.87958515e-06, + ], + ], + ), + ], + [ + np.array( + [ + [ + -1.35107208e-06, + -1.34966627e-06, + -1.34817823e-06, + ..., + 4.65378475e-06, + 4.65378475e-06, + 4.65378475e-06, + ], + [ + -1.35107208e-06, + -1.34966627e-06, + -1.34817823e-06, + ..., + 4.65378475e-06, + 4.65378475e-06, + 4.65378475e-06, + ], + [ + 3.06178804e-07, + 3.06904206e-07, + 3.07672036e-07, + ..., + 4.92477587e-06, + 4.92477714e-06, + 4.92477830e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.17896134e-06, + 5.17896381e-06, + 5.17896605e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.17896134e-06, + 5.17896381e-06, + 5.17896605e-06, + ], + ], + ), + ], + ] + bayes.predictionIntervals.reflectivityXData = [ + np.array( + [ + [ + 0.011403, + 0.013861, + 0.016848, + 0.020479, + 0.024892, + 0.030256, + 0.036777, + 0.044702, + 0.054336, + 0.066045, + 0.080279, + 0.097579, + 0.11861, + 0.14417, + 0.17524, + 0.213, + 0.25891, + 0.3147, + 0.38252, + 0.46496, + 0.56516, + ], + ], + ), + np.array( + [ + [ + 0.011403, + 0.013861, + 0.016848, + 0.020479, + 0.024892, + 0.030256, + 0.036777, + 0.044702, + 0.054336, + 0.066045, + 0.080279, + 0.097579, + 0.11861, + 0.14417, + 0.17524, + 0.213, + 0.25891, + 0.3147, + 0.38252, + 0.46496, + 0.56516, + ], + ], + ), + ] + bayes.predictionIntervals.sldXData = [ + [ + np.array( + [ + [ + 0.0, + 11.0, + 22.0, + 33.0, + 44.0, + 55.0, + 66.0, + 77.0, + 88.0, + 99.0, + 110.0, + 121.0, + 132.0, + 143.0, + 154.0, + 165.0, + 176.0, + 187.0, + 198.0, + 209.0, + 220.0, + 231.0, + 242.0, + 253.0, + 264.0, + 275.0, + 286.0, + 297.0, + 308.0, + 319.0, + ], + ], + ), + np.array( + [ + [ + 0.0, + 11.0, + 22.0, + 33.0, + 44.0, + 55.0, + 66.0, + 77.0, + 88.0, + 99.0, + 110.0, + 121.0, + 132.0, + 143.0, + 154.0, + 165.0, + 176.0, + 187.0, + 198.0, + 209.0, + 220.0, + 231.0, + 242.0, + 253.0, + 264.0, + 275.0, + 286.0, + 297.0, + 308.0, + 319.0, + ], + ], + ), + ], + ] + bayes.predictionIntervals.sampleChi = np.array( + [ + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + ], + ) bayes.confidenceIntervals = RAT.rat_core.ConfidenceIntervals() - bayes.confidenceIntervals.percentile65 = np.array([[-1.29074586e-231, 8.33251318e+000, 1.75397363e+001, 1.75397363e+001, - 9.85302945e+000, 9.85302945e+000, 8.34197863e+000, 8.34197863e+000, - 1.65750684e+001, 1.45435510e+001, 1.45435510e+001, 1.52609047e+001, - 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, 7.08098641e-007, - 7.08098641e-007, 4.65378475e-006], - [8.33251318e+000, 5.48185565e+001, 5.48185565e+001, 4.57554170e+001, - 4.57554170e+001, 1.17557273e+001, 1.17557273e+001, 3.18752608e+001, - 3.18752608e+001, 1.65750684e+001, 1.52609047e+001, 4.88237113e+001, - 4.88237113e+001, 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, - 5.87958515e-006, 5.87958515e-006]]) - bayes.confidenceIntervals.percentile95 = np.array([[-1.29074586e-231, 8.33251318e+000, 1.75397363e+001, 1.75397363e+001, - 9.85302945e+000, 9.85302945e+000, 8.34197863e+000, 8.34197863e+000, - 1.65750684e+001, 1.45435510e+001, 1.45435510e+001, 1.52609047e+001, - 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, 7.08098641e-007, - 7.08098641e-007, 4.65378475e-006], - [8.33251318e+000, 5.48185565e+001, 5.48185565e+001, 4.57554170e+001, - 4.57554170e+001, 1.17557273e+001, 1.17557273e+001, 3.18752608e+001, - 3.18752608e+001, 1.65750684e+001, 1.52609047e+001, 4.88237113e+001, - 4.88237113e+001, 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, - 5.87958515e-006, 5.87958515e-006]]) - bayes.confidenceIntervals.mean = np.array([[4.16625659e+00, 3.15755349e+01, 3.61791464e+01, 3.16475766e+01, - 2.78042232e+01, 1.08043784e+01, 1.00488530e+01, 2.01086197e+01, - 2.42251646e+01, 1.55593097e+01, 1.49022278e+01, 3.20423080e+01, - 4.85551946e+01, 3.87046084e+01, 1.45612723e+01, 3.15508089e-06, - 3.29384190e-06, 5.26668495e-06]]) + bayes.confidenceIntervals.percentile65 = np.array( + [ + [ + -1.29074586e-231, + 8.33251318e000, + 1.75397363e001, + 1.75397363e001, + 9.85302945e000, + 9.85302945e000, + 8.34197863e000, + 8.34197863e000, + 1.65750684e001, + 1.45435510e001, + 1.45435510e001, + 1.52609047e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 7.08098641e-007, + 4.65378475e-006, + ], + [ + 8.33251318e000, + 5.48185565e001, + 5.48185565e001, + 4.57554170e001, + 4.57554170e001, + 1.17557273e001, + 1.17557273e001, + 3.18752608e001, + 3.18752608e001, + 1.65750684e001, + 1.52609047e001, + 4.88237113e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 5.87958515e-006, + 5.87958515e-006, + ], + ], + ) + bayes.confidenceIntervals.percentile95 = np.array( + [ + [ + -1.29074586e-231, + 8.33251318e000, + 1.75397363e001, + 1.75397363e001, + 9.85302945e000, + 9.85302945e000, + 8.34197863e000, + 8.34197863e000, + 1.65750684e001, + 1.45435510e001, + 1.45435510e001, + 1.52609047e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 7.08098641e-007, + 4.65378475e-006, + ], + [ + 8.33251318e000, + 5.48185565e001, + 5.48185565e001, + 4.57554170e001, + 4.57554170e001, + 1.17557273e001, + 1.17557273e001, + 3.18752608e001, + 3.18752608e001, + 1.65750684e001, + 1.52609047e001, + 4.88237113e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 5.87958515e-006, + 5.87958515e-006, + ], + ], + ) + bayes.confidenceIntervals.mean = np.array( + [ + [ + 4.16625659e00, + 3.15755349e01, + 3.61791464e01, + 3.16475766e01, + 2.78042232e01, + 1.08043784e01, + 1.00488530e01, + 2.01086197e01, + 2.42251646e01, + 1.55593097e01, + 1.49022278e01, + 3.20423080e01, + 4.85551946e01, + 3.87046084e01, + 1.45612723e01, + 3.15508089e-06, + 3.29384190e-06, + 5.26668495e-06, + ], + ], + ) bayes.dreamParams = RAT.rat_core.DreamParams() bayes.dreamParams.nParams = 18.0 bayes.dreamParams.nChains = 1.0 @@ -1074,50 +2569,113 @@ def dream_bayes(): bayes.dreamParams.ABC = 0 bayes.dreamParams.IO = 0 bayes.dreamParams.storeOutput = 0 - bayes.dreamParams.R = np.array([[0.]]) + bayes.dreamParams.R = np.array([[0.0]]) bayes.dreamOutput = RAT.rat_core.DreamOutput() - bayes.dreamOutput.allChains = np.array([[[8.33251318e+00], - [5.48185565e+01], - [1.75397363e+01], - [4.57554170e+01], - [9.85302945e+00], - [1.17557273e+01], - [8.34197863e+00], - [3.18752608e+01], - [1.65750684e+01], - [1.45435510e+01], - [1.52609047e+01], - [4.88237113e+01], - [4.82866779e+01], - [2.91225389e+01], - [5.60206314e-06], - [7.08098641e-07], - [5.87958515e-06], - [4.65378475e-06], - [-4.86509830e+01], - [-5.63741277e+05]]]) + bayes.dreamOutput.allChains = np.array( + [ + [ + [8.33251318e00], + [5.48185565e01], + [1.75397363e01], + [4.57554170e01], + [9.85302945e00], + [1.17557273e01], + [8.34197863e00], + [3.18752608e01], + [1.65750684e01], + [1.45435510e01], + [1.52609047e01], + [4.88237113e01], + [4.82866779e01], + [2.91225389e01], + [5.60206314e-06], + [7.08098641e-07], + [5.87958515e-06], + [4.65378475e-06], + [-4.86509830e01], + [-5.63741277e05], + ], + ], + ) bayes.dreamOutput.outlierChains = np.array([[0.0, 0.0]]) bayes.dreamOutput.runtime = 2.6e-06 bayes.dreamOutput.iteration = 2.0 bayes.dreamOutput.modelOutput = 0.0 bayes.dreamOutput.AR = np.array([[1.0, np.nan]]) - bayes.dreamOutput.R_stat = np.array([[1.0, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, - np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]]) + bayes.dreamOutput.R_stat = np.array( + [ + [ + 1.0, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + ], + ], + ) bayes.dreamOutput.CR = np.array([[1.00000000, 0.33333333, 0.33333333, 0.33333333]]) bayes.nestedSamplerOutput = RAT.rat_core.NestedSamplerOutput() bayes.nestedSamplerOutput.logZ = 0.0 bayes.nestedSamplerOutput.nestSamples = np.array([[0.0, 0.0]]) bayes.nestedSamplerOutput.postSamples = np.array([[0.0, 0.0]]) - bayes.chain = np.array([[-1.29231905e-231, 8.33251318e+000, 5.48185565e+001, 1.75397363e+001, - 4.57554170e+001, 9.85302945e+000, 1.17557273e+001, 8.34197863e+000, - 3.18752608e+001, 1.65750684e+001, 1.45435510e+001, 1.52609047e+001, - 4.88237113e+001, 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, - 7.08098641e-007, 5.87958515e-006], - [8.33251318e+000, 5.48185565e+001, 1.75397363e+001, 4.57554170e+001, - 9.85302945e+000, 1.17557273e+001, 8.34197863e+000, 3.18752608e+001, - 1.65750684e+001, 1.45435510e+001, 1.52609047e+001, 4.88237113e+001, - 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, 7.08098641e-007, - 5.87958515e-006, 4.65378475e-006]]) + bayes.chain = np.array( + [ + [ + -1.29231905e-231, + 8.33251318e000, + 5.48185565e001, + 1.75397363e001, + 4.57554170e001, + 9.85302945e000, + 1.17557273e001, + 8.34197863e000, + 3.18752608e001, + 1.65750684e001, + 1.45435510e001, + 1.52609047e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 5.87958515e-006, + ], + [ + 8.33251318e000, + 5.48185565e001, + 1.75397363e001, + 4.57554170e001, + 9.85302945e000, + 1.17557273e001, + 8.34197863e000, + 3.18752608e001, + 1.65750684e001, + 1.45435510e001, + 1.52609047e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 5.87958515e-006, + 4.65378475e-006, + ], + ], + ) return bayes @@ -1130,210 +2688,266 @@ def dream_results(): and fitParams are taken from an optimisation with the parameters: nSamples=50000, nChains=10. """ return RAT.outputs.BayesResults( - reflectivity=[np.array([[1.14030000e-02, 1.45891447e+01], - [1.38610000e-02, 1.45739839e+01], - [1.68480000e-02, 1.45684725e+01], - [2.04790000e-02, 1.45658452e+01], - [2.48920000e-02, 1.45641513e+01], - [3.02560000e-02, 1.45628311e+01], - [3.67770000e-02, 1.45618510e+01], - [4.47020000e-02, 1.45613427e+01], - [5.43360000e-02, 1.45612940e+01], - [6.60450000e-02, 1.45613971e+01], - [8.02790000e-02, 1.45613678e+01], - [9.75790000e-02, 1.45612960e+01], - [1.18610000e-01, 1.45612799e+01], - [1.44170000e-01, 1.45612749e+01], - [1.75240000e-01, 1.45612726e+01], - [2.13000000e-01, 1.45612723e+01], - [2.58910000e-01, 1.45612724e+01], - [3.14700000e-01, 1.45612723e+01], - [3.82520000e-01, 1.45612723e+01], - [4.64960000e-01, 1.45612723e+01], - [5.65160000e-01, 1.45612723e+01]]), - np.array([[1.14030000e-02, 1.00000316e+00], - [1.38610000e-02, 1.21238320e-01], - [1.68480000e-02, 2.13433068e-02], - [2.04790000e-02, 8.71162144e-03], - [2.48920000e-02, 5.72807902e-03], - [3.02560000e-02, 3.71827525e-03], - [3.67770000e-02, 1.72067772e-03], - [4.47020000e-02, 3.51471141e-04], - [5.43360000e-02, 2.03975460e-05], - [6.60450000e-02, 1.89221181e-04], - [8.02790000e-02, 1.49280488e-04], - [9.75790000e-02, 3.86439083e-05], - [1.18610000e-01, 1.63612094e-05], - [1.44170000e-01, 6.75770325e-06], - [1.75240000e-01, 3.45955607e-06], - [2.13000000e-01, 3.20880782e-06], - [2.58910000e-01, 3.32068345e-06], - [3.14700000e-01, 3.21671807e-06], - [3.82520000e-01, 3.15612021e-06], - [4.64960000e-01, 3.15645546e-06], - [5.65160000e-01, 3.15511510e-06]])], - simulation=[np.array([[1.14030000e-02, 1.45891447e+01], - [1.38610000e-02, 1.45739839e+01], - [1.68480000e-02, 1.45684725e+01], - [2.04790000e-02, 1.45658452e+01], - [2.48920000e-02, 1.45641513e+01], - [3.02560000e-02, 1.45628311e+01], - [3.67770000e-02, 1.45618510e+01], - [4.47020000e-02, 1.45613427e+01], - [5.43360000e-02, 1.45612940e+01], - [6.60450000e-02, 1.45613971e+01], - [8.02790000e-02, 1.45613678e+01], - [9.75790000e-02, 1.45612960e+01], - [1.18610000e-01, 1.45612799e+01], - [1.44170000e-01, 1.45612749e+01], - [1.75240000e-01, 1.45612726e+01], - [2.13000000e-01, 1.45612723e+01], - [2.58910000e-01, 1.45612724e+01], - [3.14700000e-01, 1.45612723e+01], - [3.82520000e-01, 1.45612723e+01], - [4.64960000e-01, 1.45612723e+01], - [5.65160000e-01, 1.45612723e+01]]), - np.array([[1.14030000e-02, 1.00000316e+00], - [1.38610000e-02, 1.21238320e-01], - [1.68480000e-02, 2.13433068e-02], - [2.04790000e-02, 8.71162144e-03], - [2.48920000e-02, 5.72807902e-03], - [3.02560000e-02, 3.71827525e-03], - [3.67770000e-02, 1.72067772e-03], - [4.47020000e-02, 3.51471141e-04], - [5.43360000e-02, 2.03975460e-05], - [6.60450000e-02, 1.89221181e-04], - [8.02790000e-02, 1.49280488e-04], - [9.75790000e-02, 3.86439083e-05], - [1.18610000e-01, 1.63612094e-05], - [1.44170000e-01, 6.75770325e-06], - [1.75240000e-01, 3.45955607e-06], - [2.13000000e-01, 3.20880782e-06], - [2.58910000e-01, 3.32068345e-06], - [3.14700000e-01, 3.21671807e-06], - [3.82520000e-01, 3.15612021e-06], - [4.64960000e-01, 3.15645546e-06], - [5.65160000e-01, 3.15511510e-06]])], - shiftedData=[np.array([[1.1403e-02, 1.0063e+00, 1.9003e-02], - [1.3861e-02, 9.0118e-01, 1.1774e-02], - [1.6848e-02, 7.0455e-02, 1.3083e-03], - [2.0479e-02, 1.7544e-02, 5.1254e-04], - [2.4892e-02, 6.4257e-03, 2.6236e-04], - [3.0256e-02, 2.7746e-03, 8.5758e-05], - [3.6777e-02, 1.8591e-03, 4.9391e-05], - [4.4702e-02, 1.1002e-03, 3.2644e-05], - [5.4336e-02, 6.6691e-04, 2.1365e-05], - [6.6045e-02, 6.0729e-04, 1.1791e-05], - [8.0279e-02, 5.8755e-04, 1.5569e-05], - [9.7579e-02, 3.2700e-04, 6.5280e-06], - [1.1861e-01, 7.8205e-05, 2.5881e-06], - [1.4417e-01, 3.3455e-05, 1.5143e-06], - [1.7524e-01, 4.9313e-06, 5.6663e-07], - [2.1300e-01, 4.1948e-06, 6.8549e-07], - [2.5891e-01, 3.9863e-06, 8.2061e-07], - [3.1470e-01, 2.0861e-06, 6.1379e-07], - [3.8252e-01, 2.1154e-06, 6.3084e-07], - [4.6496e-01, 1.9906e-06, 6.0793e-07], - [5.6516e-01, 2.3816e-06, 7.0610e-07]]), - np.array([[1.14030000e-02, 1.20493333e-02, 7.32200000e-04], - [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], - [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], - [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], - [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], - [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], - [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], - [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], - [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], - [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], - [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], - [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], - [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], - [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], - [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], - [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], - [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], - [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], - [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], - [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], - [5.65160000e-01, 2.17460000e-06, 5.31346667e-07]])], - layerSlds=[[np.array([[3.15755349e+01, 3.35278238e-06, 4.16625659e+00], - [3.61791464e+01, 7.68327921e-07, 4.16625659e+00], - [1.00488530e+01, 2.06044530e-06, 2.78042232e+01], - [1.08043784e+01, 3.29384190e-06, 2.78042232e+01], - [2.42251646e+01, 2.35556998e-06, 1.55593097e+01], - [1.49022278e+01, 7.42138004e-07, 1.55593097e+01], - [1.49022278e+01, 7.42138004e-07, 1.55593097e+01], - [2.42251646e+01, 2.35556998e-06, 1.55593097e+01]])], - [np.array([[3.15755349e+01, 4.11636356e-06, 4.16625659e+00], - [3.61791464e+01, 1.39268494e-06, 4.16625659e+00], - [1.00488530e+01, 2.45715680e-06, 2.78042232e+01], - [1.08043784e+01, 5.26668495e-06, 2.78042232e+01], - [2.42251646e+01, 3.31348777e-06, 1.55593097e+01], - [1.49022278e+01, 1.37428245e-06, 1.55593097e+01], - [1.49022278e+01, 1.37428245e-06, 1.55593097e+01], - [2.42251646e+01, 3.31348777e-06, 1.55593097e+01]])]], - sldProfiles=[[np.array([[0.00000000e+00, 2.07301741e-06], - [1.10000000e+01, 2.07309604e-06], - [2.20000000e+01, 2.07345780e-06], - [3.30000000e+01, 2.07491687e-06], - [4.40000000e+01, 2.17562259e-06], - [5.50000000e+01, 3.22650495e-06], - [6.60000000e+01, 3.40913848e-06], - [7.70000000e+01, 3.13506253e-06], - [8.80000000e+01, 1.20456289e-06], - [9.90000000e+01, 1.27138002e-06], - [1.10000000e+02, 1.56285495e-06], - [1.21000000e+02, 1.84518709e-06], - [1.32000000e+02, 2.00498449e-06], - [1.43000000e+02, 1.96260665e-06], - [1.54000000e+02, 1.71966879e-06], - [1.65000000e+02, 1.39383267e-06], - [1.76000000e+02, 1.22970195e-06], - [1.87000000e+02, 1.41565526e-06], - [1.98000000e+02, 1.88172657e-06], - [2.09000000e+02, 2.40655867e-06], - [2.20000000e+02, 2.83570420e-06], - [2.31000000e+02, 3.11210082e-06], - [2.42000000e+02, 3.24277802e-06], - [2.53000000e+02, 3.28427452e-06], - [2.64000000e+02, 3.29268847e-06], - [2.75000000e+02, 3.29375418e-06], - [2.86000000e+02, 3.29383773e-06], - [2.97000000e+02, 3.29384178e-06], - [3.08000000e+02, 3.29384190e-06]]), - np.array([[0.00000000e+00, 2.07301819e-06], - [1.10000000e+01, 2.07310296e-06], - [2.20000000e+01, 2.07350415e-06], - [3.30000000e+01, 2.07518460e-06], - [4.40000000e+01, 2.23394767e-06], - [5.50000000e+01, 3.90646736e-06], - [6.60000000e+01, 4.18619279e-06], - [7.70000000e+01, 3.91675004e-06], - [8.80000000e+01, 1.92451547e-06], - [9.90000000e+01, 2.06988861e-06], - [1.10000000e+02, 2.47614934e-06], - [1.21000000e+02, 2.84889288e-06], - [1.32000000e+02, 3.00529286e-06], - [1.43000000e+02, 2.86310144e-06], - [1.54000000e+02, 2.49967205e-06], - [1.65000000e+02, 2.09673058e-06], - [1.76000000e+02, 1.92431424e-06], - [1.87000000e+02, 2.18829605e-06], - [1.98000000e+02, 2.83032190e-06], - [2.09000000e+02, 3.62584708e-06], - [2.20000000e+02, 4.36871153e-06], - [2.31000000e+02, 4.89806866e-06], - [2.42000000e+02, 5.16145928e-06], - [2.53000000e+02, 5.24684298e-06], - [2.64000000e+02, 5.26428707e-06], - [2.75000000e+02, 5.26650242e-06], - [2.86000000e+02, 5.26667628e-06], - [2.97000000e+02, 5.26668469e-06], - [3.08000000e+02, 5.26668495e-06]])]], - resampledLayers=[[np.array([[0., 0., 0.]])], [np.array([[0., 0., 0.]])]], + reflectivity=[ + np.array( + [ + [1.14030000e-02, 1.45891447e01], + [1.38610000e-02, 1.45739839e01], + [1.68480000e-02, 1.45684725e01], + [2.04790000e-02, 1.45658452e01], + [2.48920000e-02, 1.45641513e01], + [3.02560000e-02, 1.45628311e01], + [3.67770000e-02, 1.45618510e01], + [4.47020000e-02, 1.45613427e01], + [5.43360000e-02, 1.45612940e01], + [6.60450000e-02, 1.45613971e01], + [8.02790000e-02, 1.45613678e01], + [9.75790000e-02, 1.45612960e01], + [1.18610000e-01, 1.45612799e01], + [1.44170000e-01, 1.45612749e01], + [1.75240000e-01, 1.45612726e01], + [2.13000000e-01, 1.45612723e01], + [2.58910000e-01, 1.45612724e01], + [3.14700000e-01, 1.45612723e01], + [3.82520000e-01, 1.45612723e01], + [4.64960000e-01, 1.45612723e01], + [5.65160000e-01, 1.45612723e01], + ], + ), + np.array( + [ + [1.14030000e-02, 1.00000316e00], + [1.38610000e-02, 1.21238320e-01], + [1.68480000e-02, 2.13433068e-02], + [2.04790000e-02, 8.71162144e-03], + [2.48920000e-02, 5.72807902e-03], + [3.02560000e-02, 3.71827525e-03], + [3.67770000e-02, 1.72067772e-03], + [4.47020000e-02, 3.51471141e-04], + [5.43360000e-02, 2.03975460e-05], + [6.60450000e-02, 1.89221181e-04], + [8.02790000e-02, 1.49280488e-04], + [9.75790000e-02, 3.86439083e-05], + [1.18610000e-01, 1.63612094e-05], + [1.44170000e-01, 6.75770325e-06], + [1.75240000e-01, 3.45955607e-06], + [2.13000000e-01, 3.20880782e-06], + [2.58910000e-01, 3.32068345e-06], + [3.14700000e-01, 3.21671807e-06], + [3.82520000e-01, 3.15612021e-06], + [4.64960000e-01, 3.15645546e-06], + [5.65160000e-01, 3.15511510e-06], + ], + ), + ], + simulation=[ + np.array( + [ + [1.14030000e-02, 1.45891447e01], + [1.38610000e-02, 1.45739839e01], + [1.68480000e-02, 1.45684725e01], + [2.04790000e-02, 1.45658452e01], + [2.48920000e-02, 1.45641513e01], + [3.02560000e-02, 1.45628311e01], + [3.67770000e-02, 1.45618510e01], + [4.47020000e-02, 1.45613427e01], + [5.43360000e-02, 1.45612940e01], + [6.60450000e-02, 1.45613971e01], + [8.02790000e-02, 1.45613678e01], + [9.75790000e-02, 1.45612960e01], + [1.18610000e-01, 1.45612799e01], + [1.44170000e-01, 1.45612749e01], + [1.75240000e-01, 1.45612726e01], + [2.13000000e-01, 1.45612723e01], + [2.58910000e-01, 1.45612724e01], + [3.14700000e-01, 1.45612723e01], + [3.82520000e-01, 1.45612723e01], + [4.64960000e-01, 1.45612723e01], + [5.65160000e-01, 1.45612723e01], + ], + ), + np.array( + [ + [1.14030000e-02, 1.00000316e00], + [1.38610000e-02, 1.21238320e-01], + [1.68480000e-02, 2.13433068e-02], + [2.04790000e-02, 8.71162144e-03], + [2.48920000e-02, 5.72807902e-03], + [3.02560000e-02, 3.71827525e-03], + [3.67770000e-02, 1.72067772e-03], + [4.47020000e-02, 3.51471141e-04], + [5.43360000e-02, 2.03975460e-05], + [6.60450000e-02, 1.89221181e-04], + [8.02790000e-02, 1.49280488e-04], + [9.75790000e-02, 3.86439083e-05], + [1.18610000e-01, 1.63612094e-05], + [1.44170000e-01, 6.75770325e-06], + [1.75240000e-01, 3.45955607e-06], + [2.13000000e-01, 3.20880782e-06], + [2.58910000e-01, 3.32068345e-06], + [3.14700000e-01, 3.21671807e-06], + [3.82520000e-01, 3.15612021e-06], + [4.64960000e-01, 3.15645546e-06], + [5.65160000e-01, 3.15511510e-06], + ], + ), + ], + shiftedData=[ + np.array( + [ + [1.1403e-02, 1.0063e00, 1.9003e-02], + [1.3861e-02, 9.0118e-01, 1.1774e-02], + [1.6848e-02, 7.0455e-02, 1.3083e-03], + [2.0479e-02, 1.7544e-02, 5.1254e-04], + [2.4892e-02, 6.4257e-03, 2.6236e-04], + [3.0256e-02, 2.7746e-03, 8.5758e-05], + [3.6777e-02, 1.8591e-03, 4.9391e-05], + [4.4702e-02, 1.1002e-03, 3.2644e-05], + [5.4336e-02, 6.6691e-04, 2.1365e-05], + [6.6045e-02, 6.0729e-04, 1.1791e-05], + [8.0279e-02, 5.8755e-04, 1.5569e-05], + [9.7579e-02, 3.2700e-04, 6.5280e-06], + [1.1861e-01, 7.8205e-05, 2.5881e-06], + [1.4417e-01, 3.3455e-05, 1.5143e-06], + [1.7524e-01, 4.9313e-06, 5.6663e-07], + [2.1300e-01, 4.1948e-06, 6.8549e-07], + [2.5891e-01, 3.9863e-06, 8.2061e-07], + [3.1470e-01, 2.0861e-06, 6.1379e-07], + [3.8252e-01, 2.1154e-06, 6.3084e-07], + [4.6496e-01, 1.9906e-06, 6.0793e-07], + [5.6516e-01, 2.3816e-06, 7.0610e-07], + ], + ), + np.array( + [ + [1.14030000e-02, 1.20493333e-02, 7.32200000e-04], + [1.38610000e-02, 6.71800000e-03, 3.71853333e-04], + [1.68480000e-02, 4.10506667e-03, 2.23106667e-04], + [2.04790000e-02, 2.43306667e-03, 1.46873333e-04], + [2.48920000e-02, 1.40940000e-03, 9.59200000e-05], + [3.02560000e-02, 7.43400000e-04, 3.50226667e-05], + [3.67770000e-02, 3.51466667e-04, 1.59573333e-05], + [4.47020000e-02, 9.80666667e-05, 7.29466667e-06], + [5.43360000e-02, 1.73500000e-05, 2.59200000e-06], + [6.60450000e-02, 4.86286667e-05, 2.46453333e-06], + [8.02790000e-02, 9.71733333e-05, 4.68166667e-06], + [9.75790000e-02, 7.06533333e-05, 2.32180000e-06], + [1.18610000e-01, 1.93046667e-05, 1.00813333e-06], + [1.44170000e-01, 6.61193333e-06, 5.29773333e-07], + [1.75240000e-01, 3.23726667e-06, 3.65933333e-07], + [2.13000000e-01, 3.29920000e-06, 4.74273333e-07], + [2.58910000e-01, 1.71180000e-06, 4.24720000e-07], + [3.14700000e-01, 2.24020000e-06, 5.08946667e-07], + [3.82520000e-01, 2.73306667e-06, 5.71513333e-07], + [4.64960000e-01, 2.36153333e-06, 5.24806667e-07], + [5.65160000e-01, 2.17460000e-06, 5.31346667e-07], + ], + ), + ], + layerSlds=[ + [ + np.array( + [ + [3.15755349e01, 3.35278238e-06, 4.16625659e00], + [3.61791464e01, 7.68327921e-07, 4.16625659e00], + [1.00488530e01, 2.06044530e-06, 2.78042232e01], + [1.08043784e01, 3.29384190e-06, 2.78042232e01], + [2.42251646e01, 2.35556998e-06, 1.55593097e01], + [1.49022278e01, 7.42138004e-07, 1.55593097e01], + [1.49022278e01, 7.42138004e-07, 1.55593097e01], + [2.42251646e01, 2.35556998e-06, 1.55593097e01], + ], + ), + ], + [ + np.array( + [ + [3.15755349e01, 4.11636356e-06, 4.16625659e00], + [3.61791464e01, 1.39268494e-06, 4.16625659e00], + [1.00488530e01, 2.45715680e-06, 2.78042232e01], + [1.08043784e01, 5.26668495e-06, 2.78042232e01], + [2.42251646e01, 3.31348777e-06, 1.55593097e01], + [1.49022278e01, 1.37428245e-06, 1.55593097e01], + [1.49022278e01, 1.37428245e-06, 1.55593097e01], + [2.42251646e01, 3.31348777e-06, 1.55593097e01], + ], + ), + ], + ], + sldProfiles=[ + [ + np.array( + [ + [0.00000000e00, 2.07301741e-06], + [1.10000000e01, 2.07309604e-06], + [2.20000000e01, 2.07345780e-06], + [3.30000000e01, 2.07491687e-06], + [4.40000000e01, 2.17562259e-06], + [5.50000000e01, 3.22650495e-06], + [6.60000000e01, 3.40913848e-06], + [7.70000000e01, 3.13506253e-06], + [8.80000000e01, 1.20456289e-06], + [9.90000000e01, 1.27138002e-06], + [1.10000000e02, 1.56285495e-06], + [1.21000000e02, 1.84518709e-06], + [1.32000000e02, 2.00498449e-06], + [1.43000000e02, 1.96260665e-06], + [1.54000000e02, 1.71966879e-06], + [1.65000000e02, 1.39383267e-06], + [1.76000000e02, 1.22970195e-06], + [1.87000000e02, 1.41565526e-06], + [1.98000000e02, 1.88172657e-06], + [2.09000000e02, 2.40655867e-06], + [2.20000000e02, 2.83570420e-06], + [2.31000000e02, 3.11210082e-06], + [2.42000000e02, 3.24277802e-06], + [2.53000000e02, 3.28427452e-06], + [2.64000000e02, 3.29268847e-06], + [2.75000000e02, 3.29375418e-06], + [2.86000000e02, 3.29383773e-06], + [2.97000000e02, 3.29384178e-06], + [3.08000000e02, 3.29384190e-06], + ], + ), + np.array( + [ + [0.00000000e00, 2.07301819e-06], + [1.10000000e01, 2.07310296e-06], + [2.20000000e01, 2.07350415e-06], + [3.30000000e01, 2.07518460e-06], + [4.40000000e01, 2.23394767e-06], + [5.50000000e01, 3.90646736e-06], + [6.60000000e01, 4.18619279e-06], + [7.70000000e01, 3.91675004e-06], + [8.80000000e01, 1.92451547e-06], + [9.90000000e01, 2.06988861e-06], + [1.10000000e02, 2.47614934e-06], + [1.21000000e02, 2.84889288e-06], + [1.32000000e02, 3.00529286e-06], + [1.43000000e02, 2.86310144e-06], + [1.54000000e02, 2.49967205e-06], + [1.65000000e02, 2.09673058e-06], + [1.76000000e02, 1.92431424e-06], + [1.87000000e02, 2.18829605e-06], + [1.98000000e02, 2.83032190e-06], + [2.09000000e02, 3.62584708e-06], + [2.20000000e02, 4.36871153e-06], + [2.31000000e02, 4.89806866e-06], + [2.42000000e02, 5.16145928e-06], + [2.53000000e02, 5.24684298e-06], + [2.64000000e02, 5.26428707e-06], + [2.75000000e02, 5.26650242e-06], + [2.86000000e02, 5.26667628e-06], + [2.97000000e02, 5.26668469e-06], + [3.08000000e02, 5.26668495e-06], + ], + ), + ], + ], + resampledLayers=[[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]], calculationResults=RAT.outputs.CalculationResults( chiValues=np.array([4.6077885, 7.00028098]), - sumChi=11.608069475997699 + sumChi=11.608069475997699, ), contrastParams=RAT.outputs.ContrastParams( backgroundParams=np.array([2.37113128e-06, 1.99006694e-06]), @@ -1342,390 +2956,1645 @@ def dream_results(): bulkOut=np.array([6.01489149e-06, 1.59371685e-06]), resolutionParams=np.array([0.03, 0.03]), subRoughs=np.array([6.19503045, 6.19503045]), - resample=np.array([0.0, 0.0]) + resample=np.array([0.0, 0.0]), ), - fitParams=np.array([6.19503045e+00, 1.84420960e+01, 2.11039621e+01, 8.75538121e+00, - 3.72292994e+00, 1.84624551e+01, 1.02316734e+01, 2.31156093e+01, - 1.09906265e+01, 5.71005361e+00, 1.67933822e+01, 1.72009856e+01, - 3.00260126e+01, 2.94448999e+01, 2.37113128e-06, 1.99006694e-06, - 6.01489149e-06, 1.59371685e-06]), - fitNames=['Substrate Roughness', 'Oxide Thickness', 'SAM Tails Thickness', 'SAM Tails Hydration', - 'SAM Roughness', 'CW Thickness', 'SAM Heads Thickness', 'SAM Heads Hydration', - 'Bilayer Heads Thickness', 'Bilayer Roughness', 'Bilayer Tails Thickness', 'Bilayer Tails Hydration', - 'Bilayer Heads Hydration', 'Oxide Hydration', 'Background parameter D2O', 'Background parameter SMW', - 'D2O', 'SMW'], + fitParams=np.array( + [ + 6.19503045e00, + 1.84420960e01, + 2.11039621e01, + 8.75538121e00, + 3.72292994e00, + 1.84624551e01, + 1.02316734e01, + 2.31156093e01, + 1.09906265e01, + 5.71005361e00, + 1.67933822e01, + 1.72009856e01, + 3.00260126e01, + 2.94448999e01, + 2.37113128e-06, + 1.99006694e-06, + 6.01489149e-06, + 1.59371685e-06, + ], + ), + fitNames=[ + "Substrate Roughness", + "Oxide Thickness", + "SAM Tails Thickness", + "SAM Tails Hydration", + "SAM Roughness", + "CW Thickness", + "SAM Heads Thickness", + "SAM Heads Hydration", + "Bilayer Heads Thickness", + "Bilayer Roughness", + "Bilayer Tails Thickness", + "Bilayer Tails Hydration", + "Bilayer Heads Hydration", + "Oxide Hydration", + "Background parameter D2O", + "Background parameter SMW", + "D2O", + "SMW", + ], predictionIntervals=RAT.outputs.PredictionIntervals( - reflectivity=[np.array([[1.00000560e+00, 7.07687612e-01, 2.08315160e-02, 2.40787966e-03, - 2.17627660e-03, 2.54301700e-03, 1.76309827e-03, 6.15269679e-04, - 3.43679710e-05, 7.93625275e-05, 1.27760549e-04, 3.35799941e-05, - 6.75048751e-06, 7.64258431e-06, 6.05800395e-06, 5.60288298e-06, - 5.60333677e-06, 5.60223341e-06, 5.60206667e-06, 5.60206314e-06, - 5.60206314e-06], - [1.00000560e+00, 7.07687612e-01, 2.08315160e-02, 2.40787966e-03, - 2.17627660e-03, 2.54301700e-03, 1.76309827e-03, 6.15269679e-04, - 3.43679710e-05, 7.93625275e-05, 1.27760549e-04, 3.35799941e-05, - 6.75048751e-06, 7.64258431e-06, 6.05800395e-06, 5.60288298e-06, - 5.60333677e-06, 5.60223341e-06, 5.60206667e-06, 5.60206314e-06, - 5.60206314e-06], - [1.55201098e+01, 1.53748894e+01, 1.50402011e+01, 1.50299478e+01, - 1.50290525e+01, 1.50287935e+01, 1.50282126e+01, 1.50276044e+01, - 1.50273248e+01, 1.50273185e+01, 1.50272997e+01, 1.50272498e+01, - 1.50272364e+01, 1.50272347e+01, 1.50272335e+01, 1.50272330e+01, - 1.50272329e+01, 1.50272328e+01, 1.50272328e+01, 1.50272328e+01, - 1.50272328e+01], - [2.91397425e+01, 2.91324974e+01, 2.91281368e+01, 2.91255472e+01, - 2.91240295e+01, 2.91231836e+01, 2.91227893e+01, 2.91226872e+01, - 2.91226902e+01, 2.91226359e+01, 2.91225541e+01, 2.91225457e+01, - 2.91225448e+01, 2.91225407e+01, 2.91225398e+01, 2.91225393e+01, - 2.91225391e+01, 2.91225390e+01, 2.91225390e+01, 2.91225389e+01, - 2.91225389e+01], - [2.91397425e+01, 2.91324974e+01, 2.91281368e+01, 2.91255472e+01, - 2.91240295e+01, 2.91231836e+01, 2.91227893e+01, 2.91226872e+01, - 2.91226902e+01, 2.91226359e+01, 2.91225541e+01, 2.91225457e+01, - 2.91225448e+01, 2.91225407e+01, 2.91225398e+01, 2.91225393e+01, - 2.91225391e+01, 2.91225390e+01, 2.91225390e+01, 2.91225389e+01, - 2.91225389e+01]]), - np.array([[7.82198834e-01, 2.84434275e-02, 3.42472318e-03, 1.45801296e-03, - 2.02213149e-03, 2.00826891e-03, 1.27577246e-03, 4.27099544e-04, - 2.07304219e-05, 4.88683542e-05, 4.14000873e-05, 1.57801531e-05, - 2.08705254e-06, 2.27936213e-06, 1.09950377e-06, 7.09021331e-07, - 7.09539552e-07, 7.08228574e-07, 7.08101644e-07, 7.08098642e-07, - 7.08098641e-07], - [7.82198834e-01, 2.84434275e-02, 3.42472318e-03, 1.45801296e-03, - 2.02213149e-03, 2.00826891e-03, 1.27577246e-03, 4.27099544e-04, - 2.07304219e-05, 4.88683542e-05, 4.14000873e-05, 1.57801531e-05, - 2.08705254e-06, 2.27936213e-06, 1.09950377e-06, 7.09021331e-07, - 7.09539552e-07, 7.08228574e-07, 7.08101644e-07, 7.08098642e-07, - 7.08098641e-07], - [8.94587126e-01, 4.07514176e-01, 3.66355642e-02, 1.22207690e-02, - 5.91350591e-03, 3.17495745e-03, 1.50593011e-03, 5.80889579e-04, - 2.44654124e-04, 1.40925782e-04, 6.26965047e-05, 1.91064075e-05, - 9.45189755e-06, 6.16421495e-06, 5.17046678e-06, 4.24101973e-06, - 3.82067554e-06, 3.55352666e-06, 3.38981154e-06, 3.29631224e-06, - 3.25061722e-06], - [1.00000560e+00, 7.63076662e-01, 6.77868181e-02, 2.23160672e-02, - 9.56355479e-03, 4.26929321e-03, 1.72181442e-03, 7.25142247e-04, - 4.54691084e-04, 2.27274223e-04, 8.54009496e-05, 2.26525796e-05, - 1.63600080e-05, 9.80814666e-06, 8.98896697e-06, 7.55397947e-06, - 6.73887287e-06, 6.22237216e-06, 5.90521384e-06, 5.72401646e-06, - 5.63546023e-06], - [1.00000560e+00, 7.63076662e-01, 6.77868181e-02, 2.23160672e-02, - 9.56355479e-03, 4.26929321e-03, 1.72181442e-03, 7.25142247e-04, - 4.54691084e-04, 2.27274223e-04, 8.54009496e-05, 2.26525796e-05, - 1.63600080e-05, 9.80814666e-06, 8.98896697e-06, 7.55397947e-06, - 6.73887287e-06, 6.22237216e-06, 5.90521384e-06, 5.72401646e-06, - 5.63546023e-06]])], - sld=[[np.array([[-2.26996619e-06, -2.26938579e-06, -2.26877469e-06, ..., - 9.14568096e-07, 9.14567880e-07, 9.14567682e-07], - [-2.26996619e-06, -2.26938579e-06, -2.26877469e-06, ..., - 9.14568096e-07, 9.14567880e-07, 9.14567682e-07], - [-1.67970553e-07, -1.67671068e-07, -1.67355735e-07, ..., - 3.31763635e-06, 3.31763624e-06, 3.31763614e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.87958515e-06, 5.87958515e-06, 5.87958515e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.87958515e-06, 5.87958515e-06, 5.87958515e-06]])], - [np.array([[-1.35107208e-06, -1.34966627e-06, -1.34817823e-06, ..., - 4.65378475e-06, 4.65378475e-06, 4.65378475e-06], - [-1.35107208e-06, -1.34966627e-06, -1.34817823e-06, ..., - 4.65378475e-06, 4.65378475e-06, 4.65378475e-06], - [3.06178804e-07, 3.06904206e-07, 3.07672036e-07, ..., - 4.92477587e-06, 4.92477714e-06, 4.92477830e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.17896134e-06, 5.17896381e-06, 5.17896605e-06], - [2.07300000e-06, 2.07300000e-06, 2.07300001e-06, ..., - 5.17896134e-06, 5.17896381e-06, 5.17896605e-06]])]], - reflectivityXData=[np.array([[0.011403, 0.013861, 0.016848, 0.020479, 0.024892, 0.030256, - 0.036777, 0.044702, 0.054336, 0.066045, 0.080279, 0.097579, - 0.118610, 0.144170, 0.175240, 0.213000, 0.258910, 0.314700, - 0.382520, 0.464960, 0.565160]]), - np.array([[0.011403, 0.013861, 0.016848, 0.020479, 0.024892, 0.030256, - 0.036777, 0.044702, 0.054336, 0.066045, 0.080279, 0.097579, - 0.118610, 0.144170, 0.175240, 0.213000, 0.258910, 0.314700, - 0.382520, 0.464960, 0.565160]])], - sldXData=[[np.array([[0., 11., 22., 33., 44., 55., 66., 77., 88., 99., 110., - 121., 132., 143., 154., 165., 176., 187., 198., 209., 220., 231., - 242., 253., 264., 275., 286., 297., 308., 319.]]), - np.array([[0., 11., 22., 33., 44., 55., 66., 77., 88., 99., 110., - 121., 132., 143., 154., 165., 176., 187., 198., 209., 220., 231., - 242., 253., 264., 275., 286., 297., 308., 319.]])]], - sampleChi=np.array([1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16, - 1.12748255e+06, 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, - 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, 1.12748255e+06, - 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, 1.46133559e+16, - 1.46133559e+16, 1.12748255e+06, 1.12748255e+06, 1.46133559e+16]) + reflectivity=[ + np.array( + [ + [ + 1.00000560e00, + 7.07687612e-01, + 2.08315160e-02, + 2.40787966e-03, + 2.17627660e-03, + 2.54301700e-03, + 1.76309827e-03, + 6.15269679e-04, + 3.43679710e-05, + 7.93625275e-05, + 1.27760549e-04, + 3.35799941e-05, + 6.75048751e-06, + 7.64258431e-06, + 6.05800395e-06, + 5.60288298e-06, + 5.60333677e-06, + 5.60223341e-06, + 5.60206667e-06, + 5.60206314e-06, + 5.60206314e-06, + ], + [ + 1.00000560e00, + 7.07687612e-01, + 2.08315160e-02, + 2.40787966e-03, + 2.17627660e-03, + 2.54301700e-03, + 1.76309827e-03, + 6.15269679e-04, + 3.43679710e-05, + 7.93625275e-05, + 1.27760549e-04, + 3.35799941e-05, + 6.75048751e-06, + 7.64258431e-06, + 6.05800395e-06, + 5.60288298e-06, + 5.60333677e-06, + 5.60223341e-06, + 5.60206667e-06, + 5.60206314e-06, + 5.60206314e-06, + ], + [ + 1.55201098e01, + 1.53748894e01, + 1.50402011e01, + 1.50299478e01, + 1.50290525e01, + 1.50287935e01, + 1.50282126e01, + 1.50276044e01, + 1.50273248e01, + 1.50273185e01, + 1.50272997e01, + 1.50272498e01, + 1.50272364e01, + 1.50272347e01, + 1.50272335e01, + 1.50272330e01, + 1.50272329e01, + 1.50272328e01, + 1.50272328e01, + 1.50272328e01, + 1.50272328e01, + ], + [ + 2.91397425e01, + 2.91324974e01, + 2.91281368e01, + 2.91255472e01, + 2.91240295e01, + 2.91231836e01, + 2.91227893e01, + 2.91226872e01, + 2.91226902e01, + 2.91226359e01, + 2.91225541e01, + 2.91225457e01, + 2.91225448e01, + 2.91225407e01, + 2.91225398e01, + 2.91225393e01, + 2.91225391e01, + 2.91225390e01, + 2.91225390e01, + 2.91225389e01, + 2.91225389e01, + ], + [ + 2.91397425e01, + 2.91324974e01, + 2.91281368e01, + 2.91255472e01, + 2.91240295e01, + 2.91231836e01, + 2.91227893e01, + 2.91226872e01, + 2.91226902e01, + 2.91226359e01, + 2.91225541e01, + 2.91225457e01, + 2.91225448e01, + 2.91225407e01, + 2.91225398e01, + 2.91225393e01, + 2.91225391e01, + 2.91225390e01, + 2.91225390e01, + 2.91225389e01, + 2.91225389e01, + ], + ], + ), + np.array( + [ + [ + 7.82198834e-01, + 2.84434275e-02, + 3.42472318e-03, + 1.45801296e-03, + 2.02213149e-03, + 2.00826891e-03, + 1.27577246e-03, + 4.27099544e-04, + 2.07304219e-05, + 4.88683542e-05, + 4.14000873e-05, + 1.57801531e-05, + 2.08705254e-06, + 2.27936213e-06, + 1.09950377e-06, + 7.09021331e-07, + 7.09539552e-07, + 7.08228574e-07, + 7.08101644e-07, + 7.08098642e-07, + 7.08098641e-07, + ], + [ + 7.82198834e-01, + 2.84434275e-02, + 3.42472318e-03, + 1.45801296e-03, + 2.02213149e-03, + 2.00826891e-03, + 1.27577246e-03, + 4.27099544e-04, + 2.07304219e-05, + 4.88683542e-05, + 4.14000873e-05, + 1.57801531e-05, + 2.08705254e-06, + 2.27936213e-06, + 1.09950377e-06, + 7.09021331e-07, + 7.09539552e-07, + 7.08228574e-07, + 7.08101644e-07, + 7.08098642e-07, + 7.08098641e-07, + ], + [ + 8.94587126e-01, + 4.07514176e-01, + 3.66355642e-02, + 1.22207690e-02, + 5.91350591e-03, + 3.17495745e-03, + 1.50593011e-03, + 5.80889579e-04, + 2.44654124e-04, + 1.40925782e-04, + 6.26965047e-05, + 1.91064075e-05, + 9.45189755e-06, + 6.16421495e-06, + 5.17046678e-06, + 4.24101973e-06, + 3.82067554e-06, + 3.55352666e-06, + 3.38981154e-06, + 3.29631224e-06, + 3.25061722e-06, + ], + [ + 1.00000560e00, + 7.63076662e-01, + 6.77868181e-02, + 2.23160672e-02, + 9.56355479e-03, + 4.26929321e-03, + 1.72181442e-03, + 7.25142247e-04, + 4.54691084e-04, + 2.27274223e-04, + 8.54009496e-05, + 2.26525796e-05, + 1.63600080e-05, + 9.80814666e-06, + 8.98896697e-06, + 7.55397947e-06, + 6.73887287e-06, + 6.22237216e-06, + 5.90521384e-06, + 5.72401646e-06, + 5.63546023e-06, + ], + [ + 1.00000560e00, + 7.63076662e-01, + 6.77868181e-02, + 2.23160672e-02, + 9.56355479e-03, + 4.26929321e-03, + 1.72181442e-03, + 7.25142247e-04, + 4.54691084e-04, + 2.27274223e-04, + 8.54009496e-05, + 2.26525796e-05, + 1.63600080e-05, + 9.80814666e-06, + 8.98896697e-06, + 7.55397947e-06, + 6.73887287e-06, + 6.22237216e-06, + 5.90521384e-06, + 5.72401646e-06, + 5.63546023e-06, + ], + ], + ), + ], + sld=[ + [ + np.array( + [ + [ + -2.26996619e-06, + -2.26938579e-06, + -2.26877469e-06, + ..., + 9.14568096e-07, + 9.14567880e-07, + 9.14567682e-07, + ], + [ + -2.26996619e-06, + -2.26938579e-06, + -2.26877469e-06, + ..., + 9.14568096e-07, + 9.14567880e-07, + 9.14567682e-07, + ], + [ + -1.67970553e-07, + -1.67671068e-07, + -1.67355735e-07, + ..., + 3.31763635e-06, + 3.31763624e-06, + 3.31763614e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.87958515e-06, + 5.87958515e-06, + 5.87958515e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.87958515e-06, + 5.87958515e-06, + 5.87958515e-06, + ], + ], + ), + ], + [ + np.array( + [ + [ + -1.35107208e-06, + -1.34966627e-06, + -1.34817823e-06, + ..., + 4.65378475e-06, + 4.65378475e-06, + 4.65378475e-06, + ], + [ + -1.35107208e-06, + -1.34966627e-06, + -1.34817823e-06, + ..., + 4.65378475e-06, + 4.65378475e-06, + 4.65378475e-06, + ], + [ + 3.06178804e-07, + 3.06904206e-07, + 3.07672036e-07, + ..., + 4.92477587e-06, + 4.92477714e-06, + 4.92477830e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.17896134e-06, + 5.17896381e-06, + 5.17896605e-06, + ], + [ + 2.07300000e-06, + 2.07300000e-06, + 2.07300001e-06, + ..., + 5.17896134e-06, + 5.17896381e-06, + 5.17896605e-06, + ], + ], + ), + ], + ], + reflectivityXData=[ + np.array( + [ + [ + 0.011403, + 0.013861, + 0.016848, + 0.020479, + 0.024892, + 0.030256, + 0.036777, + 0.044702, + 0.054336, + 0.066045, + 0.080279, + 0.097579, + 0.118610, + 0.144170, + 0.175240, + 0.213000, + 0.258910, + 0.314700, + 0.382520, + 0.464960, + 0.565160, + ], + ], + ), + np.array( + [ + [ + 0.011403, + 0.013861, + 0.016848, + 0.020479, + 0.024892, + 0.030256, + 0.036777, + 0.044702, + 0.054336, + 0.066045, + 0.080279, + 0.097579, + 0.118610, + 0.144170, + 0.175240, + 0.213000, + 0.258910, + 0.314700, + 0.382520, + 0.464960, + 0.565160, + ], + ], + ), + ], + sldXData=[ + [ + np.array( + [ + [ + 0.0, + 11.0, + 22.0, + 33.0, + 44.0, + 55.0, + 66.0, + 77.0, + 88.0, + 99.0, + 110.0, + 121.0, + 132.0, + 143.0, + 154.0, + 165.0, + 176.0, + 187.0, + 198.0, + 209.0, + 220.0, + 231.0, + 242.0, + 253.0, + 264.0, + 275.0, + 286.0, + 297.0, + 308.0, + 319.0, + ], + ], + ), + np.array( + [ + [ + 0.0, + 11.0, + 22.0, + 33.0, + 44.0, + 55.0, + 66.0, + 77.0, + 88.0, + 99.0, + 110.0, + 121.0, + 132.0, + 143.0, + 154.0, + 165.0, + 176.0, + 187.0, + 198.0, + 209.0, + 220.0, + 231.0, + 242.0, + 253.0, + 264.0, + 275.0, + 286.0, + 297.0, + 308.0, + 319.0, + ], + ], + ), + ], + ], + sampleChi=np.array( + [ + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.46133559e16, + 1.12748255e06, + 1.12748255e06, + 1.46133559e16, + ], + ), ), confidenceIntervals=RAT.outputs.ConfidenceIntervals( - percentile65=np.array([[-1.29074586e-231, 8.33251318e+000, 1.75397363e+001, 1.75397363e+001, - 9.85302945e+000, 9.85302945e+000, 8.34197863e+000, 8.34197863e+000, - 1.65750684e+001, 1.45435510e+001, 1.45435510e+001, 1.52609047e+001, - 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, 7.08098641e-007, - 7.08098641e-007, 4.65378475e-006], - [8.33251318e+000, 5.48185565e+001, 5.48185565e+001, 4.57554170e+001, - 4.57554170e+001, 1.17557273e+001, 1.17557273e+001, 3.18752608e+001, - 3.18752608e+001, 1.65750684e+001, 1.52609047e+001, 4.88237113e+001, - 4.88237113e+001, 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, - 5.87958515e-006, 5.87958515e-006]]), - percentile95=np.array([[-1.29074586e-231, 8.33251318e+000, 1.75397363e+001, 1.75397363e+001, - 9.85302945e+000, 9.85302945e+000, 8.34197863e+000, 8.34197863e+000, - 1.65750684e+001, 1.45435510e+001, 1.45435510e+001, 1.52609047e+001, - 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, 7.08098641e-007, - 7.08098641e-007, 4.65378475e-006], - [8.33251318e+000, 5.48185565e+001, 5.48185565e+001, 4.57554170e+001, - 4.57554170e+001, 1.17557273e+001, 1.17557273e+001, 3.18752608e+001, - 3.18752608e+001, 1.65750684e+001, 1.52609047e+001, 4.88237113e+001, - 4.88237113e+001, 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, - 5.87958515e-006, 5.87958515e-006]]), - mean=np.array([[4.16625659e+00, 3.15755349e+01, 3.61791464e+01, 3.16475766e+01, - 2.78042232e+01, 1.08043784e+01, 1.00488530e+01, 2.01086197e+01, - 2.42251646e+01, 1.55593097e+01, 1.49022278e+01, 3.20423080e+01, - 4.85551946e+01, 3.87046084e+01, 1.45612723e+01, 3.15508089e-06, - 3.29384190e-06, 5.26668495e-06]]) + percentile65=np.array( + [ + [ + -1.29074586e-231, + 8.33251318e000, + 1.75397363e001, + 1.75397363e001, + 9.85302945e000, + 9.85302945e000, + 8.34197863e000, + 8.34197863e000, + 1.65750684e001, + 1.45435510e001, + 1.45435510e001, + 1.52609047e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 7.08098641e-007, + 4.65378475e-006, + ], + [ + 8.33251318e000, + 5.48185565e001, + 5.48185565e001, + 4.57554170e001, + 4.57554170e001, + 1.17557273e001, + 1.17557273e001, + 3.18752608e001, + 3.18752608e001, + 1.65750684e001, + 1.52609047e001, + 4.88237113e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 5.87958515e-006, + 5.87958515e-006, + ], + ], + ), + percentile95=np.array( + [ + [ + -1.29074586e-231, + 8.33251318e000, + 1.75397363e001, + 1.75397363e001, + 9.85302945e000, + 9.85302945e000, + 8.34197863e000, + 8.34197863e000, + 1.65750684e001, + 1.45435510e001, + 1.45435510e001, + 1.52609047e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 7.08098641e-007, + 4.65378475e-006, + ], + [ + 8.33251318e000, + 5.48185565e001, + 5.48185565e001, + 4.57554170e001, + 4.57554170e001, + 1.17557273e001, + 1.17557273e001, + 3.18752608e001, + 3.18752608e001, + 1.65750684e001, + 1.52609047e001, + 4.88237113e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 5.87958515e-006, + 5.87958515e-006, + ], + ], + ), + mean=np.array( + [ + [ + 4.16625659e00, + 3.15755349e01, + 3.61791464e01, + 3.16475766e01, + 2.78042232e01, + 1.08043784e01, + 1.00488530e01, + 2.01086197e01, + 2.42251646e01, + 1.55593097e01, + 1.49022278e01, + 3.20423080e01, + 4.85551946e01, + 3.87046084e01, + 1.45612723e01, + 3.15508089e-06, + 3.29384190e-06, + 5.26668495e-06, + ], + ], + ), ), dreamParams=RAT.outputs.DreamParams( nParams=18.0, @@ -1746,51 +4615,114 @@ def dream_results(): ABC=False, IO=False, storeOutput=False, - R=np.array([[0.]]), + R=np.array([[0.0]]), ), dreamOutput=RAT.outputs.DreamOutput( - allChains=np.array([[[8.33251318e+00], - [5.48185565e+01], - [1.75397363e+01], - [4.57554170e+01], - [9.85302945e+00], - [1.17557273e+01], - [8.34197863e+00], - [3.18752608e+01], - [1.65750684e+01], - [1.45435510e+01], - [1.52609047e+01], - [4.88237113e+01], - [4.82866779e+01], - [2.91225389e+01], - [5.60206314e-06], - [7.08098641e-07], - [5.87958515e-06], - [4.65378475e-06], - [-4.86509830e+01], - [-5.63741277e+05]]]), + allChains=np.array( + [ + [ + [8.33251318e00], + [5.48185565e01], + [1.75397363e01], + [4.57554170e01], + [9.85302945e00], + [1.17557273e01], + [8.34197863e00], + [3.18752608e01], + [1.65750684e01], + [1.45435510e01], + [1.52609047e01], + [4.88237113e01], + [4.82866779e01], + [2.91225389e01], + [5.60206314e-06], + [7.08098641e-07], + [5.87958515e-06], + [4.65378475e-06], + [-4.86509830e01], + [-5.63741277e05], + ], + ], + ), outlierChains=np.array([[0.0, 0.0]]), runtime=2.6e-06, iteration=2.0, modelOutput=0.0, AR=np.array([[1.0, np.nan]]), - R_stat=np.array([[1.0, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, - np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan]]), - CR=np.array([[1., 0.33333333, 0.33333333, 0.33333333]]), + R_stat=np.array( + [ + [ + 1.0, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + np.nan, + ], + ], + ), + CR=np.array([[1.0, 0.33333333, 0.33333333, 0.33333333]]), ), nestedSamplerOutput=RAT.outputs.NestedSamplerOutput( logZ=0.0, nestSamples=np.array([[0.0, 0.0]]), - postSamples=np.array([[0.0, 0.0]]) + postSamples=np.array([[0.0, 0.0]]), + ), + chain=np.array( + [ + [ + -1.29231905e-231, + 8.33251318e000, + 5.48185565e001, + 1.75397363e001, + 4.57554170e001, + 9.85302945e000, + 1.17557273e001, + 8.34197863e000, + 3.18752608e001, + 1.65750684e001, + 1.45435510e001, + 1.52609047e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 5.87958515e-006, + ], + [ + 8.33251318e000, + 5.48185565e001, + 1.75397363e001, + 4.57554170e001, + 9.85302945e000, + 1.17557273e001, + 8.34197863e000, + 3.18752608e001, + 1.65750684e001, + 1.45435510e001, + 1.52609047e001, + 4.88237113e001, + 4.82866779e001, + 2.91225389e001, + 5.60206314e-006, + 7.08098641e-007, + 5.87958515e-006, + 4.65378475e-006, + ], + ], ), - chain=np.array([[-1.29231905e-231, 8.33251318e+000, 5.48185565e+001, 1.75397363e+001, - 4.57554170e+001, 9.85302945e+000, 1.17557273e+001, 8.34197863e+000, - 3.18752608e+001, 1.65750684e+001, 1.45435510e+001, 1.52609047e+001, - 4.88237113e+001, 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, - 7.08098641e-007, 5.87958515e-006], - [8.33251318e+000, 5.48185565e+001, 1.75397363e+001, 4.57554170e+001, - 9.85302945e+000, 1.17557273e+001, 8.34197863e+000, 3.18752608e+001, - 1.65750684e+001, 1.45435510e+001, 1.52609047e+001, 4.88237113e+001, - 4.82866779e+001, 2.91225389e+001, 5.60206314e-006, 7.08098641e-007, - 5.87958515e-006, 4.65378475e-006]]) ) diff --git a/tests/test_classlist.py b/tests/test_classlist.py index 7c71b6f7..4839fb4a 100644 --- a/tests/test_classlist.py +++ b/tests/test_classlist.py @@ -1,10 +1,11 @@ """Test the ClassList.""" -from collections.abc import Iterable, Sequence -import pytest import re -from typing import Any, Union import warnings +from collections.abc import Iterable, Sequence +from typing import Any, Union + +import pytest from RAT.classlist import ClassList from tests.utils import InputAttributes, SubInputAttributes @@ -13,41 +14,44 @@ @pytest.fixture def one_name_class_list(): """A ClassList of InputAttributes, containing one element with a name defined.""" - return ClassList([InputAttributes(name='Alice')]) + return ClassList([InputAttributes(name="Alice")]) @pytest.fixture def two_name_class_list(): """A ClassList of InputAttributes, containing two elements with names defined.""" - return ClassList([InputAttributes(name='Alice'), InputAttributes(name='Bob')]) + return ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob")]) @pytest.fixture def two_name_class_list_table(): """The table representation of the ClassList defined in the "two_name_class_list" fixture.""" - return( - '+-------+-------+\n' - '| index | name |\n' - '+-------+-------+\n' - '| 0 | Alice |\n' - '| 1 | Bob |\n' - '+-------+-------+' + return ( + "+-------+-------+\n" + "| index | name |\n" + "+-------+-------+\n" + "| 0 | Alice |\n" + "| 1 | Bob |\n" + "+-------+-------+" ) @pytest.fixture def three_name_class_list(): """A ClassList of InputAttributes, containing three elements with names defined.""" - return ClassList([InputAttributes(name='Alice'), InputAttributes(name='Bob'), InputAttributes(name='Eve')]) - - -class TestInitialisation(object): - @pytest.mark.parametrize("input_object", [ - (InputAttributes()), - (InputAttributes(name='Alice')), - (InputAttributes(surname='Morgan')), - 'Alice', - ]) + return ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob"), InputAttributes(name="Eve")]) + + +class TestInitialisation: + @pytest.mark.parametrize( + "input_object", + [ + (InputAttributes()), + (InputAttributes(name="Alice")), + (InputAttributes(surname="Morgan")), + "Alice", + ], + ) def test_input_object(self, input_object: Any) -> None: """For an input of an object, the ClassList should contain a one-element list containing the object and _class_handle should be set to the type of the object. @@ -56,16 +60,19 @@ def test_input_object(self, input_object: Any) -> None: assert class_list.data == [input_object] assert isinstance(input_object, class_list._class_handle) - @pytest.mark.parametrize("input_sequence", [ - ([InputAttributes()]), - ([InputAttributes(name='Alice')]), - ([InputAttributes(surname='Morgan')]), - ([InputAttributes(name='Alice'), InputAttributes(name='Bob')]), - (InputAttributes(),), - (InputAttributes(name='Alice'),), - (InputAttributes(surname='Morgan'),), - (InputAttributes(name='Alice'), InputAttributes(name='Bob')), - ]) + @pytest.mark.parametrize( + "input_sequence", + [ + ([InputAttributes()]), + ([InputAttributes(name="Alice")]), + ([InputAttributes(surname="Morgan")]), + ([InputAttributes(name="Alice"), InputAttributes(name="Bob")]), + (InputAttributes(),), + (InputAttributes(name="Alice"),), + (InputAttributes(surname="Morgan"),), + (InputAttributes(name="Alice"), InputAttributes(name="Bob")), + ], + ) def test_input_sequence(self, input_sequence: Sequence[object]) -> None: """For an input of a sequence, the ClassList should be a list equal to the input sequence, and _class_handle should be set to the type of the objects within. @@ -75,10 +82,13 @@ def test_input_sequence(self, input_sequence: Sequence[object]) -> None: for element in input_sequence: assert isinstance(element, class_list._class_handle) - @pytest.mark.parametrize("input_sequence", [ - ([InputAttributes(name='Alice'), SubInputAttributes(name='Bob')]), - ([SubInputAttributes(name='Alice'), InputAttributes(name='Bob')]), - ]) + @pytest.mark.parametrize( + "input_sequence", + [ + ([InputAttributes(name="Alice"), SubInputAttributes(name="Bob")]), + ([SubInputAttributes(name="Alice"), InputAttributes(name="Bob")]), + ], + ) def test_input_sequence_subclass(self, input_sequence: Sequence[object]) -> None: """For an input of a sequence containing objects of a class and its subclasses, the ClassList should be a list equal to the input sequence, and _class_handle should be set to the type of the parent class. @@ -91,29 +101,41 @@ def test_input_sequence_subclass(self, input_sequence: Sequence[object]) -> None @pytest.mark.parametrize("empty_input", [([]), (())]) def test_empty_input(self, empty_input: Sequence[object]) -> None: """If we initialise a ClassList with an empty input (list or tuple), the ClassList should be an empty list, and - _class_handle should be unset.""" + _class_handle should be unset. + """ class_list = ClassList(empty_input) assert class_list.data == [] - assert not hasattr(class_list, '_class_handle') + assert not hasattr(class_list, "_class_handle") - @pytest.mark.parametrize("input_list", [ - ([InputAttributes(name='Alice'), dict(name='Bob')]), - ]) + @pytest.mark.parametrize( + "input_list", + [ + ([InputAttributes(name="Alice"), dict(name="Bob")]), + ], + ) def test_different_classes(self, input_list: Sequence[object]) -> None: """If we initialise a ClassList with an input containing multiple classes, we should raise a ValueError.""" - with pytest.raises(ValueError, - match=f"Input list contains elements of type other than '{type(input_list[0]).__name__}'"): + with pytest.raises( + ValueError, + match=f"Input list contains elements of type other than '{type(input_list[0]).__name__}'", + ): ClassList(input_list) - @pytest.mark.parametrize("input_list, name_field", [ - ([InputAttributes(name='Alice'), InputAttributes(name='Alice')], 'name'), - ([InputAttributes(id='Alice'), InputAttributes(id='Alice')], 'id'), - ]) + @pytest.mark.parametrize( + "input_list, name_field", + [ + ([InputAttributes(name="Alice"), InputAttributes(name="Alice")], "name"), + ([InputAttributes(id="Alice"), InputAttributes(id="Alice")], "id"), + ], + ) def test_identical_name_fields(self, input_list: Sequence[object], name_field: str) -> None: """If we initialise a ClassList with input objects with identical values of the name_field, - we should raise a ValueError.""" - with pytest.raises(ValueError, - match=f"Input list contains objects with the same value of the {name_field} attribute"): + we should raise a ValueError. + """ + with pytest.raises( + ValueError, + match=f"Input list contains objects with the same value of the {name_field} attribute", + ): ClassList(input_list, name_field=name_field) @@ -124,14 +146,18 @@ def test_repr_table(two_name_class_list: ClassList, two_name_class_list_table: s def test_repr_empty_table() -> None: """For empty classes with the __dict__ attribute, we should be able to print the contents of the ClassList as a - list.""" + list. + """ empty_attributes = InputAttributes() assert repr(ClassList(empty_attributes)) == repr([empty_attributes]) -@pytest.mark.parametrize("input_list", [ - (['Alice', 'Bob']), -]) +@pytest.mark.parametrize( + "input_list", + [ + (["Alice", "Bob"]), + ], +) def test_repr_list(input_list: list[str]) -> None: """For classes without the __dict__ attribute, we should be able to print the ClassList as a list.""" class_list = ClassList(input_list) @@ -143,11 +169,16 @@ def test_repr_empty_classlist() -> None: assert repr(ClassList()) == repr([]) -@pytest.mark.parametrize(["new_item", "expected_classlist"], [ - (InputAttributes(name='Eve'), ClassList([InputAttributes(name='Eve'), InputAttributes(name='Bob')])), - (InputAttributes(name='John', surname='Luther'), - ClassList([InputAttributes(name='John', surname='Luther'), InputAttributes(name='Bob')])), -]) +@pytest.mark.parametrize( + ["new_item", "expected_classlist"], + [ + (InputAttributes(name="Eve"), ClassList([InputAttributes(name="Eve"), InputAttributes(name="Bob")])), + ( + InputAttributes(name="John", surname="Luther"), + ClassList([InputAttributes(name="John", surname="Luther"), InputAttributes(name="Bob")]), + ), + ], +) def test_setitem(two_name_class_list: ClassList, new_item: InputAttributes, expected_classlist: ClassList) -> None: """We should be able to set values in an element of a ClassList using a new object.""" class_list = two_name_class_list @@ -155,21 +186,27 @@ def test_setitem(two_name_class_list: ClassList, new_item: InputAttributes, expe assert class_list == expected_classlist -@pytest.mark.parametrize("new_item", [ - (InputAttributes(name='Bob')), -]) +@pytest.mark.parametrize( + "new_item", + [ + (InputAttributes(name="Bob")), + ], +) def test_setitem_same_name_field(two_name_class_list: ClassList, new_item: InputAttributes) -> None: """If we set the name_field of an object in the ClassList to one already defined, we should raise a ValueError.""" with pytest.raises(ValueError, match="Input list contains objects with the same value of the name attribute"): two_name_class_list[0] = new_item -@pytest.mark.parametrize("new_values", [ - 'Bob', -]) +@pytest.mark.parametrize( + "new_values", + [ + "Bob", + ], +) def test_setitem_different_classes(two_name_class_list: ClassList, new_values: dict[str, Any]) -> None: """If we set the name_field of an object in the ClassList to one already defined, we should raise a ValueError.""" - with pytest.raises(ValueError, match=f"Input list contains elements of type other than 'InputAttributes'"): + with pytest.raises(ValueError, match="Input list contains elements of type other than 'InputAttributes'"): two_name_class_list[0] = new_values @@ -187,28 +224,36 @@ def test_delitem_not_present(two_name_class_list: ClassList) -> None: del class_list[2] -@pytest.mark.parametrize("added_list", [ - (ClassList(InputAttributes(name='Eve'))), - ([InputAttributes(name='Eve')]), - (InputAttributes(name='Eve'),), - (InputAttributes(name='Eve')), -]) +@pytest.mark.parametrize( + "added_list", + [ + (ClassList(InputAttributes(name="Eve"))), + ([InputAttributes(name="Eve")]), + (InputAttributes(name="Eve"),), + (InputAttributes(name="Eve")), + ], +) def test_iadd(two_name_class_list: ClassList, added_list: Iterable, three_name_class_list: ClassList) -> None: """We should be able to use the "+=" operator to add iterables to a ClassList. Individual objects should be wrapped - in a list before being added.""" + in a list before being added. + """ class_list = two_name_class_list class_list += added_list assert class_list == three_name_class_list -@pytest.mark.parametrize("added_list", [ - (ClassList([InputAttributes(name='Alice'), InputAttributes(name='Bob')])), - ([InputAttributes(name='Alice'), InputAttributes(name='Bob')]), - (InputAttributes(name='Alice'), InputAttributes(name='Bob')), -]) +@pytest.mark.parametrize( + "added_list", + [ + (ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob")])), + ([InputAttributes(name="Alice"), InputAttributes(name="Bob")]), + (InputAttributes(name="Alice"), InputAttributes(name="Bob")), + ], +) def test_iadd_empty_classlist(added_list: Sequence, two_name_class_list: ClassList) -> None: """We should be able to use the "+=" operator to add iterables to an empty ClassList, whilst also setting - _class_handle.""" + _class_handle. + """ class_list = ClassList() class_list += added_list assert class_list == two_name_class_list @@ -218,74 +263,108 @@ def test_iadd_empty_classlist(added_list: Sequence, two_name_class_list: ClassLi def test_mul(two_name_class_list: ClassList) -> None: """If we use the "*" operator on a ClassList, we should raise a TypeError.""" n = 2 - with pytest.raises(TypeError, match=re.escape(f"unsupported operand type(s) for *: " - f"'{two_name_class_list.__class__.__name__}' and " - f"'{n.__class__.__name__}'")): + with pytest.raises( + TypeError, + match=re.escape( + f"unsupported operand type(s) for *: " + f"'{two_name_class_list.__class__.__name__}' and " + f"'{n.__class__.__name__}'", + ), + ): two_name_class_list * n def test_rmul(two_name_class_list: ClassList) -> None: """If we use the "*" operator on a ClassList, we should raise a TypeError.""" n = 2 - with pytest.raises(TypeError, match=re.escape(f"unsupported operand type(s) for *: " - f"'{n.__class__.__name__}' and " - f"'{two_name_class_list.__class__.__name__}'")): + with pytest.raises( + TypeError, + match=re.escape( + f"unsupported operand type(s) for *: " + f"'{n.__class__.__name__}' and " + f"'{two_name_class_list.__class__.__name__}'", + ), + ): n * two_name_class_list def test_imul(two_name_class_list: ClassList) -> None: """If we use the "*=" operator on a ClassList, we should raise a TypeError.""" n = 2 - with pytest.raises(TypeError, match=re.escape(f"unsupported operand type(s) for *=: " - f"'{two_name_class_list.__class__.__name__}' and " - f"'{n.__class__.__name__}'")): + with pytest.raises( + TypeError, + match=re.escape( + f"unsupported operand type(s) for *=: " + f"'{two_name_class_list.__class__.__name__}' and " + f"'{n.__class__.__name__}'", + ), + ): two_name_class_list *= n -@pytest.mark.parametrize("new_object", [ - (InputAttributes(name='Eve')), -]) -def test_append_object(two_name_class_list: ClassList, - new_object: object, - three_name_class_list: ClassList) -> None: +@pytest.mark.parametrize( + "new_object", + [ + (InputAttributes(name="Eve")), + ], +) +def test_append_object(two_name_class_list: ClassList, new_object: object, three_name_class_list: ClassList) -> None: """We should be able to append to a ClassList using a new object.""" class_list = two_name_class_list class_list.append(new_object) assert class_list == three_name_class_list -@pytest.mark.parametrize("new_values", [ - ({'name': 'Eve'}), -]) -def test_append_kwargs(two_name_class_list: ClassList, - new_values: dict[str, Any], - three_name_class_list: ClassList) -> None: +@pytest.mark.parametrize( + "new_values", + [ + ({"name": "Eve"}), + ], +) +def test_append_kwargs( + two_name_class_list: ClassList, + new_values: dict[str, Any], + three_name_class_list: ClassList, +) -> None: """We should be able to append to a ClassList using keyword arguments.""" class_list = two_name_class_list class_list.append(**new_values) assert class_list == three_name_class_list -@pytest.mark.parametrize(["new_object", "new_values"], [ - (InputAttributes(name='Eve'), {'name': 'John'}), -]) -def test_append_object_and_kwargs(two_name_class_list: ClassList, - new_object: object, - new_values: dict[str, Any], - three_name_class_list: ClassList) -> None: +@pytest.mark.parametrize( + ["new_object", "new_values"], + [ + (InputAttributes(name="Eve"), {"name": "John"}), + ], +) +def test_append_object_and_kwargs( + two_name_class_list: ClassList, + new_object: object, + new_values: dict[str, Any], + three_name_class_list: ClassList, +) -> None: """If we append to a ClassList using a new object and keyword arguments, we raise a warning, and append the object, - discarding the keyword arguments.""" + discarding the keyword arguments. + """ class_list = two_name_class_list with pytest.warns(SyntaxWarning): - warnings.warn('ClassList.append() called with both an object and keyword arguments. ' - 'The keyword arguments will be ignored.', SyntaxWarning) + warnings.warn( + "ClassList.append() called with both an object and keyword arguments. " + "The keyword arguments will be ignored.", + SyntaxWarning, + stacklevel=2, + ) class_list.append(new_object, **new_values) assert class_list == three_name_class_list -@pytest.mark.parametrize("new_object", [ - (InputAttributes(name='Alice')), -]) +@pytest.mark.parametrize( + "new_object", + [ + (InputAttributes(name="Alice")), + ], +) def test_append_object_empty_classlist(new_object: object, one_name_class_list: ClassList) -> None: """We should be able to append to an empty ClassList using a new object, whilst also setting _class_handle.""" class_list = ClassList() @@ -294,83 +373,121 @@ def test_append_object_empty_classlist(new_object: object, one_name_class_list: assert isinstance(new_object, class_list._class_handle) -@pytest.mark.parametrize("new_values", [ - ({'name': 'Alice'}), -]) +@pytest.mark.parametrize( + "new_values", + [ + ({"name": "Alice"}), + ], +) def test_append_kwargs_empty_classlist(new_values: dict[str, Any]) -> None: """If we append to an empty ClassList using keyword arguments we should raise a TypeError.""" class_list = ClassList() - with pytest.raises(TypeError, match=re.escape('ClassList.append() called with keyword arguments for a ClassList ' - 'without a class defined. Call ClassList.append() with an object to ' - 'define the class.')): + with pytest.raises( + TypeError, + match=re.escape( + "ClassList.append() called with keyword arguments for a ClassList " + "without a class defined. Call ClassList.append() with an object to " + "define the class.", + ), + ): class_list.append(**new_values) -@pytest.mark.parametrize("new_object", [ - (InputAttributes(name='Alice')), -]) +@pytest.mark.parametrize( + "new_object", + [ + (InputAttributes(name="Alice")), + ], +) def test_append_object_same_name_field(two_name_class_list: ClassList, new_object: object) -> None: """If we append an object with an already-specified name_field value to a ClassList we should raise a ValueError.""" - with pytest.raises(ValueError, match=f"Input list contains objects with the same value of the " - f"{two_name_class_list.name_field} attribute"): + with pytest.raises( + ValueError, + match=f"Input list contains objects with the same value of the " f"{two_name_class_list.name_field} attribute", + ): two_name_class_list.append(new_object) -@pytest.mark.parametrize("new_values", [ - ({'name': 'Alice'}), -]) +@pytest.mark.parametrize( + "new_values", + [ + ({"name": "Alice"}), + ], +) def test_append_kwargs_same_name_field(two_name_class_list: ClassList, new_values: dict[str, Any]) -> None: """If we append an object with an already-specified name_field value to a ClassList we should raise a ValueError.""" - with pytest.raises(ValueError, match=f"Input arguments contain the {two_name_class_list.name_field} " - f"'{new_values[two_name_class_list.name_field]}', " - f"which is already specified in the ClassList"): + with pytest.raises( + ValueError, + match=f"Input arguments contain the {two_name_class_list.name_field} " + f"'{new_values[two_name_class_list.name_field]}', " + f"which is already specified in the ClassList", + ): two_name_class_list.append(**new_values) -@pytest.mark.parametrize("new_object", [ - (InputAttributes(name='Eve')) -]) +@pytest.mark.parametrize( + "new_object", + [ + (InputAttributes(name="Eve")), + ], +) def test_insert_object(two_name_class_list: ClassList, new_object: object) -> None: """We should be able to insert an object within a ClassList using a new object.""" two_name_class_list.insert(1, new_object) - assert two_name_class_list == ClassList([InputAttributes(name='Alice'), - InputAttributes(name='Eve'), - InputAttributes(name='Bob')]) + assert two_name_class_list == ClassList( + [InputAttributes(name="Alice"), InputAttributes(name="Eve"), InputAttributes(name="Bob")], + ) -@pytest.mark.parametrize("new_values", [ - ({'name': 'Eve'}) -]) +@pytest.mark.parametrize( + "new_values", + [ + ({"name": "Eve"}), + ], +) def test_insert_kwargs(two_name_class_list: ClassList, new_values: dict[str, Any]) -> None: """We should be able to insert an object within a ClassList using keyword arguments.""" two_name_class_list.insert(1, **new_values) - assert two_name_class_list == ClassList([InputAttributes(name='Alice'), - InputAttributes(name='Eve'), - InputAttributes(name='Bob')]) - - -@pytest.mark.parametrize(["new_object", "new_values"], [ - (InputAttributes(name='Eve'), {'name': 'John'}), -]) -def test_insert_object_and_kwargs(two_name_class_list: ClassList, - new_object: object, - new_values: dict[str, Any], - three_name_class_list: ClassList) -> None: + assert two_name_class_list == ClassList( + [InputAttributes(name="Alice"), InputAttributes(name="Eve"), InputAttributes(name="Bob")], + ) + + +@pytest.mark.parametrize( + ["new_object", "new_values"], + [ + (InputAttributes(name="Eve"), {"name": "John"}), + ], +) +def test_insert_object_and_kwargs( + two_name_class_list: ClassList, + new_object: object, + new_values: dict[str, Any], + three_name_class_list: ClassList, +) -> None: """If call insert() on a ClassList using a new object and keyword arguments, we raise a warning, and append the - object, discarding the keyword arguments.""" + object, discarding the keyword arguments. + """ class_list = two_name_class_list with pytest.warns(SyntaxWarning): - warnings.warn('ClassList.insert() called with both an object and keyword arguments. ' - 'The keyword arguments will be ignored.', SyntaxWarning) + warnings.warn( + "ClassList.insert() called with both an object and keyword arguments. " + "The keyword arguments will be ignored.", + SyntaxWarning, + stacklevel=2, + ) class_list.insert(1, new_object, **new_values) - assert class_list == ClassList([InputAttributes(name='Alice'), - InputAttributes(name='Eve'), - InputAttributes(name='Bob')]) + assert class_list == ClassList( + [InputAttributes(name="Alice"), InputAttributes(name="Eve"), InputAttributes(name="Bob")], + ) -@pytest.mark.parametrize("new_object", [ - (InputAttributes(name='Alice')), -]) +@pytest.mark.parametrize( + "new_object", + [ + (InputAttributes(name="Alice")), + ], +) def test_insert_object_empty_classlist(new_object: object, one_name_class_list: ClassList) -> None: """We should be able to insert a new object into an empty ClassList, whilst also setting _class_handle.""" class_list = ClassList() @@ -379,66 +496,95 @@ def test_insert_object_empty_classlist(new_object: object, one_name_class_list: assert isinstance(new_object, class_list._class_handle) -@pytest.mark.parametrize("new_values", [ - ({'name': 'Alice'}), -]) +@pytest.mark.parametrize( + "new_values", + [ + ({"name": "Alice"}), + ], +) def test_insert_kwargs_empty_classlist(new_values: dict[str, Any]) -> None: """If we append to an empty ClassList using keyword arguments we should raise a TypeError.""" class_list = ClassList() - with pytest.raises(TypeError, match=re.escape('ClassList.insert() called with keyword arguments for a ClassList ' - 'without a class defined. Call ClassList.insert() with an object to ' - 'define the class.')): + with pytest.raises( + TypeError, + match=re.escape( + "ClassList.insert() called with keyword arguments for a ClassList " + "without a class defined. Call ClassList.insert() with an object to " + "define the class.", + ), + ): class_list.insert(0, **new_values) -@pytest.mark.parametrize("new_object", [ - (InputAttributes(name='Alice')) -]) +@pytest.mark.parametrize( + "new_object", + [ + (InputAttributes(name="Alice")), + ], +) def test_insert_object_same_name(two_name_class_list: ClassList, new_object: object) -> None: """If we insert an object with an already-specified name_field value to a ClassList we should raise a ValueError.""" - with pytest.raises(ValueError, match=f"Input list contains objects with the same value of the " - f"{two_name_class_list.name_field} attribute"): + with pytest.raises( + ValueError, + match=f"Input list contains objects with the same value of the " f"{two_name_class_list.name_field} attribute", + ): two_name_class_list.insert(1, new_object) -@pytest.mark.parametrize("new_values", [ - ({'name': 'Alice'}) -]) +@pytest.mark.parametrize( + "new_values", + [ + ({"name": "Alice"}), + ], +) def test_insert_kwargs_same_name(two_name_class_list: ClassList, new_values: dict[str, Any]) -> None: """If we insert an object with an already-specified name_field value to a ClassList we should raise a ValueError.""" - with pytest.raises(ValueError, match=f"Input arguments contain the {two_name_class_list.name_field} " - f"'{new_values[two_name_class_list.name_field]}', " - f"which is already specified in the ClassList"): + with pytest.raises( + ValueError, + match=f"Input arguments contain the {two_name_class_list.name_field} " + f"'{new_values[two_name_class_list.name_field]}', " + f"which is already specified in the ClassList", + ): two_name_class_list.insert(1, **new_values) -@pytest.mark.parametrize("remove_value", [ - "Bob", - (InputAttributes(name='Bob')), -]) +@pytest.mark.parametrize( + "remove_value", + [ + "Bob", + (InputAttributes(name="Bob")), + ], +) def test_remove(two_name_class_list: ClassList, remove_value: Union[object, str]) -> None: """We should be able to remove an object either by the value of the name_field or by specifying the object - itself.""" + itself. + """ two_name_class_list.remove(remove_value) - assert two_name_class_list == ClassList([InputAttributes(name='Alice')]) + assert two_name_class_list == ClassList([InputAttributes(name="Alice")]) -@pytest.mark.parametrize("remove_value", [ - 'Eve', - (InputAttributes(name='Eve')), -]) +@pytest.mark.parametrize( + "remove_value", + [ + "Eve", + (InputAttributes(name="Eve")), + ], +) def test_remove_not_present(two_name_class_list: ClassList, remove_value: Union[object, str]) -> None: """If we remove an object not included in the ClassList we should raise a ValueError.""" with pytest.raises(ValueError, match=re.escape("list.remove(x): x not in list")): two_name_class_list.remove(remove_value) -@pytest.mark.parametrize(["count_value", "expected_count"], [ - ('Bob', 1), - (InputAttributes(name='Bob'), 1), - ('Eve', 0), - (InputAttributes(name='Eve'), 0), -]) +@pytest.mark.parametrize( + ["count_value", "expected_count"], + [ + ("Bob", 1), + (InputAttributes(name="Bob"), 1), + ("Eve", 0), + (InputAttributes(name="Eve"), 0), + ], +) def test_count(two_name_class_list: ClassList, count_value: Union[object, str], expected_count: int) -> None: """We should be able to determine the number of times an object is in the ClassList using either the object itself or its name_field value. @@ -446,10 +592,13 @@ def test_count(two_name_class_list: ClassList, count_value: Union[object, str], assert two_name_class_list.count(count_value) == expected_count -@pytest.mark.parametrize(["index_value", "expected_index"], [ - ('Bob', 1), - (InputAttributes(name='Bob'), 1), -]) +@pytest.mark.parametrize( + ["index_value", "expected_index"], + [ + ("Bob", 1), + (InputAttributes(name="Bob"), 1), + ], +) def test_index(two_name_class_list: ClassList, index_value: Union[object, str], expected_index: int) -> None: """We should be able to find the index of an object in the ClassList either by its name_field value or by specifying the object itself. @@ -457,21 +606,32 @@ def test_index(two_name_class_list: ClassList, index_value: Union[object, str], assert two_name_class_list.index(index_value) == expected_index -@pytest.mark.parametrize(["index_value", "offset", "expected_index"], [ - ('Bob', 1, 2), - (InputAttributes(name='Bob'), -3, -2), -]) -def test_index_offset(two_name_class_list: ClassList, index_value: Union[object, str], offset: int, - expected_index: int) -> None: +@pytest.mark.parametrize( + ["index_value", "offset", "expected_index"], + [ + ("Bob", 1, 2), + (InputAttributes(name="Bob"), -3, -2), + ], +) +def test_index_offset( + two_name_class_list: ClassList, + index_value: Union[object, str], + offset: int, + expected_index: int, +) -> None: """We should be able to find the index of an object in the ClassList either by its name_field value or by specifying the object itself. When using an offset, the value of the index should be shifted accordingly. """ assert two_name_class_list.index(index_value, offset) == expected_index -@pytest.mark.parametrize("index_value", [ - 'Eve', - (InputAttributes(name='Eve')), -]) + +@pytest.mark.parametrize( + "index_value", + [ + "Eve", + (InputAttributes(name="Eve")), + ], +) def test_index_not_present(two_name_class_list: ClassList, index_value: Union[object, str]) -> None: """If we try to find the index of an object not included in the ClassList we should raise a ValueError.""" # with pytest.raises(ValueError, match=f"'{index_value}' is not in list") as e: @@ -479,25 +639,32 @@ def test_index_not_present(two_name_class_list: ClassList, index_value: Union[ob two_name_class_list.index(index_value) -@pytest.mark.parametrize("extended_list", [ - (ClassList(InputAttributes(name='Eve'))), - ([InputAttributes(name='Eve')]), - (InputAttributes(name='Eve'),), - (InputAttributes(name='Eve')), -]) +@pytest.mark.parametrize( + "extended_list", + [ + (ClassList(InputAttributes(name="Eve"))), + ([InputAttributes(name="Eve")]), + (InputAttributes(name="Eve"),), + (InputAttributes(name="Eve")), + ], +) def test_extend(two_name_class_list: ClassList, extended_list: Sequence, three_name_class_list: ClassList) -> None: """We should be able to extend a ClassList using another ClassList or a sequence. Individual objects should be - wrapped in a list before being added.""" + wrapped in a list before being added. + """ class_list = two_name_class_list class_list.extend(extended_list) assert class_list == three_name_class_list -@pytest.mark.parametrize("extended_list", [ - (ClassList(InputAttributes(name='Alice'))), - ([InputAttributes(name='Alice')]), - (InputAttributes(name='Alice'),), -]) +@pytest.mark.parametrize( + "extended_list", + [ + (ClassList(InputAttributes(name="Alice"))), + ([InputAttributes(name="Alice")]), + (InputAttributes(name="Alice"),), + ], +) def test_extend_empty_classlist(extended_list: Sequence, one_name_class_list: ClassList) -> None: """We should be able to extend a ClassList using another ClassList or a sequence""" class_list = ClassList() @@ -506,144 +673,208 @@ def test_extend_empty_classlist(extended_list: Sequence, one_name_class_list: Cl assert isinstance(extended_list[-1], class_list._class_handle) -@pytest.mark.parametrize(["new_values", "expected_classlist"], [ - ({'name': 'Eve'}, ClassList([InputAttributes(name='Eve'), InputAttributes(name='Bob')])), - ({'name': 'John', 'surname': 'Luther'}, - ClassList([InputAttributes(name='John', surname='Luther'), InputAttributes(name='Bob')])), -]) -def test_set_fields(two_name_class_list: ClassList, new_values: dict[str, Any], expected_classlist: ClassList)\ - -> None: +@pytest.mark.parametrize( + ["new_values", "expected_classlist"], + [ + ({"name": "Eve"}, ClassList([InputAttributes(name="Eve"), InputAttributes(name="Bob")])), + ( + {"name": "John", "surname": "Luther"}, + ClassList([InputAttributes(name="John", surname="Luther"), InputAttributes(name="Bob")]), + ), + ], +) +def test_set_fields(two_name_class_list: ClassList, new_values: dict[str, Any], expected_classlist: ClassList) -> None: """We should be able to set field values in an element of a ClassList using keyword arguments.""" class_list = two_name_class_list class_list.set_fields(0, **new_values) assert class_list == expected_classlist -@pytest.mark.parametrize("new_values", [ - ({'name': 'Bob'}), -]) +@pytest.mark.parametrize( + "new_values", + [ + ({"name": "Bob"}), + ], +) def test_set_fields_same_name_field(two_name_class_list: ClassList, new_values: dict[str, Any]) -> None: """If we set the name_field of an object in the ClassList to one already defined, we should raise a ValueError.""" - with pytest.raises(ValueError, match=f"Input arguments contain the {two_name_class_list.name_field} " - f"'{new_values[two_name_class_list.name_field]}', " - f"which is already specified in the ClassList"): + with pytest.raises( + ValueError, + match=f"Input arguments contain the {two_name_class_list.name_field} " + f"'{new_values[two_name_class_list.name_field]}', " + f"which is already specified in the ClassList", + ): two_name_class_list.set_fields(0, **new_values) -@pytest.mark.parametrize(["class_list", "expected_names"], [ - (ClassList([InputAttributes(name='Alice'), InputAttributes(name='Bob')]), ["Alice", "Bob"]), - (ClassList([InputAttributes(id='Alice'), InputAttributes(id='Bob')], name_field='id'), ["Alice", "Bob"]), - (ClassList([InputAttributes(name='Alice'), InputAttributes(name='Bob')], name_field='id'), []), - (ClassList([InputAttributes(surname='Morgan'), InputAttributes(surname='Terwilliger')]), []), - (ClassList([InputAttributes(name='Alice', surname='Morgan'), InputAttributes(surname='Terwilliger')]), ["Alice"]), - (ClassList([InputAttributes(name='Alice', surname='Morgan'), InputAttributes(surname='Terwilliger')], - name_field='surname'), ["Morgan", "Terwilliger"]), - (ClassList(InputAttributes()), []), -]) +@pytest.mark.parametrize( + ["class_list", "expected_names"], + [ + (ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob")]), ["Alice", "Bob"]), + (ClassList([InputAttributes(id="Alice"), InputAttributes(id="Bob")], name_field="id"), ["Alice", "Bob"]), + (ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob")], name_field="id"), []), + (ClassList([InputAttributes(surname="Morgan"), InputAttributes(surname="Terwilliger")]), []), + ( + ClassList([InputAttributes(name="Alice", surname="Morgan"), InputAttributes(surname="Terwilliger")]), + ["Alice"], + ), + ( + ClassList( + [InputAttributes(name="Alice", surname="Morgan"), InputAttributes(surname="Terwilliger")], + name_field="surname", + ), + ["Morgan", "Terwilliger"], + ), + (ClassList(InputAttributes()), []), + ], +) def test_get_names(class_list: ClassList, expected_names: list[str]) -> None: """We should get a list of the values of the name_field attribute from each object with it defined in the - ClassList.""" + ClassList. + """ assert class_list.get_names() == expected_names -@pytest.mark.parametrize(["class_list", "expected_matches"], [ - (ClassList([InputAttributes(name='Alice'), InputAttributes(name='Bob')]), [(0, 'name')]), - (ClassList([InputAttributes(name='Alice'), InputAttributes(name='Bob', id='Alice')]), [(0, 'name'), (1, 'id')]), - (ClassList([InputAttributes(surname='Morgan'), InputAttributes(surname='Terwilliger')]), []), - (ClassList(InputAttributes()), []), -]) +@pytest.mark.parametrize( + ["class_list", "expected_matches"], + [ + (ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob")]), [(0, "name")]), + (ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob", id="Alice")]), [(0, "name"), (1, "id")]), + (ClassList([InputAttributes(surname="Morgan"), InputAttributes(surname="Terwilliger")]), []), + (ClassList(InputAttributes()), []), + ], +) def test_get_all_matches(class_list: ClassList, expected_matches: list[tuple]) -> None: """We should get a list of (index, field) tuples matching the given value in the ClassList.""" assert class_list.get_all_matches("Alice") == expected_matches -@pytest.mark.parametrize("input_dict", [ - ({'name': 'Eve'}), - ({'surname': 'Polastri'}), -]) +@pytest.mark.parametrize( + "input_dict", + [ + ({"name": "Eve"}), + ({"surname": "Polastri"}), + ], +) def test__validate_name_field(two_name_class_list: ClassList, input_dict: dict[str, Any]) -> None: """We should not raise an error if the input values do not contain a name_field value defined in an object in the - ClassList.""" + ClassList. + """ assert two_name_class_list._validate_name_field(input_dict) is None -@pytest.mark.parametrize("input_dict", [ - ({'name': 'Alice'}), -]) +@pytest.mark.parametrize( + "input_dict", + [ + ({"name": "Alice"}), + ], +) def test__validate_name_field_not_unique(two_name_class_list: ClassList, input_dict: dict[str, Any]) -> None: """We should raise a ValueError if we input values containing a name_field defined in an object in the ClassList.""" - with pytest.raises(ValueError, match=f"Input arguments contain the {two_name_class_list.name_field} " - f"'{input_dict[two_name_class_list.name_field]}', " - f"which is already specified in the ClassList"): + with pytest.raises( + ValueError, + match=f"Input arguments contain the {two_name_class_list.name_field} " + f"'{input_dict[two_name_class_list.name_field]}', " + f"which is already specified in the ClassList", + ): two_name_class_list._validate_name_field(input_dict) -@pytest.mark.parametrize("input_list", [ - ([InputAttributes(name='Alice'), InputAttributes(name='Bob')]), - ([InputAttributes(surname='Morgan'), InputAttributes(surname='Terwilliger')]), - ([InputAttributes(name='Alice', surname='Morgan'), InputAttributes(surname='Terwilliger')]), - ([InputAttributes()]), - ([]), -]) +@pytest.mark.parametrize( + "input_list", + [ + ([InputAttributes(name="Alice"), InputAttributes(name="Bob")]), + ([InputAttributes(surname="Morgan"), InputAttributes(surname="Terwilliger")]), + ([InputAttributes(name="Alice", surname="Morgan"), InputAttributes(surname="Terwilliger")]), + ([InputAttributes()]), + ([]), + ], +) def test__check_unique_name_fields(two_name_class_list: ClassList, input_list: Iterable) -> None: """We should not raise an error if an input list contains objects with different name_field values, or if the - name_field is not defined.""" + name_field is not defined. + """ assert two_name_class_list._check_unique_name_fields(input_list) is None -@pytest.mark.parametrize("input_list", [ - ([InputAttributes(name='Alice'), InputAttributes(name='Alice')]), -]) +@pytest.mark.parametrize( + "input_list", + [ + ([InputAttributes(name="Alice"), InputAttributes(name="Alice")]), + ], +) def test__check_unique_name_fields_not_unique(two_name_class_list: ClassList, input_list: Iterable) -> None: """We should raise a ValueError if an input list contains multiple objects with matching name_field values - defined.""" - with pytest.raises(ValueError, match=f"Input list contains objects with the same value of the " - f"{two_name_class_list.name_field} attribute"): + defined. + """ + with pytest.raises( + ValueError, + match=f"Input list contains objects with the same value of the " f"{two_name_class_list.name_field} attribute", + ): two_name_class_list._check_unique_name_fields(input_list) -@pytest.mark.parametrize("input_list", [ - ([InputAttributes(name='Alice'), InputAttributes(name='Bob')]), -]) +@pytest.mark.parametrize( + "input_list", + [ + ([InputAttributes(name="Alice"), InputAttributes(name="Bob")]), + ], +) def test__check_classes(input_list: Iterable) -> None: """We should not raise an error all objects in the ClassList are of the same type.""" class_list = ClassList([InputAttributes()]) assert class_list._check_classes(input_list) is None -@pytest.mark.parametrize("input_list", [ - ([InputAttributes(name='Alice'), dict(name='Bob')]), -]) +@pytest.mark.parametrize( + "input_list", + [ + ([InputAttributes(name="Alice"), dict(name="Bob")]), + ], +) def test__check_classes_different_classes(input_list: Iterable) -> None: """We should raise a ValueError if an input list contains objects of different types.""" class_list = ClassList([InputAttributes()]) - with pytest.raises(ValueError, match=(f"Input list contains elements of type other " - f"than '{class_list._class_handle.__name__}'")): + with pytest.raises( + ValueError, + match=(f"Input list contains elements of type other " f"than '{class_list._class_handle.__name__}'"), + ): class_list._check_classes(input_list) -@pytest.mark.parametrize(["value", "expected_output"], [ - ("Alice", InputAttributes(name='Alice')), - ("Eve", "Eve"), -]) -def test__get_item_from_name_field(two_name_class_list: ClassList, - value: str, - expected_output: Union[object, str]) -> None: +@pytest.mark.parametrize( + ["value", "expected_output"], + [ + ("Alice", InputAttributes(name="Alice")), + ("Eve", "Eve"), + ], +) +def test__get_item_from_name_field( + two_name_class_list: ClassList, + value: str, + expected_output: Union[object, str], +) -> None: """When we input the name_field value of an object defined in the ClassList, we should return the object. If the value is not the name_field of an object defined in the ClassList, we should return the value. """ assert two_name_class_list._get_item_from_name_field(value) == expected_output -@pytest.mark.parametrize(["input_list", "expected_type"], [ - ([InputAttributes(name='Alice')], InputAttributes), - ([InputAttributes(name='Alice'), SubInputAttributes(name='Bob')], InputAttributes), - ([SubInputAttributes(name='Alice'), InputAttributes(name='Bob')], InputAttributes), - ([SubInputAttributes(name='Alice'), SubInputAttributes(name='Bob')], SubInputAttributes), - ([SubInputAttributes(name='Alice'), SubInputAttributes(name='Bob'), InputAttributes(name='Eve')], InputAttributes), - ([InputAttributes(name='Alice'), dict(name='Bob')], InputAttributes), - ([dict(name='Alice'), InputAttributes(name='Bob')], dict), -]) +@pytest.mark.parametrize( + ["input_list", "expected_type"], + [ + ([InputAttributes(name="Alice")], InputAttributes), + ([InputAttributes(name="Alice"), SubInputAttributes(name="Bob")], InputAttributes), + ([SubInputAttributes(name="Alice"), InputAttributes(name="Bob")], InputAttributes), + ([SubInputAttributes(name="Alice"), SubInputAttributes(name="Bob")], SubInputAttributes), + ( + [SubInputAttributes(name="Alice"), SubInputAttributes(name="Bob"), InputAttributes(name="Eve")], + InputAttributes, + ), + ([InputAttributes(name="Alice"), dict(name="Bob")], InputAttributes), + ([dict(name="Alice"), InputAttributes(name="Bob")], dict), + ], +) def test_determine_class_handle(input_list: ClassList, expected_type: type) -> None: """The _class_handle for the ClassList should be the type that satisfies the condition "isinstance(element, type)" for all elements in the ClassList. diff --git a/tests/test_controls.py b/tests/test_controls.py index 27d48497..be37401d 100644 --- a/tests/test_controls.py +++ b/tests/test_controls.py @@ -1,11 +1,12 @@ """Test the controls module.""" -import pytest +from typing import Any, Union + import pydantic -from typing import Union, Any +import pytest -from RAT.controls import Calculate, Simplex, DE, NS, Dream, set_controls -from RAT.utils.enums import Parallel, Procedures, Display, BoundHandling, Strategies +from RAT.controls import DE, NS, Calculate, Dream, Simplex, set_controls +from RAT.utils.enums import BoundHandling, Display, Parallel, Procedures, Strategies class TestCalculate: @@ -15,100 +16,113 @@ class TestCalculate: def setup_class(self): self.calculate = Calculate() - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Single), - ('calcSldDuringFit', False), - ('resampleParams', [0.9, 50]), - ('display', Display.Iter), - ('procedure', Procedures.Calculate) - ]) + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Single), + ("calcSldDuringFit", False), + ("resampleParams", [0.9, 50]), + ("display", Display.Iter), + ("procedure", Procedures.Calculate), + ], + ) def test_calculate_property_values(self, control_property: str, value: Any) -> None: """Tests the default values of Calculate class.""" assert getattr(self.calculate, control_property) == value - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Points), - ('calcSldDuringFit', True), - ('resampleParams', [0.2, 1]), - ('display', Display.Notify) - ]) - def test_calculate_property_setters(self, control_property: str, value: Any) -> None: + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Points), + ("calcSldDuringFit", True), + ("resampleParams", [0.2, 1]), + ("display", Display.Notify), + ], + ) + def test_calculate_property_setters(self, control_property: str, value: Any) -> None: """Tests the setters of Calculate class.""" setattr(self.calculate, control_property, value) assert getattr(self.calculate, control_property) == value - @pytest.mark.parametrize("value", ['test', 'ALL', 'Contrast', True, 1, 3.0]) + @pytest.mark.parametrize("value", ["test", "ALL", "Contrast", True, 1, 3.0]) def test_calculate_parallel_validation(self, value: Any) -> None: """Tests the parallel setter validation in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.calculate, 'parallel', value) - assert exp.value.errors()[0]['msg'] == "Input should be 'single', 'points' or 'contrasts'" + self.calculate.parallel = value + assert exp.value.errors()[0]["msg"] == "Input should be 'single', 'points' or 'contrasts'" @pytest.mark.parametrize("value", [5.0, 12]) def test_calculate_calcSldDuringFit_validation(self, value: Union[int, float]) -> None: """Tests the calcSldDuringFit setter validation in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.calculate, 'calcSldDuringFit', value) - assert exp.value.errors()[0]['msg'] == "Input should be a valid boolean, unable to interpret input" + self.calculate.calcSldDuringFit = value + assert exp.value.errors()[0]["msg"] == "Input should be a valid boolean, unable to interpret input" - @pytest.mark.parametrize("value", ['test', 'iterate', "FINAL", True, 1, 3.0]) + @pytest.mark.parametrize("value", ["test", "iterate", "FINAL", True, 1, 3.0]) def test_calculate_display_validation(self, value: Any) -> None: """Tests the display setter validation in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.calculate, 'display', value) - assert exp.value.errors()[0]['msg'] == "Input should be 'off', 'iter', 'notify' or 'final'" - - @pytest.mark.parametrize("value, msg", [ - ([5.0], "List should have at least 2 items after validation, not 1"), - ([12, 13, 14], "List should have at most 2 items after validation, not 3") - ]) + self.calculate.display = value + assert exp.value.errors()[0]["msg"] == "Input should be 'off', 'iter', 'notify' or 'final'" + + @pytest.mark.parametrize( + "value, msg", + [ + ([5.0], "List should have at least 2 items after validation, not 1"), + ([12, 13, 14], "List should have at most 2 items after validation, not 3"), + ], + ) def test_calculate_resampleParams_length_validation(self, value: list, msg: str) -> None: """Tests the resampleParams setter length validation in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.calculate, 'resampleParams', value) - assert exp.value.errors()[0]['msg'] == msg - - @pytest.mark.parametrize("value, msg", [ - ([1.0, 2], "Value error, resampleParams[0] must be between 0 and 1"), - ([0.5, -0.1], "Value error, resampleParams[1] must be greater than or equal to 0") - ]) + self.calculate.resampleParams = value + assert exp.value.errors()[0]["msg"] == msg + + @pytest.mark.parametrize( + "value, msg", + [ + ([1.0, 2], "Value error, resampleParams[0] must be between 0 and 1"), + ([0.5, -0.1], "Value error, resampleParams[1] must be greater than or equal to 0"), + ], + ) def test_calculate_resampleParams_value_validation(self, value: list, msg: str) -> None: """Tests the resampleParams setter value validation in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.calculate, 'resampleParams', value) - assert exp.value.errors()[0]['msg'] == msg + self.calculate.resampleParams = value + assert exp.value.errors()[0]["msg"] == msg def test_calculate_extra_property_error(self) -> None: """Tests the extra property setter in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.calculate, 'test', 1) - assert exp.value.errors()[0]['msg'] == "Object has no attribute 'test'" + self.calculate.test = 1 + assert exp.value.errors()[0]["msg"] == "Object has no attribute 'test'" def test_calculate_initialise_procedure_error(self) -> None: """Tests the procedure property can only be initialised as "calculate" in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - Calculate(procedure='test') - assert exp.value.errors()[0]['msg'] == "Input should be " + Calculate(procedure="test") + assert exp.value.errors()[0]["msg"] == "Input should be " def test_calculate_set_procedure_error(self) -> None: """Tests the procedure property is frozen in Calculate class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.calculate, 'procedure', 'test') - assert exp.value.errors()[0]['msg'] == "Input should be " + self.calculate.procedure = "test" + assert exp.value.errors()[0]["msg"] == "Input should be " def test_repr(self) -> None: """Tests the Calculate model __repr__.""" table = self.calculate.__repr__() - table_str = ("+------------------+-----------+\n" - "| Property | Value |\n" - "+------------------+-----------+\n" - "| procedure | calculate |\n" - "| parallel | single |\n" - "| calcSldDuringFit | False |\n" - "| resampleParams | [0.9, 50] |\n" - "| display | iter |\n" - "+------------------+-----------+" - ) + table_str = ( + "+------------------+-----------+\n" + "| Property | Value |\n" + "+------------------+-----------+\n" + "| procedure | calculate |\n" + "| parallel | single |\n" + "| calcSldDuringFit | False |\n" + "| resampleParams | [0.9, 50] |\n" + "| display | iter |\n" + "+------------------+-----------+" + ) assert table == table_str @@ -120,89 +134,99 @@ class TestSimplex: def setup_class(self): self.simplex = Simplex() - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Single), - ('calcSldDuringFit', False), - ('resampleParams', [0.9, 50]), - ('display', Display.Iter), - ('procedure', Procedures.Simplex), - ('xTolerance', 1e-6), - ('funcTolerance', 1e-6), - ('maxFuncEvals', 10000), - ('maxIterations', 1000), - ('updateFreq', -1), - ('updatePlotFreq', 1) - ]) + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Single), + ("calcSldDuringFit", False), + ("resampleParams", [0.9, 50]), + ("display", Display.Iter), + ("procedure", Procedures.Simplex), + ("xTolerance", 1e-6), + ("funcTolerance", 1e-6), + ("maxFuncEvals", 10000), + ("maxIterations", 1000), + ("updateFreq", -1), + ("updatePlotFreq", 1), + ], + ) def test_simplex_property_values(self, control_property: str, value: Any) -> None: """Tests the default values of Simplex class.""" assert getattr(self.simplex, control_property) == value - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Points), - ('calcSldDuringFit', True), - ('resampleParams', [0.2, 1]), - ('display', Display.Notify), - ('xTolerance', 4e-6), - ('funcTolerance', 3e-4), - ('maxFuncEvals', 100), - ('maxIterations', 50), - ('updateFreq', 4), - ('updatePlotFreq', 3) - ]) - def test_simplex_property_setters(self, control_property: str, value: Any) -> None: + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Points), + ("calcSldDuringFit", True), + ("resampleParams", [0.2, 1]), + ("display", Display.Notify), + ("xTolerance", 4e-6), + ("funcTolerance", 3e-4), + ("maxFuncEvals", 100), + ("maxIterations", 50), + ("updateFreq", 4), + ("updatePlotFreq", 3), + ], + ) + def test_simplex_property_setters(self, control_property: str, value: Any) -> None: """Tests the setters of Simplex class.""" setattr(self.simplex, control_property, value) assert getattr(self.simplex, control_property) == value - @pytest.mark.parametrize("control_property, value", [ - ('xTolerance', -4e-6), - ('funcTolerance', -3e-4), - ('maxFuncEvals', -100), - ('maxIterations', -50) - ]) - def test_simplex_property_errors(self, control_property: str, value: Union[float, int]) -> None: + @pytest.mark.parametrize( + "control_property, value", + [ + ("xTolerance", -4e-6), + ("funcTolerance", -3e-4), + ("maxFuncEvals", -100), + ("maxIterations", -50), + ], + ) + def test_simplex_property_errors(self, control_property: str, value: Union[float, int]) -> None: """Tests the property errors of Simplex class.""" with pytest.raises(pydantic.ValidationError) as exp: setattr(self.simplex, control_property, value) - assert exp.value.errors()[0]['msg'] == "Input should be greater than 0" + assert exp.value.errors()[0]["msg"] == "Input should be greater than 0" def test_simplex_extra_property_error(self) -> None: """Tests the extra property setter in Simplex class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.simplex, 'test', 1) - assert exp.value.errors()[0]['msg'] == "Object has no attribute 'test'" + self.simplex.test = 1 + assert exp.value.errors()[0]["msg"] == "Object has no attribute 'test'" def test_simplex_initialise_procedure_error(self) -> None: """Tests the procedure property can only be initialised as "simplex" in Simplex class.""" with pytest.raises(pydantic.ValidationError) as exp: - Simplex(procedure='test') - assert exp.value.errors()[0]['msg'] == "Input should be " + Simplex(procedure="test") + assert exp.value.errors()[0]["msg"] == "Input should be " def test_simplex_set_procedure_error(self) -> None: """Tests the procedure property is frozen in Simplex class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.simplex, 'procedure', 'test') - assert exp.value.errors()[0]['msg'] == "Input should be " + self.simplex.procedure = "test" + assert exp.value.errors()[0]["msg"] == "Input should be " def test_repr(self) -> None: """Tests the Simplex model __repr__.""" table = self.simplex.__repr__() - table_str = ("+------------------+-----------+\n" - "| Property | Value |\n" - "+------------------+-----------+\n" - "| procedure | simplex |\n" - "| parallel | single |\n" - "| calcSldDuringFit | False |\n" - "| resampleParams | [0.9, 50] |\n" - "| display | iter |\n" - "| xTolerance | 1e-06 |\n" - "| funcTolerance | 1e-06 |\n" - "| maxFuncEvals | 10000 |\n" - "| maxIterations | 1000 |\n" - "| updateFreq | -1 |\n" - "| updatePlotFreq | 1 |\n" - "+------------------+-----------+" - ) + table_str = ( + "+------------------+-----------+\n" + "| Property | Value |\n" + "+------------------+-----------+\n" + "| procedure | simplex |\n" + "| parallel | single |\n" + "| calcSldDuringFit | False |\n" + "| resampleParams | [0.9, 50] |\n" + "| display | iter |\n" + "| xTolerance | 1e-06 |\n" + "| funcTolerance | 1e-06 |\n" + "| maxFuncEvals | 10000 |\n" + "| maxIterations | 1000 |\n" + "| updateFreq | -1 |\n" + "| updatePlotFreq | 1 |\n" + "+------------------+-----------+" + ) assert table == table_str @@ -214,103 +238,118 @@ class TestDE: def setup_class(self): self.de = DE() - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Single), - ('calcSldDuringFit', False), - ('resampleParams', [0.9, 50]), - ('display', Display.Iter), - ('procedure', Procedures.DE), - ('populationSize', 20), - ('fWeight', 0.5), - ('crossoverProbability', 0.8), - ('strategy', Strategies.RandomWithPerVectorDither), - ('targetValue', 1), - ('numGenerations', 500) - ]) + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Single), + ("calcSldDuringFit", False), + ("resampleParams", [0.9, 50]), + ("display", Display.Iter), + ("procedure", Procedures.DE), + ("populationSize", 20), + ("fWeight", 0.5), + ("crossoverProbability", 0.8), + ("strategy", Strategies.RandomWithPerVectorDither), + ("targetValue", 1), + ("numGenerations", 500), + ], + ) def test_de_property_values(self, control_property: str, value: Any) -> None: """Tests the default values of DE class.""" assert getattr(self.de, control_property) == value - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Points), - ('calcSldDuringFit', True), - ('resampleParams', [0.2, 1]), - ('display', Display.Notify), - ('populationSize', 20), - ('fWeight', 0.3), - ('crossoverProbability', 0.4), - ('strategy', Strategies.BestWithJitter), - ('targetValue', 2.0), - ('numGenerations', 50) - ]) - def test_de_property_setters(self, control_property: str, value: Any) -> None: + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Points), + ("calcSldDuringFit", True), + ("resampleParams", [0.2, 1]), + ("display", Display.Notify), + ("populationSize", 20), + ("fWeight", 0.3), + ("crossoverProbability", 0.4), + ("strategy", Strategies.BestWithJitter), + ("targetValue", 2.0), + ("numGenerations", 50), + ], + ) + def test_de_property_setters(self, control_property: str, value: Any) -> None: """Tests the setters of DE class.""" setattr(self.de, control_property, value) assert getattr(self.de, control_property) == value - @pytest.mark.parametrize("value, msg", [ - (0, "Input should be greater than 0"), - (2, "Input should be less than 1") - ]) - def test_de_crossoverProbability_error(self, value: int, msg: str) -> None: + @pytest.mark.parametrize( + "value, msg", + [ + (0, "Input should be greater than 0"), + (2, "Input should be less than 1"), + ], + ) + def test_de_crossoverProbability_error(self, value: int, msg: str) -> None: """Tests the crossoverProbability setter error in DE class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.de, 'crossoverProbability', value) - assert exp.value.errors()[0]['msg'] == msg - - @pytest.mark.parametrize("control_property, value", [ - ('targetValue', 0), - ('targetValue', 0.999), - ('numGenerations', -500), - ('numGenerations', 0), - ('populationSize', 0), - ('populationSize', -1) - ]) - def test_de_targetValue_numGenerations_populationSize_error(self, - control_property: str, - value: Union[int, float]) -> None: + self.de.crossoverProbability = value + assert exp.value.errors()[0]["msg"] == msg + + @pytest.mark.parametrize( + "control_property, value", + [ + ("targetValue", 0), + ("targetValue", 0.999), + ("numGenerations", -500), + ("numGenerations", 0), + ("populationSize", 0), + ("populationSize", -1), + ], + ) + def test_de_targetValue_numGenerations_populationSize_error( + self, + control_property: str, + value: Union[int, float], + ) -> None: """Tests the targetValue, numGenerations, populationSize setter error in DE class.""" with pytest.raises(pydantic.ValidationError) as exp: setattr(self.de, control_property, value) - assert exp.value.errors()[0]['msg'] == "Input should be greater than or equal to 1" + assert exp.value.errors()[0]["msg"] == "Input should be greater than or equal to 1" def test_de_extra_property_error(self) -> None: """Tests the extra property setter in DE class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.de, 'test', 1) - assert exp.value.errors()[0]['msg'] == "Object has no attribute 'test'" + self.de.test = 1 + assert exp.value.errors()[0]["msg"] == "Object has no attribute 'test'" def test_de_initialise_procedure_error(self) -> None: """Tests the procedure property can only be initialised as "de" in DE class.""" with pytest.raises(pydantic.ValidationError) as exp: - DE(procedure='test') - assert exp.value.errors()[0]['msg'] == "Input should be " + DE(procedure="test") + assert exp.value.errors()[0]["msg"] == "Input should be " def test_de_set_procedure_error(self) -> None: """Tests the procedure property is frozen in DE class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.de, 'procedure', 'test') - assert exp.value.errors()[0]['msg'] == "Input should be " + self.de.procedure = "test" + assert exp.value.errors()[0]["msg"] == "Input should be " def test_repr(self) -> None: """Tests the DE model __repr__.""" table = self.de.__repr__() - table_str = ("+----------------------+--------------------------------------+\n" - "| Property | Value |\n" - "+----------------------+--------------------------------------+\n" - "| procedure | de |\n" - "| parallel | single |\n" - "| calcSldDuringFit | False |\n" - "| resampleParams | [0.9, 50] |\n" - "| display | iter |\n" - "| populationSize | 20 |\n" - "| fWeight | 0.5 |\n" - "| crossoverProbability | 0.8 |\n" - "| strategy | Strategies.RandomWithPerVectorDither |\n" - "| targetValue | 1.0 |\n" - "| numGenerations | 500 |\n" - "+----------------------+--------------------------------------+" - ) + table_str = ( + "+----------------------+--------------------------------------+\n" + "| Property | Value |\n" + "+----------------------+--------------------------------------+\n" + "| procedure | de |\n" + "| parallel | single |\n" + "| calcSldDuringFit | False |\n" + "| resampleParams | [0.9, 50] |\n" + "| display | iter |\n" + "| populationSize | 20 |\n" + "| fWeight | 0.5 |\n" + "| crossoverProbability | 0.8 |\n" + "| strategy | Strategies.RandomWithPerVectorDither |\n" + "| targetValue | 1.0 |\n" + "| numGenerations | 500 |\n" + "+----------------------+--------------------------------------+" + ) assert table == table_str @@ -322,92 +361,105 @@ class TestNS: def setup_class(self): self.ns = NS() - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Single), - ('calcSldDuringFit', False), - ('resampleParams', [0.9, 50]), - ('display', Display.Iter), - ('procedure', Procedures.NS), - ('nLive', 150), - ('nMCMC', 0), - ('propScale', 0.1), - ('nsTolerance', 0.1) - ]) + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Single), + ("calcSldDuringFit", False), + ("resampleParams", [0.9, 50]), + ("display", Display.Iter), + ("procedure", Procedures.NS), + ("nLive", 150), + ("nMCMC", 0), + ("propScale", 0.1), + ("nsTolerance", 0.1), + ], + ) def test_ns_property_values(self, control_property: str, value: Any) -> None: """Tests the default values of NS class.""" assert getattr(self.ns, control_property) == value - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Points), - ('calcSldDuringFit', True), - ('resampleParams', [0.2, 1]), - ('display', Display.Notify), - ('nLive', 1500), - ('nMCMC', 1), - ('propScale', 0.5), - ('nsTolerance', 0.8) - ]) - def test_ns_property_setters(self, control_property: str, value: Any) -> None: + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Points), + ("calcSldDuringFit", True), + ("resampleParams", [0.2, 1]), + ("display", Display.Notify), + ("nLive", 1500), + ("nMCMC", 1), + ("propScale", 0.5), + ("nsTolerance", 0.8), + ], + ) + def test_ns_property_setters(self, control_property: str, value: Any) -> None: """Tests the setters of NS class.""" setattr(self.ns, control_property, value) assert getattr(self.ns, control_property) == value - @pytest.mark.parametrize("control_property, value, bound", [ - ('nMCMC', -0.6, 0), - ('nsTolerance', -500, 0), - ('nLive', -500, 1) - ]) + @pytest.mark.parametrize( + "control_property, value, bound", + [ + ("nMCMC", -0.6, 0), + ("nsTolerance", -500, 0), + ("nLive", -500, 1), + ], + ) def test_ns_setter_error(self, control_property: str, value: Union[int, float], bound: int) -> None: """Tests the nMCMC, nsTolerance, nLive setter error in NS class.""" with pytest.raises(pydantic.ValidationError) as exp: setattr(self.ns, control_property, value) - assert exp.value.errors()[0]['msg'] == f"Input should be greater than or equal to {bound}" - - @pytest.mark.parametrize("value, msg", [ - (0, "Input should be greater than 0"), - (2, "Input should be less than 1") - ]) - def test_ns_propScale_error(self, value: int, msg: str) -> None: + assert exp.value.errors()[0]["msg"] == f"Input should be greater than or equal to {bound}" + + @pytest.mark.parametrize( + "value, msg", + [ + (0, "Input should be greater than 0"), + (2, "Input should be less than 1"), + ], + ) + def test_ns_propScale_error(self, value: int, msg: str) -> None: """Tests the propScale error in NS class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.ns, 'propScale', value) - assert exp.value.errors()[0]['msg'] == msg + self.ns.propScale = value + assert exp.value.errors()[0]["msg"] == msg def test_ns_extra_property_error(self) -> None: """Tests the extra property setter in NS class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.ns, 'test', 1) - assert exp.value.errors()[0]['msg'] == "Object has no attribute 'test'" + self.ns.test = 1 + assert exp.value.errors()[0]["msg"] == "Object has no attribute 'test'" def test_ns_initialise_procedure_error(self) -> None: """Tests the procedure property can only be initialised as "ns" in NS class.""" with pytest.raises(pydantic.ValidationError) as exp: - NS(procedure='test') - assert exp.value.errors()[0]['msg'] == "Input should be " + NS(procedure="test") + assert exp.value.errors()[0]["msg"] == "Input should be " def test_ns_procedure_error(self) -> None: """Tests the procedure property is frozen in NS class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.ns, 'procedure', 'test') - assert exp.value.errors()[0]['msg'] == "Input should be " + self.ns.procedure = "test" + assert exp.value.errors()[0]["msg"] == "Input should be " def test_control_class_ns_repr(self) -> None: """Tests the NS model __repr__.""" table = self.ns.__repr__() - table_str = ("+------------------+-----------+\n" - "| Property | Value |\n" - "+------------------+-----------+\n" - "| procedure | ns |\n" - "| parallel | single |\n" - "| calcSldDuringFit | False |\n" - "| resampleParams | [0.9, 50] |\n" - "| display | iter |\n" - "| nLive | 150 |\n" - "| nMCMC | 0.0 |\n" - "| propScale | 0.1 |\n" - "| nsTolerance | 0.1 |\n" - "+------------------+-----------+" - ) + table_str = ( + "+------------------+-----------+\n" + "| Property | Value |\n" + "+------------------+-----------+\n" + "| procedure | ns |\n" + "| parallel | single |\n" + "| calcSldDuringFit | False |\n" + "| resampleParams | [0.9, 50] |\n" + "| display | iter |\n" + "| nLive | 150 |\n" + "| nMCMC | 0.0 |\n" + "| propScale | 0.1 |\n" + "| nsTolerance | 0.1 |\n" + "+------------------+-----------+" + ) assert table == table_str @@ -419,111 +471,125 @@ class TestDream: def setup_class(self): self.dream = Dream() - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Single), - ('calcSldDuringFit', False), - ('resampleParams', [0.9, 50]), - ('display', Display.Iter), - ('procedure', Procedures.Dream), - ('nSamples', 50000), - ('nChains', 10), - ('jumpProbability', 0.5), - ('pUnitGamma', 0.2), - ('boundHandling', BoundHandling.Fold) - ]) + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Single), + ("calcSldDuringFit", False), + ("resampleParams", [0.9, 50]), + ("display", Display.Iter), + ("procedure", Procedures.Dream), + ("nSamples", 50000), + ("nChains", 10), + ("jumpProbability", 0.5), + ("pUnitGamma", 0.2), + ("boundHandling", BoundHandling.Fold), + ], + ) def test_dream_property_values(self, control_property: str, value: Any) -> None: """Tests the default values of Dream class.""" assert getattr(self.dream, control_property) == value - @pytest.mark.parametrize("control_property, value", [ - ('parallel', Parallel.Points), - ('calcSldDuringFit', True), - ('resampleParams', [0.2, 1]), - ('display', Display.Notify), - ('nSamples', 500), - ('nChains', 1000), - ('jumpProbability', 0.7), - ('pUnitGamma', 0.3), - ('boundHandling', BoundHandling.Reflect) - ]) - def test_dream_property_setters(self, control_property: str, value: Any) -> None: + @pytest.mark.parametrize( + "control_property, value", + [ + ("parallel", Parallel.Points), + ("calcSldDuringFit", True), + ("resampleParams", [0.2, 1]), + ("display", Display.Notify), + ("nSamples", 500), + ("nChains", 1000), + ("jumpProbability", 0.7), + ("pUnitGamma", 0.3), + ("boundHandling", BoundHandling.Reflect), + ], + ) + def test_dream_property_setters(self, control_property: str, value: Any) -> None: """Tests the setters in Dream class.""" setattr(self.dream, control_property, value) assert getattr(self.dream, control_property) == value - @pytest.mark.parametrize("control_property, value, msg", [ - ('jumpProbability', 0, "Input should be greater than 0"), - ('jumpProbability', 2, "Input should be less than 1"), - ('pUnitGamma', -5, "Input should be greater than 0"), - ('pUnitGamma', 20, "Input should be less than 1") - ]) + @pytest.mark.parametrize( + "control_property, value, msg", + [ + ("jumpProbability", 0, "Input should be greater than 0"), + ("jumpProbability", 2, "Input should be less than 1"), + ("pUnitGamma", -5, "Input should be greater than 0"), + ("pUnitGamma", 20, "Input should be less than 1"), + ], + ) def test_dream_jumpProbability_pUnitGamma_error(self, control_property: str, value: int, msg: str) -> None: """Tests the jumpProbability and pUnitGamma setter errors in Dream class.""" with pytest.raises(pydantic.ValidationError) as exp: setattr(self.dream, control_property, value) - assert exp.value.errors()[0]['msg'] == msg + assert exp.value.errors()[0]["msg"] == msg @pytest.mark.parametrize("value", [-80, -2]) def test_dream_nSamples_error(self, value: int) -> None: """Tests the nSamples setter error in Dream class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.dream, 'nSamples', value) - assert exp.value.errors()[0]['msg'] == "Input should be greater than or equal to 0" + self.dream.nSamples = value + assert exp.value.errors()[0]["msg"] == "Input should be greater than or equal to 0" @pytest.mark.parametrize("value", [-5, 0]) def test_dream_nChains_error(self, value: int) -> None: """Tests the nChains setter error in Dream class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.dream, 'nChains', value) - assert exp.value.errors()[0]['msg'] == "Input should be greater than 0" + self.dream.nChains = value + assert exp.value.errors()[0]["msg"] == "Input should be greater than 0" def test_dream_extra_property_error(self) -> None: """Tests the extra property setter in Dream class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.dream, 'test', 1) - assert exp.value.errors()[0]['msg'] == "Object has no attribute 'test'" + self.dream.test = 1 + assert exp.value.errors()[0]["msg"] == "Object has no attribute 'test'" def test_dream_initialise_procedure_error(self) -> None: """Tests the procedure property can only be initialised as "dream" in Dream class.""" with pytest.raises(pydantic.ValidationError) as exp: - Dream(procedure='test') - assert exp.value.errors()[0]['msg'] == "Input should be " + Dream(procedure="test") + assert exp.value.errors()[0]["msg"] == "Input should be " def test_dream_procedure_error(self) -> None: """Tests the procedure property is frozen in Dream class.""" with pytest.raises(pydantic.ValidationError) as exp: - setattr(self.dream, 'procedure', 'test') - assert exp.value.errors()[0]['msg'] == "Input should be " + self.dream.procedure = "test" + assert exp.value.errors()[0]["msg"] == "Input should be " def test_control_class_dream_repr(self) -> None: """Tests the Dream model __repr__.""" table = self.dream.__repr__() - table_str = ("+------------------+-----------+\n" - "| Property | Value |\n" - "+------------------+-----------+\n" - "| procedure | dream |\n" - "| parallel | single |\n" - "| calcSldDuringFit | False |\n" - "| resampleParams | [0.9, 50] |\n" - "| display | iter |\n" - "| nSamples | 50000 |\n" - "| nChains | 10 |\n" - "| jumpProbability | 0.5 |\n" - "| pUnitGamma | 0.2 |\n" - "| boundHandling | fold |\n" - "| adaptPCR | False |\n" - "+------------------+-----------+" - ) + table_str = ( + "+------------------+-----------+\n" + "| Property | Value |\n" + "+------------------+-----------+\n" + "| procedure | dream |\n" + "| parallel | single |\n" + "| calcSldDuringFit | False |\n" + "| resampleParams | [0.9, 50] |\n" + "| display | iter |\n" + "| nSamples | 50000 |\n" + "| nChains | 10 |\n" + "| jumpProbability | 0.5 |\n" + "| pUnitGamma | 0.2 |\n" + "| boundHandling | fold |\n" + "| adaptPCR | False |\n" + "+------------------+-----------+" + ) assert table == table_str -@pytest.mark.parametrize(["procedure", "expected_model"], [ - ('calculate', Calculate), - ('simplex', Simplex), - ('de', DE), - ('ns', NS), - ('dream', Dream) -]) + +@pytest.mark.parametrize( + ["procedure", "expected_model"], + [ + ("calculate", Calculate), + ("simplex", Simplex), + ("de", DE), + ("ns", NS), + ("dream", Dream), + ], +) def test_set_controls(procedure: Procedures, expected_model: Union[Calculate, Simplex, DE, NS, Dream]) -> None: """We should return the correct model given the value of procedure.""" controls_model = set_controls(procedure) @@ -538,25 +604,35 @@ def test_set_controls_default_procedure() -> None: def test_set_controls_invalid_procedure() -> None: """We should return the default model when we call "set_controls" without specifying a procedure.""" - with pytest.raises(ValueError, match="The controls procedure must be one of: 'calculate', 'simplex', 'de', 'ns' " - "or 'dream'"): - set_controls('invalid') - - -@pytest.mark.parametrize(["procedure", "expected_model"], [ - ('calculate', Calculate), - ('simplex', Simplex), - ('de', DE), - ('ns', NS), - ('dream', Dream) -]) -def test_set_controls_extra_fields(procedure: Procedures, expected_model: Union[Calculate, Simplex, DE, NS, Dream])\ - -> None: + with pytest.raises( + ValueError, + match="The controls procedure must be one of: 'calculate', 'simplex', 'de', 'ns' " "or 'dream'", + ): + set_controls("invalid") + + +@pytest.mark.parametrize( + ["procedure", "expected_model"], + [ + ("calculate", Calculate), + ("simplex", Simplex), + ("de", DE), + ("ns", NS), + ("dream", Dream), + ], +) +def test_set_controls_extra_fields( + procedure: Procedures, + expected_model: Union[Calculate, Simplex, DE, NS, Dream], +) -> None: """If we provide extra fields to a controls model through "set_controls", we should print a formatted ValidationError with a custom error message. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for {expected_model.__name__}\n' - f'extra_field\n Extra inputs are not permitted. The fields for ' - f'the {procedure} controls procedure are:\n ' - f'{", ".join(expected_model.model_fields.keys())}\n'): - set_controls(procedure, extra_field='invalid') + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for {expected_model.__name__}\n' + f'extra_field\n Extra inputs are not permitted. The fields for ' + f'the {procedure} controls procedure are:\n ' + f'{", ".join(expected_model.model_fields.keys())}\n', + ): + set_controls(procedure, extra_field="invalid") diff --git a/tests/test_custom_errors.py b/tests/test_custom_errors.py index 6c8bdabb..a96cbf37 100644 --- a/tests/test_custom_errors.py +++ b/tests/test_custom_errors.py @@ -1,37 +1,49 @@ """Test the utils.custom_errors module.""" -from pydantic import create_model, ValidationError -import pytest + import re +import pytest +from pydantic import ValidationError, create_model + import RAT.utils.custom_errors @pytest.fixture def TestModel(): """Create a custom pydantic model for the tests.""" - TestModel = create_model('TestModel', int_field=(int, 1), str_field=(str, 'a'), __config__={'extra': 'forbid'}) + TestModel = create_model("TestModel", int_field=(int, 1), str_field=(str, "a"), __config__={"extra": "forbid"}) return TestModel -@pytest.mark.parametrize(["custom_errors", "expected_error_message"], [ - ({}, - "2 validation errors for TestModel\nint_field\n Input should be a valid integer, unable to parse string as an " - "integer [type=int_parsing, input_value='string', input_type=str]\nstr_field\n Input should be a valid string " - "[type=string_type, input_value=5, input_type=int]"), - ({'int_parsing': 'This is a custom error message', 'string_type': 'This is another custom error message'}, - "2 validation errors for TestModel\nint_field\n This is a custom error message [type=int_parsing, " - "input_value='string', input_type=str]\nstr_field\n This is another custom error message [type=string_type, " - "input_value=5, input_type=int]"), -]) -def test_custom_pydantic_validation_error(TestModel, custom_errors: dict[str, str], expected_error_message: str - ) -> None: +@pytest.mark.parametrize( + ["custom_errors", "expected_error_message"], + [ + ( + {}, + "2 validation errors for TestModel\nint_field\n Input should be a valid integer, unable to parse string " + "as an integer [type=int_parsing, input_value='string', input_type=str]\nstr_field\n Input should be a " + "valid string [type=string_type, input_value=5, input_type=int]", + ), + ( + {"int_parsing": "This is a custom error message", "string_type": "This is another custom error message"}, + "2 validation errors for TestModel\nint_field\n This is a custom error message [type=int_parsing, " + "input_value='string', input_type=str]\nstr_field\n This is another custom error message " + "[type=string_type, input_value=5, input_type=int]", + ), + ], +) +def test_custom_pydantic_validation_error( + TestModel, + custom_errors: dict[str, str], + expected_error_message: str, +) -> None: """When we call custom_pydantic_validation_error with custom errors, we should return an error list containing PydanticCustomErrors, otherwise we return the original set of errors. """ try: - TestModel(int_field='string', str_field=5) + TestModel(int_field="string", str_field=5) except ValidationError as exc: custom_error_list = RAT.utils.custom_errors.custom_pydantic_validation_error(exc.errors(), custom_errors) with pytest.raises(ValidationError, match=re.escape(expected_error_message)): - raise ValidationError.from_exception_data('TestModel', custom_error_list) + raise ValidationError.from_exception_data("TestModel", custom_error_list) diff --git a/tests/test_events.py b/tests/test_events.py index 11c336c2..3f2ac881 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -1,9 +1,11 @@ -import unittest.mock as mock +from unittest import mock + import pytest + import RAT.events -@pytest.mark.skip +@pytest.mark.skip() def test_event_register() -> None: first_callback = mock.Mock() second_callback = mock.Mock() @@ -27,7 +29,7 @@ def test_event_register() -> None: assert RAT.events.get_event_callback(RAT.events.EventTypes.Message) == [] -@pytest.mark.skip +@pytest.mark.skip() def test_event_notify() -> None: first_callback = mock.Mock() second_callback = mock.Mock() @@ -35,7 +37,7 @@ def test_event_notify() -> None: RAT.events.register(RAT.events.EventTypes.Message, first_callback) RAT.events.register(RAT.events.EventTypes.Plot, second_callback) RAT.events.register(RAT.events.EventTypes.Progress, third_callback) - + RAT.events.notify(RAT.events.EventTypes.Message, "Hello World") first_callback.assert_called_once_with("Hello World") second_callback.assert_not_called() @@ -50,7 +52,7 @@ def test_event_notify() -> None: first_callback.assert_called_once() second_callback.assert_called_once() third_callback.assert_called_once_with(data) - + RAT.events.clear() RAT.events.notify(RAT.events.EventTypes.Message, "Hello World") RAT.events.notify(RAT.events.EventTypes.Plot, data) diff --git a/tests/test_inputs.py b/tests/test_inputs.py index 3e9469a4..286a84f3 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -1,52 +1,93 @@ """Test the inputs module.""" +import pathlib from itertools import chain +from unittest import mock + import numpy as np -import pathlib import pytest -import unittest.mock as mock import RAT -from RAT.inputs import make_input, make_problem, make_cells, make_controls, check_indices -from RAT.utils.enums import (BoundHandling, Calculations, Display, Geometries, LayerModels, Parallel, Procedures, - TypeOptions) import RAT.wrappers -from tests.utils import dummy_function - +from RAT.inputs import check_indices, make_cells, make_controls, make_input, make_problem from RAT.rat_core import Cells, Checks, Control, Limits, Priors, ProblemDefinition +from RAT.utils.enums import ( + BoundHandling, + Calculations, + Display, + Geometries, + LayerModels, + Parallel, + Procedures, + TypeOptions, +) +from tests.utils import dummy_function @pytest.fixture def standard_layers_project(): """Add parameters to the default project for a non polarised calculation.""" - test_project = RAT.Project(data=RAT.ClassList([RAT.models.Data(name='Test Data', data=np.array([[1.0, 1.0, 1.0]]))])) - test_project.parameters.append(name='Test Thickness') - test_project.parameters.append(name='Test SLD') - test_project.parameters.append(name='Test Roughness') - test_project.custom_files.append(name='Test Custom File', filename='python_test.py', function_name='dummy_function', - language='python') - test_project.layers.append(name='Test Layer', thickness='Test Thickness', SLD='Test SLD', roughness='Test Roughness') - test_project.contrasts.append(name='Test Contrast', data='Test Data', background='Background 1', bulk_in='SLD Air', - bulk_out='SLD D2O', scalefactor='Scalefactor 1', resolution='Resolution 1', - model=['Test Layer']) + test_project = RAT.Project( + data=RAT.ClassList([RAT.models.Data(name="Test Data", data=np.array([[1.0, 1.0, 1.0]]))]), + ) + test_project.parameters.append(name="Test Thickness") + test_project.parameters.append(name="Test SLD") + test_project.parameters.append(name="Test Roughness") + test_project.custom_files.append( + name="Test Custom File", + filename="python_test.py", + function_name="dummy_function", + language="python", + ) + test_project.layers.append( + name="Test Layer", + thickness="Test Thickness", + SLD="Test SLD", + roughness="Test Roughness", + ) + test_project.contrasts.append( + name="Test Contrast", + data="Test Data", + background="Background 1", + bulk_in="SLD Air", + bulk_out="SLD D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + model=["Test Layer"], + ) return test_project @pytest.fixture def domains_project(): """Add parameters to the default project for a domains calculation.""" - test_project = RAT.Project(calculation=Calculations.Domains, - data=RAT.ClassList([RAT.models.Data(name='Test Data', data=np.array([[1.0, 1.0, 1.0]]))])) - test_project.parameters.append(name='Test Thickness') - test_project.parameters.append(name='Test SLD') - test_project.parameters.append(name='Test Roughness') - test_project.custom_files.append(name='Test Custom File', filename='matlab_test.m', language='matlab') - test_project.layers.append(name='Test Layer', thickness='Test Thickness', SLD='Test SLD', roughness='Test Roughness') - test_project.domain_contrasts.append(name='up', model=['Test Layer']) - test_project.domain_contrasts.append(name='down', model=['Test Layer']) - test_project.contrasts.append(name='Test Contrast', data='Test Data', background='Background 1', bulk_in='SLD Air', - bulk_out='SLD D2O', scalefactor='Scalefactor 1', resolution='Resolution 1', - domain_ratio='Domain Ratio 1', model=['down', 'up']) + test_project = RAT.Project( + calculation=Calculations.Domains, + data=RAT.ClassList([RAT.models.Data(name="Test Data", data=np.array([[1.0, 1.0, 1.0]]))]), + ) + test_project.parameters.append(name="Test Thickness") + test_project.parameters.append(name="Test SLD") + test_project.parameters.append(name="Test Roughness") + test_project.custom_files.append(name="Test Custom File", filename="matlab_test.m", language="matlab") + test_project.layers.append( + name="Test Layer", + thickness="Test Thickness", + SLD="Test SLD", + roughness="Test Roughness", + ) + test_project.domain_contrasts.append(name="up", model=["Test Layer"]) + test_project.domain_contrasts.append(name="down", model=["Test Layer"]) + test_project.contrasts.append( + name="Test Contrast", + data="Test Data", + background="Background 1", + bulk_in="SLD Air", + bulk_out="SLD D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + domain_ratio="Domain Ratio 1", + model=["down", "up"], + ) return test_project @@ -54,13 +95,20 @@ def domains_project(): def custom_xy_project(): """Add parameters to the default project for a non polarised calculation and use the custom xy model.""" test_project = RAT.Project(model=LayerModels.CustomXY) - test_project.parameters.append(name='Test Thickness') - test_project.parameters.append(name='Test SLD') - test_project.parameters.append(name='Test Roughness') - test_project.custom_files.append(name='Test Custom File', filename='cpp_test.dll', language='cpp') - test_project.contrasts.append(name='Test Contrast', data='Simulation', background='Background 1', bulk_in='SLD Air', - bulk_out='SLD D2O', scalefactor='Scalefactor 1', resolution='Resolution 1', - model=['Test Custom File']) + test_project.parameters.append(name="Test Thickness") + test_project.parameters.append(name="Test SLD") + test_project.parameters.append(name="Test Roughness") + test_project.custom_files.append(name="Test Custom File", filename="cpp_test.dll", language="cpp") + test_project.contrasts.append( + name="Test Contrast", + data="Simulation", + background="Background 1", + bulk_in="SLD Air", + bulk_out="SLD D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + model=["Test Custom File"], + ) return test_project @@ -87,7 +135,7 @@ def standard_layers_problem(): problem.contrastBackgroundParams = [1] problem.contrastBackgroundActions = [1] problem.contrastResolutionParams = [1] - problem.contrastCustomFiles = [float('NaN')] + problem.contrastCustomFiles = [float("NaN")] problem.contrastDomainRatios = [0] problem.resample = [False] problem.dataPresent = [1] @@ -98,8 +146,16 @@ def standard_layers_problem(): problem.fitParams = [3.0] problem.otherParams = [0.0, 0.0, 0.0, 1e-06, 0.23, 0.0, 6.35e-06, 0.03] problem.fitLimits = [[1.0, 5.0]] - problem.otherLimits = [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [1e-07, 1e-05], [0.02, 0.25], [0.0, 0.0], - [6.2e-06, 6.35e-06], [0.01, 0.05]] + problem.otherLimits = [ + [0.0, 0.0], + [0.0, 0.0], + [0.0, 0.0], + [1e-07, 1e-05], + [0.02, 0.25], + [0.0, 0.0], + [6.2e-06, 6.35e-06], + [0.01, 0.05], + ] return problem @@ -127,7 +183,7 @@ def domains_problem(): problem.contrastBackgroundParams = [1] problem.contrastBackgroundActions = [1] problem.contrastResolutionParams = [1] - problem.contrastCustomFiles = [float('NaN')] + problem.contrastCustomFiles = [float("NaN")] problem.contrastDomainRatios = [1] problem.resample = [False] problem.dataPresent = [1] @@ -138,8 +194,17 @@ def domains_problem(): problem.fitParams = [3.0] problem.otherParams = [0.0, 0.0, 0.0, 1e-06, 0.23, 0.0, 6.35e-06, 0.03, 0.5] problem.fitLimits = [[1.0, 5.0]] - problem.otherLimits = [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [1e-07, 1e-05], [0.02, 0.25], [0.0, 0.0], - [6.2e-06, 6.35e-06], [0.01, 0.05], [0.4, 0.6]] + problem.otherLimits = [ + [0.0, 0.0], + [0.0, 0.0], + [0.0, 0.0], + [1e-07, 1e-05], + [0.02, 0.25], + [0.0, 0.0], + [6.2e-06, 6.35e-06], + [0.01, 0.05], + [0.4, 0.6], + ] return problem @@ -178,8 +243,16 @@ def custom_xy_problem(): problem.fitParams = [3.0] problem.otherParams = [0.0, 0.0, 0.0, 1e-06, 0.23, 0.0, 6.35e-06, 0.03] problem.fitLimits = [[1.0, 5.0]] - problem.otherLimits = [[0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [1e-07, 1e-05], [0.02, 0.25], [0.0, 0.0], - [6.2e-06, 6.35e-06], [0.01, 0.05]] + problem.otherLimits = [ + [0.0, 0.0], + [0.0, 0.0], + [0.0, 0.0], + [1e-07, 1e-05], + [0.02, 0.25], + [0.0, 0.0], + [6.2e-06, 6.35e-06], + [0.01, 0.05], + ] return problem @@ -193,14 +266,14 @@ def standard_layers_cells(): cells.f3 = [[1.0, 1.0]] cells.f4 = [[1.0, 1.0]] cells.f5 = [[1]] - cells.f6 = [[2, 3, 4, float('nan'), 2]] - cells.f7 = ['Substrate Roughness', 'Test Thickness', 'Test SLD', 'Test Roughness'] - cells.f8 = ['Background Param 1'] - cells.f9 = ['Scalefactor 1'] + cells.f6 = [[2, 3, 4, float("nan"), 2]] + cells.f7 = ["Substrate Roughness", "Test Thickness", "Test SLD", "Test Roughness"] + cells.f8 = ["Background Param 1"] + cells.f9 = ["Scalefactor 1"] cells.f10 = [] - cells.f11 = ['SLD Air'] - cells.f12 = ['SLD D2O'] - cells.f13 = ['Resolution Param 1'] + cells.f11 = ["SLD Air"] + cells.f12 = ["SLD D2O"] + cells.f13 = ["Resolution Param 1"] cells.f14 = [dummy_function] cells.f15 = [TypeOptions.Constant] cells.f16 = [TypeOptions.Constant] @@ -221,21 +294,21 @@ def domains_cells(): cells.f3 = [[1.0, 1.0]] cells.f4 = [[1.0, 1.0]] cells.f5 = [[2, 1]] - cells.f6 = [[2, 3, 4, float('nan'), 2]] - cells.f7 = ['Substrate Roughness', 'Test Thickness', 'Test SLD', 'Test Roughness'] - cells.f8 = ['Background Param 1'] - cells.f9 = ['Scalefactor 1'] + cells.f6 = [[2, 3, 4, float("nan"), 2]] + cells.f7 = ["Substrate Roughness", "Test Thickness", "Test SLD", "Test Roughness"] + cells.f8 = ["Background Param 1"] + cells.f9 = ["Scalefactor 1"] cells.f10 = [] - cells.f11 = ['SLD Air'] - cells.f12 = ['SLD D2O'] - cells.f13 = ['Resolution Param 1'] + cells.f11 = ["SLD Air"] + cells.f12 = ["SLD D2O"] + cells.f13 = ["Resolution Param 1"] cells.f14 = [dummy_function] cells.f15 = [TypeOptions.Constant] cells.f16 = [TypeOptions.Constant] cells.f17 = [[[]]] cells.f18 = [[0, 1], [0, 1]] cells.f19 = [[1], [1]] - cells.f20 = ['Domain Ratio 1'] + cells.f20 = ["Domain Ratio 1"] return cells @@ -250,13 +323,13 @@ def custom_xy_cells(): cells.f4 = [[0.005, 0.7]] cells.f5 = [[0]] cells.f6 = [[0]] - cells.f7 = ['Substrate Roughness', 'Test Thickness', 'Test SLD', 'Test Roughness'] - cells.f8 = ['Background Param 1'] - cells.f9 = ['Scalefactor 1'] + cells.f7 = ["Substrate Roughness", "Test Thickness", "Test SLD", "Test Roughness"] + cells.f8 = ["Background Param 1"] + cells.f9 = ["Scalefactor 1"] cells.f10 = [] - cells.f11 = ['SLD Air'] - cells.f12 = ['SLD D2O'] - cells.f13 = ['Resolution Param 1'] + cells.f11 = ["SLD Air"] + cells.f12 = ["SLD D2O"] + cells.f13 = ["Resolution Param 1"] cells.f14 = [dummy_function] cells.f15 = [TypeOptions.Constant] cells.f16 = [TypeOptions.Constant] @@ -304,21 +377,41 @@ def domains_limits(): def non_polarised_priors(): """The expected priors object from "standard_layers_project" and "custom_xy_project".""" priors = Priors() - priors.param = [['Substrate Roughness', RAT.utils.enums.Priors.Uniform, 0.0, np.inf], - ['Test Thickness', RAT.utils.enums.Priors.Uniform, 0.0, np.inf], - ['Test SLD', RAT.utils.enums.Priors.Uniform, 0.0, np.inf], - ['Test Roughness', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.backgroundParam = [['Background Param 1', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.param = [ + ["Substrate Roughness", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ["Test Thickness", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ["Test SLD", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ["Test Roughness", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ] + priors.backgroundParam = [["Background Param 1", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] priors.qzshift = [] - priors.scalefactor = [['Scalefactor 1', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkIn = [['SLD Air', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkOut = [['SLD D2O', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.resolutionParam = [['Resolution Param 1', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.scalefactor = [["Scalefactor 1", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.bulkIn = [["SLD Air", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.bulkOut = [["SLD D2O", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.resolutionParam = [["Resolution Param 1", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] priors.domainRatio = [] - priors.priorNames = ['Substrate Roughness', 'Test Thickness', 'Test SLD', 'Test Roughness', 'Background Param 1', - 'Scalefactor 1', 'SLD Air', 'SLD D2O', 'Resolution Param 1'] - priors.priorValues = [[1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], - [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf]] + priors.priorNames = [ + "Substrate Roughness", + "Test Thickness", + "Test SLD", + "Test Roughness", + "Background Param 1", + "Scalefactor 1", + "SLD Air", + "SLD D2O", + "Resolution Param 1", + ] + priors.priorValues = [ + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + ] return priors @@ -327,21 +420,43 @@ def non_polarised_priors(): def domains_priors(): """The expected priors object from "domains_project".""" priors = Priors() - priors.param = [['Substrate Roughness', RAT.utils.enums.Priors.Uniform, 0.0, np.inf], - ['Test Thickness', RAT.utils.enums.Priors.Uniform, 0.0, np.inf], - ['Test SLD', RAT.utils.enums.Priors.Uniform, 0.0, np.inf], - ['Test Roughness', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.backgroundParam = [['Background Param 1', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.param = [ + ["Substrate Roughness", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ["Test Thickness", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ["Test SLD", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ["Test Roughness", RAT.utils.enums.Priors.Uniform, 0.0, np.inf], + ] + priors.backgroundParam = [["Background Param 1", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] priors.qzshift = [] - priors.scalefactor = [['Scalefactor 1', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkIn = [['SLD Air', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkOut = [['SLD D2O', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.resolutionParam = [['Resolution Param 1', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.domainRatio = [['Domain Ratio 1', RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.priorNames = ['Substrate Roughness', 'Test Thickness', 'Test SLD', 'Test Roughness', 'Background Param 1', - 'Scalefactor 1', 'SLD Air', 'SLD D2O', 'Resolution Param 1', 'Domain Ratio 1'] - priors.priorValues = [[1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], - [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf]] + priors.scalefactor = [["Scalefactor 1", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.bulkIn = [["SLD Air", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.bulkOut = [["SLD D2O", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.resolutionParam = [["Resolution Param 1", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.domainRatio = [["Domain Ratio 1", RAT.utils.enums.Priors.Uniform, 0.0, np.inf]] + priors.priorNames = [ + "Substrate Roughness", + "Test Thickness", + "Test SLD", + "Test Roughness", + "Background Param 1", + "Scalefactor 1", + "SLD Air", + "SLD D2O", + "Resolution Param 1", + "Domain Ratio 1", + ] + priors.priorValues = [ + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + [1, 0.0, np.inf], + ] return priors @@ -392,7 +507,8 @@ def standard_layers_controls(): @pytest.fixture def custom_xy_controls(): - """The expected controls object for input to the compiled RAT code given the default inputs and "custom_xy_project". + """The expected controls object for input to the compiled RAT code given the default inputs and + "custom_xy_project". """ controls = Control() controls.procedure = Procedures.Calculate @@ -449,14 +565,35 @@ def test_checks(): return checks -@pytest.mark.parametrize(["test_project", "test_problem", "test_cells", "test_limits", "test_priors", "test_controls"], [ - ("standard_layers_project", "standard_layers_problem", "standard_layers_cells", "non_polarised_limits", - "non_polarised_priors", "standard_layers_controls"), - ("custom_xy_project", "custom_xy_problem", "custom_xy_cells", "non_polarised_limits", "non_polarised_priors", - "custom_xy_controls"), - ("domains_project", "domains_problem", "domains_cells", "domains_limits", "domains_priors", - "standard_layers_controls"), -]) +@pytest.mark.parametrize( + ["test_project", "test_problem", "test_cells", "test_limits", "test_priors", "test_controls"], + [ + ( + "standard_layers_project", + "standard_layers_problem", + "standard_layers_cells", + "non_polarised_limits", + "non_polarised_priors", + "standard_layers_controls", + ), + ( + "custom_xy_project", + "custom_xy_problem", + "custom_xy_cells", + "non_polarised_limits", + "non_polarised_priors", + "custom_xy_controls", + ), + ( + "domains_project", + "domains_problem", + "domains_cells", + "domains_limits", + "domains_priors", + "standard_layers_controls", + ), + ], +) def test_make_input(test_project, test_problem, test_cells, test_limits, test_priors, test_controls, request) -> None: """When converting the "project" and "controls", we should obtain the five input objects required for the compiled RAT code. @@ -468,19 +605,33 @@ def test_make_input(test_project, test_problem, test_cells, test_limits, test_pr test_priors = request.getfixturevalue(test_priors) test_controls = request.getfixturevalue(test_controls) - parameter_fields = ["param", "backgroundParam", "scalefactor", "qzshift", "bulkIn", "bulkOut", "resolutionParam", - "domainRatio"] + parameter_fields = [ + "param", + "backgroundParam", + "scalefactor", + "qzshift", + "bulkIn", + "bulkOut", + "resolutionParam", + "domainRatio", + ] mocked_matlab_module = mock.MagicMock() mocked_engine = mock.MagicMock() mocked_matlab_module.engine.start_matlab.return_value = mocked_engine - with mock.patch.dict('sys.modules', {'matlab': mocked_matlab_module, - 'matlab.engine': mocked_matlab_module.engine}), \ - mock.patch.object(RAT.rat_core, "DylibEngine", mock.MagicMock()), \ - mock.patch.object(RAT.inputs, "get_python_handle", mock.MagicMock(return_value=dummy_function)), \ - mock.patch.object(RAT.wrappers.MatlabWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)), \ - mock.patch.object(RAT.wrappers.DylibWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)): + with mock.patch.dict( + "sys.modules", + {"matlab": mocked_matlab_module, "matlab.engine": mocked_matlab_module.engine}, + ), mock.patch.object(RAT.rat_core, "DylibEngine", mock.MagicMock()), mock.patch.object( + RAT.inputs, + "get_python_handle", + mock.MagicMock(return_value=dummy_function), + ), mock.patch.object( + RAT.wrappers.MatlabWrapper, + "getHandle", + mock.MagicMock(return_value=dummy_function), + ), mock.patch.object(RAT.wrappers.DylibWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)): problem, cells, limits, priors, controls = make_input(test_project, RAT.set_controls()) check_problem_equal(problem, test_problem) @@ -498,11 +649,14 @@ def test_make_input(test_project, test_problem, test_cells, test_limits, test_pr check_controls_equal(controls, test_controls) -@pytest.mark.parametrize(["test_project", "test_problem"], [ - ("standard_layers_project", "standard_layers_problem"), - ("custom_xy_project", "custom_xy_problem"), - ("domains_project", "domains_problem"), -]) +@pytest.mark.parametrize( + ["test_project", "test_problem"], + [ + ("standard_layers_project", "standard_layers_problem"), + ("custom_xy_project", "custom_xy_problem"), + ("domains_project", "domains_problem"), + ], +) def test_make_problem(test_project, test_problem, request) -> None: """The problem object should contain the relevant parameters defined in the input project object.""" test_project = request.getfixturevalue(test_project) @@ -512,11 +666,14 @@ def test_make_problem(test_project, test_problem, request) -> None: check_problem_equal(problem, test_problem) -@pytest.mark.parametrize("test_problem", [ - "standard_layers_problem", - "custom_xy_problem", - "domains_problem", -]) +@pytest.mark.parametrize( + "test_problem", + [ + "standard_layers_problem", + "custom_xy_problem", + "domains_problem", + ], +) def test_check_indices(test_problem, request) -> None: """The check_indices routine should not raise errors for a properly defined ProblemDefinition object.""" test_problem = request.getfixturevalue(test_problem) @@ -524,64 +681,75 @@ def test_check_indices(test_problem, request) -> None: check_indices(test_problem) -@pytest.mark.parametrize(["test_problem", "index_list", "bad_value"], [ - ("standard_layers_problem", "contrastBulkIns", [0.0]), - ("standard_layers_problem", "contrastBulkIns", [2.0]), - ("standard_layers_problem", "contrastBulkOuts", [0.0]), - ("standard_layers_problem", "contrastBulkOuts", [2.0]), - ("standard_layers_problem", "contrastScalefactors", [0.0]), - ("standard_layers_problem", "contrastScalefactors", [2.0]), - ("standard_layers_problem", "contrastBackgroundParams", [0.0]), - ("standard_layers_problem", "contrastBackgroundParams", [2.0]), - ("standard_layers_problem", "contrastResolutionParams", [0.0]), - ("standard_layers_problem", "contrastResolutionParams", [2.0]), - ("custom_xy_problem", "contrastBulkIns", [0.0]), - ("custom_xy_problem", "contrastBulkIns", [2.0]), - ("custom_xy_problem", "contrastBulkOuts", [0.0]), - ("custom_xy_problem", "contrastBulkOuts", [2.0]), - ("custom_xy_problem", "contrastScalefactors", [0.0]), - ("custom_xy_problem", "contrastScalefactors", [2.0]), - ("custom_xy_problem", "contrastBackgroundParams", [0.0]), - ("custom_xy_problem", "contrastBackgroundParams", [2.0]), - ("custom_xy_problem", "contrastResolutionParams", [0.0]), - ("custom_xy_problem", "contrastResolutionParams", [2.0]), - ("domains_problem", "contrastBulkIns", [0.0]), - ("domains_problem", "contrastBulkIns", [2.0]), - ("domains_problem", "contrastBulkOuts", [0.0]), - ("domains_problem", "contrastBulkOuts", [2.0]), - ("domains_problem", "contrastScalefactors", [0.0]), - ("domains_problem", "contrastScalefactors", [2.0]), - ("domains_problem", "contrastDomainRatios", [0.0]), - ("domains_problem", "contrastDomainRatios", [2.0]), - ("domains_problem", "contrastBackgroundParams", [0.0]), - ("domains_problem", "contrastBackgroundParams", [2.0]), - ("domains_problem", "contrastResolutionParams", [0.0]), - ("domains_problem", "contrastResolutionParams", [2.0]), -]) -def test_check_indices(test_problem, index_list, bad_value, request) -> None: +@pytest.mark.parametrize( + ["test_problem", "index_list", "bad_value"], + [ + ("standard_layers_problem", "contrastBulkIns", [0.0]), + ("standard_layers_problem", "contrastBulkIns", [2.0]), + ("standard_layers_problem", "contrastBulkOuts", [0.0]), + ("standard_layers_problem", "contrastBulkOuts", [2.0]), + ("standard_layers_problem", "contrastScalefactors", [0.0]), + ("standard_layers_problem", "contrastScalefactors", [2.0]), + ("standard_layers_problem", "contrastBackgroundParams", [0.0]), + ("standard_layers_problem", "contrastBackgroundParams", [2.0]), + ("standard_layers_problem", "contrastResolutionParams", [0.0]), + ("standard_layers_problem", "contrastResolutionParams", [2.0]), + ("custom_xy_problem", "contrastBulkIns", [0.0]), + ("custom_xy_problem", "contrastBulkIns", [2.0]), + ("custom_xy_problem", "contrastBulkOuts", [0.0]), + ("custom_xy_problem", "contrastBulkOuts", [2.0]), + ("custom_xy_problem", "contrastScalefactors", [0.0]), + ("custom_xy_problem", "contrastScalefactors", [2.0]), + ("custom_xy_problem", "contrastBackgroundParams", [0.0]), + ("custom_xy_problem", "contrastBackgroundParams", [2.0]), + ("custom_xy_problem", "contrastResolutionParams", [0.0]), + ("custom_xy_problem", "contrastResolutionParams", [2.0]), + ("domains_problem", "contrastBulkIns", [0.0]), + ("domains_problem", "contrastBulkIns", [2.0]), + ("domains_problem", "contrastBulkOuts", [0.0]), + ("domains_problem", "contrastBulkOuts", [2.0]), + ("domains_problem", "contrastScalefactors", [0.0]), + ("domains_problem", "contrastScalefactors", [2.0]), + ("domains_problem", "contrastDomainRatios", [0.0]), + ("domains_problem", "contrastDomainRatios", [2.0]), + ("domains_problem", "contrastBackgroundParams", [0.0]), + ("domains_problem", "contrastBackgroundParams", [2.0]), + ("domains_problem", "contrastResolutionParams", [0.0]), + ("domains_problem", "contrastResolutionParams", [2.0]), + ], +) +def test_check_indices_error(test_problem, index_list, bad_value, request) -> None: """The check_indices routine should raise an IndexError if a contrast list contains an index that is out of the - range of the corresponding parameter list in a ProblemDefinition object.""" - param_list = {'contrastBulkIns': 'bulkIn', - 'contrastBulkOuts': 'bulkOut', - 'contrastScalefactors': 'scalefactors', - 'contrastDomainRatios': 'domainRatio', - 'contrastBackgroundParams': 'backgroundParams', - 'contrastResolutionParams': 'resolutionParams', - } + range of the corresponding parameter list in a ProblemDefinition object. + """ + param_list = { + "contrastBulkIns": "bulkIn", + "contrastBulkOuts": "bulkOut", + "contrastScalefactors": "scalefactors", + "contrastDomainRatios": "domainRatio", + "contrastBackgroundParams": "backgroundParams", + "contrastResolutionParams": "resolutionParams", + } test_problem = request.getfixturevalue(test_problem) setattr(test_problem, index_list, bad_value) - with pytest.raises(IndexError, match=f'The problem field "{index_list}" contains: {bad_value[0]}, which lie ' - f'outside of the range of "{param_list[index_list]}"'): + with pytest.raises( + IndexError, + match=f'The problem field "{index_list}" contains: {bad_value[0]}, which lie ' + f'outside of the range of "{param_list[index_list]}"', + ): check_indices(test_problem) -@pytest.mark.parametrize(["test_project", "test_cells"], [ - ("standard_layers_project", "standard_layers_cells"), - ("custom_xy_project", "custom_xy_cells"), - ("domains_project", "domains_cells"), -]) +@pytest.mark.parametrize( + ["test_project", "test_cells"], + [ + ("standard_layers_project", "standard_layers_cells"), + ("custom_xy_project", "custom_xy_cells"), + ("domains_project", "domains_cells"), + ], +) def test_make_cells(test_project, test_cells, request) -> None: """The cells object should be populated according to the input project object.""" test_project = request.getfixturevalue(test_project) @@ -591,12 +759,18 @@ def test_make_cells(test_project, test_cells, request) -> None: mocked_matlab_engine = mock.MagicMock() mocked_matlab_module.engine.start_matlab.return_value = mocked_matlab_engine - with mock.patch.dict('sys.modules', {'matlab': mocked_matlab_module, - 'matlab.engine': mocked_matlab_module.engine}), \ - mock.patch.object(RAT.rat_core, "DylibEngine", mock.MagicMock()), \ - mock.patch.object(RAT.inputs, "get_python_handle", mock.MagicMock(return_value=dummy_function)), \ - mock.patch.object(RAT.wrappers.MatlabWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)), \ - mock.patch.object(RAT.wrappers.DylibWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)): + with mock.patch.dict( + "sys.modules", + {"matlab": mocked_matlab_module, "matlab.engine": mocked_matlab_module.engine}, + ), mock.patch.object(RAT.rat_core, "DylibEngine", mock.MagicMock()), mock.patch.object( + RAT.inputs, + "get_python_handle", + mock.MagicMock(return_value=dummy_function), + ), mock.patch.object( + RAT.wrappers.MatlabWrapper, + "getHandle", + mock.MagicMock(return_value=dummy_function), + ), mock.patch.object(RAT.wrappers.DylibWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)): cells = make_cells(test_project) check_cells_equal(cells, test_cells) @@ -617,14 +791,41 @@ def test_make_controls(standard_layers_controls, test_checks) -> None: def check_problem_equal(actual_problem, expected_problem) -> None: """Compare two instances of the "problem" object for equality.""" - scalar_fields = ["TF", "modelType", "geometry", "useImaginary", "numberOfContrasts", "numberOfLayers", - "numberOfDomainContrasts"] - - array_fields = ["params", "backgroundParams", "qzshifts", "scalefactors", "bulkIn", "bulkOut", "resolutionParams", - "domainRatio", "contrastBackgroundParams", "contrastBackgroundActions", "contrastQzshifts", - "contrastScalefactors", "contrastBulkIns", "contrastBulkOuts", "contrastResolutionParams", - "contrastDomainRatios", "resample", "dataPresent", "oilChiDataPresent", "fitParams", "otherParams", - "fitLimits", "otherLimits"] + scalar_fields = [ + "TF", + "modelType", + "geometry", + "useImaginary", + "numberOfContrasts", + "numberOfLayers", + "numberOfDomainContrasts", + ] + + array_fields = [ + "params", + "backgroundParams", + "qzshifts", + "scalefactors", + "bulkIn", + "bulkOut", + "resolutionParams", + "domainRatio", + "contrastBackgroundParams", + "contrastBackgroundActions", + "contrastQzshifts", + "contrastScalefactors", + "contrastBulkIns", + "contrastBulkOuts", + "contrastResolutionParams", + "contrastDomainRatios", + "resample", + "dataPresent", + "oilChiDataPresent", + "fitParams", + "otherParams", + "fitLimits", + "otherLimits", + ] for scalar_field in scalar_fields: assert getattr(actual_problem, scalar_field) == getattr(expected_problem, scalar_field) @@ -632,12 +833,9 @@ def check_problem_equal(actual_problem, expected_problem) -> None: assert (getattr(actual_problem, array_field) == getattr(expected_problem, array_field)).all() # Need to account for "NaN" entries in contrastCustomFiles field - assert ((actual_problem.contrastCustomFiles == expected_problem.contrastCustomFiles).all() or - ['NaN' if np.isnan(el) else el for el in actual_problem.contrastCustomFiles] == - ['NaN' if np.isnan(el) else el for el in expected_problem.contrastCustomFiles] - ) - - return None + assert (actual_problem.contrastCustomFiles == expected_problem.contrastCustomFiles).all() or [ + "NaN" if np.isnan(el) else el for el in actual_problem.contrastCustomFiles + ] == ["NaN" if np.isnan(el) else el for el in expected_problem.contrastCustomFiles] def check_cells_equal(actual_cells, expected_cells) -> None: @@ -645,30 +843,59 @@ def check_cells_equal(actual_cells, expected_cells) -> None: assert actual_cells.f1 == expected_cells.f1 # Need to test equality of the numpy arrays separately - for (a, b) in zip(actual_cells.f2, expected_cells.f2): + for a, b in zip(actual_cells.f2, expected_cells.f2): assert (a == b).all() # f6 may contain "NaN" values, so consider separately - assert (actual_cells.f6 == expected_cells.f6 or - ['NaN' if np.isnan(el) else el for entry in actual_cells.f6 for el in entry] == - ['NaN' if np.isnan(el) else el for entry in expected_cells.f6 for el in entry]) + assert actual_cells.f6 == expected_cells.f6 or [ + "NaN" if np.isnan(el) else el for entry in actual_cells.f6 for el in entry + ] == ["NaN" if np.isnan(el) else el for entry in expected_cells.f6 for el in entry] for index in chain(range(3, 6), range(7, 21)): field = f"f{index}" assert getattr(actual_cells, field) == getattr(expected_cells, field) - return None - def check_controls_equal(actual_controls, expected_controls) -> None: """Compare two instances of the "controls" object used as input for the compiled RAT code for equality.""" - controls_fields = ["procedure", "parallel", "calcSldDuringFit", "display", "xTolerance", - "funcTolerance", "maxFuncEvals", "maxIterations", "updateFreq", "updatePlotFreq", - "populationSize", "fWeight", "crossoverProbability", "strategy", "targetValue", "numGenerations", - "nLive", "nMCMC", "propScale", "nsTolerance", "nSamples", "nChains", "jumpProbability", - "pUnitGamma", "boundHandling", "adaptPCR"] - checks_fields = ["fitParam", "fitBackgroundParam", "fitQzshift", "fitScalefactor", "fitBulkIn", "fitBulkOut", - "fitResolutionParam", "fitDomainRatio"] + controls_fields = [ + "procedure", + "parallel", + "calcSldDuringFit", + "display", + "xTolerance", + "funcTolerance", + "maxFuncEvals", + "maxIterations", + "updateFreq", + "updatePlotFreq", + "populationSize", + "fWeight", + "crossoverProbability", + "strategy", + "targetValue", + "numGenerations", + "nLive", + "nMCMC", + "propScale", + "nsTolerance", + "nSamples", + "nChains", + "jumpProbability", + "pUnitGamma", + "boundHandling", + "adaptPCR", + ] + checks_fields = [ + "fitParam", + "fitBackgroundParam", + "fitQzshift", + "fitScalefactor", + "fitBulkIn", + "fitBulkOut", + "fitResolutionParam", + "fitDomainRatio", + ] # Check "resampleParams" separately as it is an array assert (actual_controls.resampleParams == expected_controls.resampleParams).all() @@ -676,5 +903,3 @@ def check_controls_equal(actual_controls, expected_controls) -> None: assert getattr(actual_controls, field) == getattr(expected_controls, field) for field in checks_fields: assert (getattr(actual_controls.checks, field) == getattr(expected_controls.checks, field)).all() - - return None diff --git a/tests/test_models.py b/tests/test_models.py index 94fd795f..657868f8 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,31 +1,35 @@ """Test the pydantic models.""" +import re +from typing import Callable + import numpy as np import pydantic import pytest -import re -from typing import Callable import RAT.models -@pytest.mark.parametrize(["model", "model_name", "model_params"], [ - (RAT.models.Background, "Background", {}), - (RAT.models.Contrast, "Contrast", {}), - (RAT.models.CustomFile, "Custom File", {}), - (RAT.models.Data, "Data", {}), - (RAT.models.DomainContrast, "Domain Contrast", {}), - (RAT.models.Layer, "Layer", {'thickness': 'Test Thickness', 'SLD': 'Test SLD', 'roughness': 'Test Roughness'}), - (RAT.models.Parameter, "Parameter", {}), - (RAT.models.Resolution, "Resolution", {}), -]) +@pytest.mark.parametrize( + ["model", "model_name", "model_params"], + [ + (RAT.models.Background, "Background", {}), + (RAT.models.Contrast, "Contrast", {}), + (RAT.models.CustomFile, "Custom File", {}), + (RAT.models.Data, "Data", {}), + (RAT.models.DomainContrast, "Domain Contrast", {}), + (RAT.models.Layer, "Layer", {"thickness": "Test Thickness", "SLD": "Test SLD", "roughness": "Test Roughness"}), + (RAT.models.Parameter, "Parameter", {}), + (RAT.models.Resolution, "Resolution", {}), + ], +) def test_default_names(model: Callable, model_name: str, model_params: dict) -> None: """When initialising multiple models without specifying a name, they should be given a default name with the format: "New ". """ model_1 = model(**model_params) model_2 = model(**model_params) - model_3 = model(name='Given Name', **model_params) + model_3 = model(name="Given Name", **model_params) model_4 = model(**model_params) assert model_1.name == f"New {model_name} 1" @@ -34,39 +38,61 @@ def test_default_names(model: Callable, model_name: str, model_params: dict) -> assert model_4.name == f"New {model_name} 3" -@pytest.mark.parametrize(["model", "model_params"], [ - (RAT.models.Background, {}), - (RAT.models.Contrast, {}), - (RAT.models.ContrastWithRatio, {}), - (RAT.models.CustomFile, {}), - (RAT.models.Data, {}), - (RAT.models.DomainContrast, {}), - (RAT.models.Layer, {'thickness': 'Test Thickness', 'SLD': 'Test SLD', 'roughness': 'Test Roughness'}), - (RAT.models.AbsorptionLayer, {'thickness': 'Test Thickness', 'SLD_real': 'Test SLD', 'SLD_imaginary': 'Test SLD', - 'roughness': 'Test Roughness'}), - (RAT.models.Parameter, {}), - (RAT.models.Resolution, {}), -]) -class TestModels(object): +@pytest.mark.parametrize( + ["model", "model_params"], + [ + (RAT.models.Background, {}), + (RAT.models.Contrast, {}), + (RAT.models.ContrastWithRatio, {}), + (RAT.models.CustomFile, {}), + (RAT.models.Data, {}), + (RAT.models.DomainContrast, {}), + (RAT.models.Layer, {"thickness": "Test Thickness", "SLD": "Test SLD", "roughness": "Test Roughness"}), + ( + RAT.models.AbsorptionLayer, + { + "thickness": "Test Thickness", + "SLD_real": "Test SLD", + "SLD_imaginary": "Test SLD", + "roughness": "Test Roughness", + }, + ), + (RAT.models.Parameter, {}), + (RAT.models.Resolution, {}), + ], +) +class TestModels: def test_initialise_with_wrong_type(self, model: Callable, model_params: dict) -> None: """When initialising a model with the wrong type for the "name" field, we should raise a ValidationError.""" - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for {model.__name__}\nname\n Input should be a valid string'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for {model.__name__}\nname\n " f"Input should be a valid string", + ): model(name=1, **model_params) def test_assignment_with_wrong_type(self, model: Callable, model_params: dict) -> None: """When assigning the "name" field of a model with the wrong type, we should raise a ValidationError.""" test_model = model(**model_params) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for {model.__name__}\nname\n Input should be a valid string'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for {model.__name__}\nname\n " f"Input should be a valid string", + ): test_model.name = 1 def test_initialise_with_zero_length_name(self, model: Callable, model_params: dict) -> None: """When initialising a model with a zero length name, we should raise a ValidationError.""" - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for {model.__name__}\nname\n String should have at least 1 character'): - model(name='', **model_params) + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for {model.__name__}\nname\n " f"String should have at least 1 character", + ): + model(name="", **model_params) def test_initialise_with_extra_fields(self, model: Callable, model_params: dict) -> None: """When initialising a model with unspecified fields, we should raise a ValidationError.""" - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for {model.__name__}\nnew_field\n Extra inputs are not permitted'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for {model.__name__}\nnew_field\n " f"Extra inputs are not permitted", + ): model(new_field=1, **model_params) @@ -74,12 +100,15 @@ def test_data_eq() -> None: """If we use the Data.__eq__ method with an object that is not a pydantic BaseModel, we should return "NotImplemented". """ - assert RAT.models.Data().__eq__('data') == NotImplemented + assert RAT.models.Data().__eq__("data") == NotImplemented -@pytest.mark.parametrize("input_data", [ - (np.array([[1.0, 1.0, 1.0]])), -]) +@pytest.mark.parametrize( + "input_data", + [ + (np.array([[1.0, 1.0, 1.0]])), + ], +) def test_data_dimension(input_data: np.ndarray[float]) -> None: """The "data" field of the "Data" model should be a two-dimensional numpy array with at least three values in the second dimension. @@ -88,81 +117,113 @@ def test_data_dimension(input_data: np.ndarray[float]) -> None: assert (test_data.data == input_data).all() -@pytest.mark.parametrize("input_data", [ - (np.array([])), - (np.array([1.0, 1.0])), -]) +@pytest.mark.parametrize( + "input_data", + [ + (np.array([])), + (np.array([1.0, 1.0])), + ], +) def test_data_too_few_dimensions(input_data: np.ndarray[float]) -> None: - """If the "data" field of the "Data" model is not a two-dimensional numpy array we should raise a ValidationError. + """If the "data" field of the "Data" model is not a two-dimensional numpy array we should raise a + ValidationError. """ - with pytest.raises(pydantic.ValidationError, match='1 validation error for Data\ndata\n Value error, "data" must ' - 'have at least two dimensions'): + with pytest.raises( + pydantic.ValidationError, + match='1 validation error for Data\ndata\n Value error, "data" must ' "have at least two dimensions", + ): RAT.models.Data(data=input_data) -@pytest.mark.parametrize("input_data", [ - (np.array([[]])), - (np.array([[1.0]])), - (np.array([[1.0, 1.0]])), -]) +@pytest.mark.parametrize( + "input_data", + [ + (np.array([[]])), + (np.array([[1.0]])), + (np.array([[1.0, 1.0]])), + ], +) def test_data_too_few_values(input_data: np.ndarray[float]) -> None: """If the second dimension of the array in the "data" field of the "Data" model has fewer than three values we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match='1 validation error for Data\ndata\n Value error, "data" must ' - 'have at least three columns'): + with pytest.raises( + pydantic.ValidationError, + match='1 validation error for Data\ndata\n Value error, "data" must ' "have at least three columns", + ): RAT.models.Data(data=input_data) -@pytest.mark.parametrize("input_range", [ - ([1.0, 2.0]), -]) +@pytest.mark.parametrize( + "input_range", + [ + ([1.0, 2.0]), + ], +) def test_data_ranges(input_range: list[float]) -> None: """The "data_range" and "simulation_range" fields of the "Data" model should contain exactly two values.""" assert RAT.models.Data(data_range=input_range).data_range == input_range assert RAT.models.Data(simulation_range=input_range).simulation_range == input_range -@pytest.mark.parametrize("input_range", [ - ([]), - ([1.0]), - ([1.0, 2.0, 3.0]), -]) +@pytest.mark.parametrize( + "input_range", + [ + ([]), + ([1.0]), + ([1.0, 2.0, 3.0]), + ], +) def test_two_values_in_data_range(input_range: list[float]) -> None: """If the "data_range" field of the "Data" model contains more or less than two values, we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Data\ndata_range\n List should have ' - f'at {"least" if len(input_range) < 2 else "most"} 2 items ' - f'after validation, not {len(input_range)}'): + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Data\ndata_range\n List should have ' + f'at {"least" if len(input_range) < 2 else "most"} 2 items ' + f'after validation, not {len(input_range)}', + ): RAT.models.Data(data_range=input_range) -@pytest.mark.parametrize("input_range", [ - ([]), - ([1.0]), - ([1.0, 2.0, 3.0]), -]) +@pytest.mark.parametrize( + "input_range", + [ + ([]), + ([1.0]), + ([1.0, 2.0, 3.0]), + ], +) def test_two_values_in_simulation_range(input_range: list[float]) -> None: """If the "simulation_range" field of the "Data" model contains more or less than two values, we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Data\nsimulation_range\n List should ' - f'have at {"least" if len(input_range) < 2 else "most"} 2 items ' - f'after validation, not {len(input_range)}'): + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Data\nsimulation_range\n List should ' + f'have at {"least" if len(input_range) < 2 else "most"} 2 items ' + f'after validation, not {len(input_range)}', + ): RAT.models.Data(simulation_range=input_range) -@pytest.mark.parametrize("field", [ - 'data_range', - 'simulation_range' -]) +@pytest.mark.parametrize( + "field", + [ + "data_range", + "simulation_range", + ], +) def test_min_max_in_range(field: str) -> None: """If the maximum value of the "data_range" or "simulation_range" fields of the "Data" model is greater than the minimum value, we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Data\n{field}\n Value error, {field} ' - f'"min" value is greater than the "max" value'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Data\n{field}\n Value error, {field} " + f'"min" value is greater than the "max" value', + ): RAT.models.Data(**{field: [1.0, 0.0]}) @@ -175,47 +236,69 @@ def test_default_ranges() -> None: assert test_data.simulation_range == [1.0, 3.0] -@pytest.mark.parametrize("test_range", [ - [0.0, 2.0], - [2.0, 4.0], - [0.0, 4.0], -]) +@pytest.mark.parametrize( + "test_range", + [ + [0.0, 2.0], + [2.0, 4.0], + [0.0, 4.0], + ], +) def test_data_range(test_range) -> None: """If "data" is specified but the "data_range" lies outside of the limits of the data we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=re.escape(f'1 validation error for Data\n Value error, The ' - f'data_range value of: {test_range} must lie within ' - f'the min/max values of the data: [1.0, 3.0]')): + with pytest.raises( + pydantic.ValidationError, + match=re.escape( + f"1 validation error for Data\n Value error, The " + f"data_range value of: {test_range} must lie within " + f"the min/max values of the data: [1.0, 3.0]", + ), + ): RAT.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]]), data_range=test_range) -@pytest.mark.parametrize("test_range", [ - [0.0, 2.0], - [2.0, 4.0], - [1.5, 2.5], -]) +@pytest.mark.parametrize( + "test_range", + [ + [0.0, 2.0], + [2.0, 4.0], + [1.5, 2.5], + ], +) def test_simulation_range(test_range) -> None: """If "data" is specified but the "simulation_range" lies within the limits of the data we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=re.escape(f'1 validation error for Data\n Value error, The ' - f'simulation_range value of: {test_range} must lie ' - f'outside of the min/max values of the data: ' - f'[1.0, 3.0]')): + with pytest.raises( + pydantic.ValidationError, + match=re.escape( + f"1 validation error for Data\n Value error, The " + f"simulation_range value of: {test_range} must lie " + f"outside of the min/max values of the data: " + f"[1.0, 3.0]", + ), + ): RAT.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]]), simulation_range=test_range) -@pytest.mark.parametrize(["minimum", "value", "maximum"], [ - (0.0, 2.0, 1.0), - (0, 1, 0), - (1, -1, 1), -]) +@pytest.mark.parametrize( + ["minimum", "value", "maximum"], + [ + (0.0, 2.0, 1.0), + (0, 1, 0), + (1, -1, 1), + ], +) def test_parameter_range(minimum: float, value: float, maximum: float) -> None: """For the "Parameter" model, if the value of the "value" field does not lie with the values given in the "min" and "max" fields, we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Parameter\n Value error, value ' - f'{float(value)} is not within the defined range: ' - f'{float(minimum)} <= value <= {float(maximum)}'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Parameter\n Value error, value " + f"{float(value)} is not within the defined range: " + f"{float(minimum)} <= value <= {float(maximum)}", + ): RAT.models.Parameter(min=minimum, value=value, max=maximum) diff --git a/tests/test_outputs.py b/tests/test_outputs.py index f5e79417..ef08f302 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -1,5 +1,4 @@ -""" -Test the outputs module using the example calculation from "DSPC_standard_layers.py". +"""Test the outputs module using the example calculation from "DSPC_standard_layers.py". We use the example for both a reflectivity calculation, and Bayesian analysis using the Dream algorithm. """ @@ -10,14 +9,16 @@ import RAT.outputs import RAT.rat_core from RAT.utils.enums import Procedures - from tests.utils import check_results_equal -@pytest.mark.parametrize(["test_procedure", "test_output_results", "test_bayes", "test_results"], [ - (Procedures.Calculate, "reflectivity_calculation_output_results", None, "reflectivity_calculation_results"), - (Procedures.Dream, "dream_output_results", "dream_bayes", "dream_results"), -]) +@pytest.mark.parametrize( + ["test_procedure", "test_output_results", "test_bayes", "test_results"], + [ + (Procedures.Calculate, "reflectivity_calculation_output_results", None, "reflectivity_calculation_results"), + (Procedures.Dream, "dream_output_results", "dream_bayes", "dream_results"), + ], +) def test_make_results(test_procedure, test_output_results, test_bayes, test_results, request) -> None: """The python results object should contain the relevant parameters defined in the C++ results and bayes objects.""" test_output_results = request.getfixturevalue(test_output_results) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index f3980a2b..95e03ffd 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -1,53 +1,46 @@ import os -import re -import pytest import pickle -from unittest.mock import patch -from unittest.mock import MagicMock +import re +from unittest.mock import MagicMock, patch + import matplotlib.pyplot as plt +import pytest + from RAT.rat_core import PlotEventData from RAT.utils.plotting import Figure, plot_ref_sld_helper - -TEST_DIR_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), - 'test_data') +TEST_DIR_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data") def data() -> PlotEventData: - """ - Creates the fixture for the tests. - """ - data_path = os.path.join(TEST_DIR_PATH, 'plotting_data.pickle') - with open(data_path, 'rb') as f: + """Creates the fixture for the tests.""" + data_path = os.path.join(TEST_DIR_PATH, "plotting_data.pickle") + with open(data_path, "rb") as f: loaded_data = pickle.load(f) - + data = PlotEventData() - data.modelType = loaded_data['modelType'] - data.dataPresent = loaded_data['dataPresent'] - data.subRoughs = loaded_data['subRoughs'] - data.resample = loaded_data['resample'] - data.resampledLayers = loaded_data['resampledLayers'] - data.reflectivity = loaded_data['reflectivity'] - data.shiftedData = loaded_data['shiftedData'] - data.sldProfiles = loaded_data['sldProfiles'] + data.modelType = loaded_data["modelType"] + data.dataPresent = loaded_data["dataPresent"] + data.subRoughs = loaded_data["subRoughs"] + data.resample = loaded_data["resample"] + data.resampledLayers = loaded_data["resampledLayers"] + data.reflectivity = loaded_data["reflectivity"] + data.shiftedData = loaded_data["shiftedData"] + data.sldProfiles = loaded_data["sldProfiles"] return data @pytest.fixture def fig() -> Figure: - """ - Creates the fixture for the tests. - """ - plt.close('all') + """Creates the fixture for the tests.""" + plt.close("all") figure = Figure(1, 3) fig = plot_ref_sld_helper(fig=figure, data=data()) return fig def test_figure_axis_formating(fig: Figure) -> None: - """ - Tests the axis formating of the figure. - """ + """Tests the axis formating of the figure.""" ref_plot = fig._ax[0] sld_plot = fig._ax[1] @@ -58,19 +51,17 @@ def test_figure_axis_formating(fig: Figure) -> None: assert ref_plot.get_xscale() == "log" assert ref_plot.get_ylabel() == "Ref" assert ref_plot.get_yscale() == "log" - assert [label._text for label in ref_plot.get_legend().texts] == ['ref 1', 'ref 2', 'ref 3'] + 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_xscale() == "linear" assert sld_plot.get_ylabel() == "SLD" assert sld_plot.get_yscale() == "linear" - assert [label._text for label in sld_plot.get_legend().texts] == ['sld 1', 'sld 2', 'sld 3'] + 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: - """ - Tests the color formating of the figure. - """ + """Tests the color formating of the figure.""" ref_plot = fig._ax[0] sld_plot = fig._ax[1] @@ -78,68 +69,68 @@ def test_figure_color_formating(fig: Figure) -> None: assert len(sld_plot.get_lines()) == 6 for axis_ix in range(len(ref_plot.get_lines())): - ax1 = axis_ix*2 + ax1 = axis_ix * 2 ax2 = ax1 + 1 # Tests whether the color of the line and the errorbars match on the ref_plot - assert (ref_plot.containers[ax1][2][0]._original_edgecolor == - ref_plot.containers[ax2][2][0]._original_edgecolor == - ref_plot.get_lines()[axis_ix].get_color()) + assert ( + ref_plot.containers[ax1][2][0]._original_edgecolor + == ref_plot.containers[ax2][2][0]._original_edgecolor + == ref_plot.get_lines()[axis_ix].get_color() + ) # Tests whether the color of the sld and resampled_sld match on the sld_plot - assert (sld_plot.get_lines()[ax1].get_color() == - sld_plot.get_lines()[ax2].get_color()) + 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 + """Tests whether the eventhandlers for close_event and key_press_event in the figure are linked to the class methods. """ - pattern = r'\(([^\]]+)\)' + pattern = r"\(([^\]]+)\)" + index = 0 - for ix, val in fig._fig.canvas.callbacks.callbacks['close_event'].items(): + 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'][ix]._func_ref.__repr__() - close_event_callback = re.findall(pattern, - canvas_close_event_callback)[0] + 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(): + 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'][ix]._func_ref.__repr__() - key_press_event_callback = re.findall(pattern, - canvas_key_press_event_callback)[0] + 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 + """Tests whether the eventhandlers for close_event and key_press_event update variables that stop while loop in wait_for_close. """ assert not fig._esc_pressed - on_key_mock_event = type('MockEvent', (object,), {'key': 'escape'}) + 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') + fig._close("test") assert fig._close_clicked -@patch("RAT.utils.plotting.plt.waitforbuttonpress") +@patch("RAT.utils.plotting.plt.waitforbuttonpress") def test_wait_for_close(mock: MagicMock, fig: Figure) -> None: - """ - Tests the _wait_for_close method stops the + """Tests the _wait_for_close method stops the while loop when _esc_pressed is True. """ + def mock_wait_for_button_press(timeout): fig._esc_pressed = True @@ -149,10 +140,9 @@ def mock_wait_for_button_press(timeout): assert fig._esc_pressed -@patch("RAT.utils.plotting.makeSLDProfileXY") +@patch("RAT.utils.plotting.makeSLDProfileXY") def test_sld_profile_function_call(mock: MagicMock) -> None: - """ - Tests the makeSLDProfileXY function called with + """Tests the makeSLDProfileXY function called with correct args. """ plot_ref_sld_helper(data()) diff --git a/tests/test_project.py b/tests/test_project.py index 9eb15163..1afaba82 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -1,124 +1,163 @@ """Test the project module.""" import copy -import numpy as np -import pydantic import os -import pytest import shutil -from typing import Callable import tempfile +from typing import Callable + +import numpy as np +import pydantic +import pytest import RAT from RAT.utils.enums import Calculations, LayerModels +layer_params = {"thickness": "Test Thickness", "SLD": "Test SLD", "roughness": "Test Roughness"} +absorption_layer_params = { + "thickness": "Test Thickness", + "SLD_real": "Test SLD", + "SLD_imaginary": "Test SLD", + "roughness": "Test Roughness", +} -layer_params = {'thickness': 'Test Thickness', 'SLD': 'Test SLD', 'roughness': 'Test Roughness'} -absorption_layer_params = {'thickness': 'Test Thickness', 'SLD_real': 'Test SLD', 'SLD_imaginary': 'Test SLD', - 'roughness': 'Test Roughness'} @pytest.fixture def test_project(): """Add parameters to the default project, so each ClassList can be tested properly.""" - test_project = RAT.Project(data=RAT.ClassList([RAT.models.Data(name='Simulation', data=np.array([[1.0, 1.0, 1.0]]))])) - test_project.parameters.append(name='Test Thickness') - test_project.parameters.append(name='Test SLD') - test_project.parameters.append(name='Test Roughness') - test_project.custom_files.append(name='Test Custom File') - test_project.layers.append(name='Test Layer', thickness='Test Thickness', SLD='Test SLD', roughness='Test Roughness') - test_project.contrasts.append(name='Test Contrast', data='Simulation', background='Background 1', bulk_in='SLD Air', - bulk_out='SLD D2O', scalefactor='Scalefactor 1', resolution='Resolution 1', - model=['Test Layer']) + test_project = RAT.Project( + data=RAT.ClassList([RAT.models.Data(name="Simulation", data=np.array([[1.0, 1.0, 1.0]]))]), + ) + test_project.parameters.append(name="Test Thickness") + test_project.parameters.append(name="Test SLD") + test_project.parameters.append(name="Test Roughness") + test_project.custom_files.append(name="Test Custom File") + test_project.layers.append( + name="Test Layer", + thickness="Test Thickness", + SLD="Test SLD", + roughness="Test Roughness", + ) + test_project.contrasts.append( + name="Test Contrast", + data="Simulation", + background="Background 1", + bulk_in="SLD Air", + bulk_out="SLD D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + model=["Test Layer"], + ) return test_project @pytest.fixture def default_project_repr(): """A string of the output of repr() for a Project model with no parameters specified.""" - return( - 'Calculation: ---------------------------------------------------------------------------------------\n\n' - 'non polarised\n\n' - 'Model: ---------------------------------------------------------------------------------------------\n\n' - 'standard layers\n\n' - 'Geometry: ------------------------------------------------------------------------------------------\n\n' - 'air/substrate\n\n' - 'Parameters: ----------------------------------------------------------------------------------------\n\n' - '+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n' - '| index | name | min | value | max | fit | prior type | mu | sigma |\n' - '+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n' - '| 0 | Substrate Roughness | 1.0 | 3.0 | 5.0 | True | uniform | 0.0 | inf |\n' - '+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n\n' - 'Bulk In: -------------------------------------------------------------------------------------------\n\n' - '+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n' - '| index | name | min | value | max | fit | prior type | mu | sigma |\n' - '+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n' - '| 0 | SLD Air | 0.0 | 0.0 | 0.0 | False | uniform | 0.0 | inf |\n' - '+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n\n' - 'Bulk Out: ------------------------------------------------------------------------------------------\n\n' - '+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n' - '| index | name | min | value | max | fit | prior type | mu | sigma |\n' - '+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n' - '| 0 | SLD D2O | 6.2e-06 | 6.35e-06 | 6.35e-06 | False | uniform | 0.0 | inf |\n' - '+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n\n' - 'Scalefactors: --------------------------------------------------------------------------------------\n\n' - '+-------+---------------+------+-------+------+-------+------------+-----+-------+\n' - '| index | name | min | value | max | fit | prior type | mu | sigma |\n' - '+-------+---------------+------+-------+------+-------+------------+-----+-------+\n' - '| 0 | Scalefactor 1 | 0.02 | 0.23 | 0.25 | False | uniform | 0.0 | inf |\n' - '+-------+---------------+------+-------+------+-------+------------+-----+-------+\n\n' - 'Background Parameters: -----------------------------------------------------------------------------\n\n' - '+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n' - '| index | name | min | value | max | fit | prior type | mu | sigma |\n' - '+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n' - '| 0 | Background Param 1 | 1e-07 | 1e-06 | 1e-05 | False | uniform | 0.0 | inf |\n' - '+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n\n' - 'Backgrounds: ---------------------------------------------------------------------------------------\n\n' - '+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n' - '| index | name | type | value 1 | value 2 | value 3 | value 4 | value 5 |\n' - '+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n' - '| 0 | Background 1 | constant | Background Param 1 | | | | |\n' - '+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n\n' - 'Resolution Parameters: -----------------------------------------------------------------------------\n\n' - '+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n' - '| index | name | min | value | max | fit | prior type | mu | sigma |\n' - '+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n' - '| 0 | Resolution Param 1 | 0.01 | 0.03 | 0.05 | False | uniform | 0.0 | inf |\n' - '+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n\n' - 'Resolutions: ---------------------------------------------------------------------------------------\n\n' - '+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n' - '| index | name | type | value 1 | value 2 | value 3 | value 4 | value 5 |\n' - '+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n' - '| 0 | Resolution 1 | constant | Resolution Param 1 | | | | |\n' - '+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n\n' - 'Data: ----------------------------------------------------------------------------------------------\n\n' - '+-------+------------+------+------------+------------------+\n' - '| index | name | data | data range | simulation range |\n' - '+-------+------------+------+------------+------------------+\n' - '| 0 | Simulation | [] | [] | [0.005, 0.7] |\n' - '+-------+------------+------+------------+------------------+\n\n') + return ( + "Calculation: ---------------------------------------------------------------------------------------\n\n" + "non polarised\n\n" + "Model: ---------------------------------------------------------------------------------------------\n\n" + "standard layers\n\n" + "Geometry: ------------------------------------------------------------------------------------------\n\n" + "air/substrate\n\n" + "Parameters: ----------------------------------------------------------------------------------------\n\n" + "+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n" + "| index | name | min | value | max | fit | prior type | mu | sigma |\n" + "+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n" + "| 0 | Substrate Roughness | 1.0 | 3.0 | 5.0 | True | uniform | 0.0 | inf |\n" + "+-------+---------------------+-----+-------+-----+------+------------+-----+-------+\n\n" + "Bulk In: -------------------------------------------------------------------------------------------\n\n" + "+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n" + "| index | name | min | value | max | fit | prior type | mu | sigma |\n" + "+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n" + "| 0 | SLD Air | 0.0 | 0.0 | 0.0 | False | uniform | 0.0 | inf |\n" + "+-------+---------+-----+-------+-----+-------+------------+-----+-------+\n\n" + "Bulk Out: ------------------------------------------------------------------------------------------\n\n" + "+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n" + "| index | name | min | value | max | fit | prior type | mu | sigma |\n" + "+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n" + "| 0 | SLD D2O | 6.2e-06 | 6.35e-06 | 6.35e-06 | False | uniform | 0.0 | inf |\n" + "+-------+---------+---------+----------+----------+-------+------------+-----+-------+\n\n" + "Scalefactors: --------------------------------------------------------------------------------------\n\n" + "+-------+---------------+------+-------+------+-------+------------+-----+-------+\n" + "| index | name | min | value | max | fit | prior type | mu | sigma |\n" + "+-------+---------------+------+-------+------+-------+------------+-----+-------+\n" + "| 0 | Scalefactor 1 | 0.02 | 0.23 | 0.25 | False | uniform | 0.0 | inf |\n" + "+-------+---------------+------+-------+------+-------+------------+-----+-------+\n\n" + "Background Parameters: -----------------------------------------------------------------------------\n\n" + "+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n" + "| index | name | min | value | max | fit | prior type | mu | sigma |\n" + "+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n" + "| 0 | Background Param 1 | 1e-07 | 1e-06 | 1e-05 | False | uniform | 0.0 | inf |\n" + "+-------+--------------------+-------+-------+-------+-------+------------+-----+-------+\n\n" + "Backgrounds: ---------------------------------------------------------------------------------------\n\n" + "+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n" + "| index | name | type | value 1 | value 2 | value 3 | value 4 | value 5 |\n" + "+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n" + "| 0 | Background 1 | constant | Background Param 1 | | | | |\n" + "+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n\n" + "Resolution Parameters: -----------------------------------------------------------------------------\n\n" + "+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n" + "| index | name | min | value | max | fit | prior type | mu | sigma |\n" + "+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n" + "| 0 | Resolution Param 1 | 0.01 | 0.03 | 0.05 | False | uniform | 0.0 | inf |\n" + "+-------+--------------------+------+-------+------+-------+------------+-----+-------+\n\n" + "Resolutions: ---------------------------------------------------------------------------------------\n\n" + "+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n" + "| index | name | type | value 1 | value 2 | value 3 | value 4 | value 5 |\n" + "+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n" + "| 0 | Resolution 1 | constant | Resolution Param 1 | | | | |\n" + "+-------+--------------+----------+--------------------+---------+---------+---------+---------+\n\n" + "Data: ----------------------------------------------------------------------------------------------\n\n" + "+-------+------------+------+------------+------------------+\n" + "| index | name | data | data range | simulation range |\n" + "+-------+------------+------+------------+------------------+\n" + "| 0 | Simulation | [] | [] | [0.005, 0.7] |\n" + "+-------+------------+------+------------+------------------+\n\n" + ) @pytest.fixture def test_project_script(): return ( - "# THIS FILE IS GENERATED FROM RAT VIA THE \"WRITE_SCRIPT\" ROUTINE. IT IS NOT PART OF THE RAT CODE.\n\n" + '# THIS FILE IS GENERATED FROM RAT VIA THE "WRITE_SCRIPT" ROUTINE. IT IS NOT PART OF THE RAT CODE.\n\n' "import RAT\nfrom RAT.models import *\nfrom numpy import array, inf\n\n" - "problem = RAT.Project(\n name='', calculation='non polarised', model='standard layers', geometry='air/substrate', absorption=False,\n" - " parameters=RAT.ClassList([ProtectedParameter(name='Substrate Roughness', min=1.0, value=3.0, max=5.0, fit=True, prior_type='uniform', mu=0.0, sigma=inf)," - " Parameter(name='Test Thickness', min=0.0, value=0.0, max=0.0, fit=False, prior_type='uniform', mu=0.0, sigma=inf)," + "problem = RAT.Project(\n" + " name='', calculation='non polarised', model='standard layers', geometry='air/substrate'," + " absorption=False,\n" + " parameters=RAT.ClassList(" + "[ProtectedParameter(name='Substrate Roughness', min=1.0, value=3.0, max=5.0, fit=True, prior_type='uniform'," + " mu=0.0, sigma=inf)," + " Parameter(name='Test Thickness', min=0.0, value=0.0, max=0.0, fit=False, prior_type='uniform', mu=0.0," + " sigma=inf)," " Parameter(name='Test SLD', min=0.0, value=0.0, max=0.0, fit=False, prior_type='uniform', mu=0.0, sigma=inf)," - " Parameter(name='Test Roughness', min=0.0, value=0.0, max=0.0, fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" - " background_parameters=RAT.ClassList([Parameter(name='Background Param 1', min=1e-07, value=1e-06, max=1e-05, fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" - " scalefactors=RAT.ClassList([Parameter(name='Scalefactor 1', min=0.02, value=0.23, max=0.25, fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" - " bulk_in=RAT.ClassList([Parameter(name='SLD Air', min=0.0, value=0.0, max=0.0, fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" - " bulk_out=RAT.ClassList([Parameter(name='SLD D2O', min=6.2e-06, value=6.35e-06, max=6.35e-06, fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" - " resolution_parameters=RAT.ClassList([Parameter(name='Resolution Param 1', min=0.01, value=0.03, max=0.05, fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" - " backgrounds=RAT.ClassList([Background(name='Background 1', type='constant', value_1='Background Param 1', value_2='', value_3='', value_4='', value_5='')]),\n" - " resolutions=RAT.ClassList([Resolution(name='Resolution 1', type='constant', value_1='Resolution Param 1', value_2='', value_3='', value_4='', value_5='')]),\n" - " custom_files=RAT.ClassList([CustomFile(name='Test Custom File', filename='', function_name='', language='python', path='')]),\n" - " data=RAT.ClassList([Data(name='Simulation', data=array([[1., 1., 1.]]), data_range=[1.0, 1.0], simulation_range=[1.0, 1.0])]),\n" - " layers=RAT.ClassList([Layer(name='Test Layer', thickness='Test Thickness', SLD='Test SLD', roughness='Test Roughness', hydration='', hydrate_with='bulk out')]),\n" - " contrasts=RAT.ClassList([Contrast(name='Test Contrast', data='Simulation', background='Background 1', background_action='add', bulk_in='SLD Air', bulk_out='SLD D2O', scalefactor='Scalefactor 1', resolution='Resolution 1', resample=False, model=['Test Layer'])]),\n" + " Parameter(name='Test Roughness', min=0.0, value=0.0, max=0.0, fit=False, prior_type='uniform', mu=0.0," + " sigma=inf)" + "]),\n" + " background_parameters=RAT.ClassList([Parameter(name='Background Param 1', min=1e-07, value=1e-06," + " max=1e-05, fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" + " scalefactors=RAT.ClassList([Parameter(name='Scalefactor 1', min=0.02, value=0.23, max=0.25, fit=False," + " prior_type='uniform', mu=0.0, sigma=inf)]),\n" + " bulk_in=RAT.ClassList([Parameter(name='SLD Air', min=0.0, value=0.0, max=0.0, fit=False," + " prior_type='uniform', mu=0.0, sigma=inf)]),\n" + " bulk_out=RAT.ClassList([Parameter(name='SLD D2O', min=6.2e-06, value=6.35e-06, max=6.35e-06, fit=False," + " prior_type='uniform', mu=0.0, sigma=inf)]),\n" + " resolution_parameters=RAT.ClassList([Parameter(name='Resolution Param 1', min=0.01, value=0.03, max=0.05," + " fit=False, prior_type='uniform', mu=0.0, sigma=inf)]),\n" + " backgrounds=RAT.ClassList([Background(name='Background 1', type='constant', value_1='Background Param 1'," + " value_2='', value_3='', value_4='', value_5='')]),\n" + " resolutions=RAT.ClassList([Resolution(name='Resolution 1', type='constant', value_1='Resolution Param 1'," + " value_2='', value_3='', value_4='', value_5='')]),\n" + " custom_files=RAT.ClassList([CustomFile(name='Test Custom File', filename='', function_name=''," + " language='python', path='')]),\n" + " data=RAT.ClassList([Data(name='Simulation', data=array([[1., 1., 1.]]), data_range=[1.0, 1.0]," + " simulation_range=[1.0, 1.0])]),\n" + " layers=RAT.ClassList([Layer(name='Test Layer', thickness='Test Thickness', SLD='Test SLD'," + " roughness='Test Roughness', hydration='', hydrate_with='bulk out')]),\n" + " contrasts=RAT.ClassList([Contrast(name='Test Contrast', data='Simulation', background='Background 1'," + " background_action='add', bulk_in='SLD Air', bulk_out='SLD D2O', scalefactor='Scalefactor 1'," + " resolution='Resolution 1', resample=False, model=['Test Layer'])]),\n" " )\n" ) @@ -144,186 +183,260 @@ def test_classlists_specific_cases() -> None: options. """ project = RAT.Project(calculation=Calculations.Domains, absorption=True) - assert project.layers._class_handle.__name__ == 'AbsorptionLayer' - assert project.contrasts._class_handle.__name__ == 'ContrastWithRatio' - - -@pytest.mark.parametrize(["input_model", "model_params"], [ - (RAT.models.Background, {}), - (RAT.models.Contrast, {}), - (RAT.models.ContrastWithRatio, {}), - (RAT.models.CustomFile, {}), - (RAT.models.Data, {}), - (RAT.models.DomainContrast, {}), - (RAT.models.Layer, layer_params), - (RAT.models.AbsorptionLayer, absorption_layer_params), - (RAT.models.Resolution, {}), -]) + assert project.layers._class_handle.__name__ == "AbsorptionLayer" + assert project.contrasts._class_handle.__name__ == "ContrastWithRatio" + + +@pytest.mark.parametrize( + ["input_model", "model_params"], + [ + (RAT.models.Background, {}), + (RAT.models.Contrast, {}), + (RAT.models.ContrastWithRatio, {}), + (RAT.models.CustomFile, {}), + (RAT.models.Data, {}), + (RAT.models.DomainContrast, {}), + (RAT.models.Layer, layer_params), + (RAT.models.AbsorptionLayer, absorption_layer_params), + (RAT.models.Resolution, {}), + ], +) def test_initialise_wrong_classes(input_model: Callable, model_params: dict) -> None: """If the "Project" model is initialised with incorrect classes, we should raise a ValidationError.""" - with pytest.raises(pydantic.ValidationError, match='1 validation error for Project\nparameters\n Value error, ' - '"parameters" ClassList contains objects other than ' - '"Parameter"'): + with pytest.raises( + pydantic.ValidationError, + match="1 validation error for Project\nparameters\n Value error, " + '"parameters" ClassList contains objects other than ' + '"Parameter"', + ): RAT.Project(parameters=RAT.ClassList(input_model(**model_params))) -@pytest.mark.parametrize(["input_model", "model_params", "absorption", "actual_model_name"], [ - (RAT.models.Layer, layer_params, True, "AbsorptionLayer"), - (RAT.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), -]) -def test_initialise_wrong_layers(input_model: Callable, model_params: dict, absorption: bool, - actual_model_name: str) -> None: +@pytest.mark.parametrize( + ["input_model", "model_params", "absorption", "actual_model_name"], + [ + (RAT.models.Layer, layer_params, True, "AbsorptionLayer"), + (RAT.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), + ], +) +def test_initialise_wrong_layers( + input_model: Callable, + model_params: dict, + absorption: bool, + actual_model_name: str, +) -> None: """If the "Project" model is initialised with the incorrect layer model given the value of absorption, we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\nlayers\n Value error, ' - f'"layers" ClassList contains objects other than ' - f'"{actual_model_name}"'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\nlayers\n Value error, " + f'"layers" ClassList contains objects other than ' + f'"{actual_model_name}"', + ): RAT.Project(absorption=absorption, layers=RAT.ClassList(input_model(**model_params))) -@pytest.mark.parametrize(["input_model", "calculation", "actual_model_name"], [ - (RAT.models.Contrast, Calculations.Domains, "ContrastWithRatio"), - (RAT.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast"), -]) -def test_initialise_wrong_contrasts(input_model: Callable, calculation: Calculations, - actual_model_name: str) -> None: +@pytest.mark.parametrize( + ["input_model", "calculation", "actual_model_name"], + [ + (RAT.models.Contrast, Calculations.Domains, "ContrastWithRatio"), + (RAT.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast"), + ], +) +def test_initialise_wrong_contrasts(input_model: Callable, calculation: Calculations, actual_model_name: str) -> None: """If the "Project" model is initialised with the incorrect contrast model given the value of calculation, we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\ncontrasts\n Value error, ' - f'"contrasts" ClassList contains objects other than ' - f'"{actual_model_name}"'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\ncontrasts\n Value error, " + f'"contrasts" ClassList contains objects other than ' + f'"{actual_model_name}"', + ): RAT.Project(calculation=calculation, contrasts=RAT.ClassList(input_model())) -@pytest.mark.parametrize("input_parameter", [ - (RAT.models.Parameter(name='Test Parameter')), - (RAT.models.Parameter(name='Substrate Roughness')), -]) +@pytest.mark.parametrize( + "input_parameter", + [ + (RAT.models.Parameter(name="Test Parameter")), + (RAT.models.Parameter(name="Substrate Roughness")), + ], +) def test_initialise_without_substrate_roughness(input_parameter: Callable) -> None: """If the "Project" model is initialised without "Substrate Roughness as a protected parameter, add it to the front of the "parameters" ClassList. """ - project = RAT.Project(parameters=RAT.ClassList(RAT.models.Parameter(name='Substrate Roughness'))) - assert project.parameters[0] == RAT.models.ProtectedParameter(name='Substrate Roughness') - - -@pytest.mark.parametrize(["field", "wrong_input_model", "model_params"], [ - ('backgrounds', RAT.models.Resolution, {}), - ('contrasts', RAT.models.Layer, layer_params), - ('domain_contrasts', RAT.models.Parameter, {}), - ('custom_files', RAT.models.Data, {}), - ('data', RAT.models.Contrast, {}), - ('layers', RAT.models.DomainContrast, {}), - ('parameters', RAT.models.CustomFile, {}), - ('resolutions', RAT.models.Background, {}), -]) + project = RAT.Project(parameters=RAT.ClassList(RAT.models.Parameter(name="Substrate Roughness"))) + assert project.parameters[0] == RAT.models.ProtectedParameter(name="Substrate Roughness") + + +@pytest.mark.parametrize( + ["field", "wrong_input_model", "model_params"], + [ + ("backgrounds", RAT.models.Resolution, {}), + ("contrasts", RAT.models.Layer, layer_params), + ("domain_contrasts", RAT.models.Parameter, {}), + ("custom_files", RAT.models.Data, {}), + ("data", RAT.models.Contrast, {}), + ("layers", RAT.models.DomainContrast, {}), + ("parameters", RAT.models.CustomFile, {}), + ("resolutions", RAT.models.Background, {}), + ], +) def test_assign_wrong_classes(test_project, field: str, wrong_input_model: Callable, model_params: dict) -> None: """If we assign incorrect classes to the "Project" model, we should raise a ValidationError.""" - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n{field}\n Value error, ' - f'"{field}" ClassList contains objects other than ' - f'"{RAT.project.model_in_classlist[field]}"'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n{field}\n Value error, " + f'"{field}" ClassList contains objects other than ' + f'"{RAT.project.model_in_classlist[field]}"', + ): setattr(test_project, field, RAT.ClassList(wrong_input_model(**model_params))) -@pytest.mark.parametrize(["wrong_input_model", "model_params", "absorption", "actual_model_name"], [ - (RAT.models.Layer, layer_params, True, "AbsorptionLayer"), - (RAT.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), -]) -def test_assign_wrong_layers(wrong_input_model: Callable, model_params: dict, absorption: bool, - actual_model_name: str) -> None: +@pytest.mark.parametrize( + ["wrong_input_model", "model_params", "absorption", "actual_model_name"], + [ + (RAT.models.Layer, layer_params, True, "AbsorptionLayer"), + (RAT.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), + ], +) +def test_assign_wrong_layers( + wrong_input_model: Callable, + model_params: dict, + absorption: bool, + actual_model_name: str, +) -> None: """If we assign incorrect classes to the "Project" model, we should raise a ValidationError.""" project = RAT.Project(absorption=absorption) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\nlayers\n Value error, ' - f'"layers" ClassList contains objects other than ' - f'"{actual_model_name}"'): - setattr(project, 'layers', RAT.ClassList(wrong_input_model(**model_params))) - - -@pytest.mark.parametrize(["wrong_input_model", "calculation", "actual_model_name"], [ - (RAT.models.Contrast, Calculations.Domains, "ContrastWithRatio"), - (RAT.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast"), -]) + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\nlayers\n Value error, " + f'"layers" ClassList contains objects other than ' + f'"{actual_model_name}"', + ): + project.layers = RAT.ClassList(wrong_input_model(**model_params)) + + +@pytest.mark.parametrize( + ["wrong_input_model", "calculation", "actual_model_name"], + [ + (RAT.models.Contrast, Calculations.Domains, "ContrastWithRatio"), + (RAT.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast"), + ], +) def test_assign_wrong_contrasts(wrong_input_model: Callable, calculation: Calculations, actual_model_name: str) -> None: """If we assign incorrect classes to the "Project" model, we should raise a ValidationError.""" project = RAT.Project(calculation=calculation) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\ncontrasts\n Value error, ' - f'"contrasts" ClassList contains objects other than ' - f'"{actual_model_name}"'): - setattr(project, 'contrasts', RAT.ClassList(wrong_input_model())) - - -@pytest.mark.parametrize(["field", "model_params"], [ - ('backgrounds', {}), - ('contrasts', {}), - ('custom_files', {}), - ('data', {}), - ('layers', layer_params), - ('parameters', {}), - ('resolutions', {}), -]) + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\ncontrasts\n Value error, " + f'"contrasts" ClassList contains objects other than ' + f'"{actual_model_name}"', + ): + project.contrasts = RAT.ClassList(wrong_input_model()) + + +@pytest.mark.parametrize( + ["field", "model_params"], + [ + ("backgrounds", {}), + ("contrasts", {}), + ("custom_files", {}), + ("data", {}), + ("layers", layer_params), + ("parameters", {}), + ("resolutions", {}), + ], +) def test_assign_models(test_project, field: str, model_params: dict) -> None: """If the "Project" model is initialised with models rather than ClassLists, we should raise a ValidationError.""" input_model = getattr(RAT.models, RAT.project.model_in_classlist[field]) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n{field}\n Input should be ' - f'an instance of ClassList'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n{field}\n Input should be " f"an instance of ClassList", + ): setattr(test_project, field, input_model(**model_params)) def test_wrapped_routines(test_project) -> None: """When initialising a project, several ClassList routines should be wrapped.""" - wrapped_methods = ['_setitem', '_delitem', '_iadd', 'append', 'insert', 'pop', 'remove', 'clear', 'extend', - 'set_fields'] + wrapped_methods = [ + "_setitem", + "_delitem", + "_iadd", + "append", + "insert", + "pop", + "remove", + "clear", + "extend", + "set_fields", + ] for class_list in RAT.project.class_lists: attribute = getattr(test_project, class_list) for methodName in wrapped_methods: - assert hasattr(getattr(attribute, methodName), '__wrapped__') + assert hasattr(getattr(attribute, methodName), "__wrapped__") def test_set_domain_ratios(test_project) -> None: """If we are not running a domains calculation, the "domain_ratios" field of the model should always be empty.""" assert test_project.domain_ratios == [] - test_project.domain_ratios.append(name='New Domain Ratio') + test_project.domain_ratios.append(name="New Domain Ratio") assert test_project.domain_ratios == [] -@pytest.mark.parametrize("project_parameters", [ - ({'calculation': Calculations.NonPolarised, 'model': LayerModels.StandardLayers}), - ({'calculation': Calculations.NonPolarised, 'model': LayerModels.CustomLayers}), - ({'calculation': Calculations.NonPolarised, 'model': LayerModels.CustomXY}), - ({'calculation': Calculations.Domains, 'model': LayerModels.CustomLayers}), - ({'calculation': Calculations.Domains, 'model': LayerModels.CustomXY}), -]) +@pytest.mark.parametrize( + "project_parameters", + [ + ({"calculation": Calculations.NonPolarised, "model": LayerModels.StandardLayers}), + ({"calculation": Calculations.NonPolarised, "model": LayerModels.CustomLayers}), + ({"calculation": Calculations.NonPolarised, "model": LayerModels.CustomXY}), + ({"calculation": Calculations.Domains, "model": LayerModels.CustomLayers}), + ({"calculation": Calculations.Domains, "model": LayerModels.CustomXY}), + ], +) def test_set_domain_contrasts(project_parameters: dict) -> None: """If we are not running a domains calculation with standard layers, the "domain_contrasts" field of the model should always be empty. """ project = RAT.Project(**project_parameters) assert project.domain_contrasts == [] - project.domain_contrasts.append(name='New Domain Contrast') + project.domain_contrasts.append(name="New Domain Contrast") assert project.domain_contrasts == [] -@pytest.mark.parametrize("project_parameters", [ - ({'model': LayerModels.CustomLayers}), - ({'model': LayerModels.CustomXY}), -]) +@pytest.mark.parametrize( + "project_parameters", + [ + ({"model": LayerModels.CustomLayers}), + ({"model": LayerModels.CustomXY}), + ], +) def test_set_layers(project_parameters: dict) -> None: """If we are not using a standard layers model, the "layers" field of the model should always be empty.""" project = RAT.Project(**project_parameters) assert project.layers == [] - project.layers.append(name='New Layer', thickness='Test Thickness', SLD='Test SLD', roughness='Test Roughness') + project.layers.append(name="New Layer", thickness="Test Thickness", SLD="Test SLD", roughness="Test Roughness") assert project.layers == [] -@pytest.mark.parametrize(["input_calculation", "input_contrast", "new_calculation", "new_contrast_model", - "num_domain_ratios"], [ - (Calculations.NonPolarised, RAT.models.Contrast, Calculations.Domains, "ContrastWithRatio", 1), - (Calculations.Domains, RAT.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast", 0), -]) -def test_set_calculation(input_calculation: Calculations, input_contrast: Callable, new_calculation: Calculations, - new_contrast_model: str, num_domain_ratios: int) -> None: +@pytest.mark.parametrize( + ["input_calculation", "input_contrast", "new_calculation", "new_contrast_model", "num_domain_ratios"], + [ + (Calculations.NonPolarised, RAT.models.Contrast, Calculations.Domains, "ContrastWithRatio", 1), + (Calculations.Domains, RAT.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast", 0), + ], +) +def test_set_calculation( + input_calculation: Calculations, + input_contrast: Callable, + new_calculation: Calculations, + new_contrast_model: str, + num_domain_ratios: int, +) -> None: """When changing the value of the calculation option, the "contrasts" ClassList should switch to using the appropriate Contrast model. """ @@ -336,16 +449,23 @@ def test_set_calculation(input_calculation: Calculations, input_contrast: Callab assert len(project.domain_ratios) == num_domain_ratios -@pytest.mark.parametrize(["new_calc", "new_model", "expected_contrast_model"], [ - (Calculations.NonPolarised, LayerModels.StandardLayers, ['Test Layer']), - (Calculations.NonPolarised, LayerModels.CustomLayers, []), - (Calculations.NonPolarised, LayerModels.CustomXY, []), - (Calculations.Domains, LayerModels.StandardLayers, []), - (Calculations.Domains, LayerModels.CustomLayers, []), - (Calculations.Domains, LayerModels.CustomXY, []), -]) -def test_set_contrast_model_field(test_project, new_calc: Calculations, new_model: LayerModels, - expected_contrast_model: list[str]) -> None: +@pytest.mark.parametrize( + ["new_calc", "new_model", "expected_contrast_model"], + [ + (Calculations.NonPolarised, LayerModels.StandardLayers, ["Test Layer"]), + (Calculations.NonPolarised, LayerModels.CustomLayers, []), + (Calculations.NonPolarised, LayerModels.CustomXY, []), + (Calculations.Domains, LayerModels.StandardLayers, []), + (Calculations.Domains, LayerModels.CustomLayers, []), + (Calculations.Domains, LayerModels.CustomXY, []), + ], +) +def test_set_contrast_model_field( + test_project, + new_calc: Calculations, + new_model: LayerModels, + expected_contrast_model: list[str], +) -> None: """If we change the calculation and model such that the values of the "model" field of the "contrasts" model come from a different field of the project, we should clear the contrast "model" field. """ @@ -354,40 +474,78 @@ def test_set_contrast_model_field(test_project, new_calc: Calculations, new_mode assert test_project.contrasts[0].model == expected_contrast_model -@pytest.mark.parametrize(["input_model", "test_contrast_model", "error_message"], [ - (LayerModels.StandardLayers, ['Test Domain Ratio'], - 'For a standard layers domains calculation the "model" field of "contrasts" must contain exactly two values.'), - (LayerModels.StandardLayers, ['Test Domain Ratio', 'Test Domain Ratio', 'Test Domain Ratio'], - 'For a standard layers domains calculation the "model" field of "contrasts" must contain exactly two values.'), - (LayerModels.CustomLayers, ['Test Custom File', 'Test Custom File'], - 'For a custom model calculation the "model" field of "contrasts" cannot contain more than one value.'), -]) -def test_check_contrast_model_length(test_project, input_model: LayerModels, test_contrast_model: list[str], - error_message: str) -> None: +@pytest.mark.parametrize( + ["input_model", "test_contrast_model", "error_message"], + [ + ( + LayerModels.StandardLayers, + ["Test Domain Ratio"], + 'For a standard layers domains calculation the "model" field of "contrasts" must contain exactly two ' + "values.", + ), + ( + LayerModels.StandardLayers, + ["Test Domain Ratio", "Test Domain Ratio", "Test Domain Ratio"], + 'For a standard layers domains calculation the "model" field of "contrasts" must contain exactly two ' + "values.", + ), + ( + LayerModels.CustomLayers, + ["Test Custom File", "Test Custom File"], + 'For a custom model calculation the "model" field of "contrasts" cannot contain more than one value.', + ), + ], +) +def test_check_contrast_model_length( + test_project, + input_model: LayerModels, + test_contrast_model: list[str], + error_message: str, +) -> None: """If we are not running a domains calculation with standard layers, the "domain_contrasts" field of the model should always be empty. """ - test_domain_ratios = RAT.ClassList(RAT.models.Parameter(name='Test Domain Ratio')) + test_domain_ratios = RAT.ClassList(RAT.models.Parameter(name="Test Domain Ratio")) test_contrasts = RAT.ClassList(RAT.models.ContrastWithRatio(model=test_contrast_model)) - with pytest.raises(pydantic.ValidationError, - match=f'1 validation error for Project\n Value error, {error_message}'): - RAT.Project(calculation=Calculations.Domains, model=input_model, domain_ratios=test_domain_ratios, - contrasts=test_contrasts) - - -@pytest.mark.parametrize(["input_layer", "model_params", "input_absorption", "new_layer_model"], [ - (RAT.models.Layer, layer_params, False, "AbsorptionLayer"), - (RAT.models.AbsorptionLayer, absorption_layer_params, True, "Layer"), -]) -def test_set_absorption(input_layer: Callable, model_params: dict, input_absorption: bool, new_layer_model: str) -> None: + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, {error_message}", + ): + RAT.Project( + calculation=Calculations.Domains, + model=input_model, + domain_ratios=test_domain_ratios, + contrasts=test_contrasts, + ) + + +@pytest.mark.parametrize( + ["input_layer", "model_params", "input_absorption", "new_layer_model"], + [ + (RAT.models.Layer, layer_params, False, "AbsorptionLayer"), + (RAT.models.AbsorptionLayer, absorption_layer_params, True, "Layer"), + ], +) +def test_set_absorption( + input_layer: Callable, + model_params: dict, + input_absorption: bool, + new_layer_model: str, +) -> None: """When changing the value of the absorption option, the "layers" ClassList should switch to using the appropriate Layer model. """ - project = RAT.Project(absorption=input_absorption, - parameters=RAT.ClassList([RAT.models.Parameter(name='Test Thickness'), - RAT.models.Parameter(name='Test SLD'), - RAT.models.Parameter(name='Test Roughness')]), - layers=RAT.ClassList(input_layer(**model_params))) + project = RAT.Project( + absorption=input_absorption, + parameters=RAT.ClassList( + [ + RAT.models.Parameter(name="Test Thickness"), + RAT.models.Parameter(name="Test SLD"), + RAT.models.Parameter(name="Test Roughness"), + ], + ), + layers=RAT.ClassList(input_layer(**model_params)), + ) project.absorption = not input_absorption assert project.absorption is not input_absorption @@ -395,182 +553,275 @@ def test_set_absorption(input_layer: Callable, model_params: dict, input_absorpt assert project.layers._class_handle.__name__ == new_layer_model -@pytest.mark.parametrize("delete_operation", [ - 'project.parameters.__delitem__(0)', - 'project.parameters.pop()', - 'project.parameters.remove("Substrate Roughness")', - 'project.parameters.clear()', -]) +@pytest.mark.parametrize( + "delete_operation", + [ + "project.parameters.__delitem__(0)", + "project.parameters.pop()", + 'project.parameters.remove("Substrate Roughness")', + "project.parameters.clear()", + ], +) def test_check_protected_parameters(delete_operation) -> None: """If we try to remove a protected parameter, we should raise an error.""" project = RAT.Project() - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, Can\'t delete' - f' the protected parameters: Substrate Roughness'): + with pytest.raises( + pydantic.ValidationError, + match="1 validation error for Project\n Value error, Can't delete" + " the protected parameters: Substrate Roughness", + ): eval(delete_operation) # Ensure model was not deleted - assert project.parameters[0].name == 'Substrate Roughness' - - -@pytest.mark.parametrize(["model", "field"], [ - ('background_parameters', 'value_1'), - ('resolution_parameters', 'value_1'), - ('parameters', 'roughness'), - ('data', 'data'), - ('backgrounds', 'background'), - ('bulk_in', 'bulk_in'), - ('bulk_out', 'bulk_out'), - ('scalefactors', 'scalefactor'), - ('resolutions', 'resolution'), -]) + assert project.parameters[0].name == "Substrate Roughness" + + +@pytest.mark.parametrize( + ["model", "field"], + [ + ("background_parameters", "value_1"), + ("resolution_parameters", "value_1"), + ("parameters", "roughness"), + ("data", "data"), + ("backgrounds", "background"), + ("bulk_in", "bulk_in"), + ("bulk_out", "bulk_out"), + ("scalefactors", "scalefactor"), + ("resolutions", "resolution"), + ], +) def test_rename_models(test_project, model: str, field: str) -> None: """When renaming a model in the project, the new name should be recorded when that model is referred to elsewhere in the project. """ - getattr(test_project, model).set_fields(-1, name='New Name') + getattr(test_project, model).set_fields(-1, name="New Name") attribute = RAT.project.model_names_used_in[model].attribute - assert getattr(getattr(test_project, attribute)[-1], field) == 'New Name' - - -@pytest.mark.parametrize("field", [ - 'value_1', - 'value_2', - 'value_3', - 'value_4', - 'value_5', -]) + assert getattr(getattr(test_project, attribute)[-1], field) == "New Name" + + +@pytest.mark.parametrize( + "field", + [ + "value_1", + "value_2", + "value_3", + "value_4", + "value_5", + ], +) def test_allowed_backgrounds(field: str) -> None: """If the "value" fields of the Background model are set to values that are not specified in the background parameters, we should raise a ValidationError. """ - test_background = RAT.models.Background(**{field: 'undefined'}) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "backgrounds" must be ' - f'defined in "background_parameters".'): + test_background = RAT.models.Background(**{field: "undefined"}) + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"undefined" in the "{field}" field of "backgrounds" must be ' + f'defined in "background_parameters".', + ): RAT.Project(backgrounds=RAT.ClassList(test_background)) -@pytest.mark.parametrize("field", [ - 'thickness', - 'SLD', - 'roughness', -]) +@pytest.mark.parametrize( + "field", + [ + "thickness", + "SLD", + "roughness", + ], +) def test_allowed_layers(field: str) -> None: """If the "thickness", "SLD", or "roughness" fields of the Layer model are set to values that are not specified in the parameters, we should raise a ValidationError. """ - test_layer = RAT.models.Layer(**{**layer_params, field: 'undefined'}) - - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "layers" must be ' - f'defined in "parameters".'): - RAT.Project(absorption=False, parameters=RAT.ClassList([RAT.models.Parameter(name='Test Thickness'), - RAT.models.Parameter(name='Test SLD'), - RAT.models.Parameter(name='Test Roughness')]), - layers=RAT.ClassList(test_layer)) - - -@pytest.mark.parametrize("field", [ - 'thickness', - 'SLD_real', - 'SLD_imaginary', - 'roughness', -]) + test_layer = RAT.models.Layer(**{**layer_params, field: "undefined"}) + + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"undefined" in the "{field}" field of "layers" must be ' + f'defined in "parameters".', + ): + RAT.Project( + absorption=False, + parameters=RAT.ClassList( + [ + RAT.models.Parameter(name="Test Thickness"), + RAT.models.Parameter(name="Test SLD"), + RAT.models.Parameter(name="Test Roughness"), + ], + ), + layers=RAT.ClassList(test_layer), + ) + + +@pytest.mark.parametrize( + "field", + [ + "thickness", + "SLD_real", + "SLD_imaginary", + "roughness", + ], +) def test_allowed_absorption_layers(field: str) -> None: """If the "thickness", "SLD_real", "SLD_imaginary", or "roughness" fields of the AbsorptionLayer model are set to values that are not specified in the parameters, we should raise a ValidationError. """ - test_layer = RAT.models.AbsorptionLayer(**{**absorption_layer_params, field: 'undefined'}) - - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "layers" must be ' - f'defined in "parameters".'): - RAT.Project(absorption=True, parameters=RAT.ClassList([RAT.models.Parameter(name='Test Thickness'), - RAT.models.Parameter(name='Test SLD'), - RAT.models.Parameter(name='Test Roughness')]), - layers=RAT.ClassList(test_layer)) - - -@pytest.mark.parametrize("field", [ - 'value_1', - 'value_2', - 'value_3', - 'value_4', - 'value_5', -]) + test_layer = RAT.models.AbsorptionLayer(**{**absorption_layer_params, field: "undefined"}) + + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"undefined" in the "{field}" field of "layers" must be ' + f'defined in "parameters".', + ): + RAT.Project( + absorption=True, + parameters=RAT.ClassList( + [ + RAT.models.Parameter(name="Test Thickness"), + RAT.models.Parameter(name="Test SLD"), + RAT.models.Parameter(name="Test Roughness"), + ], + ), + layers=RAT.ClassList(test_layer), + ) + + +@pytest.mark.parametrize( + "field", + [ + "value_1", + "value_2", + "value_3", + "value_4", + "value_5", + ], +) def test_allowed_resolutions(field: str) -> None: """If the "value" fields of the Resolution model are set to values that are not specified in the background parameters, we should raise a ValidationError. """ - test_resolution = RAT.models.Resolution(**{field: 'undefined'}) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "resolutions" must be ' - f'defined in "resolution_parameters".'): + test_resolution = RAT.models.Resolution(**{field: "undefined"}) + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"undefined" in the "{field}" field of "resolutions" must be ' + f'defined in "resolution_parameters".', + ): RAT.Project(resolutions=RAT.ClassList(test_resolution)) -@pytest.mark.parametrize(["field", "model_name"], [ - ('data', 'data'), - ('background', 'backgrounds'), - ('bulk_in', 'bulk_in'), - ('bulk_out', 'bulk_out'), - ('scalefactor', 'scalefactors'), - ('resolution', 'resolutions'), -]) +@pytest.mark.parametrize( + ["field", "model_name"], + [ + ("data", "data"), + ("background", "backgrounds"), + ("bulk_in", "bulk_in"), + ("bulk_out", "bulk_out"), + ("scalefactor", "scalefactors"), + ("resolution", "resolutions"), + ], +) def test_allowed_contrasts(field: str, model_name: str) -> None: """If the fields of the Contrast model are set to values not specified in the other respective models of the project, we should raise a ValidationError. """ - test_contrast = RAT.models.Contrast(**{field: 'undefined'}) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "contrasts" must be ' - f'defined in "{model_name}".'): + test_contrast = RAT.models.Contrast(**{field: "undefined"}) + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"undefined" in the "{field}" field of "contrasts" must be ' + f'defined in "{model_name}".', + ): RAT.Project(calculation=Calculations.NonPolarised, contrasts=RAT.ClassList(test_contrast)) -@pytest.mark.parametrize(["field", "model_name"], [ - ('data', 'data'), - ('background', 'backgrounds'), - ('bulk_in', 'bulk_in'), - ('bulk_out', 'bulk_out'), - ('scalefactor', 'scalefactors'), - ('resolution', 'resolutions'), - ('domain_ratio', 'domain_ratios'), -]) +@pytest.mark.parametrize( + ["field", "model_name"], + [ + ("data", "data"), + ("background", "backgrounds"), + ("bulk_in", "bulk_in"), + ("bulk_out", "bulk_out"), + ("scalefactor", "scalefactors"), + ("resolution", "resolutions"), + ("domain_ratio", "domain_ratios"), + ], +) def test_allowed_contrasts_with_ratio(field: str, model_name: str) -> None: """If the fields of the ContrastWithRatio model are set to values not specified in the other respective models of the project, we should raise a ValidationError. """ - test_contrast = RAT.models.ContrastWithRatio(**{field: 'undefined'}) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "contrasts" must be ' - f'defined in "{model_name}".'): + test_contrast = RAT.models.ContrastWithRatio(**{field: "undefined"}) + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"undefined" in the "{field}" field of "contrasts" must be ' + f'defined in "{model_name}".', + ): RAT.Project(calculation=Calculations.Domains, contrasts=RAT.ClassList(test_contrast)) -@pytest.mark.parametrize(["input_calc", "input_model", "test_contrast", "field_name"], [ - (Calculations.Domains, LayerModels.StandardLayers, - RAT.models.ContrastWithRatio(name='Test Contrast', model=['undefined', 'undefined']), 'domain_contrasts'), - (Calculations.Domains, LayerModels.CustomLayers, - RAT.models.ContrastWithRatio(name='Test Contrast', model=['undefined']), 'custom_files'), - (Calculations.Domains, LayerModels.CustomXY, - RAT.models.ContrastWithRatio(name='Test Contrast', model=['undefined']), 'custom_files'), - (Calculations.NonPolarised, LayerModels.StandardLayers, - RAT.models.Contrast(name='Test Contrast', model=['undefined', 'undefined', 'undefined']), 'layers'), - (Calculations.NonPolarised, LayerModels.CustomLayers, - RAT.models.Contrast(name='Test Contrast', model=['undefined']), 'custom_files'), - (Calculations.NonPolarised, LayerModels.CustomXY, - RAT.models.Contrast(name='Test Contrast', model=['undefined']), 'custom_files'), -]) -def test_allowed_contrast_models(input_calc: Calculations, input_model: LayerModels, test_contrast: 'RAT.models', - field_name: str) -> None: +@pytest.mark.parametrize( + ["input_calc", "input_model", "test_contrast", "field_name"], + [ + ( + Calculations.Domains, + LayerModels.StandardLayers, + RAT.models.ContrastWithRatio(name="Test Contrast", model=["undefined", "undefined"]), + "domain_contrasts", + ), + ( + Calculations.Domains, + LayerModels.CustomLayers, + RAT.models.ContrastWithRatio(name="Test Contrast", model=["undefined"]), + "custom_files", + ), + ( + Calculations.Domains, + LayerModels.CustomXY, + RAT.models.ContrastWithRatio(name="Test Contrast", model=["undefined"]), + "custom_files", + ), + ( + Calculations.NonPolarised, + LayerModels.StandardLayers, + RAT.models.Contrast(name="Test Contrast", model=["undefined", "undefined", "undefined"]), + "layers", + ), + ( + Calculations.NonPolarised, + LayerModels.CustomLayers, + RAT.models.Contrast(name="Test Contrast", model=["undefined"]), + "custom_files", + ), + ( + Calculations.NonPolarised, + LayerModels.CustomXY, + RAT.models.Contrast(name="Test Contrast", model=["undefined"]), + "custom_files", + ), + ], +) +def test_allowed_contrast_models( + input_calc: Calculations, + input_model: LayerModels, + test_contrast: "RAT.models", + field_name: str, +) -> None: """If any value in the model field of the contrasts is set to a value not specified in the appropriate part of the project, we should raise a ValidationError. """ - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The values: ' - f'"{", ".join(test_contrast.model)}" in the "model" field of ' - f'"contrasts" must be defined in "{field_name}".'): + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Project\n Value error, The values: ' + f'"{", ".join(test_contrast.model)}" in the "model" field of ' + f'"contrasts" must be defined in "{field_name}".', + ): RAT.Project(calculation=input_calc, model=input_model, contrasts=RAT.ClassList(test_contrast)) @@ -578,10 +829,13 @@ def test_allowed_domain_contrast_models() -> None: """If any value in the model field of the domain_contrasts is set to a value not specified in the "layers" field of the project, we should raise a ValidationError. """ - test_contrast = RAT.models.DomainContrast(name='Test Domain Contrast', model=['undefined']) - with pytest.raises(pydantic.ValidationError, match='1 validation error for Project\n Value error, The values: ' - '"undefined" in the "model" field of "domain_contrasts" must be ' - 'defined in "layers".'): + test_contrast = RAT.models.DomainContrast(name="Test Domain Contrast", model=["undefined"]) + with pytest.raises( + pydantic.ValidationError, + match="1 validation error for Project\n Value error, The values: " + '"undefined" in the "model" field of "domain_contrasts" must be ' + 'defined in "layers".', + ): RAT.Project(calculation=Calculations.Domains, domain_contrasts=RAT.ClassList(test_contrast)) @@ -592,92 +846,117 @@ def test_repr(default_project_repr: str) -> None: def test_get_all_names(test_project) -> None: """We should be able to get the names of all the models defined in the project.""" - assert test_project.get_all_names() == {'parameters': ['Substrate Roughness', 'Test Thickness', 'Test SLD', - 'Test Roughness'], - 'bulk_in': ['SLD Air'], - 'bulk_out': ['SLD D2O'], - 'scalefactors': ['Scalefactor 1'], - 'domain_ratios': [], - 'background_parameters': ['Background Param 1'], - 'backgrounds': ['Background 1'], - 'resolution_parameters': ['Resolution Param 1'], - 'resolutions': ['Resolution 1'], - 'custom_files': ['Test Custom File'], - 'data': ['Simulation'], - 'layers': ['Test Layer'], - 'domain_contrasts': [], - 'contrasts': ['Test Contrast'] - } + assert test_project.get_all_names() == { + "parameters": ["Substrate Roughness", "Test Thickness", "Test SLD", "Test Roughness"], + "bulk_in": ["SLD Air"], + "bulk_out": ["SLD D2O"], + "scalefactors": ["Scalefactor 1"], + "domain_ratios": [], + "background_parameters": ["Background Param 1"], + "backgrounds": ["Background 1"], + "resolution_parameters": ["Resolution Param 1"], + "resolutions": ["Resolution 1"], + "custom_files": ["Test Custom File"], + "data": ["Simulation"], + "layers": ["Test Layer"], + "domain_contrasts": [], + "contrasts": ["Test Contrast"], + } def test_get_all_protected_parameters(test_project) -> None: """We should be able to get the names of all the protected parameters defined in the project.""" - assert test_project.get_all_protected_parameters() == {'parameters': ['Substrate Roughness'], - 'bulk_in': [], - 'bulk_out': [], - 'scalefactors': [], - 'domain_ratios': [], - 'background_parameters': [], - 'resolution_parameters': [] - } - - -@pytest.mark.parametrize("test_value", [ - '', - 'Background Param 1', -]) + assert test_project.get_all_protected_parameters() == { + "parameters": ["Substrate Roughness"], + "bulk_in": [], + "bulk_out": [], + "scalefactors": [], + "domain_ratios": [], + "background_parameters": [], + "resolution_parameters": [], + } + + +@pytest.mark.parametrize( + "test_value", + [ + "", + "Background Param 1", + ], +) def test_check_allowed_values(test_value: str) -> None: """We should not raise an error if string values are defined and on the list of allowed values.""" project = RAT.Project.model_construct(backgrounds=RAT.ClassList(RAT.models.Background(value_1=test_value))) assert project.check_allowed_values("backgrounds", ["value_1"], ["Background Param 1"]) is None -@pytest.mark.parametrize("test_value", [ - "Undefined Param", -]) +@pytest.mark.parametrize( + "test_value", + [ + "Undefined Param", + ], +) def test_check_allowed_values_not_on_list(test_value: str) -> None: """If string values are defined and are not included on the list of allowed values we should raise a ValueError.""" project = RAT.Project.model_construct(backgrounds=RAT.ClassList(RAT.models.Background(value_1=test_value))) - with pytest.raises(ValueError, match=f'The value "{test_value}" in the "value_1" field of "backgrounds" must be ' - f'defined in "background_parameters".'): + with pytest.raises( + ValueError, + match=f'The value "{test_value}" in the "value_1" field of "backgrounds" must be ' + f'defined in "background_parameters".', + ): project.check_allowed_values("backgrounds", ["value_1"], ["Background Param 1"]) -@pytest.mark.parametrize("test_values", [ - [], - ['Test Layer'], -]) +@pytest.mark.parametrize( + "test_values", + [ + [], + ["Test Layer"], + ], +) def test_check_contrast_model_allowed_values(test_values: list[str]) -> None: - """We should not raise an error if values are defined in a non-empty list and all are on the list of allowed values. + """We should not raise an error if values are defined in a non-empty list and all are on the list of allowed + values. """ - project = RAT.Project.model_construct(contrasts=RAT.ClassList(RAT.models.Contrast(name='Test Contrast', - model=test_values))) + project = RAT.Project.model_construct( + contrasts=RAT.ClassList(RAT.models.Contrast(name="Test Contrast", model=test_values)), + ) assert project.check_contrast_model_allowed_values("contrasts", ["Test Layer"], "layers") is None -@pytest.mark.parametrize("test_values", [ - ["Undefined Param"], - ["Test Layer", "Undefined Param"], -]) -def test_check_allowed_values_not_on_list(test_values: list[str]) -> None: +@pytest.mark.parametrize( + "test_values", + [ + ["Undefined Param"], + ["Test Layer", "Undefined Param"], + ], +) +def test_check_allowed_contrast_model_not_on_list(test_values: list[str]) -> None: """If string values are defined in a non-empty list and any of them are not included on the list of allowed values we should raise a ValueError. """ - project = RAT.Project.model_construct(contrasts=RAT.ClassList(RAT.models.Contrast(name='Test Contrast', - model=test_values))) - with pytest.raises(ValueError, match=f'The values: "{", ".join(str(i) for i in test_values)}" in the "model" field ' - f'of "contrasts" must be defined in "layers".'): + project = RAT.Project.model_construct( + contrasts=RAT.ClassList(RAT.models.Contrast(name="Test Contrast", model=test_values)), + ) + with pytest.raises( + ValueError, + match=f'The values: "{", ".join(str(i) for i in test_values)}" in the "model" field ' + f'of "contrasts" must be defined in "layers".', + ): project.check_contrast_model_allowed_values("contrasts", ["Test Layer"], "layers") -@pytest.mark.parametrize(["input_calc", "input_model", "expected_field_name"], [ - (Calculations.Domains, LayerModels.StandardLayers, 'domain_contrasts'), - (Calculations.NonPolarised, LayerModels.StandardLayers, 'layers'), - (Calculations.Domains, LayerModels.CustomLayers, 'custom_files'), - (Calculations.NonPolarised, LayerModels.CustomLayers, 'custom_files'), - (Calculations.Domains, LayerModels.CustomXY, 'custom_files'), - (Calculations.NonPolarised, LayerModels.CustomXY, 'custom_files'), -]) +@pytest.mark.parametrize( + ["input_calc", "input_model", "expected_field_name"], + [ + (Calculations.Domains, LayerModels.StandardLayers, "domain_contrasts"), + (Calculations.NonPolarised, LayerModels.StandardLayers, "layers"), + (Calculations.Domains, LayerModels.CustomLayers, "custom_files"), + (Calculations.NonPolarised, LayerModels.CustomLayers, "custom_files"), + (Calculations.Domains, LayerModels.CustomXY, "custom_files"), + (Calculations.NonPolarised, LayerModels.CustomXY, "custom_files"), + ], +) def test_get_contrast_model_field(input_calc: Calculations, input_model: LayerModels, expected_field_name: str) -> None: """Each combination of calculation and model determines the field where the values of "model" field of "contrasts" are defined. @@ -686,236 +965,275 @@ def test_get_contrast_model_field(input_calc: Calculations, input_model: LayerMo assert project.get_contrast_model_field() == expected_field_name -@pytest.mark.parametrize("input_filename", [ - "test_script.py", - "test_script" -]) +@pytest.mark.parametrize( + "input_filename", + [ + "test_script.py", + "test_script", + ], +) def test_write_script(test_project, temp_dir, test_project_script, input_filename: str) -> None: """Test the script we write to regenerate the project is created and runs as expected.""" - test_project.write_script('problem', os.path.join(temp_dir, input_filename)) + test_project.write_script("problem", os.path.join(temp_dir, input_filename)) # Test the file is written in the correct place - script_path = os.path.join(temp_dir, 'test_script.py') + script_path = os.path.join(temp_dir, "test_script.py") assert os.path.isfile(script_path) # Test the contents of the file are as expected - with open(script_path, 'r') as f: + with open(script_path) as f: script = f.read() assert script == test_project_script # Test we get the project object we expect when running the script exec(script) - new_project = locals()['problem'] + new_project = locals()["problem"] for class_list in RAT.project.class_lists: assert getattr(new_project, class_list) == getattr(test_project, class_list) -@pytest.mark.parametrize("extension", [ - ".txt" - ".f90" - ".m" - ".pyc" -]) +@pytest.mark.parametrize( + "extension", + [ + ".txt", + ".f90", + ".m", + ".pyc", + ], +) def test_write_script_wrong_extension(test_project, extension: str) -> None: """If we try to write the script to anything other than a ".py" file, we raise a ValueError.""" with pytest.raises(ValueError, match='The script name provided to "write_script" must use the ".py" format'): - test_project.write_script('problem', 'test' + extension) - - -@pytest.mark.parametrize(["class_list", "field"], [ - ('backgrounds', 'value_1'), - ('backgrounds', 'value_2'), - ('backgrounds', 'value_3'), - ('backgrounds', 'value_4'), - ('backgrounds', 'value_5'), - ('resolutions', 'value_1'), - ('resolutions', 'value_2'), - ('resolutions', 'value_3'), - ('resolutions', 'value_4'), - ('resolutions', 'value_5'), - ('layers', 'thickness'), - ('layers', 'SLD'), - ('layers', 'roughness'), - ('contrasts', 'data'), - ('contrasts', 'background'), - ('contrasts', 'bulk_in'), - ('contrasts', 'bulk_out'), - ('contrasts', 'scalefactor'), - ('contrasts', 'resolution'), -]) + test_project.write_script("problem", "test" + extension) + + +@pytest.mark.parametrize( + ["class_list", "field"], + [ + ("backgrounds", "value_1"), + ("backgrounds", "value_2"), + ("backgrounds", "value_3"), + ("backgrounds", "value_4"), + ("backgrounds", "value_5"), + ("resolutions", "value_1"), + ("resolutions", "value_2"), + ("resolutions", "value_3"), + ("resolutions", "value_4"), + ("resolutions", "value_5"), + ("layers", "thickness"), + ("layers", "SLD"), + ("layers", "roughness"), + ("contrasts", "data"), + ("contrasts", "background"), + ("contrasts", "bulk_in"), + ("contrasts", "bulk_out"), + ("contrasts", "scalefactor"), + ("contrasts", "resolution"), + ], +) def test_wrap_set(test_project, class_list: str, field: str) -> None: """If we set the field values of a model in a ClassList as undefined values, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "{class_list}" must be ' - f'defined in ' - f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".'): - test_attribute.set_fields(0, **{field: 'undefined'}) + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Project\n Value error, The value ' + f'"undefined" in the "{field}" field of "{class_list}" must be ' + f'defined in ' + f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".', + ): + test_attribute.set_fields(0, **{field: "undefined"}) # Ensure invalid model was not changed assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "parameter", "field"], [ - ('background_parameters', 'Background Param 1', 'value_1'), - ('resolution_parameters', 'Resolution Param 1', 'value_1'), - ('parameters', 'Test SLD', 'SLD'), - ('data', 'Simulation', 'data'), - ('backgrounds', 'Background 1', 'background'), - ('bulk_in', 'SLD Air', 'bulk_in'), - ('bulk_out', 'SLD D2O', 'bulk_out'), - ('scalefactors', 'Scalefactor 1', 'scalefactor'), - ('resolutions', 'Resolution 1', 'resolution'), -]) +@pytest.mark.parametrize( + ["class_list", "parameter", "field"], + [ + ("background_parameters", "Background Param 1", "value_1"), + ("resolution_parameters", "Resolution Param 1", "value_1"), + ("parameters", "Test SLD", "SLD"), + ("data", "Simulation", "data"), + ("backgrounds", "Background 1", "background"), + ("bulk_in", "SLD Air", "bulk_in"), + ("bulk_out", "SLD D2O", "bulk_out"), + ("scalefactors", "Scalefactor 1", "scalefactor"), + ("resolutions", "Resolution 1", "resolution"), + ], +) def test_wrap_del(test_project, class_list: str, parameter: str, field: str) -> None: """If we delete a model in a ClassList containing values defined elsewhere, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) index = test_attribute.index(parameter) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"{parameter}" in the "{field}" field of ' - f'"{RAT.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"{parameter}" in the "{field}" field of ' + f'"{RAT.project.model_names_used_in[class_list].attribute}" ' + f'must be defined in "{class_list}".', + ): del test_attribute[index] # Ensure model was not deleted assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "field", "model_params"], [ - ('backgrounds', 'value_1', {}), - ('backgrounds', 'value_2', {}), - ('backgrounds', 'value_3', {}), - ('backgrounds', 'value_4', {}), - ('backgrounds', 'value_5', {}), - ('resolutions', 'value_1', {}), - ('resolutions', 'value_2', {}), - ('resolutions', 'value_3', {}), - ('resolutions', 'value_4', {}), - ('resolutions', 'value_5', {}), - ('layers', 'thickness', layer_params), - ('layers', 'SLD', layer_params), - ('layers', 'roughness', layer_params), - ('contrasts', 'data', {}), - ('contrasts', 'background', {}), - ('contrasts', 'bulk_in', {}), - ('contrasts', 'bulk_out', {}), - ('contrasts', 'scalefactor', {}), - ('contrasts', 'resolution', {}), -]) +@pytest.mark.parametrize( + ["class_list", "field", "model_params"], + [ + ("backgrounds", "value_1", {}), + ("backgrounds", "value_2", {}), + ("backgrounds", "value_3", {}), + ("backgrounds", "value_4", {}), + ("backgrounds", "value_5", {}), + ("resolutions", "value_1", {}), + ("resolutions", "value_2", {}), + ("resolutions", "value_3", {}), + ("resolutions", "value_4", {}), + ("resolutions", "value_5", {}), + ("layers", "thickness", layer_params), + ("layers", "SLD", layer_params), + ("layers", "roughness", layer_params), + ("contrasts", "data", {}), + ("contrasts", "background", {}), + ("contrasts", "bulk_in", {}), + ("contrasts", "bulk_out", {}), + ("contrasts", "scalefactor", {}), + ("contrasts", "resolution", {}), + ], +) def test_wrap_iadd(test_project, class_list: str, field: str, model_params: dict) -> None: """If we add a model containing undefined values to a ClassList, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) input_model = getattr(RAT.models, RAT.project.model_in_classlist[class_list]) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "{class_list}" must be ' - f'defined in ' - f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".'): - test_attribute += [input_model(**{**model_params, field: 'undefined'})] + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Project\n Value error, The value ' + f'"undefined" in the "{field}" field of "{class_list}" must be ' + f'defined in ' + f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".', + ): + test_attribute += [input_model(**{**model_params, field: "undefined"})] # Ensure invalid model was not added assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "field", "model_params"], [ - ('backgrounds', 'value_1', {}), - ('backgrounds', 'value_2', {}), - ('backgrounds', 'value_3', {}), - ('backgrounds', 'value_4', {}), - ('backgrounds', 'value_5', {}), - ('resolutions', 'value_1', {}), - ('resolutions', 'value_2', {}), - ('resolutions', 'value_3', {}), - ('resolutions', 'value_4', {}), - ('resolutions', 'value_5', {}), - ('layers', 'thickness', layer_params), - ('layers', 'SLD', layer_params), - ('layers', 'roughness', layer_params), - ('contrasts', 'data', {}), - ('contrasts', 'background', {}), - ('contrasts', 'bulk_in', {}), - ('contrasts', 'bulk_out', {}), - ('contrasts', 'scalefactor', {}), - ('contrasts', 'resolution', {}), -]) +@pytest.mark.parametrize( + ["class_list", "field", "model_params"], + [ + ("backgrounds", "value_1", {}), + ("backgrounds", "value_2", {}), + ("backgrounds", "value_3", {}), + ("backgrounds", "value_4", {}), + ("backgrounds", "value_5", {}), + ("resolutions", "value_1", {}), + ("resolutions", "value_2", {}), + ("resolutions", "value_3", {}), + ("resolutions", "value_4", {}), + ("resolutions", "value_5", {}), + ("layers", "thickness", layer_params), + ("layers", "SLD", layer_params), + ("layers", "roughness", layer_params), + ("contrasts", "data", {}), + ("contrasts", "background", {}), + ("contrasts", "bulk_in", {}), + ("contrasts", "bulk_out", {}), + ("contrasts", "scalefactor", {}), + ("contrasts", "resolution", {}), + ], +) def test_wrap_append(test_project, class_list: str, field: str, model_params: dict) -> None: """If we append a model containing undefined values to a ClassList, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) input_model = getattr(RAT.models, RAT.project.model_in_classlist[class_list]) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "{class_list}" must be ' - f'defined in ' - f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".'): - test_attribute.append(input_model(**{**model_params, field: 'undefined'})) + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Project\n Value error, The value ' + f'"undefined" in the "{field}" field of "{class_list}" must be ' + f'defined in ' + f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".', + ): + test_attribute.append(input_model(**{**model_params, field: "undefined"})) # Ensure invalid model was not appended assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "field", "model_params"], [ - ('backgrounds', 'value_1', {}), - ('backgrounds', 'value_2', {}), - ('backgrounds', 'value_3', {}), - ('backgrounds', 'value_4', {}), - ('backgrounds', 'value_5', {}), - ('resolutions', 'value_1', {}), - ('resolutions', 'value_2', {}), - ('resolutions', 'value_3', {}), - ('resolutions', 'value_4', {}), - ('resolutions', 'value_5', {}), - ('layers', 'thickness', layer_params), - ('layers', 'SLD', layer_params), - ('layers', 'roughness', layer_params), - ('contrasts', 'data', {}), - ('contrasts', 'background', {}), - ('contrasts', 'bulk_in', {}), - ('contrasts', 'bulk_out', {}), - ('contrasts', 'scalefactor', {}), - ('contrasts', 'resolution', {}), -]) +@pytest.mark.parametrize( + ["class_list", "field", "model_params"], + [ + ("backgrounds", "value_1", {}), + ("backgrounds", "value_2", {}), + ("backgrounds", "value_3", {}), + ("backgrounds", "value_4", {}), + ("backgrounds", "value_5", {}), + ("resolutions", "value_1", {}), + ("resolutions", "value_2", {}), + ("resolutions", "value_3", {}), + ("resolutions", "value_4", {}), + ("resolutions", "value_5", {}), + ("layers", "thickness", layer_params), + ("layers", "SLD", layer_params), + ("layers", "roughness", layer_params), + ("contrasts", "data", {}), + ("contrasts", "background", {}), + ("contrasts", "bulk_in", {}), + ("contrasts", "bulk_out", {}), + ("contrasts", "scalefactor", {}), + ("contrasts", "resolution", {}), + ], +) def test_wrap_insert(test_project, class_list: str, field: str, model_params: dict) -> None: """If we insert a model containing undefined values into a ClassList, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) input_model = getattr(RAT.models, RAT.project.model_in_classlist[class_list]) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "{class_list}" must be ' - f'defined in ' - f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".'): - test_attribute.insert(0, input_model(**{**model_params, field: 'undefined'})) + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Project\n Value error, The value ' + f'"undefined" in the "{field}" field of "{class_list}" must be ' + f'defined in ' + f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".', + ): + test_attribute.insert(0, input_model(**{**model_params, field: "undefined"})) # Ensure invalid model was not inserted assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "field"], [ - ('backgrounds', 'value_1'), - ('backgrounds', 'value_2'), - ('backgrounds', 'value_3'), - ('backgrounds', 'value_4'), - ('backgrounds', 'value_5'), - ('resolutions', 'value_1'), - ('resolutions', 'value_2'), - ('resolutions', 'value_3'), - ('resolutions', 'value_4'), - ('resolutions', 'value_5'), - ('contrasts', 'data'), - ('contrasts', 'background'), - ('contrasts', 'bulk_in'), - ('contrasts', 'bulk_out'), - ('contrasts', 'scalefactor'), - ('contrasts', 'resolution'), -]) +@pytest.mark.parametrize( + ["class_list", "field"], + [ + ("backgrounds", "value_1"), + ("backgrounds", "value_2"), + ("backgrounds", "value_3"), + ("backgrounds", "value_4"), + ("backgrounds", "value_5"), + ("resolutions", "value_1"), + ("resolutions", "value_2"), + ("resolutions", "value_3"), + ("resolutions", "value_4"), + ("resolutions", "value_5"), + ("contrasts", "data"), + ("contrasts", "background"), + ("contrasts", "bulk_in"), + ("contrasts", "bulk_out"), + ("contrasts", "scalefactor"), + ("contrasts", "resolution"), + ], +) def test_wrap_insert_type_error(test_project, class_list: str, field: str) -> None: """If we raise a TypeError using the wrapped insert routine, we should re-raise the error.""" test_attribute = getattr(test_project, class_list) @@ -929,117 +1247,141 @@ def test_wrap_insert_type_error(test_project, class_list: str, field: str) -> No assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "parameter", "field"], [ - ('background_parameters', 'Background Param 1', 'value_1'), - ('resolution_parameters', 'Resolution Param 1', 'value_1'), - ('parameters', 'Test SLD', 'SLD'), - ('data', 'Simulation', 'data'), - ('backgrounds', 'Background 1', 'background'), - ('bulk_in', 'SLD Air', 'bulk_in'), - ('bulk_out', 'SLD D2O', 'bulk_out'), - ('scalefactors', 'Scalefactor 1', 'scalefactor'), - ('resolutions', 'Resolution 1', 'resolution'), -]) +@pytest.mark.parametrize( + ["class_list", "parameter", "field"], + [ + ("background_parameters", "Background Param 1", "value_1"), + ("resolution_parameters", "Resolution Param 1", "value_1"), + ("parameters", "Test SLD", "SLD"), + ("data", "Simulation", "data"), + ("backgrounds", "Background 1", "background"), + ("bulk_in", "SLD Air", "bulk_in"), + ("bulk_out", "SLD D2O", "bulk_out"), + ("scalefactors", "Scalefactor 1", "scalefactor"), + ("resolutions", "Resolution 1", "resolution"), + ], +) def test_wrap_pop(test_project, class_list: str, parameter: str, field: str) -> None: """If we pop a model in a ClassList containing values defined elsewhere, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) index = test_attribute.index(parameter) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"{parameter}" in the "{field}" field of ' - f'"{RAT.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"{parameter}" in the "{field}" field of ' + f'"{RAT.project.model_names_used_in[class_list].attribute}" ' + f'must be defined in "{class_list}".', + ): test_attribute.pop(index) # Ensure model was not popped assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "parameter", "field"], [ - ('background_parameters', 'Background Param 1', 'value_1'), - ('resolution_parameters', 'Resolution Param 1', 'value_1'), - ('parameters', 'Test SLD', 'SLD'), - ('data', 'Simulation', 'data'), - ('backgrounds', 'Background 1', 'background'), - ('bulk_in', 'SLD Air', 'bulk_in'), - ('bulk_out', 'SLD D2O', 'bulk_out'), - ('scalefactors', 'Scalefactor 1', 'scalefactor'), - ('resolutions', 'Resolution 1', 'resolution'), -]) +@pytest.mark.parametrize( + ["class_list", "parameter", "field"], + [ + ("background_parameters", "Background Param 1", "value_1"), + ("resolution_parameters", "Resolution Param 1", "value_1"), + ("parameters", "Test SLD", "SLD"), + ("data", "Simulation", "data"), + ("backgrounds", "Background 1", "background"), + ("bulk_in", "SLD Air", "bulk_in"), + ("bulk_out", "SLD D2O", "bulk_out"), + ("scalefactors", "Scalefactor 1", "scalefactor"), + ("resolutions", "Resolution 1", "resolution"), + ], +) def test_wrap_remove(test_project, class_list: str, parameter: str, field: str) -> None: """If we remove a model in a ClassList containing values defined elsewhere, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"{parameter}" in the "{field}" field of ' - f'"{RAT.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"{parameter}" in the "{field}" field of ' + f'"{RAT.project.model_names_used_in[class_list].attribute}" ' + f'must be defined in "{class_list}".', + ): test_attribute.remove(parameter) # Ensure model was not removed assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "parameter", "field"], [ - ('background_parameters', 'Background Param 1', 'value_1'), - ('resolution_parameters', 'Resolution Param 1', 'value_1'), - ('parameters', 'Test Thickness', 'thickness'), - ('data', 'Simulation', 'data'), - ('backgrounds', 'Background 1', 'background'), - ('bulk_in', 'SLD Air', 'bulk_in'), - ('bulk_out', 'SLD D2O', 'bulk_out'), - ('scalefactors', 'Scalefactor 1', 'scalefactor'), - ('resolutions', 'Resolution 1', 'resolution'), -]) +@pytest.mark.parametrize( + ["class_list", "parameter", "field"], + [ + ("background_parameters", "Background Param 1", "value_1"), + ("resolution_parameters", "Resolution Param 1", "value_1"), + ("parameters", "Test Thickness", "thickness"), + ("data", "Simulation", "data"), + ("backgrounds", "Background 1", "background"), + ("bulk_in", "SLD Air", "bulk_in"), + ("bulk_out", "SLD D2O", "bulk_out"), + ("scalefactors", "Scalefactor 1", "scalefactor"), + ("resolutions", "Resolution 1", "resolution"), + ], +) def test_wrap_clear(test_project, class_list: str, parameter: str, field: str) -> None: """If we clear a ClassList containing models with values defined elsewhere, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"{parameter}" in the "{field}" field of ' - f'"{RAT.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".'): + with pytest.raises( + pydantic.ValidationError, + match=f"1 validation error for Project\n Value error, The value " + f'"{parameter}" in the "{field}" field of ' + f'"{RAT.project.model_names_used_in[class_list].attribute}" ' + f'must be defined in "{class_list}".', + ): test_attribute.clear() # Ensure list was not cleared assert test_attribute == orig_class_list -@pytest.mark.parametrize(["class_list", "field", "model_params"], [ - ('backgrounds', 'value_1', {}), - ('backgrounds', 'value_2', {}), - ('backgrounds', 'value_3', {}), - ('backgrounds', 'value_4', {}), - ('backgrounds', 'value_5', {}), - ('resolutions', 'value_1', {}), - ('resolutions', 'value_2', {}), - ('resolutions', 'value_3', {}), - ('resolutions', 'value_4', {}), - ('resolutions', 'value_5', {}), - ('layers', 'thickness', layer_params), - ('layers', 'SLD', layer_params), - ('layers', 'roughness', layer_params), - ('contrasts', 'data', {}), - ('contrasts', 'background', {}), - ('contrasts', 'bulk_in', {}), - ('contrasts', 'bulk_out', {}), - ('contrasts', 'scalefactor', {}), - ('contrasts', 'resolution', {}), -]) +@pytest.mark.parametrize( + ["class_list", "field", "model_params"], + [ + ("backgrounds", "value_1", {}), + ("backgrounds", "value_2", {}), + ("backgrounds", "value_3", {}), + ("backgrounds", "value_4", {}), + ("backgrounds", "value_5", {}), + ("resolutions", "value_1", {}), + ("resolutions", "value_2", {}), + ("resolutions", "value_3", {}), + ("resolutions", "value_4", {}), + ("resolutions", "value_5", {}), + ("layers", "thickness", layer_params), + ("layers", "SLD", layer_params), + ("layers", "roughness", layer_params), + ("contrasts", "data", {}), + ("contrasts", "background", {}), + ("contrasts", "bulk_in", {}), + ("contrasts", "bulk_out", {}), + ("contrasts", "scalefactor", {}), + ("contrasts", "resolution", {}), + ], +) def test_wrap_extend(test_project, class_list: str, field: str, model_params: dict) -> None: """If we extend a ClassList with model containing undefined values, we should raise a ValidationError.""" test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) input_model = getattr(RAT.models, RAT.project.model_in_classlist[class_list]) - with pytest.raises(pydantic.ValidationError, match=f'1 validation error for Project\n Value error, The value ' - f'"undefined" in the "{field}" field of "{class_list}" must be ' - f'defined in ' - f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".'): - test_attribute.extend([input_model(**{**model_params, field: 'undefined'})]) + with pytest.raises( + pydantic.ValidationError, + match=f'1 validation error for Project\n Value error, The value ' + f'"undefined" in the "{field}" field of "{class_list}" must be ' + f'defined in ' + f'"{RAT.project.values_defined_in[f"{class_list}.{field}"]}".', + ): + test_attribute.extend([input_model(**{**model_params, field: "undefined"})]) # Ensure invalid model was not appended assert test_attribute == orig_class_list diff --git a/tests/test_run.py b/tests/test_run.py index 3fcaac2b..115fc971 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -1,18 +1,17 @@ -""" -Test the run module using the example calculation from "DSPC_standard_layers.py". +"""Test the run module using the example calculation from "DSPC_standard_layers.py". We use the example for both a reflectivity calculation, and Bayesian analysis using the Dream algorithm. """ +from unittest import mock + import numpy as np import pytest -import unittest.mock as mock import RAT import RAT.outputs import RAT.rat_core from RAT.utils.enums import Calculations, Geometries, LayerModels, Procedures - from tests.utils import check_results_equal @@ -21,50 +20,215 @@ def input_project(): """A cut-down version of the input Project object for a reflectivity calculation set out in "DSPC_standard_layers.py". """ - project = RAT.Project(name="original_dspc_bilayer", calculation="non polarised", model="standard layers", - geometry="substrate/liquid", absorption=False) + project = RAT.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.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) @@ -81,10 +245,20 @@ def input_project(): 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) + 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 @@ -99,10 +273,31 @@ def reflectivity_calculation_problem(): problem.modelType = LayerModels.StandardLayers problem.geometry = Geometries.SubstrateLiquid problem.useImaginary = False - problem.params = np.array([3.000e+00, 1.954e+01, 3.390e-06, 2.266e+01, -4.010e-07, 5.252e+00, - 5.640e+00, 1.712e+01, 0.000e+00, 8.560e+00, 1.750e-06, 4.545e+01, - 1.070e+01, 1.470e-06, 6.014e+00, 1.782e+01, -4.610e-07, 1.764e+01, - 3.615e+01, 1.000e+02, 2.361e+01]) + problem.params = np.array( + [ + 3.000e00, + 1.954e01, + 3.390e-06, + 2.266e01, + -4.010e-07, + 5.252e00, + 5.640e00, + 1.712e01, + 0.000e00, + 8.560e00, + 1.750e-06, + 4.545e01, + 1.070e01, + 1.470e-06, + 6.014e00, + 1.782e01, + -4.610e-07, + 1.764e01, + 3.615e01, + 1.000e02, + 2.361e01, + ], + ) problem.bulkIn = np.array([2.073e-06]) problem.bulkOut = np.array([5.98e-06, 2.21e-06]) problem.qzshifts = np.array([0.0]) @@ -125,40 +320,80 @@ def reflectivity_calculation_problem(): problem.numberOfContrasts = 2.0 problem.numberOfLayers = 6.0 problem.numberOfDomainContrasts = 0.0 - problem.fitParams = np.array([3.000e+00, 1.954e+01, 2.266e+01, 5.252e+00, 5.640e+00, 1.712e+01, 8.560e+00, - 4.545e+01, 1.070e+01, 6.014e+00, 1.782e+01, 1.764e+01, 3.615e+01, 2.361e+01, - 2.230e-06, 3.380e-06, 5.980e-06, 2.210e-06]) - problem.otherParams = np.array([3.390e-06, -4.010e-07, 0.000e+00, 1.750e-06, 1.470e-06, -4.610e-07, - 1.000e+02, 1.000e-01, 1.500e-01, 2.073e-06, 3.000e-02]) - problem.fitLimits = np.array([[1.00e+00, 1.00e+01], - [5.00e+00, 6.00e+01], - [1.50e+01, 3.50e+01], - [1.00e+00, 5.00e+01], - [1.00e+00, 1.50e+01], - [1.00e+01, 2.80e+01], - [5.00e+00, 1.70e+01], - [1.00e+01, 5.00e+01], - [7.00e+00, 1.70e+01], - [2.00e+00, 1.50e+01], - [1.40e+01, 2.20e+01], - [1.00e+01, 5.00e+01], - [1.00e+01, 5.00e+01], - [0.00e+00, 6.00e+01], - [5.00e-10, 7.00e-06], - [1.00e-10, 4.99e-06], - [5.50e-06, 6.40e-06], - [1.00e-06, 4.99e-06]]) - problem.otherLimits = np.array([[3.39e-06, 3.41e-06], - [-5.00e-07, -3.00e-07], - [0.00e+00, 1.00e-09], - [1.00e-07, 2.00e-06], - [5.00e-07, 1.50e-06], - [-5.00e-07, 0.00e+00], - [9.99e+01, 1.00e+02], - [5.00e-02, 2.00e-01], - [5.00e-02, 2.00e-01], - [2.00e-06, 2.10e-06], - [1.00e-02, 5.00e-02]]) + problem.fitParams = np.array( + [ + 3.000e00, + 1.954e01, + 2.266e01, + 5.252e00, + 5.640e00, + 1.712e01, + 8.560e00, + 4.545e01, + 1.070e01, + 6.014e00, + 1.782e01, + 1.764e01, + 3.615e01, + 2.361e01, + 2.230e-06, + 3.380e-06, + 5.980e-06, + 2.210e-06, + ], + ) + problem.otherParams = np.array( + [ + 3.390e-06, + -4.010e-07, + 0.000e00, + 1.750e-06, + 1.470e-06, + -4.610e-07, + 1.000e02, + 1.000e-01, + 1.500e-01, + 2.073e-06, + 3.000e-02, + ], + ) + problem.fitLimits = np.array( + [ + [1.00e00, 1.00e01], + [5.00e00, 6.00e01], + [1.50e01, 3.50e01], + [1.00e00, 5.00e01], + [1.00e00, 1.50e01], + [1.00e01, 2.80e01], + [5.00e00, 1.70e01], + [1.00e01, 5.00e01], + [7.00e00, 1.70e01], + [2.00e00, 1.50e01], + [1.40e01, 2.20e01], + [1.00e01, 5.00e01], + [1.00e01, 5.00e01], + [0.00e00, 6.00e01], + [5.00e-10, 7.00e-06], + [1.00e-10, 4.99e-06], + [5.50e-06, 6.40e-06], + [1.00e-06, 4.99e-06], + ], + ) + problem.otherLimits = np.array( + [ + [3.39e-06, 3.41e-06], + [-5.00e-07, -3.00e-07], + [0.00e00, 1.00e-09], + [1.00e-07, 2.00e-06], + [5.00e-07, 1.50e-06], + [-5.00e-07, 0.00e00], + [9.99e01, 1.00e02], + [5.00e-02, 2.00e-01], + [5.00e-02, 2.00e-01], + [2.00e-06, 2.10e-06], + [1.00e-02, 5.00e-02], + ], + ) return problem @@ -175,12 +410,31 @@ def dream_problem(): problem.modelType = LayerModels.StandardLayers problem.geometry = Geometries.SubstrateLiquid problem.useImaginary = False - problem.params = np.array([6.19503045e+00, 1.84420960e+01, 3.39000000e-06, 2.11039621e+01, - -4.01000000e-07, 8.75538121e+00, 3.72292994e+00, 1.84624551e+01, - 0.00000000e+00, 1.02316734e+01, 1.75000000e-06, 2.31156093e+01, - 1.09906265e+01, 1.47000000e-06, 5.71005361e+00, 1.67933822e+01, - -4.61000000e-07, 1.72009856e+01, 3.00260126e+01, 1.00000000e+02, - 2.94448999e+01]) + problem.params = np.array( + [ + 6.19503045e00, + 1.84420960e01, + 3.39000000e-06, + 2.11039621e01, + -4.01000000e-07, + 8.75538121e00, + 3.72292994e00, + 1.84624551e01, + 0.00000000e00, + 1.02316734e01, + 1.75000000e-06, + 2.31156093e01, + 1.09906265e01, + 1.47000000e-06, + 5.71005361e00, + 1.67933822e01, + -4.61000000e-07, + 1.72009856e01, + 3.00260126e01, + 1.00000000e02, + 2.94448999e01, + ], + ) problem.bulkIn = np.array([2.073e-06]) problem.bulkOut = np.array([6.01489149e-06, 1.59371685e-06]) problem.qzshifts = np.array([0.0]) @@ -203,51 +457,99 @@ def dream_problem(): problem.numberOfContrasts = 2.0 problem.numberOfLayers = 6.0 problem.numberOfDomainContrasts = 0.0 - problem.fitParams = np.array([6.19503045e+00, 1.84420960e+01, 2.11039621e+01, 8.75538121e+00, - 3.72292994e+00, 1.84624551e+01, 1.02316734e+01, 2.31156093e+01, - 1.09906265e+01, 5.71005361e+00, 1.67933822e+01, 1.72009856e+01, - 3.00260126e+01, 2.94448999e+01, 2.37113128e-06, 1.99006694e-06, - 6.01489149e-06, 1.59371685e-06]) - problem.otherParams = np.array([3.390e-06, -4.010e-07, 0.000e+00, 1.750e-06, 1.470e-06, -4.610e-07, - 1.000e+02, 1.000e-01, 1.500e-01, 2.073e-06, 3.000e-02, 0.000e+00]) - problem.fitLimits = np.array([[1.00e+00, 1.00e+01], - [5.00e+00, 6.00e+01], - [1.50e+01, 3.50e+01], - [1.00e+00, 5.00e+01], - [1.00e+00, 1.50e+01], - [1.00e+01, 2.80e+01], - [5.00e+00, 1.70e+01], - [1.00e+01, 5.00e+01], - [7.00e+00, 1.70e+01], - [2.00e+00, 1.50e+01], - [1.40e+01, 2.20e+01], - [1.00e+01, 5.00e+01], - [1.00e+01, 5.00e+01], - [0.00e+00, 6.00e+01], - [5.00e-10, 7.00e-06], - [1.00e-10, 4.99e-06], - [5.50e-06, 6.40e-06], - [1.00e-06, 4.99e-06]]) - problem.otherLimits = np.array([[3.39e-06, 3.41e-06], - [-5.00e-07, -3.00e-07], - [0.00e+00, 1.00e-09], - [1.00e-07, 2.00e-06], - [5.00e-07, 1.50e-06], - [-5.00e-07, 0.00e+00], - [9.99e+01, 1.00e+02], - [5.00e-02, 2.00e-01], - [5.00e-02, 2.00e-01], - [2.00e-06, 2.10e-06], - [1.00e-02, 5.00e-02], - [0.00e+00, 0.00e+00]]) + problem.fitParams = np.array( + [ + 6.19503045e00, + 1.84420960e01, + 2.11039621e01, + 8.75538121e00, + 3.72292994e00, + 1.84624551e01, + 1.02316734e01, + 2.31156093e01, + 1.09906265e01, + 5.71005361e00, + 1.67933822e01, + 1.72009856e01, + 3.00260126e01, + 2.94448999e01, + 2.37113128e-06, + 1.99006694e-06, + 6.01489149e-06, + 1.59371685e-06, + ], + ) + problem.otherParams = np.array( + [ + 3.390e-06, + -4.010e-07, + 0.000e00, + 1.750e-06, + 1.470e-06, + -4.610e-07, + 1.000e02, + 1.000e-01, + 1.500e-01, + 2.073e-06, + 3.000e-02, + 0.000e00, + ], + ) + problem.fitLimits = np.array( + [ + [1.00e00, 1.00e01], + [5.00e00, 6.00e01], + [1.50e01, 3.50e01], + [1.00e00, 5.00e01], + [1.00e00, 1.50e01], + [1.00e01, 2.80e01], + [5.00e00, 1.70e01], + [1.00e01, 5.00e01], + [7.00e00, 1.70e01], + [2.00e00, 1.50e01], + [1.40e01, 2.20e01], + [1.00e01, 5.00e01], + [1.00e01, 5.00e01], + [0.00e00, 6.00e01], + [5.00e-10, 7.00e-06], + [1.00e-10, 4.99e-06], + [5.50e-06, 6.40e-06], + [1.00e-06, 4.99e-06], + ], + ) + problem.otherLimits = np.array( + [ + [3.39e-06, 3.41e-06], + [-5.00e-07, -3.00e-07], + [0.00e00, 1.00e-09], + [1.00e-07, 2.00e-06], + [5.00e-07, 1.50e-06], + [-5.00e-07, 0.00e00], + [9.99e01, 1.00e02], + [5.00e-02, 2.00e-01], + [5.00e-02, 2.00e-01], + [2.00e-06, 2.10e-06], + [1.00e-02, 5.00e-02], + [0.00e00, 0.00e00], + ], + ) return problem -@pytest.mark.parametrize(["test_procedure", "test_output_problem", "test_output_results", "test_bayes", "test_results"], [ - (Procedures.Calculate, "reflectivity_calculation_problem", "reflectivity_calculation_output_results", None, "reflectivity_calculation_results"), - (Procedures.Dream, "dream_problem", "dream_output_results", "dream_bayes", "dream_results"), -]) +@pytest.mark.parametrize( + ["test_procedure", "test_output_problem", "test_output_results", "test_bayes", "test_results"], + [ + ( + Procedures.Calculate, + "reflectivity_calculation_problem", + "reflectivity_calculation_output_results", + None, + "reflectivity_calculation_results", + ), + (Procedures.Dream, "dream_problem", "dream_output_results", "dream_bayes", "dream_results"), + ], +) def test_run(test_procedure, test_output_problem, test_output_results, test_bayes, test_results, request) -> None: input_project = request.getfixturevalue("input_project") test_output_problem = request.getfixturevalue(test_output_problem) @@ -257,9 +559,11 @@ def test_run(test_procedure, test_output_problem, test_output_results, test_baye test_results = request.getfixturevalue(test_results) - with mock.patch.object(RAT.rat_core, "RATMain", mock.MagicMock(return_value=(test_output_problem, - test_output_results, - test_bayes))): + with mock.patch.object( + RAT.rat_core, + "RATMain", + mock.MagicMock(return_value=(test_output_problem, test_output_results, test_bayes)), + ): # Use default project as we patch RATMain to give the desired outputs project, results = RAT.run(input_project, RAT.set_controls(procedure=test_procedure)) diff --git a/tests/test_wrappers.py b/tests/test_wrappers.py index fc8ef7a3..aa135c34 100644 --- a/tests/test_wrappers.py +++ b/tests/test_wrappers.py @@ -1,28 +1,28 @@ import pathlib -import unittest.mock as mock +from unittest import mock + import pytest + import RAT.wrappers def test_matlab_wrapper() -> None: - with mock.patch.dict('sys.modules', {'matlab': mock.MagicMock(side_effect=ImportError)}): - with pytest.raises(ImportError): - RAT.wrappers.MatlabWrapper('demo.m') + with mock.patch.dict("sys.modules", {"matlab": mock.MagicMock(side_effect=ImportError)}), pytest.raises( + ImportError, + ): + RAT.wrappers.MatlabWrapper("demo.m") mocked_matlab_module = mock.MagicMock() mocked_engine = mock.MagicMock() mocked_matlab_module.engine.start_matlab.return_value = mocked_engine - - # mocked_matlab_module.engine = mock.MagicMock() - with mock.patch.dict('sys.modules', {'matlab': mocked_matlab_module, - 'matlab.engine': mocked_matlab_module.engine}): - wrapper = RAT.wrappers.MatlabWrapper('demo.m') - assert wrapper.function_name == 'demo' + with mock.patch.dict("sys.modules", {"matlab": mocked_matlab_module, "matlab.engine": mocked_matlab_module.engine}): + wrapper = RAT.wrappers.MatlabWrapper("demo.m") + assert wrapper.function_name == "demo" mocked_engine.cd.assert_called_once() - assert pathlib.Path(mocked_engine.cd.call_args[0][0]).samefile('.') + assert pathlib.Path(mocked_engine.cd.call_args[0][0]).samefile(".") handle = wrapper.getHandle() - + mocked_engine.demo.return_value = ([2], 5) result = handle([1], [2], [3], 0) assert result == ([2], 5) @@ -34,13 +34,13 @@ def test_matlab_wrapper() -> None: assert result == ([3, 1], 7) assert wrapper.engine.demo.call_args[0] == ([4], [5], [6], 2, 2) assert mocked_engine.demo.call_count == 2 - + def test_dylib_wrapper() -> None: mocked_engine = mock.MagicMock() - with mock.patch('RAT.wrappers.RAT.rat_core.DylibEngine', mocked_engine): - wrapper = RAT.wrappers.DylibWrapper('demo.dylib', 'demo') - mocked_engine.assert_called_once_with('demo.dylib', 'demo') + with mock.patch("RAT.wrappers.RAT.rat_core.DylibEngine", mocked_engine): + wrapper = RAT.wrappers.DylibWrapper("demo.dylib", "demo") + mocked_engine.assert_called_once_with("demo.dylib", "demo") wrapper.engine.invoke.return_value = ([2], 5) handle = wrapper.getHandle() diff --git a/tests/utils.py b/tests/utils.py index 18a4c376..03833ee3 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,16 +1,16 @@ import numpy as np -from typing import Any import RAT.outputs class InputAttributes: """Set input arguments as class attributes.""" + def __init__(self, **kwargs) -> None: for key, value in kwargs.items(): setattr(self, key, value) - def __eq__(self, other: Any): + def __eq__(self, other: object): if isinstance(other, InputAttributes): return self.__dict__ == other.__dict__ return False @@ -18,12 +18,10 @@ def __eq__(self, other: Any): class SubInputAttributes(InputAttributes): """Trivial subclass of InputAttributes.""" - pass def dummy_function() -> None: """Trivial function for function handle tests.""" - pass def check_results_equal(actual_results, expected_results) -> None: @@ -32,21 +30,26 @@ def check_results_equal(actual_results, expected_results) -> None: We focus here on the fields common to both results objects, and also check the equality of the subclasses "CalculationResults" and "ContrastParams". """ - list_fields = ["reflectivity", "simulation", "shiftedData"] double_list_fields = ["layerSlds", "sldProfiles", "resampledLayers"] - contrast_param_fields = ["backgroundParams", "scalefactors", "bulkIn", "bulkOut", "resolutionParams", "subRoughs", - "resample"] - - assert ((isinstance(actual_results, RAT.outputs.Results) and - isinstance(expected_results, RAT.outputs.Results)) or - (isinstance(actual_results, RAT.outputs.BayesResults) and - isinstance(expected_results, RAT.outputs.BayesResults))) + contrast_param_fields = [ + "backgroundParams", + "scalefactors", + "bulkIn", + "bulkOut", + "resolutionParams", + "subRoughs", + "resample", + ] + + assert (isinstance(actual_results, RAT.outputs.Results) and isinstance(expected_results, RAT.outputs.Results)) or ( + isinstance(actual_results, RAT.outputs.BayesResults) and isinstance(expected_results, RAT.outputs.BayesResults) + ) # The first set of fields are either 1D or 2D python lists containing numpy arrays. # Hence, we need to compare them element-wise. for list_field in list_fields: - for (a, b) in zip(getattr(actual_results, list_field), getattr(expected_results, list_field)): + for a, b in zip(getattr(actual_results, list_field), getattr(expected_results, list_field)): assert (a == b).all() for list_field in double_list_fields: @@ -54,7 +57,7 @@ def check_results_equal(actual_results, expected_results) -> None: expected_list = getattr(expected_results, list_field) assert len(actual_list) == len(expected_list) for i in range(len(actual_list)): - for (a, b) in zip(actual_list[i], expected_list[i]): + for a, b in zip(actual_list[i], expected_list[i]): assert (a == b).all() # Compare the final fields @@ -71,47 +74,65 @@ def check_results_equal(actual_results, expected_results) -> None: if isinstance(actual_results, RAT.outputs.BayesResults) and isinstance(expected_results, RAT.outputs.BayesResults): check_bayes_fields_equal(actual_results, expected_results) - return None - def check_bayes_fields_equal(actual_results, expected_results) -> None: """Compare two instances of the "BayesResults" object for equality. We focus here on the fields and subclasses specific to the Bayesian optimisation. """ - # The BayesResults object consists of a number of subclasses, each containing fields of differing formats. subclasses = ["predictionIntervals", "confidenceIntervals", "dreamParams", "dreamOutput", "nestedSamplerOutput"] - param_fields = {"predictionIntervals": [], - "confidenceIntervals": [], - "dreamParams": ["nParams", "nChains", "nGenerations", "parallel", "CPU", "jumpProbability", - "pUnitGamma", "nCR", "delta", "steps", "zeta", "outlier", "adaptPCR", "thinning", - "epsilon", "ABC", "IO", "storeOutput"], - "dreamOutput": ["runtime", "iteration", "modelOutput"], - "nestedSamplerOutput": ["logZ"] - } - - list_fields = {"predictionIntervals": ["reflectivity", "reflectivityXData"], - "confidenceIntervals": [], - "dreamParams": [], - "dreamOutput": [], - "nestedSamplerOutput": [] - } - - double_list_fields = {"predictionIntervals": ["sld", "sldXData"], - "confidenceIntervals": [], - "dreamParams": [], - "dreamOutput": [], - "nestedSamplerOutput": [] - } - - array_fields = {"predictionIntervals": ["sampleChi"], - "confidenceIntervals": ["percentile65", "percentile95", "mean"], - "dreamParams": ["R"], - "dreamOutput": ["allChains", "outlierChains", "AR", "R_stat", "CR"], - "nestedSamplerOutput": ["nestSamples", "postSamples"], - } + param_fields = { + "predictionIntervals": [], + "confidenceIntervals": [], + "dreamParams": [ + "nParams", + "nChains", + "nGenerations", + "parallel", + "CPU", + "jumpProbability", + "pUnitGamma", + "nCR", + "delta", + "steps", + "zeta", + "outlier", + "adaptPCR", + "thinning", + "epsilon", + "ABC", + "IO", + "storeOutput", + ], + "dreamOutput": ["runtime", "iteration", "modelOutput"], + "nestedSamplerOutput": ["logZ"], + } + + list_fields = { + "predictionIntervals": ["reflectivity", "reflectivityXData"], + "confidenceIntervals": [], + "dreamParams": [], + "dreamOutput": [], + "nestedSamplerOutput": [], + } + + double_list_fields = { + "predictionIntervals": ["sld", "sldXData"], + "confidenceIntervals": [], + "dreamParams": [], + "dreamOutput": [], + "nestedSamplerOutput": [], + } + + array_fields = { + "predictionIntervals": ["sampleChi"], + "confidenceIntervals": ["percentile65", "percentile95", "mean"], + "dreamParams": ["R"], + "dreamOutput": ["allChains", "outlierChains", "AR", "R_stat", "CR"], + "nestedSamplerOutput": ["nestSamples", "postSamples"], + } for subclass in subclasses: actual_subclass = getattr(actual_results, subclass) @@ -121,7 +142,7 @@ def check_bayes_fields_equal(actual_results, expected_results) -> None: assert getattr(actual_subclass, field) == getattr(expected_subclass, field) for field in list_fields[subclass]: - for (a, b) in zip(getattr(actual_subclass, field), getattr(expected_subclass, field)): + for a, b in zip(getattr(actual_subclass, field), getattr(expected_subclass, field)): assert (a == b).all() for field in double_list_fields[subclass]: @@ -129,7 +150,7 @@ def check_bayes_fields_equal(actual_results, expected_results) -> None: expected_list = getattr(expected_subclass, field) assert len(actual_list) == len(expected_list) for i in range(len(actual_list)): - for (a, b) in zip(actual_list[i], expected_list[i]): + for a, b in zip(actual_list[i], expected_list[i]): assert (a == b).all() # Need to account for the arrays that are initialised as "NaN" in the compiled code @@ -137,10 +158,9 @@ def check_bayes_fields_equal(actual_results, expected_results) -> None: actual_array = getattr(actual_subclass, array) expected_array = getattr(expected_subclass, array) for i in range(len(actual_array)): - assert ((actual_array == expected_array).all() or - (['NaN' if np.isnan(el) else el for el in actual_array[i]] == - ['NaN' if np.isnan(el) else el for el in expected_array[i]])) + assert (actual_array == expected_array).all() or ( + ["NaN" if np.isnan(el) else el for el in actual_array[i]] + == ["NaN" if np.isnan(el) else el for el in expected_array[i]] + ) assert (actual_results.chain == expected_results.chain).all() - - return None