diff --git a/.github/workflows/build_wheel.yml b/.github/workflows/build_wheel.yml index db91cf86..688118ed 100644 --- a/.github/workflows/build_wheel.yml +++ b/.github/workflows/build_wheel.yml @@ -11,12 +11,14 @@ jobs: strategy: fail-fast: true matrix: - platform: [windows-latest, ubuntu-latest, macos-13, macos-14] + platform: [windows-latest, ubuntu-latest, macos-15-intel, macos-14] env: CIBW_SKIP: 'pp*' CIBW_ARCHS: 'auto64' - CIBW_PROJECT_REQUIRES_PYTHON: '>=3.9' + CIBW_MANYLINUX_X86_64_IMAGE: 'manylinux_2_28' + CIBW_PROJECT_REQUIRES_PYTHON: '>=3.10' CIBW_TEST_REQUIRES: 'pytest' + MACOSX_DEPLOYMENT_TARGET: '14.0' defaults: run: shell: bash -l {0} @@ -24,18 +26,19 @@ jobs: runs-on: ${{ matrix.platform }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: submodules: true - - name: Set up Python version ${{ matrix.version }} - uses: actions/setup-python@v4 + - name: Set up Python version + uses: actions/setup-python@v6 with: python-version: "3.x" - name: Install OMP (MacOS Intel) - if: matrix.platform == 'macos-13' + if: matrix.platform == 'macos-15-intel' run: | - brew install llvm libomp - echo "export CC=/usr/local/opt/llvm/bin/clang" >> ~/.bashrc + brew install llvm@20 libomp + echo "export CC=/usr/local/opt/llvm@20/bin/clang" >> ~/.bashrc + echo "export CXX=/usr/local/opt/llvm@20/bin/clang++" >> ~/.bashrc echo "export CFLAGS=\"$CFLAGS -I/usr/local/opt/libomp/include\"" >> ~/.bashrc echo "export CXXFLAGS=\"$CXXFLAGS -I/usr/local/opt/libomp/include\"" >> ~/.bashrc echo "export LDFLAGS=\"$LDFLAGS -Wl,-rpath,/usr/local/opt/libomp/lib -L/usr/local/opt/libomp/lib -lomp\"" >> ~/.bashrc @@ -43,8 +46,9 @@ jobs: - name: Install OMP (MacOS M1) if: matrix.platform == 'macos-14' run: | - brew install llvm libomp - echo "export CC=/opt/homebrew/opt/llvm/bin/clang" >> ~/.bashrc + brew install llvm@20 libomp + echo "export CC=/opt/homebrew/opt/llvm@20/bin/clang" >> ~/.bashrc + echo "export CXX=/opt/homebrew/opt/llvm@20/bin/clang++" >> ~/.bashrc echo "export CFLAGS=\"$CFLAGS -I/opt/homebrew/opt/libomp/include\"" >> ~/.bashrc echo "export CXXFLAGS=\"$CXXFLAGS -I/opt/homebrew/opt/libomp/include\"" >> ~/.bashrc echo "export LDFLAGS=\"$LDFLAGS -Wl,-rpath,/opt/homebrew/opt/libomp/lib -L/opt/homebrew/opt/libomp/lib -lomp\"" >> ~/.bashrc @@ -60,9 +64,10 @@ jobs: # of local package. mkdir tmp cp -r tests tmp/tests/ + export PATH="$pythonLocation:$PATH" CIBW_TEST_COMMAND='cd ${pwd}/tmp && python -m pytest tests' echo "CIBW_TEST_COMMAND=${CIBW_TEST_COMMAND}" >> $GITHUB_ENV - python -m pip install cibuildwheel==2.16.5 + python -m pip install cibuildwheel python -m cibuildwheel --output-dir ./wheelhouse - uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c0cbe3c..8ac33f95 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,6 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + submodules: true - name: Build sdist run: | pip install pybind11 diff --git a/.github/workflows/run_ruff.yml b/.github/workflows/run_ruff.yml index 5fc5b79f..64637b07 100644 --- a/.github/workflows/run_ruff.yml +++ b/.github/workflows/run_ruff.yml @@ -7,8 +7,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: chartboost/ruff-action@v1 - - uses: chartboost/ruff-action@v1 - with: - args: 'format --check' + - uses: astral-sh/ruff-action@v3 + - run: ruff format --check \ No newline at end of file diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 191ee87b..7dce1346 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -19,31 +19,42 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-latest, windows-latest, macos-13] - version: ["3.9", "3.x"] + platform: [windows-latest, ubuntu-latest, macos-15-intel, macos-latest] + version: ["3.10", "3.13"] defaults: run: shell: bash -l {0} - runs-on: ${{ matrix.os }} + runs-on: ${{ matrix.platform}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: submodules: true - name: Set up Python version ${{ matrix.version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.version }} - - name: Install OMP (MacOS) - if: runner.os == 'macOS' + - name: Install OMP (MacOS Intel) + if: matrix.platform == 'macos-15-intel' run: | - brew install llvm libomp - echo "export CC=/usr/local/opt/llvm/bin/clang" >> ~/.bashrc + brew install llvm@20 libomp + echo "export CC=/usr/local/opt/llvm@20/bin/clang" >> ~/.bashrc + echo "export CXX=/usr/local/opt/llvm@20/bin/clang++" >> ~/.bashrc echo "export CFLAGS=\"$CFLAGS -I/usr/local/opt/libomp/include\"" >> ~/.bashrc echo "export CXXFLAGS=\"$CXXFLAGS -I/usr/local/opt/libomp/include\"" >> ~/.bashrc echo "export LDFLAGS=\"$LDFLAGS -Wl,-rpath,/usr/local/opt/libomp/lib -L/usr/local/opt/libomp/lib -lomp\"" >> ~/.bashrc source ~/.bashrc + - name: Install OMP (MacOS M1) + if: matrix.platform == 'macos-latest' + run: | + brew install llvm@20 libomp + echo "export CC=/opt/homebrew/opt/llvm@20/bin/clang" >> ~/.bashrc + echo "export CXX=/opt/homebrew/opt/llvm@20/bin/clang++" >> ~/.bashrc + echo "export CFLAGS=\"$CFLAGS -I/opt/homebrew/opt/libomp/include\"" >> ~/.bashrc + echo "export CXXFLAGS=\"$CXXFLAGS -I/opt/homebrew/opt/libomp/include\"" >> ~/.bashrc + echo "export LDFLAGS=\"$LDFLAGS -Wl,-rpath,/opt/homebrew/opt/libomp/lib -L/opt/homebrew/opt/libomp/lib -lomp\"" >> ~/.bashrc + source ~/.bashrc - name: Install OMP (Linux) if: runner.os == 'Linux' run: | @@ -51,5 +62,6 @@ jobs: sudo apt install libomp-dev - name: Install and Test with pytest run: | - python -m pip install -e .[Dev] - pytest tests/ --cov=RATapi --cov-report=term + export PATH="$pythonLocation:$PATH" + python -m pip install -e .[dev,orso] + pytest tests/ --cov=ratapi --cov-report=term diff --git a/.gitignore b/.gitignore index 5cab62d3..51a84ffe 100644 --- a/.gitignore +++ b/.gitignore @@ -7,11 +7,17 @@ __pycache__/ .idea .vscode +# direnv +.envrc + # Unit test / coverage reports htmlcov/ .coverage .cache/ +# Temp files +tmp/ + # Build _build docs/.buildinfo @@ -31,3 +37,9 @@ dist/* # Local pre-commit hooks .pre-commit-config.yaml + +# Jupyter notebook checkpoints +.ipynb_checkpoints/* + +# Lock file for uv env +uv.lock diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 157a515f..6980c2c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,7 @@ issue has not been reported already) or submitting a pull request. Create Developer Environment ---------------------------- -This project targets Python 3.9 or later. Install an appropriate version of Python and other dependencies +This project targets Python 3.10 or later. Install an appropriate version of Python and other dependencies Then create a fork of the python-RAT repo, and clone the fork diff --git a/MANIFEST.in b/MANIFEST.in index 086d5f71..a4a255ab 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,5 @@ include README.md -recursive-include cpp/RAT * +recursive-include cpp * prune tests prune */__pycache__ global-exclude .git diff --git a/RATapi/__init__.py b/RATapi/__init__.py deleted file mode 100644 index a8ce43b3..00000000 --- a/RATapi/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -import RATapi.examples as examples -from RATapi import events, models -from RATapi.classlist import ClassList -from RATapi.controls import Controls -from RATapi.project import Project -from RATapi.run import run -from RATapi.utils import convert, plotting - -__all__ = ["examples", "models", "events", "ClassList", "Controls", "Project", "run", "plotting", "convert"] diff --git a/RATapi/classlist.py b/RATapi/classlist.py deleted file mode 100644 index 20512b22..00000000 --- a/RATapi/classlist.py +++ /dev/null @@ -1,403 +0,0 @@ -"""The classlist module. Contains the ClassList class, which defines a list containing instances of a particular -class. -""" - -import collections -import contextlib -import warnings -from collections.abc import Iterable, Sequence -from typing import Any, Union - -import numpy as np -import prettytable - - -class ClassList(collections.UserList): - """List of instances of a particular class. - - This class subclasses collections.UserList to construct a list intended to store ONLY instances of a particular - class, given on initialisation. Any attempt to introduce an object of a different type will raise a ValueError. - The class must be able to accept attribute values using keyword arguments. In addition, if the class has the - attribute given in the ClassList's "name_field" attribute (the default is "name"), the ClassList will ensure that - all objects within the ClassList have unique values for that attribute. It is then possible to use this attribute - of an object in the .remove(), .count(), and .index() routines in place of the full object. Due to the requirement - of unique values of the name_field attribute, the multiplication operators __mul__, __rmul__, and __imul__ have - been disabled, since they cannot allow for unique attribute values by definition. - - We extend the UserList class to enable objects to be added and modified using just the keyword arguments, enable - the object name_field attribute to be used in place of the full object, and ensure all elements are of the - specified type, with unique name_field attributes defined. - - Parameters - ---------- - init_list : Sequence [object] or object, optional - 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 - - # Set input as list if necessary - if init_list and not (isinstance(init_list, Sequence) and not isinstance(init_list, str)): - init_list = [init_list] - - # Set class to be used for this instance of the ClassList, checking that all elements of the input list are of - # the same type and have unique values of the specified name_field - if init_list: - self._class_handle = self._determine_class_handle(init_list) - self._check_classes(init_list) - self._check_unique_name_fields(init_list) - - super().__init__(init_list) - - def __str__(self): - try: - [model.__dict__ for model in self.data] - except AttributeError: - output = str(self.data) - 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__] - table.add_rows( - [ - [index] - + list( - f"{'Data array: ['+' x '.join(str(i) for i in v.shape) if v.size > 0 else '['}]" - if isinstance(v, np.ndarray) - else "\n".join(element for element in v) - if k == "model" - else str(v) - for k, v in model.__dict__.items() - ) - for index, model in enumerate(self.data) - ] - ) - output = table.get_string() - else: - output = str(self.data) - return output - - def __getitem__(self, index: Union[int, slice, str, object]) -> object: - """Get an item by its index, name, a slice, or the object itself.""" - if isinstance(index, (int, slice)): - return self.data[index] - elif isinstance(index, (str, object)): - return self.data[self.index(index)] - else: - raise IndexError("ClassLists can only be indexed by integers, slices, name strings, or objects.") - - def __setitem__(self, index: int, item: object) -> None: - """Replace the object at an existing index of the ClassList.""" - self._setitem(index, item) - - def _setitem(self, index: int, item: object) -> None: - """Auxiliary routine of "__setitem__" used to enable wrapping.""" - self._check_classes(self + [item]) - self._check_unique_name_fields(self + [item]) - self.data[index] = item - - def __delitem__(self, index: int) -> None: - """Delete an object from the list by index.""" - self._delitem(index) - - 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": - """Define in-place addition using the "+=" operator.""" - return self._iadd(other) - - 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"): - self._class_handle = self._determine_class_handle(self + other) - self._check_classes(self + other) - self._check_unique_name_fields(self + other) - super().__iadd__(other) - return self - - def __mul__(self, n: int) -> None: - """Define multiplication using the "*" operator.""" - raise TypeError(f"unsupported operand type(s) for *: '{self.__class__.__name__}' and '{n.__class__.__name__}'") - - def __rmul__(self, n: int) -> None: - """Define multiplication using the "*" operator.""" - raise TypeError(f"unsupported operand type(s) for *: '{n.__class__.__name__}' and '{self.__class__.__name__}'") - - def __imul__(self, n: int) -> None: - """Define in-place multiplication using the "*=" operator.""" - raise TypeError(f"unsupported operand type(s) for *=: '{self.__class__.__name__}' and '{n.__class__.__name__}'") - - def append(self, obj: object = None, **kwargs) -> None: - """Append a new object to the ClassList using either the object itself, or keyword arguments to set attribute - values. - - Parameters - ---------- - obj : object, optional - An instance of the class specified by self._class_handle. - **kwargs : dict[str, Any], optional - The input keyword arguments for a new object in the ClassList. - - Raises - ------ - ValueError - Raised if the input arguments contain a name_field value already defined in the ClassList. - - Warnings - -------- - 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, - stacklevel=2, - ) - if obj: - 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.", - ) - self._validate_name_field(kwargs) - self.data.append(self._class_handle(**kwargs)) - - def insert(self, index: int, obj: object = None, **kwargs) -> None: - """Insert a new object into the ClassList at a given index using either the object itself, or keyword arguments - to set attribute values. - - Parameters - ---------- - index: int - The index at which to insert a new object in the ClassList. - obj : object, optional - An instance of the class specified by self._class_handle. - **kwargs : dict[str, Any], optional - The input keyword arguments for a new object in the ClassList. - - Raises - ------ - ValueError - Raised if the input arguments contain a name_field value already defined in the ClassList. - - Warnings - -------- - 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, - stacklevel=2, - ) - if obj: - 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.", - ) - self._validate_name_field(kwargs) - self.data.insert(index, self._class_handle(**kwargs)) - - def remove(self, item: Union[object, str]) -> None: - """Remove an object from the ClassList using either the object itself or its name_field value.""" - item = self._get_item_from_name_field(item) - self.data.remove(item) - - def count(self, item: Union[object, str]) -> int: - """Return the number of times an object appears in the ClassList using either the object itself or its - name_field value. - """ - item = self._get_item_from_name_field(item) - return self.data.count(item) - - def index(self, item: Union[object, str], offset: bool = False, *args) -> int: - """Return the index of a particular object in the ClassList using either the object itself or its - name_field value. If offset is specified, add one to the index. This is used to account for one-based indexing. - """ - item = self._get_item_from_name_field(item) - return self.data.index(item, *args) + int(offset) - - 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"): - self._class_handle = self._determine_class_handle(self + other) - self._check_classes(self + other) - self._check_unique_name_fields(self + other) - self.data.extend(other) - - def set_fields(self, index: int, **kwargs) -> None: - """Assign the values of an existing object's attributes using keyword arguments.""" - self._validate_name_field(kwargs) - class_handle = self.data[index].__class__ - new_fields = {**self.data[index].__dict__, **kwargs} - self.data[index] = class_handle(**new_fields) - - def get_names(self) -> list[str]: - """Return a list of the values of the name_field attribute of each class object in the list. - - Returns - ------- - 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)] - - def get_all_matches(self, value: Any) -> list[tuple]: - """Return a list of all (index, field) tuples where the value of the field is equal to the given value. - - Parameters - ---------- - value : str - The value we are searching for in the ClassList. - - Returns - ------- - : 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 - ] - - 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 - used within the ClassList. - - Parameters - ---------- - input_args : dict [str, Any] - The input keyword arguments for a new object in the ClassList. - - Raises - ------ - ValueError - Raised if the input arguments contain a name_field value already defined in the ClassList. - - """ - names = [name.lower() for name in self.get_names()] - with contextlib.suppress(KeyError): - if input_args[self.name_field].lower() 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", - ) - - 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 - objects. - - Parameters - ---------- - input_list : iterable - An iterable of instances of the class given in self._class_handle. - - Raises - ------ - ValueError - Raised if the input list defines more than one object with the same value of name_field. - - """ - names = [getattr(model, self.name_field).lower() for model in input_list if hasattr(model, self.name_field)] - if len(set(names)) != len(names): - raise ValueError(f"Input list contains objects with the same value of the {self.name_field} attribute") - - def _check_classes(self, input_list: Iterable[object]) -> None: - """Raise a ValueError if any object in a list of objects is not of the type specified by self._class_handle. - - Parameters - ---------- - input_list : iterable - A list of instances of the class given in self._class_handle. - - Raises - ------ - 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__}'") - - def _get_item_from_name_field(self, value: Union[object, str]) -> Union[object, str]: - """Return the object with the given value of the name_field attribute in the ClassList. - - Parameters - ---------- - value : object or str - Either an object in the ClassList, or the value of the name_field attribute of an object in the ClassList. - - Returns - ------- - 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. - - """ - try: - lower_value = value.lower() - except AttributeError: - lower_value = value - - return next((model for model in self.data if getattr(model, self.name_field).lower() == lower_value), value) - - @staticmethod - def _determine_class_handle(input_list: Sequence[object]): - """When inputting a sequence of object to a ClassList, the _class_handle should be set as the type of the - element which satisfies "issubclass" for all of the other elements. - - Parameters - ---------- - input_list : Sequence [object] - A list of instances to populate the ClassList. - - Returns - ------- - 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]): - class_handle = type(this_element) - break - else: - class_handle = type(input_list[0]) - - return class_handle diff --git a/RATapi/controls.py b/RATapi/controls.py deleted file mode 100644 index 78b2ff5f..00000000 --- a/RATapi/controls.py +++ /dev/null @@ -1,143 +0,0 @@ -import warnings - -import prettytable -from pydantic import ( - BaseModel, - Field, - ValidationError, - ValidatorFunctionWrapHandler, - field_validator, - model_serializer, - model_validator, -) - -from RATapi.utils.custom_errors import custom_pydantic_validation_error -from RATapi.utils.enums import BoundHandling, Display, Parallel, Procedures, Strategies - -common_fields = ["procedure", "parallel", "calcSldDuringFit", "resampleParams", "display"] -update_fields = ["updateFreq", "updatePlotFreq"] -fields = { - "calculate": common_fields, - "simplex": [*common_fields, "xTolerance", "funcTolerance", "maxFuncEvals", "maxIterations", *update_fields], - "de": [ - *common_fields, - "populationSize", - "fWeight", - "crossoverProbability", - "strategy", - "targetValue", - "numGenerations", - *update_fields, - ], - "ns": [*common_fields, "nLive", "nMCMC", "propScale", "nsTolerance"], - "dream": [*common_fields, "nSamples", "nChains", "jumpProbability", "pUnitGamma", "boundHandling", "adaptPCR"], -} - - -class Controls(BaseModel, validate_assignment=True, extra="forbid"): - """The full set of controls parameters for all five procedures that are required for the compiled RAT code.""" - - # All Procedures - procedure: Procedures = Procedures.Calculate - parallel: Parallel = Parallel.Single - calcSldDuringFit: bool = False - resampleParams: list[float] = Field([0.9, 50], min_length=2, max_length=2) - display: Display = Display.Iter - # Simplex - xTolerance: float = Field(1.0e-6, gt=0.0) - funcTolerance: float = Field(1.0e-6, gt=0.0) - maxFuncEvals: int = Field(10000, gt=0) - maxIterations: int = Field(1000, gt=0) - # Simplex and DE - updateFreq: int = 1 - updatePlotFreq: int = 20 - # DE - populationSize: int = Field(20, ge=1) - fWeight: float = 0.5 - crossoverProbability: float = Field(0.8, gt=0.0, lt=1.0) - strategy: Strategies = Strategies.RandomWithPerVectorDither - targetValue: float = Field(1.0, ge=1.0) - numGenerations: int = Field(500, ge=1) - # NS - nLive: int = Field(150, ge=1) - nMCMC: float = Field(0.0, ge=0.0) - propScale: float = Field(0.1, gt=0.0, lt=1.0) - nsTolerance: float = Field(0.1, ge=0.0) - # Dream - nSamples: int = Field(20000, ge=0) - nChains: int = Field(10, gt=0) - jumpProbability: float = Field(0.5, gt=0.0, lt=1.0) - pUnitGamma: float = Field(0.2, gt=0.0, lt=1.0) - boundHandling: BoundHandling = BoundHandling.Reflect - adaptPCR: bool = True - - @model_validator(mode="wrap") - def warn_setting_incorrect_properties(self, handler: ValidatorFunctionWrapHandler) -> "Controls": - """Raise a warning if the user sets fields that apply to other procedures.""" - model_input = self - try: - input_dict = model_input.__dict__ - except AttributeError: - input_dict = model_input - - validated_self = None - try: - validated_self = handler(self) - except ValidationError as exc: - procedure = input_dict.get("procedure", Procedures.Calculate) - custom_error_msgs = { - "extra_forbidden": f'Extra inputs are not permitted. The fields for the "{procedure}"' - f' controls procedure are:\n ' - f'{", ".join(fields.get("procedure", []))}\n', - } - custom_error_list = custom_pydantic_validation_error(exc.errors(), custom_error_msgs) - raise ValidationError.from_exception_data(exc.title, custom_error_list, hide_input=True) from None - - if isinstance(model_input, validated_self.__class__): - # This is for changing fields in a defined model - changed_fields = [key for key in input_dict if input_dict[key] != validated_self.__dict__[key]] - elif isinstance(model_input, dict): - # This is for a newly-defined model - changed_fields = input_dict.keys() - else: - raise ValueError('The input to the "Controls" model is invalid.') - - new_procedure = validated_self.procedure - allowed_fields = fields[new_procedure] - for field in changed_fields: - if field not in allowed_fields: - incorrect_procedures = [key for (key, value) in fields.items() if field in value] - warnings.warn( - f'\nThe current controls procedure is "{new_procedure}", but the property' - f' "{field}" applies instead to the {", ".join(incorrect_procedures)} procedure.\n\n' - f' The fields for the "{new_procedure}" controls procedure are:\n' - f' {", ".join(fields[new_procedure])}\n', - stacklevel=2, - ) - - return validated_self - - @field_validator("resampleParams") - @classmethod - def check_resample_params(cls, values: list[float]) -> list[float]: - """Make sure each of the two values of resampleParams satisfy their conditions.""" - if not 0 < values[0] < 1: - raise ValueError("resampleParams[0] must be between 0 and 1") - if values[1] < 0: - raise ValueError("resampleParams[1] must be greater than or equal to 0") - return values - - @model_serializer - def serialize(self): - """Filter fields so only those applying to the chosen procedure are serialized.""" - return {model_field: getattr(self, model_field) for model_field in fields[self.procedure]} - - def __repr__(self) -> str: - fields_repr = ", ".join(repr(v) if a is None else f"{a}={v!r}" for a, v in self.model_dump().items()) - return f"{self.__repr_name__()}({fields_repr})" - - def __str__(self) -> str: - table = prettytable.PrettyTable() - table.field_names = ["Property", "Value"] - table.add_rows([[k, v] for k, v in self.model_dump().items()]) - return table.get_string() diff --git a/RATapi/examples/__init__.py b/RATapi/examples/__init__.py deleted file mode 100644 index 6d29206f..00000000 --- a/RATapi/examples/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -from RATapi.examples.absorption.absorption import absorption -from RATapi.examples.convert_rascal_project import convert_rascal -from RATapi.examples.domains.domains_custom_layers import domains_custom_layers -from RATapi.examples.domains.domains_custom_XY import domains_custom_XY -from RATapi.examples.domains.domains_standard_layers import domains_standard_layers -from RATapi.examples.non_polarised.DSPC_custom_layers import DSPC_custom_layers -from RATapi.examples.non_polarised.DSPC_custom_XY import DSPC_custom_XY -from RATapi.examples.non_polarised.DSPC_standard_layers import DSPC_standard_layers - -__all__ = [ - "absorption", - "domains_custom_layers", - "domains_custom_XY", - "domains_standard_layers", - "DSPC_custom_layers", - "DSPC_custom_XY", - "DSPC_standard_layers", - "convert_rascal", -] diff --git a/RATapi/examples/absorption/__init__.py b/RATapi/examples/absorption/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/RATapi/examples/convert_rascal_project/__init__.py b/RATapi/examples/convert_rascal_project/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/RATapi/examples/convert_rascal_project/convert_rascal.py b/RATapi/examples/convert_rascal_project/convert_rascal.py deleted file mode 100644 index d5d54e1a..00000000 --- a/RATapi/examples/convert_rascal_project/convert_rascal.py +++ /dev/null @@ -1,28 +0,0 @@ -from pprint import pp - -import RATapi as RAT - - -# convert R1 project to Project class -def convert_rascal(): - project = RAT.utils.convert.r1_to_project_class("R1monolayerVolumeModel.mat") - - # change values if you like, including ones not supported by R1 - project.parameters["Head Thickness"].prior_type = "gaussian" - project.parameters["Theta"].mu = 2.0 - project.parameters["Area per molecule"].sigma = 50.0 - - # convert DSPC standard layers example to a struct and save as file - lipid_bilayer_project = RAT.examples.DSPC_standard_layers()[0] - RAT.utils.convert.project_class_to_r1(lipid_bilayer_project, filename="lipid_bilayer.mat") - - # convert and return as a Python dictionary - struct = RAT.utils.convert.project_class_to_r1(lipid_bilayer_project, return_struct=True) - - return project, struct - - -if __name__ == "__main__": - project, struct = convert_rascal() - print(project) - pp(struct) diff --git a/RATapi/examples/data/__init__.py b/RATapi/examples/data/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/RATapi/examples/domains/__init__.py b/RATapi/examples/domains/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/RATapi/examples/languages/__init__.py b/RATapi/examples/languages/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/RATapi/examples/non_polarised/__init__.py b/RATapi/examples/non_polarised/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/RATapi/inputs.py b/RATapi/inputs.py deleted file mode 100644 index 07dc7087..00000000 --- a/RATapi/inputs.py +++ /dev/null @@ -1,472 +0,0 @@ -"""Converts python models to the necessary inputs for the compiled RAT code""" - -import importlib -import os -import pathlib -from typing import Callable, Union - -import RATapi -import RATapi.controls -import RATapi.wrappers -from RATapi.rat_core import Cells, Checks, Control, Limits, Priors, ProblemDefinition -from RATapi.utils.enums import Calculations, Languages, LayerModels, TypeOptions - - -def make_input( - project: RATapi.Project, controls: RATapi.Controls -) -> 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 - ---------- - project : RAT.Project - The project model, which defines the physical system under study. - controls : RAT.Controls - The controls model, which defines algorithmic properties. - - Returns - ------- - problem : RAT.rat_core.ProblemDefinition - The problem input used in the compiled RAT code. - cells : RAT.rat_core.Cells - The set of inputs that are defined in MATLAB as cell arrays. - limits : RAT.rat_core.Limits - A list of min/max values for each parameter defined in the project. - priors : RAT.rat_core.Priors - 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} - - problem = make_problem(project) - cells = make_cells(project) - - checks = Checks() - limits = Limits() - priors = Priors() - - for class_list in RATapi.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)], - ) - - # Use dummy values for qzshifts - checks.fitQzshift = [] - limits.qzshift = [] - priors.qzshift = [] - - priors.priorNames = [ - param.name for class_list in RATapi.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 RATapi.project.parameter_class_lists - for param in getattr(project, class_list) - ] - - if project.model == LayerModels.CustomXY: - controls.calcSldDuringFit = True - - cpp_controls = make_controls(controls, checks) - - return problem, cells, limits, priors, cpp_controls - - -def make_problem(project: RATapi.Project) -> ProblemDefinition: - """Constructs the problem input required for the compiled RAT code. - - Parameters - ---------- - project : RAT.Project - The project model, which defines the physical system under study. - - Returns - ------- - problem : RAT.rat_core.ProblemDefinition - The problem input used in the compiled RAT code. - - """ - 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) - else: - contrast_custom_files = [project.custom_files.index(contrast.model[0], True) for contrast in project.contrasts] - - # Set background parameters, with -1 used to indicate a data background - contrast_background_params = [] - - for contrast in project.contrasts: - background = project.backgrounds[project.backgrounds.index(contrast.background)] - if background.type == TypeOptions.Data: - contrast_background_params.append(-1) - else: - contrast_background_params.append(project.background_parameters.index(background.value_1, True)) - - # Set resolution parameters, with -1 used to indicate a data resolution - contrast_resolution_params = [] - - for contrast in project.contrasts: - resolution = project.resolutions[project.resolutions.index(contrast.resolution)] - if resolution.type == TypeOptions.Data: - contrast_resolution_params.append(-1) - else: - contrast_resolution_params.append(project.resolution_parameters.index(resolution.value_1, True)) - - problem = ProblemDefinition() - - problem.TF = project.calculation - problem.modelType = project.model - problem.geometry = project.geometry - problem.useImaginary = project.absorption - problem.params = [param.value for param in project.parameters] - problem.bulkIn = [param.value for param in project.bulk_in] - problem.bulkOut = [param.value for param in project.bulk_out] - problem.qzshifts = [0.0] - problem.scalefactors = [param.value for param in project.scalefactors] - problem.domainRatio = [param.value for param in project.domain_ratios] - problem.backgroundParams = [param.value for param in project.background_parameters] - problem.resolutionParams = [param.value for param in project.resolution_parameters] - 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.contrastBackgroundParams = contrast_background_params - problem.contrastBackgroundActions = [action_id[contrast.background_action] for contrast in project.contrasts] - problem.contrastResolutionParams = contrast_resolution_params - problem.contrastCustomFiles = contrast_custom_files - problem.resample = make_resample(project) - problem.dataPresent = make_data_present(project) - problem.oilChiDataPresent = [0] * len(project.contrasts) - problem.numberOfContrasts = len(project.contrasts) - problem.numberOfLayers = len(project.layers) - problem.numberOfDomainContrasts = len(project.domain_contrasts) - problem.fitParams = [ - param.value - for class_list in RATapi.project.parameter_class_lists - for param in getattr(project, class_list) - if param.fit - ] - problem.fitLimits = [ - [param.min, param.max] - for class_list in RATapi.project.parameter_class_lists - for param in getattr(project, class_list) - if param.fit - ] - problem.otherParams = [ - param.value - for class_list in RATapi.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 RATapi.project.parameter_class_lists - for param in getattr(project, class_list) - if not param.fit - ] - - check_indices(problem) - - return problem - - -def make_resample(project: RATapi.Project) -> list[int]: - """Constructs the "resample" field of the problem input required for the compiled RAT code. - - Parameters - ---------- - project : RAT.Project - The project model, which defines the physical system under study. - - Returns - ------- - : list[int] - The "resample" field of the problem input used in the compiled RAT code. - - """ - return [contrast.resample for contrast in project.contrasts] - - -def make_data_present(project: RATapi.Project) -> list[int]: - """Constructs the "dataPresent" field of the problem input required for the compiled RAT code. - - Parameters - ---------- - project : RAT.Project - The project model, which defines the physical system under study. - - Returns - ------- - : 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 - ] - - -def check_indices(problem: ProblemDefinition) -> None: - """Checks the indices in contrast lists in a ProblemDefinition object lie within the range of the corresponding - parameter lists. - - Parameters - ---------- - 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", - } - - # Check the indices -- note we have switched to 1-based indexing at this point - 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}"', - ) - - -def make_cells(project: RATapi.Project) -> Cells: - """Constructs the cells input required for the compiled RAT code. - - Note that the order of the inputs (i.e, f1 to f20) has been hard--coded into the compiled RAT code. - - Parameters - ---------- - project : RAT.Project - The project model, which defines the physical system under study. - - Returns - ------- - 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} - - # 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 - ] - else: - 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.append(hydrate_id[layer.hydrate_with]) - - layer_details.append(layer_params) - - # Find contrast data in project.data classlist - all_data = [] - data_limits = [] - 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 - simulation_range = project.data[data_index].simulation_range - - if data_range: - data_limits.append(data_range) - else: - data_limits.append([0.0, 0.0]) - - if simulation_range: - simulation_limits.append(simulation_range) - else: - simulation_limits.append([0.0, 0.0]) - - file_handles = [] - for custom_file in project.custom_files: - full_path = os.path.join(custom_file.path, custom_file.filename) - if custom_file.language == Languages.Python: - file_handles.append(get_python_handle(custom_file.filename, custom_file.function_name, custom_file.path)) - elif custom_file.language == Languages.Matlab: - file_handles.append(RATapi.wrappers.MatlabWrapper(full_path).getHandle()) - elif custom_file.language == Languages.Cpp: - file_handles.append(RATapi.wrappers.DylibWrapper(full_path, custom_file.function_name).getHandle()) - - # Populate the set of cells - cells = Cells() - cells.f1 = [[0, 1]] * len(project.contrasts) # This is marked as "to do" in RAT - cells.f2 = all_data - cells.f3 = data_limits - cells.f4 = simulation_limits - cells.f5 = [contrast_model if contrast_model else [0] for contrast_model in contrast_models] - cells.f6 = layer_details if project.model == LayerModels.StandardLayers else [[0]] - cells.f7 = [param.name for param in project.parameters] - cells.f8 = [param.name for param in project.background_parameters] - cells.f9 = [param.name for param in project.scalefactors] - cells.f10 = [] # Placeholder for qzshifts - cells.f11 = [param.name for param in project.bulk_in] - cells.f12 = [param.name for param in project.bulk_out] - cells.f13 = [param.name for param in project.resolution_parameters] - cells.f14 = file_handles - cells.f15 = [param.type for param in project.backgrounds] - cells.f16 = [param.type for param in project.resolutions] - - 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 - ] - - cells.f20 = [param.name for param in project.domain_ratios] - cells.f21 = [contrast.name for contrast in project.contrasts] - - return cells - - -def get_python_handle(file_name: str, function_name: str, path: Union[str, pathlib.Path] = "") -> Callable: - """Get the function handle from a function defined in a python module located anywhere within the filesystem. - - Parameters - ---------- - file_name : str - The name of the file containing the function of interest. - function_name : str - The name of the function we wish to obtain the handle for within the module. - path : str - The path to the file containing the function (default is "", which represent the working directory). - - Returns - ------- - 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) - spec.loader.exec_module(custom_module) - handle = getattr(custom_module, function_name) - return handle - - -def make_controls(input_controls: RATapi.Controls, checks: Checks) -> Control: - """Converts the controls object to the format required by the compiled RAT code. - - Parameters - ---------- - input_controls : RAT.Controls - The controls model, which defines algorithmic properties. - checks : Rat.rat_core.Checks - States whether or not to fit each parameter defined in the project. - - Returns - ------- - controls : RAT.rat_core.Control - The controls object used in the compiled RAT code. - - """ - controls = Control() - - controls.procedure = input_controls.procedure - controls.parallel = input_controls.parallel - controls.calcSldDuringFit = input_controls.calcSldDuringFit - controls.resampleParams = input_controls.resampleParams - controls.display = input_controls.display - # Simplex - controls.xTolerance = input_controls.xTolerance - controls.funcTolerance = input_controls.funcTolerance - controls.maxFuncEvals = input_controls.maxFuncEvals - controls.maxIterations = input_controls.maxIterations - controls.updateFreq = input_controls.updateFreq - controls.updatePlotFreq = input_controls.updatePlotFreq - # DE - controls.populationSize = input_controls.populationSize - controls.fWeight = input_controls.fWeight - controls.crossoverProbability = input_controls.crossoverProbability - controls.strategy = input_controls.strategy.value # Required for the IntEnum - controls.targetValue = input_controls.targetValue - controls.numGenerations = input_controls.numGenerations - # NS - controls.nLive = input_controls.nLive - controls.nMCMC = input_controls.nMCMC - controls.propScale = input_controls.propScale - controls.nsTolerance = input_controls.nsTolerance - # Dream - controls.nSamples = input_controls.nSamples - controls.nChains = input_controls.nChains - controls.jumpProbability = input_controls.jumpProbability - controls.pUnitGamma = input_controls.pUnitGamma - controls.boundHandling = input_controls.boundHandling - controls.adaptPCR = input_controls.adaptPCR - # Checks - controls.checks = checks - - return controls diff --git a/RATapi/models.py b/RATapi/models.py deleted file mode 100644 index 560f7c92..00000000 --- a/RATapi/models.py +++ /dev/null @@ -1,349 +0,0 @@ -"""The models module. Contains the pydantic models used by RAT to store project parameters.""" - -import pathlib -from typing import Any, Union - -import numpy as np -import prettytable -from pydantic import BaseModel, Field, ValidationInfo, field_validator, model_validator - -from RATapi.utils.enums import BackgroundActions, Hydration, Languages, Priors, TypeOptions - -try: - from enum import StrEnum -except ImportError: - from strenum import StrEnum - - -def int_sequence(): - """Iterate through integers for use as model counters.""" - num = 1 - while True: - yield str(num) - num += 1 - - -# Create a counter for each model -background_number = int_sequence() -contrast_number = int_sequence() -custom_file_number = int_sequence() -data_number = int_sequence() -domain_contrast_number = int_sequence() -layer_number = int_sequence() -parameter_number = int_sequence() -resolution_number = int_sequence() - - -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})" - - def __str__(self): - table = prettytable.PrettyTable() - table.field_names = [key.replace("_", " ") for key in self.__dict__] - table.add_row(list(self.__dict__.values())) - return table.get_string() - - -class Background(RATModel): - """Defines the Backgrounds in RAT.""" - - 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 = "" - - @field_validator("type") - @classmethod - def validate_unimplemented_backgrounds(cls, type: TypeOptions): - """Raise an error if currently unsupported Data or Function backgrounds are used.""" - # FIXME: once data/function backgrounds have been implemented, - # please remember to remove the @pytest.mark.skip decorators used to skip the tests: - # - tests/test_project.py::test_check_allowed_background_resolution_values_data - # - tests/test_project.py::test_check_allowed_background_resolution_values_on_data_list - if type == TypeOptions.Data: - raise NotImplementedError("Data backgrounds are not yet supported.") - if type == TypeOptions.Function: - raise NotImplementedError("Function backgrounds are not yet supported.") - return type - - -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 = "" - background_action: BackgroundActions = BackgroundActions.Add - bulk_in: str = "" - bulk_out: str = "" - scalefactor: str = "" - resolution: str = "" - resample: bool = False - model: list[str] = [] - - def __str__(self): - table = prettytable.PrettyTable() - table.field_names = [key.replace("_", " ") for key in self.__dict__] - model_entry = "\n".join(element for element in self.model) - table.add_row( - [ - self.name, - self.data, - self.background, - self.background_action, - self.bulk_in, - self.bulk_out, - self.scalefactor, - self.resolution, - self.resample, - model_entry, - ] - ) - return table.get_string() - - -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 = "" - background_action: BackgroundActions = BackgroundActions.Add - bulk_in: str = "" - bulk_out: str = "" - scalefactor: str = "" - resolution: str = "" - resample: bool = False - domain_ratio: str = "" - model: list[str] = [] - - def __str__(self): - table = prettytable.PrettyTable() - table.field_names = [key.replace("_", " ") for key in self.__dict__] - model_entry = "\n".join(element for element in self.model) - table.add_row( - [ - self.name, - self.data, - self.background, - self.background_action, - self.bulk_in, - self.bulk_out, - self.scalefactor, - self.resolution, - self.resample, - model_entry, - ] - ) - return table.get_string() - - -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 = "" - language: Languages = Languages.Python - 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") - 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 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) - 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") - @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') from None - else: - if data.shape[1] < 3: - raise ValueError('"data" must have at least three columns') from None - return data - - @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.""" - if limits[0] > limits[1]: - raise ValueError(f'{info.field_name} "min" value is greater than the "max" value') - return limits - - def model_post_init(self, __context: Any) -> None: - """If the "data_range" and "simulation_range" fields are not set, but "data" is supplied, the ranges should be - set to the min and max values of the first column (assumed to be q) of the supplied data. - """ - if self.data.shape[0] > 0: - data_min = float(np.min(self.data[:, 0])) - data_max = float(np.max(self.data[:, 0])) - for field in ["data_range", "simulation_range"]: - 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": - """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}]", - ) - return self - - 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__ - - 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__ - ) - else: - return NotImplemented # delegate to the other item in the comparison - - def __str__(self): - table = prettytable.PrettyTable() - table.field_names = [key.replace("_", " ") for key in self.__dict__] - array_entry = f"{'Data array: ['+' x '.join(str(i) for i in self.data.shape) if self.data.size > 0 else '['}]" - table.add_row([self.name, array_entry, self.data_range, self.simulation_range]) - return table.get_string() - - -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) - model: list[str] = [] - - def __str__(self): - table = prettytable.PrettyTable() - table.field_names = [key.replace("_", " ") for key in self.__dict__] - model_entry = "\n".join(element for element in self.model) - table.add_row([self.name, model_entry]) - return table.get_string() - - -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) - thickness: str - SLD: str = Field(validation_alias="SLD_real") - roughness: 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) - thickness: str - SLD_real: str = Field(validation_alias="SLD") - SLD_imaginary: str = "" - roughness: 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) - min: float = 0.0 - value: float = 0.0 - max: float = 0.0 - fit: bool = False - prior_type: Priors = Priors.Uniform - mu: float = 0.0 - sigma: float = np.inf - - @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}") - return self - - @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}") - 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) - type: TypeOptions = TypeOptions.Constant - value_1: str = "" - value_2: str = "" - value_3: str = "" - value_4: str = "" - value_5: str = "" diff --git a/RATapi/outputs.py b/RATapi/outputs.py deleted file mode 100644 index d082f527..00000000 --- a/RATapi/outputs.py +++ /dev/null @@ -1,275 +0,0 @@ -"""Converts outputs from the compiled RAT code to python dataclasses""" - -from dataclasses import dataclass -from typing import Any, Optional, Union - -import numpy as np - -import RATapi.rat_core -from RATapi.utils.enums import Procedures - - -def get_field_string(field: str, value: Any, array_limit: int): - """Returns a string representation of class fields where large and multidimensional arrays are represented by their - shape. - - Parameters - ---------- - field : str - The name of the field in the RAT output class. - value : Any - The value of the given field in the RAT output class. - array_limit : int - The maximum length of 1D arrays which will be fully displayed. - - Returns - ------- - field_string : str - The string representation of the field in the RAT output class. - """ - array_text = "Data array: " - if isinstance(value, list) and len(value) > 0: - if isinstance(value[0], np.ndarray): - array_strings = [f"{array_text}[{' x '.join(str(i) for i in array.shape)}]" for array in value] - field_string = f"{field} = [{', '.join(str(string) for string in array_strings)}],\n" - elif isinstance(value[0], list) and len(value[0]) > 0 and isinstance(value[0][0], np.ndarray): - array_strings = [ - [f"{array_text}[{' x '.join(str(i) for i in array.shape)}]" for array in sub_list] for sub_list in value - ] - list_strings = [f"[{', '.join(string for string in list_string)}]" for list_string in array_strings] - field_string = f"{field} = [{', '.join(list_strings)}],\n" - else: - field_string = f"{field} = {str(value)},\n" - elif isinstance(value, np.ndarray): - if value.ndim == 1 and value.size < array_limit: - field_string = f"{field} = {str(value) if value.size > 0 else '[]'},\n" - else: - field_string = f"{field} = {array_text}[{' x '.join(str(i) for i in value.shape)}],\n" - else: - field_string = f"{field} = {str(value)},\n" - - return field_string - - -class RATResult: - def __str__(self): - output = f"{self.__class__.__name__}(\n" - for key, value in self.__dict__.items(): - output += "\t" + get_field_string(key, value, 100) - output += ")" - return output - - -@dataclass -class CalculationResults(RATResult): - chiValues: np.ndarray - sumChi: float - - -@dataclass -class ContrastParams(RATResult): - backgroundParams: np.ndarray - scalefactors: np.ndarray - bulkIn: np.ndarray - bulkOut: np.ndarray - resolutionParams: np.ndarray - subRoughs: np.ndarray - resample: np.ndarray - - -@dataclass -class Results: - reflectivity: list - simulation: list - shiftedData: list - layerSlds: list - sldProfiles: list - resampledLayers: list - calculationResults: CalculationResults - contrastParams: ContrastParams - fitParams: np.ndarray - fitNames: list[str] - - def __str__(self): - output = "" - for key, value in self.__dict__.items(): - output += get_field_string(key, value, 100) - return output - - -@dataclass -class PredictionIntervals(RATResult): - reflectivity: list - sld: list - reflectivityXData: list - sldXData: list - sampleChi: np.ndarray - - -@dataclass -class ConfidenceIntervals(RATResult): - percentile95: np.ndarray - percentile65: np.ndarray - mean: np.ndarray - - -@dataclass -class DreamParams(RATResult): - nParams: float - nChains: float - nGenerations: float - parallel: bool - CPU: float - jumpProbability: float - pUnitGamma: float - nCR: float - delta: float - steps: float - zeta: float - outlier: str - adaptPCR: bool - thinning: float - epsilon: float - ABC: bool - IO: bool - storeOutput: bool - R: np.ndarray - - -@dataclass -class DreamOutput(RATResult): - allChains: np.ndarray - outlierChains: np.ndarray - runtime: float - iteration: float - modelOutput: float - AR: np.ndarray - R_stat: np.ndarray - CR: np.ndarray - - -@dataclass -class NestedSamplerOutput(RATResult): - logZ: float - nestSamples: np.ndarray - postSamples: np.ndarray - - -@dataclass -class BayesResults(Results): - predictionIntervals: PredictionIntervals - confidenceIntervals: ConfidenceIntervals - dreamParams: DreamParams - dreamOutput: DreamOutput - nestedSamplerOutput: NestedSamplerOutput - chain: np.ndarray - - -def make_results( - procedure: Procedures, - output_results: RATapi.rat_core.OutputResult, - bayes_results: Optional[RATapi.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, - ) - contrast_params = ContrastParams( - backgroundParams=output_results.contrastParams.backgroundParams, - scalefactors=output_results.contrastParams.scalefactors, - bulkIn=output_results.contrastParams.bulkIn, - bulkOut=output_results.contrastParams.bulkOut, - resolutionParams=output_results.contrastParams.resolutionParams, - subRoughs=output_results.contrastParams.subRoughs, - 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, - ) - - confidence_intervals = ConfidenceIntervals( - percentile95=bayes_results.confidenceIntervals.percentile95, - percentile65=bayes_results.confidenceIntervals.percentile65, - mean=bayes_results.confidenceIntervals.mean, - ) - - dream_params = DreamParams( - nParams=bayes_results.dreamParams.nParams, - nChains=bayes_results.dreamParams.nChains, - nGenerations=bayes_results.dreamParams.nGenerations, - parallel=bool(bayes_results.dreamParams.parallel), - CPU=bayes_results.dreamParams.CPU, - jumpProbability=bayes_results.dreamParams.jumpProbability, - pUnitGamma=bayes_results.dreamParams.pUnitGamma, - nCR=bayes_results.dreamParams.nCR, - delta=bayes_results.dreamParams.delta, - steps=bayes_results.dreamParams.steps, - zeta=bayes_results.dreamParams.zeta, - outlier=bayes_results.dreamParams.outlier, - adaptPCR=bool(bayes_results.dreamParams.adaptPCR), - thinning=bayes_results.dreamParams.thinning, - epsilon=bayes_results.dreamParams.epsilon, - ABC=bool(bayes_results.dreamParams.ABC), - IO=bool(bayes_results.dreamParams.IO), - storeOutput=bool(bayes_results.dreamParams.storeOutput), - R=bayes_results.dreamParams.R, - ) - - dream_output = DreamOutput( - allChains=bayes_results.dreamOutput.allChains, - outlierChains=bayes_results.dreamOutput.outlierChains, - runtime=bayes_results.dreamOutput.runtime, - iteration=bayes_results.dreamOutput.iteration, - modelOutput=bayes_results.dreamOutput.modelOutput, - AR=bayes_results.dreamOutput.AR, - R_stat=bayes_results.dreamOutput.R_stat, - CR=bayes_results.dreamOutput.CR, - ) - - nested_sampler_output = NestedSamplerOutput( - logZ=bayes_results.nestedSamplerOutput.logZ, - nestSamples=bayes_results.nestedSamplerOutput.nestSamples, - postSamples=bayes_results.nestedSamplerOutput.postSamples, - ) - - results = BayesResults( - reflectivity=output_results.reflectivity, - simulation=output_results.simulation, - shiftedData=output_results.shiftedData, - layerSlds=output_results.layerSlds, - sldProfiles=output_results.sldProfiles, - resampledLayers=output_results.resampledLayers, - calculationResults=calculation_results, - contrastParams=contrast_params, - fitParams=output_results.fitParams, - fitNames=output_results.fitNames, - predictionIntervals=prediction_intervals, - confidenceIntervals=confidence_intervals, - dreamParams=dream_params, - dreamOutput=dream_output, - nestedSamplerOutput=nested_sampler_output, - chain=bayes_results.chain, - ) - - else: - results = Results( - reflectivity=output_results.reflectivity, - simulation=output_results.simulation, - shiftedData=output_results.shiftedData, - layerSlds=output_results.layerSlds, - sldProfiles=output_results.sldProfiles, - resampledLayers=output_results.resampledLayers, - calculationResults=calculation_results, - contrastParams=contrast_params, - fitParams=output_results.fitParams, - fitNames=output_results.fitNames, - ) - - return results diff --git a/RATapi/project.py b/RATapi/project.py deleted file mode 100644 index 3351ce93..00000000 --- a/RATapi/project.py +++ /dev/null @@ -1,717 +0,0 @@ -"""The project module. Defines and stores all the input data required for reflectivity calculations in RAT.""" - -import collections -import copy -import functools -import os -from typing import Any, Callable - -import numpy as np -from pydantic import BaseModel, ValidationError, ValidationInfo, field_validator, model_validator - -import RATapi.models -from RATapi.classlist import ClassList -from RATapi.utils.custom_errors import custom_pydantic_validation_error -from RATapi.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.constant.value_1": "background_parameters", - "backgrounds.constant.value_2": "background_parameters", - "backgrounds.constant.value_3": "background_parameters", - "backgrounds.constant.value_4": "background_parameters", - "backgrounds.constant.value_5": "background_parameters", - "backgrounds.data.value_1": "data", - "backgrounds.data.value_2": "data", - "backgrounds.data.value_3": "data", - "backgrounds.data.value_4": "data", - "backgrounds.data.value_5": "data", - "resolutions.constant.value_1": "resolution_parameters", - "resolutions.constant.value_2": "resolution_parameters", - "resolutions.constant.value_3": "resolution_parameters", - "resolutions.constant.value_4": "resolution_parameters", - "resolutions.constant.value_5": "resolution_parameters", - "resolutions.data.value_1": "data", - "resolutions.data.value_2": "data", - "resolutions.data.value_3": "data", - "resolutions.data.value_4": "data", - "resolutions.data.value_5": "data", - "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): - """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 = "" - calculation: Calculations = Calculations.NonPolarised - model: LayerModels = LayerModels.StandardLayers - geometry: Geometries = Geometries.AirSubstrate - absorption: bool = False - - parameters: ClassList = ClassList() - - bulk_in: ClassList = ClassList( - RATapi.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( - RATapi.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( - RATapi.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( - RATapi.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( - RATapi.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( - RATapi.models.Background(name="Background 1", type=TypeOptions.Constant, value_1="Background Param 1"), - ) - - resolution_parameters: ClassList = ClassList( - RATapi.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( - RATapi.models.Resolution(name="Resolution 1", type=TypeOptions.Constant, value_1="Resolution Param 1"), - ) - - custom_files: ClassList = ClassList() - data: ClassList = ClassList() - layers: ClassList = ClassList() - domain_contrasts: ClassList = ClassList() - contrasts: ClassList = ClassList() - - _all_names: dict - _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", - ) - @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" - - model = getattr(RATapi.models, model_name) - if not all(isinstance(element, model) for element in value): - raise ValueError(f'"{info.field_name}" ClassList contains objects other than "{model_name}"') - return value - - def model_post_init(self, __context: Any) -> None: - """Initialises the class in the ClassLists for empty data fields, sets protected parameters, gets names of all - defined parameters, determines the contents of the "model" field in contrasts, and wraps ClassList routines to - control revalidation. - """ - # Ensure all ClassLists have the correct _class_handle defined - layer_field = self.layers - if not hasattr(layer_field, "_class_handle"): - if self.absorption: - layer_field._class_handle = RATapi.models.AbsorptionLayer - else: - layer_field._class_handle = RATapi.models.Layer - - contrast_field = self.contrasts - if not hasattr(contrast_field, "_class_handle"): - if self.calculation == Calculations.Domains: - contrast_field._class_handle = RATapi.models.ContrastWithRatio - else: - contrast_field._class_handle = RATapi.models.Contrast - - for field_name, model in model_in_classlist.items(): - field = getattr(self, field_name) - if not hasattr(field, "_class_handle"): - field._class_handle = getattr(RATapi.models, model) - - if "Substrate Roughness" not in [name.title() for name in self.parameters.get_names()]: - self.parameters.insert( - 0, - RATapi.models.ProtectedParameter( - name="Substrate Roughness", - min=1.0, - value=3.0, - max=5.0, - fit=True, - prior_type=RATapi.models.Priors.Uniform, - mu=0.0, - sigma=np.inf, - ), - ) - elif "Substrate Roughness" not in [name.title() for name in self.get_all_protected_parameters()["parameters"]]: - # 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") - self.parameters.insert(0, RATapi.models.ProtectedParameter(**substrate_roughness_values)) - - if "Simulation" not in [name.title() for name in self.data.get_names()]: - self.data.insert(0, RATapi.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() - self._protected_parameters = self.get_all_protected_parameters() - - # 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", - ] - - 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": - """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": - """If we are not running a domains calculation with standard layers, ensure the domain_contrasts component of - the model is empty. - """ - if not (self.calculation == Calculations.Domains and self.model == LayerModels.StandardLayers): - self.domain_contrasts.data = [] - return self - - @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": - """Apply the calc setting to the project.""" - contrast_list = [] - handle = self.contrasts._class_handle.__name__ - if self.calculation == Calculations.Domains and handle == "Contrast": - for contrast in self.contrasts: - contrast_list.append(RATapi.models.ContrastWithRatio(**contrast.model_dump())) - self.contrasts.data = contrast_list - self.domain_ratios.data = [ - RATapi.models.Parameter( - name="Domain Ratio 1", - min=0.4, - value=0.5, - max=0.6, - fit=False, - prior_type=RATapi.models.Priors.Uniform, - mu=0.0, - sigma=np.inf, - ), - ] - self.contrasts._class_handle = RATapi.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"] - contrast_list.append(RATapi.models.Contrast(**contrast_params)) - self.contrasts.data = contrast_list - self.contrasts._class_handle = RATapi.models.Contrast - return self - - @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. - """ - model_field = self.get_contrast_model_field() - if model_field != self._contrast_model_field: - for contrast in self.contrasts: - contrast.model = [] - 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. - """ - 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.", - ) - 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.", - ) - return self - - @model_validator(mode="after") - def set_absorption(self) -> "Project": - """Apply the absorption setting to the project.""" - layer_list = [] - handle = self.layers._class_handle.__name__ - if self.absorption and handle == "Layer": - for layer in self.layers: - layer_list.append(RATapi.models.AbsorptionLayer(**layer.model_dump())) - self.layers.data = layer_list - self.layers._class_handle = RATapi.models.AbsorptionLayer - elif not self.absorption and handle == "AbsorptionLayer": - for layer in self.layers: - layer_params = layer.model_dump() - del layer_params["SLD_imaginary"] - layer_list.append(RATapi.models.Layer(**layer_params)) - self.layers.data = layer_list - self.layers._class_handle = RATapi.models.Layer - return self - - @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: - 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: - 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: - 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": - """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_background_resolution_values( - "backgrounds", value_fields, self.background_parameters.get_names(), self.data.get_names() - ) - self.check_allowed_background_resolution_values( - "resolutions", value_fields, self.resolution_parameters.get_names(), self.data.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": - """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, RATapi.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 - ] - 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 __str__(self): - output = "" - for key, value in self.__dict__.items(): - if value: - output += f'{key.replace("_", " ").title() + ": " :-<100}\n\n' - try: - output += value.value + "\n\n" # For enums - except AttributeError: - output += str(value) + "\n\n" - return output - - def get_all_names(self): - """Record the names of all models defined in the project.""" - return {class_list: getattr(self, class_list).get_names() for class_list in class_lists} - - 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, RATapi.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. - - Parameters - ---------- - attribute : str - The attribute of Project being validated. - field_list : list [str] - The fields of the attribute to be checked for valid values. - allowed_values : list [str] - The list of allowed values for the fields given in field_list. - - Raises - ------ - 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, "") - 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_allowed_background_resolution_values( - self, attribute: str, field_list: list[str], allowed_constants: list[str], allowed_data: list[str] - ) -> None: - """Check the values of the given fields in the given model are in the supplied list of allowed values. - - For backgrounds and resolutions, the list of allowed values depends on whether the type of the - background/resolution is "constant" or "data". - - Parameters - ---------- - attribute : str - The attribute of Project being validated. - field_list : list [str] - The fields of the attribute to be checked for valid values. - allowed_constants : list [str] - The list of allowed values for the fields given in field_list if the type is "constant". - allowed_data : list [str] - The list of allowed values for the fields given in field_list if the type is "data". - - Raises - ------ - ValueError - Raised if any field in field_list has a value not specified in allowed_constants or allowed_data as - appropriate. - - """ - class_list = getattr(self, attribute) - for model in class_list: - if model.type == TypeOptions.Constant: - allowed_values = allowed_constants - elif model.type == TypeOptions.Data: - allowed_values = allowed_data - else: - raise ValueError('"Function" type backgrounds and resolutions are not yet supported.') - - for field in field_list: - 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}.{model.type}.{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. - - Parameters - ---------- - contrast_attribute : str - The specific contrast attribute of Project being validated (either "contrasts" or "domain_contrasts"). - allowed_values : list [str] - The list of allowed values for the model of the contrast_attribute. - allowed_field : str - The name of the field in the project in which the allowed_values are defined. - - Raises - ------ - 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 = 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}".', - ) - - def get_contrast_model_field(self): - """Get the field used to define the contents of the "model" field in contrasts. - - Returns - ------- - 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" - else: - model_field = "layers" - else: - model_field = "custom_files" - return model_field - - 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 - ---------- - obj_name : str, optional - 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": - 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", - ) - - # Need imports - f.write("import RATapi\nfrom RATapi.models import *\nfrom numpy import array, inf\n\n") - - f.write( - f"{obj_name} = RATapi.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}=RATapi.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. - - Parameters - ---------- - class_list : ClassList - The ClassList defined in the "Project" model that is being modified. - func : Callable - The routine being wrapped. - - Returns - ------- - 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(class_list.data) - return_value = None - try: - return_value = func(*args, **kwargs) - Project.model_validate(self) - except ValidationError as exc: - class_list.data = previous_state - custom_error_list = custom_pydantic_validation_error(exc.errors()) - raise ValidationError.from_exception_data(exc.title, custom_error_list, hide_input=True) from None - except (TypeError, ValueError): - class_list.data = previous_state - raise - finally: - del previous_state - return return_value - - return wrapped_func diff --git a/RATapi/run.py b/RATapi/run.py deleted file mode 100644 index a3ae5636..00000000 --- a/RATapi/run.py +++ /dev/null @@ -1,94 +0,0 @@ -import time - -from tqdm import tqdm - -import RATapi.rat_core -from RATapi.inputs import make_input -from RATapi.outputs import make_results -from RATapi.utils.enums import Display - - -class ProgressBar: - """Creates a progress bar that gets updates from the progress event during a - calculation - - Parameters - ---------- - display : bool, default: True - Indicates if displaying is allowed - - """ - - def __init__(self, display=True): - self.display = display - - def __enter__(self): - if self.display: - RATapi.events.register(RATapi.events.EventTypes.Progress, self.updateProgress) - self.pbar = tqdm(total=100, desc="", delay=1, bar_format="{l_bar}{bar}", ncols=90, disable=not self.display) - self.pbar.delay = 0 - return self.pbar - - def updateProgress(self, event): - """Callback for the progress event. - - Parameters - ---------- - event: ProgressEventData - The progress event data. - """ - - value = event.percent * 100 - self.pbar.desc = event.message - self.pbar.update(value - self.pbar.n) - - def __exit__(self, _exc_type, _exc_val, _traceback): - self.pbar.leave = False - if self.display: - RATapi.events.clear(RATapi.events.EventTypes.Progress, self.updateProgress) - - -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", - } - - horizontal_line = "\u2500" * 107 + "\n" - display_on = controls.display != Display.Off - problem_definition, cells, limits, priors, cpp_controls = make_input(project, controls) - - if display_on: - print("Starting RAT " + horizontal_line) - - start = time.time() - with ProgressBar(display=display_on): - problem_definition, output_results, bayes_results = RATapi.rat_core.RATMain( - problem_definition, - cells, - limits, - cpp_controls, - priors, - ) - end = time.time() - - if display_on: - print(f"Elapsed time is {end-start:.3f} seconds\n") - - results = make_results(controls.procedure, output_results, bayes_results) - - # Update parameter values in project - for class_list in RATapi.project.parameter_class_lists: - for index, value in enumerate(getattr(problem_definition, parameter_field[class_list])): - getattr(project, class_list)[index].value = value - - if display_on: - print("Finished RAT " + horizontal_line) - - return project, results diff --git a/RATapi/utils/__init__.py b/RATapi/utils/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/RATapi/utils/enums.py b/RATapi/utils/enums.py deleted file mode 100644 index 26eea4a9..00000000 --- a/RATapi/utils/enums.py +++ /dev/null @@ -1,114 +0,0 @@ -from enum import Enum - -try: - from enum import StrEnum -except ImportError: - from strenum import StrEnum - - -class RATEnum(StrEnum): - @classmethod - def _missing_(cls, value: str): - value = value.lower() - - # Replace common alternative spellings - value = value.replace("-", " ").replace("_", " ").replace("++", "pp").replace("polarized", "polarised") - - for member in cls: - if member.value.lower() == value: - return member - return None - - -# Controls -class Procedures(RATEnum): - """Defines the available options for procedures""" - - Calculate = "calculate" - Simplex = "simplex" - DE = "de" - NS = "ns" - DREAM = "dream" - - -class Parallel(RATEnum): - """Defines the available options for parallelization""" - - Single = "single" - Points = "points" - Contrasts = "contrasts" - - -class Display(RATEnum): - """Defines the available options for display""" - - Off = "off" - Iter = "iter" - Notify = "notify" - Final = "final" - - -class Strategies(Enum): - """Defines the available options for strategies""" - - Random = 1 - LocalToBest = 2 - BestWithJitter = 3 - RandomWithPerVectorDither = 4 - RandomWithPerGenerationDither = 5 - RandomEitherOrAlgorithm = 6 - - -class BoundHandling(RATEnum): - """Defines the available options for bound handling""" - - Off = "off" - Reflect = "reflect" - Bound = "bound" - Fold = "fold" - - -# Models -class TypeOptions(RATEnum): - Constant = "constant" - Data = "data" - Function = "function" - - -class BackgroundActions(RATEnum): - Add = "add" - Subtract = "subtract" - - -class Languages(RATEnum): - Cpp = "cpp" - Python = "python" - Matlab = "matlab" - - -class Hydration(RATEnum): - None_ = "none" - BulkIn = "bulk in" - BulkOut = "bulk out" - - -class Priors(RATEnum): - Uniform = "uniform" - Gaussian = "gaussian" - - -# Project -class Calculations(RATEnum): - NonPolarised = "non polarised" - Domains = "domains" - - -class LayerModels(RATEnum): - CustomLayers = "custom layers" - CustomXY = "custom xy" - StandardLayers = "standard layers" - - -class Geometries(RATEnum): - AirSubstrate = "air/substrate" - SubstrateLiquid = "substrate/liquid" diff --git a/RATapi/utils/plotting.py b/RATapi/utils/plotting.py deleted file mode 100644 index 4d66770a..00000000 --- a/RATapi/utils/plotting.py +++ /dev/null @@ -1,833 +0,0 @@ -"""Plots using the matplotlib library""" - -from functools import partial, wraps -from math import ceil, floor, sqrt -from statistics import stdev -from textwrap import fill -from typing import Callable, Literal, Optional, Union - -import matplotlib -import matplotlib.pyplot as plt -import numpy as np -from matplotlib.axes._axes import Axes -from scipy.ndimage import gaussian_filter1d -from scipy.stats import gaussian_kde, lognorm, norm - -import RATapi -import RATapi.inputs -import RATapi.outputs -from RATapi.rat_core import PlotEventData, makeSLDProfileXY - - -def plot_errorbars(ax: Axes, x: np.ndarray, y: np.ndarray, err: np.ndarray, one_sided: bool, color: str): - """Plots the error bars. - - Parameters - ---------- - ax : matplotlib.axes._axes.Axes - The axis on which to draw errorbars - x : np.ndarray - The shifted data x axis data - y : np.ndarray - The shifted data y axis data - err : np.ndarray - The shifted data e data - one_sided : bool - 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) - ax.scatter(x=x, y=y, s=3, marker="o", color=color) - - -def plot_ref_sld_helper( - data: PlotEventData, - fig: Optional[matplotlib.pyplot.figure] = None, - delay: bool = True, - confidence_intervals: Union[dict, None] = None, -): - """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 : matplotlib.pyplot.figure, optional - The figure class that has two subplots - delay : bool, default: True - Controls whether to delay 0.005s after plot is created - confidence_intervals : dict or None, default None - The Bayesian confidence intervals for reflectivity and SLD. - Only relevant if the procedure used is Bayesian (NS or DREAM) - - Returns - ------- - fig : matplotlib.pyplot.figure - The figure class that has two subplots - - """ - preserve_zoom = False - - if fig is None: - fig = plt.subplots(1, 2)[0] - elif len(fig.axes) != 2: - fig.clf() - fig.subplots(1, 2) - fig.subplots_adjust(wspace=0.3) - - ref_plot: plt.Axes = fig.axes[0] - sld_plot: plt.Axes = fig.axes[1] - if ref_plot.lines and fig.canvas.toolbar is not None: - preserve_zoom = True - fig.canvas.toolbar.push_current() - - # Clears the previous plots - ref_plot.cla() - sld_plot.cla() - - for i, (r, sd, sld, name) in enumerate( - zip(data.reflectivity, data.shiftedData, data.sldProfiles, data.contrastNames), - ): - # Calculate the divisor - 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=name, linewidth=2) - color = ref_plot.get_lines()[-1].get_color() - - # Plot confidence intervals if required - if confidence_intervals is not None: - ref_min, ref_max = confidence_intervals["reflectivity"][i] - # FIXME: remove x-data once rascalsoftware/RAT#249 is merged - ref_x_data = confidence_intervals["reflectivity-x-data"][i][0] - ref_plot.fill_between(ref_x_data, ref_min / div, ref_max / div, alpha=0.6, color="grey") - - if data.dataPresent[i]: - sd_x = sd[:, 0] - 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)) - 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)) - 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)): - label = name if len(sld) == 1 else f"{name} Domain {j+1}" - sld_plot.plot(sld[j][:, 0], sld[j][:, 1], label=label, linewidth=1) - - # Plot confidence intervals if required - if confidence_intervals is not None: - sld_min, sld_max = confidence_intervals["sld"][i][j] - # FIXME: remove x-data once rascalsoftware/RAT#249 is merged - sld_x_data = confidence_intervals["sld-x-data"][i][j][0] - sld_plot.fill_between(sld_x_data, sld_min, sld_max, alpha=0.6, color="grey") - - 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, - ) - - # Format the axis - ref_plot.set_yscale("log") - ref_plot.set_xscale("log") - ref_plot.set_xlabel("$Q_{z} (\u00c5^{-1})$") - ref_plot.set_ylabel("Reflectivity") - ref_plot.legend() - ref_plot.grid() - - sld_plot.set_xlabel("$Z (\u00c5)$") - sld_plot.set_ylabel("$SLD (\u00c5^{-2})$") - sld_plot.legend() - sld_plot.grid() - - if preserve_zoom: - fig.canvas.toolbar.back() - if delay: - plt.pause(0.005) - - return fig - - -def plot_ref_sld( - project: RATapi.Project, - results: Union[RATapi.outputs.Results, RATapi.outputs.BayesResults], - block: bool = False, - return_fig: bool = False, - bayes: Literal[65, 95, None] = None, -) -> Union[plt.Figure, None]: - """Plots the reflectivity and SLD profiles. - - Parameters - ---------- - project : Project - An instance of the Project class - results : Union[Results, BayesResults] - The result from the calculation - block : bool, default: False - Indicates the plot should block until it is closed - return_fig : bool, default False - If True, return the figure instead of displaying it. - bayes : 65, 95 or None, default None - Whether to shade Bayesian confidence intervals. Can be `None` - (if no intervals), `65` to show 65% confidence intervals, - and `95` to show 95% confidence intervals. - - Returns - ------- - Figure or None - Returns Figure if `return_fig` is True, else returns nothing. - - """ - data = PlotEventData() - - data.modelType = project.model - data.reflectivity = results.reflectivity - data.shiftedData = results.shiftedData - data.sldProfiles = results.sldProfiles - data.resampledLayers = results.resampledLayers - data.dataPresent = RATapi.inputs.make_data_present(project) - data.subRoughs = results.contrastParams.subRoughs - data.resample = RATapi.inputs.make_resample(project) - data.contrastNames = [contrast.name for contrast in project.contrasts] - - if bayes: - if isinstance(results, RATapi.outputs.BayesResults): - # the predictionIntervals data consists of 5 rows: - # row 0: min with 95% confidence - # row 1: min with 65% confidence - # row 2: mean - # row 3: max with 65% confidence - # row 4: max with 95% confidence - if bayes == 95: - interval = [0, 4] - elif bayes == 65: - interval = [1, 3] - else: - raise ValueError("Parameter `bayes` must be 95, 65 or None") - confidence_intervals = { - "reflectivity": [ - (ref_inter[interval[0]], ref_inter[interval[1]]) - for ref_inter in results.predictionIntervals.reflectivity - ], - "sld": [ - [(sld_inter[interval[0]], sld_inter[interval[1]]) for sld_inter in sld] - for sld in results.predictionIntervals.sld - ], - # FIXME: remove x-data once rascalsoftware/RAT#249 is merged - "reflectivity-x-data": results.predictionIntervals.reflectivityXData, - "sld-x-data": results.predictionIntervals.sldXData, - } - else: - raise ValueError( - "Shaded confidence intervals are only available for the results of Bayesian analysis (NS or DREAM)" - ) - else: - confidence_intervals = None - - figure = plt.subplots(1, 2)[0] - - plot_ref_sld_helper(data, figure, confidence_intervals=confidence_intervals) - - if return_fig: - return figure - - plt.show(block=block) - - -class LivePlot: - """Creates a plot that gets updates from the plot event during a - calculation - - Parameters - ---------- - block : bool, default: False - Indicates the plot should block until it is closed - - """ - - def __init__(self, block=False): - self.block = block - self.closed = False - - def __enter__(self): - self.figure = plt.subplots(1, 2)[0] - self.figure.canvas.mpl_connect("close_event", self._setCloseState) - self.figure.show() - RATapi.events.register(RATapi.events.EventTypes.Plot, self.plotEvent) - - return self.figure - - def _setCloseState(self, _): - """Close event handler""" - self.closed = True - - def plotEvent(self, event): - """Callback for the plot event. - - Parameters - ---------- - event: PlotEventData - The plot event data. - """ - if not self.closed and self.figure.number in plt.get_fignums(): - plot_ref_sld_helper(event, self.figure) - - def __exit__(self, _exc_type, _exc_val, _traceback): - RATapi.events.clear(RATapi.events.EventTypes.Plot, self.plotEvent) - if not self.closed and self.figure.number in plt.get_fignums(): - plt.show(block=self.block) - - -def assert_bayesian(name: str): - """Decorator to ensure the results passed to a function are Bayesian. - - Parameters - ---------- - name : str - The name of the plot for the error message. - - """ - - def decorator(func: Callable): - @wraps(func) - def inner(results, *args, **kwargs): - if isinstance(results, RATapi.outputs.BayesResults): - return func(results, *args, **kwargs) - raise ValueError(f"{name} plots are only available for the results of Bayesian analysis (NS or DREAM)") - - return inner - - return decorator - - -def name_to_index(param: Union[str, int], names: list[str]): - """Convert parameter names to indices.""" - if isinstance(param, str): - if param not in names: - raise ValueError(f"Parameter {param} is not in this analysis.") - param = names.index(param) - elif isinstance(param, int): - if param > len(names) or param < 0: - raise IndexError(f"Index {param} has been given, but indices must be between zero and {len(names)}.") - else: - raise ValueError(f"Parameters must be given as indices or names, not {type(param)}.") - return param - - -@assert_bayesian("Corner") -def plot_corner( - results: RATapi.outputs.BayesResults, - params: Union[list[Union[int, str]], None] = None, - smooth: bool = True, - block: bool = False, - return_fig: bool = False, - hist_kwargs: Union[dict, None] = None, - hist2d_kwargs: Union[dict, None] = None, -): - """Create a corner plot from a Bayesian analysis. - - Parameters - ---------- - results : BayesResults - The results from a Bayesian calculation. - params : list[int or str], default None - The indices or names of a subset of parameters if required. - If None, uses all indices. - smooth : bool, default True - Whether to apply Gaussian smoothing to the corner plot. - block : bool, default False - Whether Python should block until the plot is closed. - return_fig: bool, default False - If True, return the figure as an object instead of showing it. - hist_kwargs : dict - Extra keyword arguments to pass to the 1d histograms. - Default is {'density': True, 'bins': 25} - hist2d_kwargs : dict - Extra keyword arguments to pass to the 2d histograms. - Default is {'density': True, 'bins': 25} - - Returns - ------- - Figure or None - If `return_fig` is True, return the figure - otherwise, return nothing. - - """ - fitname_to_index = partial(name_to_index, names=results.fitNames) - - if params is None: - params = range(0, len(results.fitNames)) - else: - params = list(map(fitname_to_index, params)) - - # defaults are applied inside each function - just pass blank dicts for now - if hist_kwargs is None: - hist_kwargs = {} - if hist2d_kwargs is None: - hist2d_kwargs = {} - - num_params = len(params) - - fig, axes = plt.subplots(num_params, num_params, figsize=(2 * num_params, 2 * num_params)) - # i is row, j is column - for i, row_param in enumerate(params): - for j, col_param in enumerate(params): - current_axes: Axes = axes[i][j] - if i == j: # diagonal: histograms - plot_one_hist(results, param=row_param, smooth=smooth, axes=current_axes, **hist_kwargs) - elif i > j: # lower triangle: 2d histograms - plot_contour( - results, x_param=row_param, y_param=col_param, smooth=smooth, axes=current_axes, **hist2d_kwargs - ) - elif i < j: # upper triangle: no plot - current_axes.set_visible(False) - # remove label if on inside of corner plot - if j != 0: - current_axes.get_yaxis().set_visible(False) - if i != len(params) - 1: - current_axes.get_xaxis().set_visible(False) - # make labels invisible as titles cover that - current_axes.set_ylabel("") - current_axes.set_xlabel("") - - fig.tight_layout() - if return_fig: - return fig - fig.show() - if block: - fig.wait_for_close() - - -@assert_bayesian("Histogram") -def plot_one_hist( - results: RATapi.outputs.BayesResults, - param: Union[int, str], - smooth: bool = True, - sigma: Union[float, None] = None, - estimated_density: Literal["normal", "lognor", "kernel", None] = None, - axes: Union[Axes, None] = None, - block: bool = False, - return_fig: bool = False, - **hist_settings, -): - """Plot the marginalised posterior for a parameter of a Bayesian analysis. - - Parameters - ---------- - results : BayesResults - The results from a Bayesian calculation. - param : Union[int, str] - Either the index or name of a parameter. - block : bool, default False - Whether Python should block until the plot is closed. - smooth : bool, default True - Whether to apply Gaussian smoothing to the histogram. - Defaults to True. - sigma: float or None, default None - If given, is used as the sigma-parameter for the Gaussian smoothing. - If None, the default (1/3rd of parameter chain standard deviation) is used. - estimated_density : 'normal', 'lognor', 'kernel' or None, default None - If None (default), ignore. Else, add an estimated density - of the given form on top of the histogram by the following estimations: - 'normal': normal Gaussian. - 'lognor': Log-normal probability density. - 'kernel': kernel density estimation. - axes: Axes or None, default None - If provided, plot on the given Axes object. - block : bool, default False - Whether Python should block until the plot is closed. - return_fig: bool, default False - If True, return the figure as an object instead of showing it. - **hist_settings : - Settings passed to `np.histogram`. By default, the settings - passed are `bins = 25` and `density = True`. - - Returns - ------- - Figure or None - If `return_fig` is True, return the figure - otherwise, return nothing. - - """ - chain = results.chain - param = name_to_index(param, results.fitNames) - - if axes is None: - fig, axes = plt.subplots(1, 1) - else: - fig = None - - # apply default settings if not set by user - default_settings = {"bins": 25, "density": True} - hist_settings = {**default_settings, **hist_settings} - - parameter_chain = chain[:, param] - counts, bins = np.histogram(parameter_chain, **hist_settings) - mean_y = np.mean(parameter_chain) - sd_y = np.std(parameter_chain) - - if smooth: - if sigma is None: - sigma = sd_y / 2 - counts = gaussian_filter1d(counts, sigma) - axes.hist( - bins[:-1], - bins, - weights=counts, - edgecolor="black", - linewidth=1.2, - color="white", - ) - - axes.set_title(fill(results.fitNames[param], 20)) # use `fill` to wrap long titles - - if estimated_density: - dx = bins[1] - bins[0] - if estimated_density == "normal": - t = np.linspace(mean_y - 3.5 * sd_y, mean_y + 3.5 * sd_y) - axes.plot(t, norm.pdf(t, loc=mean_y, scale=sd_y**2)) - elif estimated_density == "lognor": - t = np.linspace(bins[0] - 0.5 * dx, bins[-1] + 2 * dx) - axes.plot(t, lognorm.pdf(t, np.mean(np.log(parameter_chain)), np.std(np.log(parameter_chain)))) - elif estimated_density == "kernel": - t = np.linspace(bins[0] - 2 * dx, bins[-1] + 2 * dx, 200) - kde = gaussian_kde(parameter_chain) - axes.plot(t, kde.evaluate(t)) - else: - raise ValueError( - f"{estimated_density} is not a supported estimated density function." - " Supported functions are 'normal' 'lognor' or 'kernel'." - ) - - # adding the estimated density extends the figure range - reset it to histogram range - x_range = hist_settings.get("range", (parameter_chain.min(), parameter_chain.max())) - axes.set_xlim(x_range) - - if fig is not None: - if return_fig: - return fig - fig.show() - if block: - fig.wait_for_close() - - -@assert_bayesian("Contour") -def plot_contour( - results: RATapi.outputs.BayesResults, - x_param: Union[int, str], - y_param: Union[int, str], - smooth: bool = True, - sigma: Union[tuple[float], None] = None, - axes: Union[Axes, None] = None, - block: bool = False, - return_fig: bool = False, - **hist2d_settings, -): - """Plot a 2D histogram of two indexed chain parameters, with contours. - - Parameters - ---------- - results : RATapi.outputs.BayesResults - The results of a Bayesian analysis. - x_param : int - The index or name of the parameter on the x-axis. - y_param : int - The index or name ofthe parameter on the y-axis. - smooth : bool, default True - If True, apply Gaussian smoothing to the histogram. - sigma : tuple[float] or None, default None - If given, is used as parameters for Gaussian smoothing in x and y direction respectively. - If None, defaults to the standard deviation of the parameter chain in either direction. - axes: Axes or None, default None - If provided, plot on the given Axes object. - block : bool, default False - Whether Python should block until the plot is closed. - return_fig: bool, default False - If True, return the figure as an object instead of showing it. - **hist2d_settings: - Settings passed to `np.histogram2d`. - Default settings are `bins = 25` and `density = True`. - - Returns - ------- - Figure or None - If `return_fig` is True, return the figure - otherwise, return nothing. - - """ - if axes is None: - fig, axes = plt.subplots(1, 1) - else: - fig = None - x_param = name_to_index(x_param, results.fitNames) - y_param = name_to_index(y_param, results.fitNames) - - default_settings = {"bins": 25, "density": True} - hist2d_settings = {**default_settings, **hist2d_settings} - - counts, y_bins, x_bins = np.histogram2d(results.chain[:, x_param], results.chain[:, y_param], **hist2d_settings) - counts = counts.T # for some reason the counts given by numpy are sideways - if smooth: - if sigma is None: - sigma_x = stdev(results.chain[:, x_param]) / 2 - sigma_y = stdev(results.chain[:, y_param]) / 2 - else: - sigma_x, sigma_y = sigma - # perform a 1d smooth along both axes - counts = gaussian_filter1d(counts, axis=0, sigma=sigma_x) - counts = gaussian_filter1d(counts, axis=1, sigma=sigma_y) - - axes.pcolormesh(x_bins, y_bins, counts.max() - counts.T, cmap=matplotlib.colormaps["Greys"].reversed()) - axes.contour(x_bins[:-1], y_bins[:-1], counts.max() - counts.T, colors="black") - axes.set_xlabel(results.fitNames[x_param]) - axes.set_ylabel(results.fitNames[y_param]) - - if fig is not None: - if return_fig: - return fig - fig.show() - if block: - fig.wait_for_close() - - -def panel_plot_helper(plot_func: Callable, indices: list[int]) -> matplotlib.figure.Figure: - """Helper function for panel-based plots. - - Parameters - ---------- - plot_func : Callable - A function which plots one parameter on an Axes object, given its index. - - Returns - ------- - matplotlib.figure.Figure - A figure containing a grid of plots over the indices in `indices`. - """ - nplots = len(indices) - nrows, ncols = ceil(sqrt(nplots)), round(sqrt(nplots)) - fig = plt.subplots(nrows, ncols, figsize=(2.5 * ncols, 2 * nrows))[0] - axs = fig.get_axes() - - for plot_num, index in enumerate(indices): - plot_func(axs[plot_num], index) - - # blank unused plots - for i in range(nplots, len(axs)): - axs[i].set_visible(False) - - fig.tight_layout() - return fig - - -@assert_bayesian("Histogram") -def plot_hists( - results: RATapi.outputs.BayesResults, - params: Union[list[Union[int, str]], None] = None, - smooth: bool = True, - sigma: Union[float, None] = None, - estimated_density: Union[ - dict[Literal["normal", "lognor", "kernel", None]], Literal["normal", "lognor", "kernel", None] - ] = None, - block: bool = False, - return_fig: bool = False, - **hist_settings, -): - """Plot marginalised posteriors for several parameters from a Bayesian analysis. - - Parameters - ---------- - results : BayesResults - The results from a Bayesian calculation. - params : list[int], default None - The indices or names of a subset of parameters if required. - If None, uses all indices. - smooth : bool, default True - Whether to apply a Gaussian smoothing to the histogram. - Defaults to True. - sigma: float or None, default None - If given, is used as the sigma-parameter for the Gaussian smoothing. - If None, the default (1/3rd of parameter chain standard deviation) is used. - estimated_density : dict, default None - If None (default), ignore. - Can also be a string 'normal', 'lognor' or 'kernel' to apply the same estimated density to all parameters. - Else, a dictionary where the keys are - indices or names of parameters, and values denote an estimated density - of the given form on top of the histogram: - None : do not plot estimated density for this parameter. - 'normal': normal Gaussian. - 'lognor': Log-normal probability density. - 'kernel': kernel density estimation. - To provide a default estimated density function to all parameters that haven't been specifically set, - pass the 'default' key, - e.g. to apply 'normal' to all unset parameters, set `estimated_density = {'default': 'normal'}`. - block : bool, default False - Whether Python should block until the plot is closed. - return_fig: bool, default False - If True, return the figure as an object instead of showing it. - hist_settings : - Settings passed to `np.histogram`. By default, the settings - passed are `bins = 25` and `density = True`. - - Returns - ------- - Figure or None - If `return_fig` is True, return the figure - otherwise, return nothing. - - """ - - # first convert names to indices if given - fitname_to_index = partial(name_to_index, names=results.fitNames) - - if params is None: - params = range(0, len(results.fitNames)) - else: - params = list(map(fitname_to_index, params)) - - if estimated_density is not None: - - def validate_dens_type(dens_type: Union[str, None], param: str): - """Check estimated density is a supported type.""" - if dens_type not in [None, "normal", "lognor", "kernel"]: - raise ValueError( - f"Parameter {param} has estimated density function {dens_type}," - " which is not supported. Supported estimated density functions" - " are 'normal', 'lognor', and 'kernel'." - ) - return dens_type - - if isinstance(estimated_density, str): - validate_dens_type(estimated_density, "default") - estimated_density = {fitname_to_index(param): estimated_density for param in params} - else: - default = estimated_density.pop("default", None) - validate_dens_type(default, "default") - default_density = {fitname_to_index(param): default for param in params} - # convert names to indices and ensure density types given are correct - estimated_density = { - name_to_index(k, results.fitNames): validate_dens_type(v, k) for k, v in estimated_density.items() - } - # merge other estimated densities into default dict - estimated_density = {**default_density, **estimated_density} - else: - estimated_density = {} - - fig = panel_plot_helper( - lambda ax, i: plot_one_hist( - results, - i, - smooth=smooth, - sigma=sigma, - estimated_density=estimated_density.get(i, None), - axes=ax, - **hist_settings, - ), - params, - ) - if return_fig: - return fig - fig.show() - if block: - fig.wait_for_close() - - -@assert_bayesian("Chain") -def plot_chain( - results: RATapi.outputs.BayesResults, - params: Union[list[Union[int, str]], None] = None, - maxpoints: int = 15000, - block: bool = False, - return_fig: bool = False, -): - """Plot the MCMC chain for each parameter of a Bayesian analysis. - - Parameters - ---------- - results : RATapi.outputs.BayesResults - The results of a Bayesian analysis. - params : list[int], default None - The indices or names of a subset of parameters if required. - If None, uses all indices. - maxpoints : int - The maximum number of points to plot for each parameter. - block : bool, default False - Whether Python should block until the plot is closed. - return_fig: bool, default False - If True, return the figure as an object instead of showing it. - - Returns - ------- - Figure or None - If `return_fig` is True, return the figure - otherwise, return nothing. - - """ - chain = results.chain - nsimulations, nplots = chain.shape - skip = floor(nsimulations / maxpoints) # to evenly distribute points plotted - - # convert names to indices if given - fitname_to_index = partial(name_to_index, names=results.fitNames) - - if params is None: - params = range(0, len(results.fitNames)) - else: - params = list(map(fitname_to_index, params)) - - def plot_one_chain(axes: Axes, i: int): - axes.plot(range(0, nsimulations, skip), chain[:, i][0:nsimulations:skip]) - axes.set_title(results.fitNames[i]) - - fig = panel_plot_helper(plot_one_chain, params) - if return_fig: - return fig - fig.show() - if block: - fig.wait_for_close() - - -def plot_bayes(project: RATapi.Project, results: RATapi.outputs.BayesResults): - """Plot the results of a Bayesian analysis with confidence information. - - This produces an unshaded reflectivity/SLD plot, a reflectivity/SLD plot with shaded 95% confidence - intervals, a grid of histograms giving probability density for each parameter, and a corner plot for - all parameters. - - Parameters - project : Project - An instance of the Project class - results : Union[Results, BayesResults] - The result from the calculation - block : bool, default: False - Indicates the plot should block until it is closed - - """ - if isinstance(results, RATapi.outputs.BayesResults): - plot_ref_sld(project, results) - plot_ref_sld(project, results, bayes=95) - plot_hists(results) - plot_corner(results) - else: - raise ValueError("Bayes plots are only available for the results of Bayesian analysis (NS or DREAM)") diff --git a/RATapi/wrappers.py b/RATapi/wrappers.py deleted file mode 100644 index 19a49fb2..00000000 --- a/RATapi/wrappers.py +++ /dev/null @@ -1,115 +0,0 @@ -import pathlib -from contextlib import suppress -from typing import Callable, Tuple - -import numpy as np -from numpy.typing import ArrayLike - -import RATapi.rat_core - - -def start_matlab(): - """Starts MATLAB asynchronously and returns a future to retrieve the engine later - - Returns - ------- - future : matlab.engine.futureresult.FutureResult - A future used to get the actual matlab engine - - """ - future = None - with suppress(ImportError): - import matlab.engine - - future = matlab.engine.start_matlab(background=True) - - return future - - -class MatlabWrapper: - """Creates a python callback for a MATLAB function. - - Parameters - ---------- - filename : string - The path of the file containing MATLAB function - - """ - - loader = start_matlab() - - def __init__(self, filename: str) -> None: - if self.loader is None: - raise ImportError("matlabengine is required to use MatlabWrapper") from None - - self.engine = self.loader.result() - path = pathlib.Path(filename) - self.engine.cd(str(path.parent), nargout=0) - self.function_name = path.stem - - def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], Tuple[ArrayLike, float]]: - """Returns a wrapper for the custom MATLAB function - - Returns - ------- - 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, - ) - 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 - - -class DylibWrapper: - """Creates a python callback for a function in dynamic library. - - Parameters - ---------- - filename : str - 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 = RATapi.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 - - Returns - ------- - 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: - 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 handle diff --git a/README.md b/README.md index e4566708..46cc348e 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,11 @@ To install in local directory: matlabengine is an optional dependency only required for Matlab custom functions. The version of matlabengine should match the version of Matlab installed on the machine. This can be installed as shown below: - pip install -e .[Matlab-2023a] + pip install -e .[matlab-2023a] Development dependencies can be installed as shown below - pip install -e .[Dev] + pip install -e .[dev] To build wheel: diff --git a/cpp/RAT b/cpp/RAT index 5e3622f7..e1e879c6 160000 --- a/cpp/RAT +++ b/cpp/RAT @@ -1 +1 @@ -Subproject commit 5e3622f7d2d8cb48cab153d6660fce650b868d38 +Subproject commit e1e879c6eda6f1dee7a82b97dbbabd85d091017e diff --git a/cpp/includes/defines.h b/cpp/includes/defines.h new file mode 100644 index 00000000..097ad0eb --- /dev/null +++ b/cpp/includes/defines.h @@ -0,0 +1,679 @@ +#ifndef RAT_DEFINES_H +#define RAT_DEFINES_H + +#include +#include +#include + +namespace py = pybind11; + +const std::string docsProgressEventData = R"(The Python binding for the C++ progressEventData struct. +The progress event shows the percentage completion for the calculation. This can be emitted by +the DREAM algorithm only. + +Parameters +---------- +message : str + The title text for the event. +percent : float + The percentage of the calculation completed (as a number between 0 and 1) +)"; + +struct ProgressEventData +{ + std::string message; + double percent; +}; + +const std::string docsPlotEventData = R"(The Python binding for the C++ plotEventData struct. +The plot event data contains intermediate results from the calculation. This can be emitted +by the Simplex and DE algorithms only. + +Parameters +---------- +reflectivity : list + The reflectivity curves for each contrast, with the same range as the data + (``data_range`` in the contrast's ``Data`` object) +shiftedData : list + The data with scalefactors and background corrections applied. +sldProfiles : list + The SLD profiles for each contrast. +resampledLayers : list + If resampling is used, the SLD for each contrast after resampling has been performed. +subRoughs : np.ndarray[np.float] + The substrate roughness values for each contrast. +resample : np.ndarray[np.float] + An array containing whether each contrast was resampled. +dataPresent : np.ndarray[np.float] + Non-zero values indicates if data is present for the contrast. +modelType : str + The model type for the project. +contrastNames : list + The names of all contrasts in the project. +)"; + +struct PlotEventData +{ + py::list reflectivity; + py::list shiftedData; + py::list sldProfiles; + py::list resampledLayers; + py::array_t subRoughs; + py::array_t resample; + py::array_t dataPresent; + std::string modelType; + py::list contrastNames; +}; + + +const std::string docsPredictionIntervals = R"(The Python binding for the C++ predictionIntervals struct. +The Bayesian prediction intervals for 95% and 65% confidence. + +For ``reflectivity`` and ``sld``, each list item is an array +with five rows. The rows represent: + +- 0: the 5th percentile; +- 1: the 35th percentile; +- 2: the mean value of the interval; +- 3: the 65th percentile; +- 4: the 95th percentile. + +Parameters +---------- +reflectivity : list + The prediction interval data for reflectivity of each contrast. +sld : list + The prediction interval data for SLD of each contrast. +sampleChi : np.ndarray[np.float] + The value of sumChi at each point of the Markov chain. +)"; + +struct PredictionIntervals +{ + py::list reflectivity; + py::list sld; + py::array_t sampleChi; +}; + +const std::string docsConfidenceIntervals = R"(The Python binding for the C++ confidenceIntervals struct. +The 65% and 95% confidence intervals for the best fit results. + +Parameters +---------- +percentile95 : np.ndarray[np.float] + The 95% confidence intervals for each fit parameter. +percentile65 : np.ndarray[np.float] + The 65% confidence intervals for each fit parameter. +mean : np.ndarray[np.float] + The mean values for each fit parameter. +)"; + +struct ConfidenceIntervals +{ + py::array_t percentile95; + py::array_t percentile65; + py::array_t mean; +}; + +const std::string docsNestedSamplerOutput = R"(The Python binding for the C++ nestedSamplerOutput struct. +The output information from the Nested Sampler (ns). + +Parameters +---------- +logZ : float + The natural logarithm of the evidence Z for the parameter values. +logZErr : float + The estimated uncertainty in the final value of logZ. +nestSamples : np.ndarray[np.float] + ``NestedSamplerOutput.nestSamples[i, j]`` represents the values + sampled at iteration ``i``, where this value is: + + - the value sampled for parameter ``j``, for ``j`` in ``0:nParams``, + - the minimum log-likelihood for ``j = nParams + 1``. + +postSamples : np.ndarray[np.float] + The posterior values at the points sampled in ``NestedSamplerOutput.nestSamples``. +)"; + +struct NestedSamplerOutput +{ + real_T logZ; + real_T logZErr; + py::array_t nestSamples; + py::array_t postSamples; +}; + +const std::string docsDreamParams = R"(The Python binding for the C++ dreamParams struct. +The parameters used by the inner DREAM algorithm. + +Parameters +---------- +nParams : float + The number of parameters used by the algorithm. +nChains : float + The number of MCMC chains used by the algorithm. +nGenerations : float + The number of DE generations calculated per iteration. +parallel : bool + Whether the algorithm should run chains in parallel. +CPU : float + The number of processor cores used for parallel chains. +jumpProbability : float + A probability range for the size of jumps when performing subspace sampling. +pUnitGamma : float + The probability that the scaling-down factor of jumps will be ignored + and a larger jump will be taken for one iteration. +nCR : float + The number of crossovers performed each iteration. +delta : float + The number of chain mutation pairs proposed each iteration. +steps : float + The number of MCMC steps to perform between conversion checks. +zeta : float + The ergodicity of the algorithm. +outlier : str + What test should be used to detect outliers. +adaptPCR : bool + Whether the crossover probability for differential evolution should be + adapted by the algorithm as it runs. +thinning : float + The thinning rate of each Markov chain (to reduce memory intensity) +epsilon : float + The cutoff threshold for Approximate Bayesian Computation (if used) +ABC : bool + Whether Approximate Bayesian Computation is used. +IO : bool + Whether the algorithm should perform IO writes of the model in parallel. +storeOutput : bool + Whether output model simulations are performed. +R : np.np.ndarray[np.float] + An array where row ``i`` is the list of chains + with which chain ``i`` can mutate. +)"; + +struct DreamParams +{ + real_T nParams; + real_T nChains; + real_T nGenerations; + boolean_T parallel; + real_T CPU; + real_T jumpProbability; + real_T pUnitGamma; + real_T nCR; + real_T delta; + real_T steps; + real_T zeta; + std::string outlier; + boolean_T adaptPCR; + real_T thinning; + real_T epsilon; + boolean_T ABC; + boolean_T IO; + boolean_T storeOutput; + py::array_t R; +}; + +const std::string docsDreamOutput = R"(The Python binding for the C++ DreamOutput struct. +The diagnostic output information from DREAM. + +Parameters +---------- +allChains : np.ndarray[np.float] + An ``nGenerations`` x ``nParams + 2`` x ``nChains`` size array, + where ``chain_k = DreamOutput.allChains[:, :, k]`` + is the data of chain ``k`` in the final iteration; + for generation i of the final iteration, ``chain_k[i, j]`` represents: + + - the sampled value of parameter ``j`` for ``j in 0:nParams``; + - the associated log-prior for those sampled values for ``j = nParams + 1``; + - the associated log-likelihood for those sampled values for ``j = nParams + 2``. + +outlierChains : np.ndarray[np.float] + A two-column array where ``DreamOutput.AR[i, 1]`` is the index of a chain + and ``DreamOutput.AR[i, 0]`` is the length of that chain when it was removed + for being an outlier. +runtime : float + The runtime of the DREAM algorithm in seconds. +iteration : float + The number of iterations performed. +AR : np.ndarray[np.float] + A two-column array where ``DreamOutput.AR[i, 0]`` is an iteration number + and ``DreamOutput.AR[i, 1]`` is the average acceptance rate of chain step + proposals for that iteration. +R_stat : np.ndarray[np.float] + An array where ``DreamOutput.R_stat[i, 0]`` is an iteration number and + ``DreamOutput.R_stat[i, j]`` is the convergence statistic for parameter ``j`` + at that iteration (where chains are indexed 1 to ``nParams`` inclusive). +CR : np.ndarray[np.float] + A four-column array where ``DreamOutput.CR[i, 0]`` is an iteration number, + ``and DreamOutput.CR[i, j]`` is the selection probability of the ``j``'th crossover + value for that iteration. +)"; + +struct DreamOutput +{ + py::array_t allChains; + py::array_t outlierChains; + real_T runtime; + real_T iteration; + py::array_t AR; + py::array_t R_stat; + py::array_t CR; +}; + +const std::string docsOutputBayesResult = R"(The Python binding for the C++ bayesResults struct. +The results of a Bayesian RAT calculation. + +Parameters +---------- +predictionIntervals : RATapi.rat_core.PredictionIntervals + The prediction intervals. +confidenceIntervals : RATapi.rat_core.ConfidenceIntervals + The 65% and 95% confidence intervals for the best fit results. +dreamParams : RATapi.rat_core.DreamParams + The parameters used by DREAM, if relevant. +dreamOutput : RATapi.rat_core.DreamOutput + The output from DREAM if DREAM was used. +nestedSamplerOutput : RATapi.rat_core.NestedSamplerOutput + The output from nested sampling if ns was used. +chain : np.ndarray + The MCMC chains for each parameter. + The ``i``'th column of the array contains the chain for parameter ``fitNames[i]``. +)"; + +struct OutputBayesResult +{ + PredictionIntervals predictionIntervals; + ConfidenceIntervals confidenceIntervals; + DreamParams dreamParams; + DreamOutput dreamOutput; + NestedSamplerOutput nestedSamplerOutput; + py::array_t chain; +}; + +const std::string docsCalculation = R"(The Python binding for the C++ calculationResult struct. +The goodness of fit from the Abeles calculation. + +Parameters +---------- +chiValues : np.ndarray[np.float] + The chi-squared value for each contrast. +sumChi : float + The sum of the chiValues array. +)"; + +struct Calculation +{ + py::array_t chiValues; + real_T sumChi; +}; + +const std::string docsContrastParams = R"(The Python binding for the C++ contrastParams struct. +The experimental parameters for each contrast. + +Parameters +---------- +scalefactors : np.ndarray[np.float] + The scalefactor values for each contrast. +bulkIn : np.ndarray[np.float] + The bulk in values for each contrast. +bulkOut : np.ndarray[np.float] + The bulk out values for each contrast. +subRoughs : np.ndarray[np.float] + The substrate roughness values for each contrast. +resample : np.ndarray[np.float] + An array containing whether each contrast was resampled. +)"; + +struct ContrastParams +{ + py::array_t scalefactors; + py::array_t bulkIn; + py::array_t bulkOut; + py::array_t subRoughs; + py::array_t resample; +}; + +const std::string docsOutputResult = R"(The C++ result struct of a RAT calculation. + +Parameters +---------- +reflectivity : list + The reflectivity curves for each contrast, with the same range as the data + (``data_range`` in the contrast's ``Data`` object) +simulation : list + The reflectivity curves for each contrast, which can be a wider range to allow extrapolation + (``simulation_range`` in the contrast's ``Data`` object). +shiftedData : list + The data with scalefactors and background corrections applied. +backgrounds : list + The background for each contrast defined over the simulation range. +resolutions : list + The resolution for each contrast defined over the simulation range. +sldProfiles : list + The SLD profiles for each contrast. +layers : list + The array of layer parameter values for each contrast. +resampledLayers : list + If resampling is used, the array of layer parameter values for each contrast after resampling has been performed. +calculationResults : RATapi.rat_core.Calculation + The chi-squared fit results from the final calculation and fit. +contrastParams : RATapi.rat_core.ContrastParams + The experimental parameters for the contrasts. +fitParams : np.ndarray[np.float] + The best fit value of the parameter with name ``fitNames[i]``. +fitNames : list[str] + The names of the fit parameters, where ``fitNames[i]`` is the name + of the parameter with value given in ``fitParams[i]``. +)"; + +struct OutputResult { + py::list reflectivity; + py::list simulation; + py::list shiftedData; + py::list backgrounds; + py::list resolutions; + py::list sldProfiles; + py::list layers; + py::list resampledLayers; + Calculation calculationResults {}; + ContrastParams contrastParams {}; + py::array_t fitParams; + py::list fitNames; +}; + +const std::string docsNameStore = R"(The Python binding for the C++ names struct which +contains names of all parameters in the project. + +Parameters +---------- +params : list + Names of params in the problem definition. +backgroundParams : list + Names of backgroundParams in the problem definition. +scalefactors : list + Names of scalefactors in the problem definition. +bulkIns : list + Names of bulkIns in the problem definition. +bulkName: list + Names of bulkOuts in the problem definition. +resolutionParams : list + Names of resolutionParams in the problem definition. +domainRatios : list + Names of domainRatios in the problem definition. +)"; + +struct NameStore { + py::list params; + py::list backgroundParams; + py::list scalefactors; + py::list bulkIns; + py::list bulkOuts; + py::list resolutionParams; + py::list domainRatios; + py::list contrasts; +}; + + +const std::string docsChecks = R"(The Python binding for the C++ checks struct which contains +flags indicating which parameters should be fitted in the project. + +For each attribute, if index ``i`` is non-zero, then parameter ``i`` in that attribute is fitted, e.g. if ``Checks.scalefactors = [0.0, 1.0, 1.0]``, then the second and third scalefactors are fitted and the first is not. + +Parameters +---------- +params : np.ndarray[np.float] + Non-zero values indicates which params is fitted. +backgroundParams : np.ndarray[np.float] + Non-zero values indicates which backgroundParams is fitted. +scalefactors : np.ndarray[np.float] + Non-zero values indicates which scalefactors is fitted. +bulkIns : np.ndarray[np.float] + Non-zero values indicates which bulkIns is fitted. +bulkOuts : np.ndarray[np.float] + Non-zero values indicates which bulkOuts is fitted. +resolutionParams : np.ndarray[np.float] + Non-zero values indicates which resolutionParams is fitted. +domainRatios : np.ndarray[np.float] + Non-zero values indicates which domainRatios is fitted. +)"; + +struct Checks { + py::array_t params; + py::array_t backgroundParams; + py::array_t scalefactors; + py::array_t bulkIns; + py::array_t bulkOuts; + py::array_t resolutionParams; + py::array_t domainRatios; +}; + +const std::string docsProblemDefinition = R"(The Python binding for the C++ problem struct. + +Parameters +---------- +TF : str + The target function for the calculation which can be 'normal' or 'domains'. +resample : np.ndarray[np.float] + If ``resample[i]`` is non-zero, then contrast ``i`` will be resampled. +data : list + Data for each contrast. +dataPresent : np.ndarray[np.float] + If ``dataPresent[i]`` is non-zero, then contrast ``i`` has experimental data. +dataLimits : list + Data limits for each contrast. +simulationLimits : list; + Simulation for each contrast. +numberOfContrasts : int + Number of contrasts. +geometry : str + The geometry to use which can be 'air/substrate' or 'substrate/liquid' +useImaginary : bool + Indicates whether imaginary component is used for the SLD value in layers, i.e. + absorption is set to True for the project. +repeatLayers : list + Information about repeating layers for each contrast. This is currently not being used. +contrastBackgroundParams : list + Indices of backgroundParams used for each contrast +contrastBackgroundTypes : list + Background type for each contrast. +contrastBackgroundActions : list + Background action for each contrast. +contrastScalefactors : np.ndarray[np.float] + Indices of scalefactors used for each contrast. +contrastBulkIns : np.ndarray[np.float] + Indices of BulkIns used for each contrast. +contrastBulkOuts : np.ndarray[np.float] + Indices of BulkIns used for each contrast. +contrastResolutionParams : list + Indices of resolutionParams used for each contrast +contrastResolutionTypes : list + Resolution type for each contrast. +backgroundParams : np.ndarray[np.float] + Background parameter values. +scalefactors : np.ndarray[np.float] + Scalefactors values. +bulkIns : np.ndarray[np.float] + BulkIn values. +bulkOuts : np.ndarray[np.float] + BulkOut values. +resolutionParams : np.ndarray[np.float] + Resolution parameter values. +params : np.ndarray[np.float] + Parameter values. +numberOfLayers : int + Number of layers. +contrastLayers : list + Indices of layers added to the model of each contrast. +layersDetails : list + Indices of parameters in each layer. +customFiles : object + Iterable with custom file functions +modelType : str + The layer model type which can be 'standard layers', 'custom layers', or 'custom xy'. +contrastCustomFiles : np.ndarray[np.float] + Indices of CustomFiles used for each domain contrast +contrastDomainRatios : np.ndarray[np.float] + Indices of DomainRatios used for each domain contrast +domainRatios : np.ndarray[np.float] + Domain ratio values +numberOfDomainContrasts : int + Number of domain contrasts. +domainContrastLayers : list + Indices of layers added to the model of each domain contrast. +fitParams : np.ndarray[np.float] + Values of fitted parameters. +fitLimits : np.ndarray[np.float] + Limits of fitted parameters. +priorNames : list + Parameter names for for all parameters in the problem definition. +priorValues : np.ndarray[np.float] + Prior type, mu, and sigma for all parameters in the problem definition. +names : RATapi.rat_core.NameStore + Names of all parameters. +checks : RATapi.rat_core.Checks + Flags indicating which parameters should be fitted. +)"; + +struct ProblemDefinition { + std::string TF {}; + py::array_t resample; + py::list data; + py::array_t dataPresent; + py::list dataLimits; + py::list simulationLimits; + real_T numberOfContrasts; + std::string geometry {}; + boolean_T useImaginary {}; + py::list repeatLayers; + py::list contrastBackgroundParams; + py::list contrastBackgroundTypes; + py::list contrastBackgroundActions; + py::array_t contrastScalefactors; + py::array_t contrastBulkIns; + py::array_t contrastBulkOuts; + py::list contrastResolutionParams; + py::list contrastResolutionTypes; + py::array_t backgroundParams; + py::array_t scalefactors; + py::array_t bulkIns; + py::array_t bulkOuts; + py::array_t resolutionParams; + py::array_t params; + real_T numberOfLayers {}; + py::list contrastLayers; + py::list layersDetails; + py::object customFiles; + std::string modelType {}; + py::array_t contrastCustomFiles; + py::array_t contrastDomainRatios; + py::array_t domainRatios; + real_T numberOfDomainContrasts {}; + py::list domainContrastLayers; + py::array_t fitParams; + py::array_t fitLimits; + py::list priorNames; + py::array_t priorValues; + NameStore names; + Checks checks {}; +}; + + +const std::string docsControl = R"(The Python binding for the C++ controls struct. + +Parameters +---------- +parallel : str + How the calculation should be parallelised (This uses the Parallel Computing Toolbox). Can be 'single', 'contrasts' or 'points'. +procedure : str + Which procedure RAT should execute. Can be 'calculate', 'simplex', 'de', 'ns', or 'dream'. +numSimulationPoints : int + The number of points used for a reflectivity simulation where no data is present. +resampleMinAngle : float + The upper threshold on the angle between three sampled points for resampling, in units of radians over pi. +resampleNPoints : int + The number of initial points to use for resampling. +display : str + How much RAT should print to the terminal. Can be 'off', 'iter', 'notify', or 'final'. +IPCFilePath : str + The path of the inter process communication file. +updateFreq : int + [SIMPLEX, DE] Number of iterations between printing progress updates to the terminal. +updatePlotFreq : int + [SIMPLEX, DE] Number of iterations between updates to live plots. +xTolerance : float + [SIMPLEX] The termination tolerance for step size. +funcTolerance : float + [SIMPLEX] The termination tolerance for change in chi-squared. +maxFuncEvals : int + [SIMPLEX] The maximum number of function evaluations before the algorithm terminates. +maxIterations : int + [SIMPLEX] The maximum number of iterations before the algorithm terminates. +populationSize : int + [DE] The number of candidate solutions that exist at any time. +fWeight : float + [DE] The step size for how different mutations are to their parents. +crossoverProbability : float + [DE] The probability of exchange of parameters between individuals at any iteration. +strategy : int + [DE] The algorithm used to generate new candidates. +targetValue : float + [DE] The value of chi-squared at which the algorithm will terminate. +numGenerations : int + [DE] The maximum number of iterations before the algorithm terminates. +nLive : int + [NS] The number of points to sample. +nMCMC : int + [NS] If non-zero, an MCMC process with ``nMCMC`` chains will be used instead of MultiNest. +propScale : float + [NS] A scaling factor for the ellipsoid generated by MultiNest. +nsTolerance : float + [NS] The tolerance threshold for when the algorithm should terminate. +nSamples : int + [DREAM] The number of samples in the initial population for each chain. +nChains : int + [DREAM] The number of Markov chains to use in the algorithm. +jumpProbability : float + [DREAM] The probability range for the size of jumps in sampling. Larger values mean more variable jumps. +pUnitGamma : float + [DREAM] The probability that the scaling-down factor of jumps will be ignored and a larger jump will be taken. +boundHandling : str + [DREAM] How steps past the space boundaries should be handled. Can be 'off', 'reflect', 'bound', or 'fold'. +adaptPCR : bool + [DREAM] Whether the crossover probability for differential evolution should be adapted during the run. +)"; + +struct Control { + std::string parallel {}; + std::string procedure {}; + std::string display {}; + real_T xTolerance {}; + real_T funcTolerance {}; + real_T maxFuncEvals {}; + real_T maxIterations {}; + real_T populationSize {}; + real_T fWeight {}; + real_T crossoverProbability {}; + real_T targetValue {}; + real_T numGenerations {}; + real_T strategy {}; + real_T nLive {}; + real_T nMCMC {}; + real_T propScale {}; + real_T nsTolerance {}; + real_T numSimulationPoints {}; + real_T resampleMinAngle {}; + real_T resampleNPoints {}; + real_T updateFreq {}; + real_T updatePlotFreq {}; + real_T nSamples {}; + real_T nChains {}; + real_T jumpProbability {}; + real_T pUnitGamma {}; + std::string boundHandling {}; + boolean_T adaptPCR; + std::string IPCFilePath {}; +}; + +#endif // RAT_DEFINES_H \ No newline at end of file diff --git a/cpp/includes/functions.h b/cpp/includes/functions.h new file mode 100644 index 00000000..3ced72fe --- /dev/null +++ b/cpp/includes/functions.h @@ -0,0 +1,500 @@ +#ifndef RAT_FUNCTIONS_H +#define RAT_FUNCTIONS_H + +#include +#include +#include +#include +#include "../RAT/classHandle.hpp" + +namespace py = pybind11; + +template +auto customCaller(std::string identifier, Function f, Args&& ... args) -> decltype((*f)(std::forward(args)...)) +{ + try + { + return (*f)(std::forward(args)...); + } + catch(const std::runtime_error& re) + { + std::string errorMsg; + size_t start_pos = std::string(re.what()).find("$id"); + if(start_pos == std::string::npos) + { + errorMsg = std::string("Error occurred when setting ") + identifier + ". " + re.what(); + } + else + { + errorMsg = re.what(); + errorMsg.replace(start_pos, 3, identifier); + } + + throw std::runtime_error(errorMsg); + } +} + +class Library: public CallbackInterface +{ + public: + + py::function function; + + Library(const py::function function){ + this->function = function; + }; + + + void setOutput(py::tuple& result, std::vector& output, double *outputSize) + { + int nRows = 0, idx = 0; + for (py::handle rowHandle : result[0]) + { + py::list rows = py::cast(rowHandle); + for (py::handle value : rows) + { + output.push_back(py::cast(value)); + idx++; + } + nRows++; + } + + outputSize[0] = nRows; + outputSize[1] = (nRows == 0) ? 0 : idx / nRows; + } + + // Backgrounds + void invoke(std::vector& xdata, std::vector& params, std::vector& output) + { + auto f = py::cast>(this->function); + auto result = f(py::cast(xdata), py::cast(params)); + for (py::handle rowHandle : result) + { + if (py::isinstance(rowHandle)) + output.push_back(py::cast(py::cast(rowHandle)[0])); + else + output.push_back(py::cast(rowHandle)); + + } + }; + + // Domain overload + void invoke(std::vector& params, std::vector& bulkIn, std::vector& bulkOut, + int contrast, int domainNumber, std::vector& output, double *outputSize, double *roughness) + { + auto f = py::cast>(this->function); + auto result = f(py::cast(params), py::cast(bulkIn), py::cast(bulkOut), contrast, domainNumber); + *roughness = py::cast(result[1]); + setOutput(result, output, outputSize); + }; + + // Non-Domain overload + void invoke(std::vector& params, std::vector& bulkIn, std::vector& bulkOut, + int contrast, std::vector& output, double *outputSize, double *roughness) + { + auto f = py::cast>(this->function); + auto result = f(py::cast(params), py::cast(bulkIn), py::cast(bulkOut), contrast); + *roughness = py::cast(result[1]); + setOutput(result, output, outputSize); + }; +}; + + +void stringToRatBoundedArray(std::string value, char_T result_data[], int32_T result_size[2]) +{ + result_size[0] = 1; + result_size[1] = value.length(); + + for (int32_T idx1{0}; idx1 < value.length(); idx1++) { + result_data[idx1] = value[idx1]; + } +} + +void stringToRatCharArray(std::string value, coder::array& result) +{ + result.set_size(1, value.length()); + + for (int32_T idx{0}; idx < value.length(); idx++) { + result[idx] = value[idx]; + } +} + +void stringFromRatBoundedArray(const char_T array_data[], const int32_T array_size[2], std::string& result) +{ + result.resize(array_size[1]); + memcpy(&result[0], array_data, array_size[1]); +} + + +coder::array pyArrayToRatRowArray1d(py::array_t value) +{ + coder::array result; + + py::buffer_info buffer_info = value.request(); + + if (buffer_info.size == 0) + return result; + + if (buffer_info.ndim != 1) + throw std::runtime_error("Expects a 1D numeric array"); + + result.set_size(1, buffer_info.shape[0]); + for (int32_T idx0{0}; idx0 < buffer_info.shape[0]; idx0++) { + result[idx0] = value.at(idx0); + } + + return result; +} + +coder::bounded_array pyArrayToRatBoundedArray(py::array_t value) +{ + coder::bounded_array result {}; + + py::buffer_info buffer_info = value.request(); + + if (buffer_info.size == 0) + return result; + + if (buffer_info.ndim != 1) + throw std::runtime_error("Expects a 1D numeric array"); + + result.size[0] = 1; + result.size[1] = buffer_info.shape[0]; + for (int32_T idx0{0}; idx0 < buffer_info.shape[0]; idx0++) { + result.data[idx0] = value.at(idx0); + } + + return result; +} + +coder::bounded_array pyArrayToRatBoundedArray3(py::array_t value) +{ + coder::bounded_array result {}; + + py::buffer_info buffer_info = value.request(); + + if (buffer_info.size == 0) + return result; + + if (buffer_info.ndim != 1) + throw std::runtime_error("Expects a 1D numeric array"); + + result.size[0] = 1; + result.size[1] = buffer_info.shape[0]; + for (int32_T idx0{0}; idx0 < buffer_info.shape[0]; idx0++) { + result.data[idx0] = value.at(idx0); + } + + return result; +} + +coder::array pyArrayToRatArray2d(py::array_t value) +{ + coder::array result; + + py::buffer_info buffer_info = value.request(); + + if (buffer_info.size == 0) + return result; + + if (buffer_info.ndim != 2) + throw std::runtime_error("Expects a 2D numeric array"); + + result.set_size(buffer_info.shape[0], buffer_info.shape[1]); + + int32_T idx {0}; + for (int32_T idx0{0}; idx0 < buffer_info.shape[0]; idx0++) { + for (int32_T idx1{0}; idx1 < buffer_info.shape[1]; idx1++) { + idx = idx0 + result.size(0) * idx1; + result[idx] = value.at(idx0, idx1); + } + } + + return result; +} + +coder::array pyListToRatCellWrap1(py::list values) +{ + coder::array result; + result.set_size(1, values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + py::array_t casted_array = py::cast(array); + result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatArray2d, casted_array); + idx++; + } + + return result; +} + +coder::array pyListToRatCellWrap2(py::list values) +{ + coder::array result; + result.set_size(1, values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + py::array_t casted_array = py::cast(array); + if (casted_array.size() != 2) + throw std::runtime_error("Expects a 2D list where each row contains exactly 2 numbers"); + result[idx].f1[0] = casted_array.at(0); + result[idx].f1[1] = casted_array.at(1); + idx++; + } + + return result; +} + + +coder::array pyListToRatCellWrap3(py::list values) +{ + coder::array result; + result.set_size(1, values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + py::array_t casted_array = py::cast(array); + result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatBoundedArray3, casted_array); + idx++; + } + + return result; +} + +coder::array pyListToRatCellWrap4(py::list values) +{ + coder::array result; + result.set_size(1, values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + py::array_t casted_array = py::cast(array); + result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatBoundedArray3, casted_array); + idx++; + } + + return result; +} + +coder::array pyListToRatCellWrap5(py::list values) +{ + coder::array result; + result.set_size(1, values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + py::array_t casted_array = py::cast(array); + result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatRowArray1d, casted_array); + idx++; + } + + return result; +} + +coder::array pyListToRatCellWrap6(py::list values) +{ + coder::array result; + result.set_size(1, values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + py::array_t casted_array = py::cast(array); + result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatBoundedArray, casted_array); + idx++; + } + + return result; +} + +coder::array pyListToRatCellWrap01d(py::list values) +{ + coder::array result; + result.set_size(values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + if (py::isinstance(array)) { + std::string name = py::cast(array); + stringToRatBoundedArray(name, result[idx].f1.data, result[idx].f1.size); + idx++; + } + else + throw std::runtime_error("Expects a 1D list of strings"); + } + + return result; +} + +coder::array pyListToRatCellWrap02d(py::list values) +{ + coder::array result; + result.set_size(1, values.size()); + int32_T idx {0}; + for (py::handle array: values) + { + if (py::isinstance(array)) { + std::string name = py::cast(array); + stringToRatBoundedArray(name, result[idx].f1.data, result[idx].f1.size); + idx++; + } + else + throw std::runtime_error("Expects a 1D list of strings"); + } + + return result; +} + +coder::array py_function_array_to_rat_cell_wrap_0(py::object values) +{ + auto handles = py::cast(values); + coder::array result; + result.set_size(1, handles.size()); + int32_T idx {0}; + for (py::handle array: handles) + { + auto func = py::cast(array); + std::string func_ptr = convertPtr2String(new Library(func)); + stringToRatBoundedArray(func_ptr, result[idx].f1.data, result[idx].f1.size); + idx++; + } + + return result; +} +template +py::array_t pyArrayFromRatArray1d(T array, bool isCol=true) +{ + auto size = isCol ? array.size(1) : array.size(0); + auto result_array = py::array_t(size); + std::memcpy(result_array.request().ptr, array.data(), result_array.nbytes()); + + return result_array; +} + +py::array_t pyArrayFromRatArray2d(coder::array array) +{ + auto result_array = py::array_t({array.size(0), array.size(1)}); + std::memcpy(result_array.request().ptr, array.data(), result_array.nbytes()); + + return result_array; +} + +py::list pyListFromRatCellWrap01d(coder::array values) +{ + py::list result; + for (int32_T idx0{0}; idx0 < values.size(0); idx0++) { + std::string tmp; + stringFromRatBoundedArray(values[idx0].f1.data, values[idx0].f1.size, tmp); + result.append(tmp); + } + + return result; +} + +py::list pyListFromRatCellWrap02d(coder::array values) +{ + py::list result; + for (int32_T idx0{0}; idx0 < values.size(1); idx0++) { + std::string tmp; + stringFromRatBoundedArray(values[idx0].f1.data, values[idx0].f1.size, tmp); + result.append(tmp); + } + + return result; +} + +py::list pyListFromRatCellWrap2(coder::array values) +{ + py::list result; + + for (int32_T idx0{0}; idx0 < values.size(1); idx0++) { + py::list inner = py::make_tuple(values[idx0].f1[0], values[idx0].f1[1]); + result.append(inner); + } + + return result; +} + +template +py::list pyList1DFromRatCellWrap2D(const T& values) +{ + py::list result; + + for (int32_T idx0{0}; idx0 < values.size(1); idx0++) { + result.append(pyArrayFromRatArray2d(values[idx0].f1)); + } + + return result; +} + +template +py::list pyList1DFromRatCellWrap1D(const T& values) +{ + py::list result; + + for (int32_T idx0{0}; idx0 < values.size(0); idx0++) { + result.append(pyArrayFromRatArray2d(values[idx0].f1)); + } + + return result; +} + +template +py::list pyList2dFromRatCellWrap(const T& values) +{ + py::list result; + int32_T idx {0}; + for (int32_T idx0{0}; idx0 < values.size(0); idx0++) { + py::list inner; + for (int32_T idx1{0}; idx1 < values.size(1); idx1++) { + idx = idx0 + values.size(0) * idx1; + inner.append(pyArrayFromRatArray2d(values[idx].f1)); + } + result.append(inner); + } + + return result; +} + +template +py::list pyListFromBoundedCellWrap(const T& values) +{ + py::list result; + + for (int32_T idx0{0}; idx0 < values.size(1); idx0++) { + auto array = py::array_t({values[idx0].f1.size[0]}); + std::memcpy(array.request().ptr, values[idx0].f1.data, array.nbytes()); + + result.append(array); + } + + return result; +} + +template +py::array_t pyArray1dFromBoundedArray(const T& array) +{ + auto result_array = py::array_t({array.size[0]}); + std::memcpy(result_array.request().ptr, array.data, result_array.nbytes()); + + return result_array; +} + +template +py::array_t pyArray2dFromBoundedArray(const T& array) +{ + auto result_array = py::array_t({array.size[0], array.size[1]}); + std::memcpy(result_array.request().ptr, array.data, result_array.nbytes()); + + return result_array; +} + +py::array_t pyArrayFromRatArray3d(coder::array array) +{ + auto result_array = py::array_t({array.size(0), array.size(1), array.size(2)}); + std::memcpy(result_array.request().ptr, array.data(), result_array.nbytes()); + + return result_array; +} + +#endif // RAT_FUNCTIONS_H \ No newline at end of file diff --git a/cpp/rat.cpp b/cpp/rat.cpp index 0a599601..957ba4fa 100644 --- a/cpp/rat.cpp +++ b/cpp/rat.cpp @@ -16,89 +16,16 @@ setup_pybind11(cfg) #include "RAT/RATMain_initialize.h" #include "RAT/RATMain_terminate.h" #include "RAT/RATMain_types.h" -#include "RAT/makeSLDProfileXY.h" -#include "RAT/classHandle.hpp" +#include "RAT/makeSLDProfile.h" #include "RAT/dylib.hpp" #include "RAT/events/eventManager.h" +#include "includes/defines.h" +#include "includes/functions.h" namespace py = pybind11; const int DEFAULT_DOMAIN = -1; - -template -auto customCaller(std::string identifier, Function f, Args&& ... args) -> decltype((*f)(std::forward(args)...)) -{ - try - { - return (*f)(std::forward(args)...); - } - catch(const std::runtime_error& re) - { - std::string errorMsg; - size_t start_pos = std::string(re.what()).find("$id"); - if(start_pos == std::string::npos) - { - errorMsg = std::string("Error occurred when setting ") + identifier + ". " + re.what(); - } - else - { - errorMsg = re.what(); - errorMsg.replace(start_pos, 3, identifier); - } - - throw std::runtime_error(errorMsg); - } -} - -class Library: public CallbackInterface -{ - public: - - py::function function; - - Library(const py::function function){ - this->function = function; - }; - - - void setOutput(py::tuple& result, std::vector& output, double *outputSize) - { - int nRows = 0, idx = 0; - for (py::handle rowHandle : result[0]) - { - py::list rows = py::cast(rowHandle); - for (py::handle value : rows) - { - output.push_back(py::cast(value)); - idx++; - } - nRows++; - } - - outputSize[0] = nRows; - outputSize[1] = (nRows == 0) ? 0 : idx / nRows; - } - - // Domain overload - void invoke(std::vector& params, std::vector& bulkIn, std::vector& bulkOut, - int contrast, int domainNumber, std::vector& output, double *outputSize, double *roughness) - { - auto f = py::cast>(this->function); - auto result = f(py::cast(params), py::cast(bulkIn), py::cast(bulkOut), contrast, domainNumber); - *roughness = py::cast(result[1]); - setOutput(result, output, outputSize); - }; - - // Non-Domain overload - void invoke(std::vector& params, std::vector& bulkIn, std::vector& bulkOut, - int contrast, std::vector& output, double *outputSize, double *roughness) - { - auto f = py::cast>(this->function); - auto result = f(py::cast(params), py::cast(bulkIn), py::cast(bulkOut), contrast); - *roughness = py::cast(result[1]); - setOutput(result, output, outputSize); - }; -}; +const int DEFAULT_NREPEATS = 1; class DylibEngine { @@ -119,6 +46,21 @@ class DylibEngine ~DylibEngine(){}; + py::list invoke(std::vector& xdata, std::vector& params) + { + try{ + std::vector output; + + auto func = library->get_function&, std::vector&, std::vector&)>(functionName); + func(xdata, params, output); + + return py::cast(output); + + }catch (const dylib::symbol_error &) { + throw std::runtime_error("failed to get dynamic library symbol for " + functionName); + } + }; + py::tuple invoke(std::vector& params, std::vector& bulkIn, std::vector& bulkOut, int contrast, int domain=DEFAULT_DOMAIN) { try{ @@ -155,25 +97,6 @@ class DylibEngine }; }; -struct ProgressEventData -{ - std::string message; - double percent; -}; - -struct PlotEventData -{ - py::list reflectivity; - py::list shiftedData; - py::list sldProfiles; - py::list resampledLayers; - py::array_t subRoughs; - py::array_t resample; - py::array_t dataPresent; - std::string modelType; - py::list contrastNames; -}; - class EventBridge { public: @@ -298,576 +221,89 @@ class EventBridge }; }; -struct PredictionIntervals -{ - py::list reflectivity; - py::list sld; - py::list reflectivityXData; - py::list sldXData; - py::array_t sampleChi; -}; - -struct ConfidenceIntervals -{ - py::array_t percentile95; - py::array_t percentile65; - py::array_t mean; -}; - -struct NestedSamplerOutput -{ - real_T logZ; - py::array_t nestSamples; - py::array_t postSamples; -}; - -struct DreamParams +RAT::b_ParamNames createParamNamesStruct(const NameStore& names) { - real_T nParams; - real_T nChains; - real_T nGenerations; - boolean_T parallel; - real_T CPU; - real_T jumpProbability; - real_T pUnitGamma; - real_T nCR; - real_T delta; - real_T steps; - real_T zeta; - std::string outlier; - boolean_T adaptPCR; - real_T thinning; - real_T epsilon; - boolean_T ABC; - boolean_T IO; - boolean_T storeOutput; - py::array_t R; -}; - -struct DreamOutput -{ - py::array_t allChains; - py::array_t outlierChains; - real_T runtime; - real_T iteration; - real_T modelOutput; - py::array_t AR; - py::array_t R_stat; - py::array_t CR; -}; - -struct BayesResults -{ - PredictionIntervals predictionIntervals; - ConfidenceIntervals confidenceIntervals; - DreamParams dreamParams; - DreamOutput dreamOutput; - NestedSamplerOutput nestedSamplerOutput; - py::array_t chain; -}; - -struct Priors -{ - py::list param; - py::list backgroundParam; - py::list resolutionParam; - py::list bulkIn; - py::list bulkOut; - py::list qzshift; - py::list scalefactor; - py::list domainRatio; - py::list priorNames; - py::array_t priorValues; -}; - -struct Checks { - py::array_t fitParam; - py::array_t fitBackgroundParam; - py::array_t fitQzshift; - py::array_t fitScalefactor; - py::array_t fitBulkIn; - py::array_t fitBulkOut; - py::array_t fitResolutionParam; - py::array_t fitDomainRatio; -}; - -struct Calculation -{ - py::array_t chiValues; - real_T sumChi; -}; - -struct ContrastParams -{ - py::array_t backgroundParams; - py::array_t scalefactors; - py::array_t bulkIn; - py::array_t bulkOut; - py::array_t resolutionParams; - py::array_t subRoughs; - py::array_t resample; -}; - -struct OutputResult { - py::list reflectivity; - py::list simulation; - py::list shiftedData; - py::list layerSlds; - py::list sldProfiles; - py::list resampledLayers; - Calculation calculationResults {}; - ContrastParams contrastParams; - py::array_t fitParams; - py::list fitNames; -}; - -struct Limits { - py::array_t param; - py::array_t backgroundParam; - py::array_t scalefactor; - py::array_t qzshift; - py::array_t bulkIn; - py::array_t bulkOut; - py::array_t resolutionParam; - py::array_t domainRatio; -}; - -struct Cells { - py::list f1; - py::list f2; - py::list f3; - py::list f4; - py::list f5; - py::list f6; - py::list f7; - py::list f8; - py::list f9; - py::list f10; - py::list f11; - py::list f12; - py::list f13; - py::list f14; - py::list f15; - py::list f16; - py::list f17; - py::list f18; - py::list f19; - py::list f20; - py::list f21; -}; - -struct ProblemDefinition { - py::array_t contrastBackgroundParams; - py::array_t contrastBackgroundActions; - std::string TF {}; - py::array_t resample; - py::array_t dataPresent; - py::array_t oilChiDataPresent; - real_T numberOfContrasts; - std::string geometry {}; - bool useImaginary {}; - py::array_t contrastQzshifts; - py::array_t contrastScalefactors; - py::array_t contrastBulkIns; - py::array_t contrastBulkOuts; - py::array_t contrastResolutionParams; - py::array_t backgroundParams; - py::array_t qzshifts; - py::array_t scalefactors; - py::array_t bulkIn; - py::array_t bulkOut; - py::array_t resolutionParams; - py::array_t params; - real_T numberOfLayers {}; - std::string modelType {}; - py::array_t contrastCustomFiles; - py::array_t contrastDomainRatios; - py::array_t domainRatio; - real_T numberOfDomainContrasts {}; - py::array_t fitParams; - py::array_t otherParams; - py::array_t fitLimits; - py::array_t otherLimits; -}; - -struct Control { - std::string parallel {}; - std::string procedure {}; - std::string display {}; - real_T xTolerance {}; - real_T funcTolerance {}; - real_T maxFuncEvals {}; - real_T maxIterations {}; - real_T populationSize {}; - real_T fWeight {}; - real_T crossoverProbability {}; - real_T targetValue {}; - real_T numGenerations {}; - real_T strategy {}; - real_T nLive {}; - real_T nMCMC {}; - real_T propScale {}; - real_T nsTolerance {}; - boolean_T calcSldDuringFit {}; - py::array_t resampleParams; - real_T updateFreq {}; - real_T updatePlotFreq {}; - real_T nSamples {}; - real_T nChains {}; - real_T jumpProbability {}; - real_T pUnitGamma {}; - std::string boundHandling {}; - boolean_T adaptPCR; - Checks checks {}; -}; - - -void stringToRatArray(std::string value, char_T result_data[], int32_T result_size[2]) -{ - result_size[0] = 1; - result_size[1] = value.length(); - - for (int32_T idx1{0}; idx1 < value.length(); idx1++) { - result_data[idx1] = value[idx1]; - } -} - -void stringToRatCharArray(std::string value, coder::array& result) -{ - result.set_size(1, value.length()); - - for (int32_T idx{0}; idx < value.length(); idx++) { - result[idx] = value[idx]; - } -} - -coder::array pyArrayToRatArray1d(py::array_t value) -{ - coder::array result; - - py::buffer_info buffer_info = value.request(); - - if (buffer_info.size == 0) - return result; - - if (buffer_info.ndim != 1) - throw std::runtime_error("Expects a 1D numeric array"); - - result.set_size(1, buffer_info.shape[0]); - for (int32_T idx0{0}; idx0 < buffer_info.shape[0]; idx0++) { - result[idx0] = value.at(idx0); - } - - return result; -} - -coder::bounded_array pyArrayToRatBoundedArray(py::array_t value) -{ - coder::bounded_array result {}; - - py::buffer_info buffer_info = value.request(); - - if (buffer_info.size == 0) - return result; + RAT::b_ParamNames names_struct; + names_struct.params = customCaller("NameStore.params", pyListToRatCellWrap02d, names.params); + names_struct.backgroundParams = customCaller("NameStore.backgroundParams", pyListToRatCellWrap02d, names.backgroundParams); + names_struct.scalefactors = customCaller("NameStore.scalefactors", pyListToRatCellWrap02d, names.scalefactors); + names_struct.bulkIns = customCaller("NameStore.bulkIns", pyListToRatCellWrap02d, names.bulkIns); + names_struct.bulkOuts = customCaller("NameStore.bulkOuts", pyListToRatCellWrap02d, names.bulkOuts); + names_struct.resolutionParams = customCaller("NameStore.resolutionParams", pyListToRatCellWrap02d, names.resolutionParams); + names_struct.domainRatios = customCaller("NameStore.domainRatios", pyListToRatCellWrap02d, names.domainRatios); + names_struct.contrasts = customCaller("NameStore.contrasts", pyListToRatCellWrap02d, names.contrasts); - if (buffer_info.ndim != 1) - throw std::runtime_error("Expects a 1D numeric array"); - - result.size[0] = 1; - result.size[1] = buffer_info.shape[0]; - for (int32_T idx0{0}; idx0 < buffer_info.shape[0]; idx0++) { - result.data[idx0] = value.at(idx0); - } - - return result; + return names_struct; } -coder::array pyArrayToRatArray2d(py::array_t value) +RAT::CheckFlags createCheckFlagsStruct(const Checks& checks) { - coder::array result; - - py::buffer_info buffer_info = value.request(); - - if (buffer_info.size == 0) - return result; - - if (buffer_info.ndim != 2) - throw std::runtime_error("Expects a 2D numeric array"); + RAT::CheckFlags checks_struct; + checks_struct.params = customCaller("Checks.params", pyArrayToRatRowArray1d, checks.params); + checks_struct.backgroundParams = customCaller("Checks.backgroundParams", pyArrayToRatRowArray1d, checks.backgroundParams); + checks_struct.scalefactors = customCaller("Checks.scalefactors", pyArrayToRatRowArray1d, checks.scalefactors); + checks_struct.bulkIns = customCaller("Checks.bulkIns", pyArrayToRatRowArray1d, checks.bulkIns); + checks_struct.bulkOuts = customCaller("Checks.bulkOuts", pyArrayToRatRowArray1d, checks.bulkOuts); + checks_struct.resolutionParams = customCaller("Checks.resolutionParams", pyArrayToRatRowArray1d, checks.resolutionParams); + checks_struct.domainRatios = customCaller("Checks.domainRatios", pyArrayToRatRowArray1d, checks.domainRatios); - result.set_size(buffer_info.shape[0], buffer_info.shape[1]); - - int32_T idx {0}; - for (int32_T idx0{0}; idx0 < buffer_info.shape[0]; idx0++) { - for (int32_T idx1{0}; idx1 < buffer_info.shape[1]; idx1++) { - idx = idx0 + result.size(0) * idx1; - result[idx] = value.at(idx0, idx1); - } - } - - return result; -} - -coder::array pyListToUnboundedCell0(py::list values) -{ - coder::array result; - result.set_size(values.size()); - int32_T idx {0}; - for (py::handle list: values) - { - py::list value = py::cast(list); - if (py::len(list) != 4 || !py::isinstance(value[0]) || !py::isinstance(value[1]) || - !py::isinstance(value[2]) || !py::isinstance(value[3])) - throw std::runtime_error("Expects a 2D list where each row must contain 4 elements. " - "Columns 1 and 2 must be strings and Columns 3 and 4 must be numeric arrays"); - stringToRatCharArray(value[0].cast(), result[idx].f1); - stringToRatCharArray(value[1].cast(), result[idx].f2); - result[idx].f3 = value[2].cast(); - result[idx].f4 = value[3].cast(); - idx++; - } - - return result; -} - -coder::array pyListToUnboundedCell1(py::list values) -{ - coder::array result; - result.set_size(values.size()); - int32_T idx {0}; - for (py::handle list: values) - { - if (py::isinstance(list)) { - std::string value = py::cast(list); - stringToRatCharArray(value, result[idx].f1); - idx++; - } - else - throw std::runtime_error("Expects a 1D list of strings"); - } - - return result; + return checks_struct; } -RAT::struct0_T createStruct0(const ProblemDefinition& problem) +RAT::b_ProblemDefinition createProblemDefinitionStruct(const ProblemDefinition& problem) { - RAT::struct0_T problem_struct; + RAT::b_ProblemDefinition problem_struct; + stringToRatBoundedArray(problem.TF, problem_struct.TF.data, problem_struct.TF.size); + problem_struct.resample = customCaller("Problem.resample", pyArrayToRatRowArray1d, problem.resample); + problem_struct.data = customCaller("Problem.data", pyListToRatCellWrap1, problem.data); + problem_struct.dataPresent = customCaller("Problem.dataPresent", pyArrayToRatRowArray1d, problem.dataPresent); + problem_struct.dataLimits = customCaller("Problem.dataLimits", pyListToRatCellWrap2, problem.dataLimits); + problem_struct.simulationLimits = customCaller("Problem.simulationLimits", pyListToRatCellWrap2, problem.simulationLimits); + problem_struct.numberOfContrasts = problem.numberOfContrasts; + stringToRatBoundedArray(problem.geometry, problem_struct.geometry.data, problem_struct.geometry.size); problem_struct.useImaginary = problem.useImaginary; - + problem_struct.repeatLayers = customCaller("Problem.repeatLayers", pyArrayToRatRowArray1d, problem.repeatLayers); + problem_struct.contrastBackgroundParams = customCaller("Problem.contrastBackgroundParams", pyListToRatCellWrap3, problem.contrastBackgroundParams); + problem_struct.contrastBackgroundTypes = customCaller("Problem.contrastBackgroundTypes", pyListToRatCellWrap02d, problem.contrastBackgroundTypes); + problem_struct.contrastBackgroundActions = customCaller("Problem.contrastBackgroundActions", pyListToRatCellWrap02d, problem.contrastBackgroundActions); + problem_struct.contrastScalefactors = customCaller("Problem.contrastScalefactors", pyArrayToRatRowArray1d, problem.contrastScalefactors); + problem_struct.contrastBulkIns = customCaller("Problem.contrastBulkIns", pyArrayToRatRowArray1d, problem.contrastBulkIns); + problem_struct.contrastBulkOuts = customCaller("Problem.contrastBulkOuts", pyArrayToRatRowArray1d, problem.contrastBulkOuts); + problem_struct.contrastResolutionParams = customCaller("Problem.contrastResolutionParams", pyListToRatCellWrap4, problem.contrastResolutionParams); + problem_struct.contrastResolutionTypes = customCaller("Problem.contrastResolutionTypes", pyListToRatCellWrap02d, problem.contrastResolutionTypes); + problem_struct.backgroundParams = customCaller("Problem.backgroundParams", pyArrayToRatRowArray1d, problem.backgroundParams); + problem_struct.scalefactors = customCaller("Problem.scalefactors", pyArrayToRatRowArray1d, problem.scalefactors); + problem_struct.bulkIns = customCaller("Problem.bulkIns", pyArrayToRatRowArray1d, problem.bulkIns); + problem_struct.bulkOuts = customCaller("Problem.bulkOuts", pyArrayToRatRowArray1d, problem.bulkOuts); + problem_struct.resolutionParams = customCaller("Problem.resolutionParams", pyArrayToRatRowArray1d, problem.resolutionParams); + problem_struct.params = customCaller("Problem.params", pyArrayToRatRowArray1d, problem.params); problem_struct.numberOfLayers = problem.numberOfLayers; + problem_struct.contrastLayers = customCaller("Problem.contrastLayers", pyListToRatCellWrap5, problem.contrastLayers); + problem_struct.layersDetails = customCaller("Problem.layersDetails", pyListToRatCellWrap6, problem.layersDetails); + problem_struct.customFiles = customCaller("Problem.customFiles", py_function_array_to_rat_cell_wrap_0, problem.customFiles); + stringToRatBoundedArray(problem.modelType, problem_struct.modelType.data, problem_struct.modelType.size); + problem_struct.contrastCustomFiles = customCaller("Problem.contrastCustomFiles", pyArrayToRatRowArray1d, problem.contrastCustomFiles); + problem_struct.contrastDomainRatios = customCaller("Problem.contrastDomainRatios", pyArrayToRatRowArray1d, problem.contrastDomainRatios); + problem_struct.domainRatios = customCaller("Problem.domainRatios", pyArrayToRatRowArray1d, problem.domainRatios); problem_struct.numberOfDomainContrasts = problem.numberOfDomainContrasts; - problem_struct.numberOfContrasts = problem.numberOfContrasts; - - stringToRatArray(problem.modelType, problem_struct.modelType.data, problem_struct.modelType.size); - stringToRatArray(problem.geometry, problem_struct.geometry.data, problem_struct.geometry.size); - stringToRatArray(problem.TF, problem_struct.TF.data, problem_struct.TF.size); - - problem_struct.contrastBackgroundParams = customCaller("Problem.contrastBackgroundParams", pyArrayToRatArray1d, problem.contrastBackgroundParams); - problem_struct.contrastBackgroundActions = customCaller("Problem.contrastBackgroundActions", pyArrayToRatArray1d, problem.contrastBackgroundActions); - problem_struct.resample = customCaller("Problem.resample", pyArrayToRatArray1d, problem.resample); - problem_struct.dataPresent = customCaller("Problem.dataPresent", pyArrayToRatArray1d, problem.dataPresent); - problem_struct.oilChiDataPresent = customCaller("Problem.oilChiDataPresent", pyArrayToRatArray1d, problem.oilChiDataPresent); - problem_struct.contrastQzshifts = customCaller("Problem.contrastQzshifts", pyArrayToRatArray1d, problem.contrastQzshifts); - problem_struct.contrastScalefactors = customCaller("Problem.contrastScalefactors", pyArrayToRatArray1d, problem.contrastScalefactors); - problem_struct.contrastBulkIns = customCaller("Problem.contrastBulkIns", pyArrayToRatArray1d, problem.contrastBulkIns); - problem_struct.contrastBulkOuts = customCaller("Problem.contrastBulkOuts", pyArrayToRatArray1d, problem.contrastBulkOuts); - problem_struct.contrastResolutionParams = customCaller("Problem.contrastResolutionParams", pyArrayToRatArray1d, problem.contrastResolutionParams); - problem_struct.backgroundParams = customCaller("Problem.backgroundParams", pyArrayToRatArray1d, problem.backgroundParams); - problem_struct.qzshifts = customCaller("Problem.qzshifts", pyArrayToRatArray1d, problem.qzshifts); - problem_struct.scalefactors = customCaller("Problem.scalefactors", pyArrayToRatArray1d, problem.scalefactors); - problem_struct.bulkIn = customCaller("Problem.bulkIn", pyArrayToRatArray1d, problem.bulkIn); - problem_struct.bulkOut = customCaller("Problem.bulkOut", pyArrayToRatArray1d, problem.bulkOut); - problem_struct.resolutionParams = customCaller("Problem.resolutionParams", pyArrayToRatArray1d, problem.resolutionParams); - problem_struct.params = customCaller("Problem.params", pyArrayToRatArray1d, problem.params); - - problem_struct.contrastCustomFiles = customCaller("Problem.contrastCustomFiles", pyArrayToRatArray1d, problem.contrastCustomFiles); - problem_struct.contrastDomainRatios = customCaller("Problem.contrastDomainRatios", pyArrayToRatArray1d, problem.contrastDomainRatios); - problem_struct.domainRatio = customCaller("Problem.domainRatio", pyArrayToRatArray1d, problem.domainRatio); - - problem_struct.fitParams = customCaller("Problem.fitParams", pyArrayToRatArray1d, problem.fitParams); - problem_struct.otherParams = customCaller("Problem.otherParams", pyArrayToRatArray1d, problem.otherParams); + problem_struct.domainContrastLayers = customCaller("Problem.domainContrastLayers", pyListToRatCellWrap5, problem.domainContrastLayers); + problem_struct.fitParams = customCaller("Problem.fitParams", pyArrayToRatRowArray1d, problem.fitParams); problem_struct.fitLimits = customCaller("Problem.fitLimits", pyArrayToRatArray2d, problem.fitLimits); - problem_struct.otherLimits = customCaller("Problem.otherLimits", pyArrayToRatArray2d, problem.otherLimits); + problem_struct.priorNames = customCaller("Problem.priorNames", pyListToRatCellWrap01d, problem.priorNames); + problem_struct.priorValues = customCaller("Problem.priorValues", pyArrayToRatArray2d, problem.priorValues); - return problem_struct; -} + problem_struct.names = createParamNamesStruct(problem.names); + problem_struct.checks = createCheckFlagsStruct(problem.checks); -RAT::struct1_T createStruct1(const Limits& limits) -{ - RAT::struct1_T limits_struct; - limits_struct.param = customCaller("Limits.param", pyArrayToRatArray2d, limits.param); - limits_struct.backgroundParam = customCaller("Limits.backgroundParam", pyArrayToRatArray2d, limits.backgroundParam); - limits_struct.qzshift = customCaller("Limits.qzshift", pyArrayToRatArray2d, limits.qzshift); - limits_struct.scalefactor = customCaller("Limits.scalefactor", pyArrayToRatArray2d, limits.scalefactor); - limits_struct.bulkIn = customCaller("Limits.bulkIn", pyArrayToRatArray2d, limits.bulkIn); - limits_struct.bulkOut = customCaller("Limits.bulkOut", pyArrayToRatArray2d, limits.bulkOut); - limits_struct.resolutionParam = customCaller("Limits.resolutionParam", pyArrayToRatArray2d, limits.resolutionParam); - limits_struct.domainRatio = customCaller("Limits.domainRatio", pyArrayToRatArray2d, limits.domainRatio); - - return limits_struct; -} - -RAT::struct3_T createStruct3(const Checks& checks) -{ - RAT::struct3_T checks_struct; - checks_struct.fitParam = customCaller("Checks.fitParam", pyArrayToRatArray1d, checks.fitParam); - checks_struct.fitBackgroundParam = customCaller("Checks.fitBackgroundParam", pyArrayToRatArray1d, checks.fitBackgroundParam); - checks_struct.fitQzshift = customCaller("Checks.fitQzshift", pyArrayToRatArray1d, checks.fitQzshift); - checks_struct.fitScalefactor = customCaller("Checks.fitScalefactor", pyArrayToRatArray1d, checks.fitScalefactor); - checks_struct.fitBulkIn = customCaller("Checks.fitBulkIn", pyArrayToRatArray1d, checks.fitBulkIn); - checks_struct.fitBulkOut = customCaller("Checks.fitBulkOut", pyArrayToRatArray1d, checks.fitBulkOut); - checks_struct.fitResolutionParam = customCaller("Checks.fitResolutionParam", pyArrayToRatArray1d, checks.fitResolutionParam); - checks_struct.fitDomainRatio = customCaller("Checks.fitDomainRatio", pyArrayToRatArray1d, checks.fitDomainRatio); - - return checks_struct; -} -RAT::struct4_T createStruct4(const Priors& priors) -{ - RAT::struct4_T priors_struct; - priors_struct.param = customCaller("Priors.param", pyListToUnboundedCell0, priors.param); - priors_struct.backgroundParam = customCaller("Priors.backgroundParam", pyListToUnboundedCell0, priors.backgroundParam); - priors_struct.resolutionParam = customCaller("Priors.resolutionParam", pyListToUnboundedCell0, priors.resolutionParam); - priors_struct.qzshift = customCaller("Priors.qzshift", pyListToUnboundedCell0, priors.qzshift); - priors_struct.scalefactor = customCaller("Priors.scalefactor", pyListToUnboundedCell0, priors.scalefactor); - priors_struct.bulkIn = customCaller("Priors.bulkIn", pyListToUnboundedCell0, priors.bulkIn); - priors_struct.bulkOut = customCaller("Priors.bulkOut", pyListToUnboundedCell0, priors.bulkOut); - priors_struct.domainRatio = customCaller("Priors.domainRatio", pyListToUnboundedCell0, priors.domainRatio); - priors_struct.priorNames = customCaller("Priors.priorNames", pyListToUnboundedCell1, priors.priorNames); - priors_struct.priorValues = customCaller("Priors.priorValues", pyArrayToRatArray2d, priors.priorValues); - - return priors_struct; -} - -coder::array pyListToRatCellWrap2(py::list values) -{ - coder::array result; - result.set_size(1, values.size()); - int32_T idx {0}; - for (py::handle array: values) - { - py::array_t casted_array = py::cast(array); - if (casted_array.size() != 2) - throw std::runtime_error("Expects a 2D list where each row contains exactly 2 numbers"); - result[idx].f1[0] = casted_array.at(0); - result[idx].f1[1] = casted_array.at(1); - idx++; - } - - return result; -} - -coder::array pyListToRatCellWrap3(py::list values) -{ - coder::array result; - result.set_size(1, values.size()); - int32_T idx {0}; - for (py::handle array: values) - { - py::array_t casted_array = py::cast(array); - result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatArray2d, casted_array); - idx++; - } - - return result; -} - -coder::array pyListToRatCellWrap4(py::list values) -{ - coder::array result; - result.set_size(1, values.size()); - int32_T idx {0}; - for (py::handle array: values) - { - py::array_t casted_array = py::cast(array); - result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatArray1d, casted_array); - idx++; - } - - return result; -} - -coder::array pyListToRatCellWrap5(py::list values) -{ - coder::array result; - result.set_size(values.size()); - int32_T idx {0}; - for (py::handle array: values) - { - py::array_t casted_array = py::cast(array); - result[idx].f1 = customCaller("$id[" + std::to_string(idx) +"]", pyArrayToRatBoundedArray, casted_array); - idx++; - } - - return result; -} - -coder::array pyListToRatCellWrap6(py::list values) -{ - coder::array result; - result.set_size(1, values.size()); - int32_T idx {0}; - for (py::handle array: values) - { - if (py::isinstance(array)) { - std::string name = py::cast(array); - stringToRatArray(name, result[idx].f1.data, result[idx].f1.size); - idx++; - } - else - throw std::runtime_error("Expects a 1D list of strings"); - } - - return result; -} - -coder::array py_function_array_to_rat_cell_wrap_6(py::list values) -{ - coder::array result; - result.set_size(1, values.size()); - int32_T idx {0}; - for (py::handle array: values) - { - auto func = py::cast(array); - std::string func_ptr = convertPtr2String(new Library(func)); - stringToRatArray(func_ptr, result[idx].f1.data, result[idx].f1.size); - idx++; - } - - return result; + return problem_struct; } -RAT::cell_7 createCell7(const Cells& cells) -{ - RAT::cell_7 cells_struct; - cells_struct.f1 = customCaller("Cells.f1", pyListToRatCellWrap2, cells.f1); - cells_struct.f2 = customCaller("Cells.f2", pyListToRatCellWrap3, cells.f2); - cells_struct.f3 = customCaller("Cells.f3", pyListToRatCellWrap2, cells.f3); - cells_struct.f4 = customCaller("Cells.f4", pyListToRatCellWrap2, cells.f4); - cells_struct.f5 = customCaller("Cells.f5", pyListToRatCellWrap4, cells.f5); - cells_struct.f6 = customCaller("Cells.f6", pyListToRatCellWrap5, cells.f6); - cells_struct.f7 = customCaller("Cells.f7", pyListToRatCellWrap6, cells.f7); - cells_struct.f8 = customCaller("Cells.f8", pyListToRatCellWrap6, cells.f8); - cells_struct.f9 = customCaller("Cells.f9", pyListToRatCellWrap6, cells.f9); - cells_struct.f10 = customCaller("Cells.f10", pyListToRatCellWrap6, cells.f10); - cells_struct.f11 = customCaller("Cells.f11", pyListToRatCellWrap6, cells.f11); - cells_struct.f12 = customCaller("Cells.f12", pyListToRatCellWrap6, cells.f12); - cells_struct.f13 = customCaller("Cells.f13", pyListToRatCellWrap6, cells.f13); - cells_struct.f14 = customCaller("Cells.f14", py_function_array_to_rat_cell_wrap_6, cells.f14); - cells_struct.f15 = customCaller("Cells.f15", pyListToRatCellWrap6, cells.f15); - cells_struct.f16 = customCaller("Cells.f16", pyListToRatCellWrap6, cells.f16); - cells_struct.f17 = customCaller("Cells.f17", pyListToRatCellWrap3, cells.f17); - cells_struct.f18 = customCaller("Cells.f18", pyListToRatCellWrap2, cells.f18); - cells_struct.f19 = customCaller("Cells.f19", pyListToRatCellWrap4, cells.f19); - cells_struct.f20 = customCaller("Cells.f20", pyListToRatCellWrap6, cells.f20); - cells_struct.f21 = customCaller("Cells.f21", pyListToRatCellWrap6, cells.f21); - - return cells_struct; -} -RAT::struct2_T createStruct2T(const Control& control) +RAT::Controls createControlsStruct(const Control& control) { - RAT::struct2_T control_struct; + RAT::Controls control_struct; control_struct.funcTolerance = control.funcTolerance; control_struct.maxFuncEvals = control.maxFuncEvals; control_struct.maxIterations = control.maxIterations; @@ -881,89 +317,86 @@ RAT::struct2_T createStruct2T(const Control& control) control_struct.nMCMC = control.nMCMC; control_struct.propScale = control.propScale; control_struct.nsTolerance = control.nsTolerance; - control_struct.calcSldDuringFit = control.calcSldDuringFit; + control_struct.numSimulationPoints = control.numSimulationPoints; control_struct.updateFreq = control.updateFreq; control_struct.updatePlotFreq = control.updatePlotFreq; control_struct.nSamples = control.nSamples; control_struct.nChains = control.nChains; control_struct.jumpProbability = control.jumpProbability; control_struct.pUnitGamma = control.pUnitGamma; - stringToRatArray(control.parallel, control_struct.parallel.data, control_struct.parallel.size); - stringToRatArray(control.procedure, control_struct.procedure.data, control_struct.procedure.size); - stringToRatArray(control.display, control_struct.display.data, control_struct.display.size); + stringToRatBoundedArray(control.parallel, control_struct.parallel.data, control_struct.parallel.size); + stringToRatBoundedArray(control.procedure, control_struct.procedure.data, control_struct.procedure.size); + stringToRatBoundedArray(control.display, control_struct.display.data, control_struct.display.size); control_struct.xTolerance = control.xTolerance; - control_struct.resampleParams[0] = control.resampleParams.at(0); - control_struct.resampleParams[1] = control.resampleParams.at(1); - stringToRatArray(control.boundHandling, control_struct.boundHandling.data, control_struct.boundHandling.size); + control_struct.resampleMinAngle = control.resampleMinAngle; + control_struct.resampleNPoints = control.resampleNPoints; + stringToRatBoundedArray(control.boundHandling, control_struct.boundHandling.data, control_struct.boundHandling.size); control_struct.adaptPCR = control.adaptPCR; - control_struct.checks = createStruct3(control.checks); + control_struct.calcSLD = false; + stringToRatBoundedArray(control.IPCFilePath, control_struct.IPCFilePath.data, control_struct.IPCFilePath.size); return control_struct; } -py::array_t pyArrayFromRatArray1d(coder::array array) -{ - auto size = (array.size(0) > 1) ? array.size(0) : array.size(1); - auto result_array = py::array_t(size); - std::memcpy(result_array.request().ptr, array.data(), result_array.nbytes()); - - return result_array; -} - -py::array_t pyArrayFromRatArray2d(coder::array array) -{ - auto result_array = py::array_t({array.size(0), array.size(1)}); - std::memcpy(result_array.request().ptr, array.data(), result_array.nbytes()); - - return result_array; -} - - -OutputResult OutputResultFromStruct5T(const RAT::struct5_T result) +OutputResult OutputResultFromStruct(const RAT::Results result) { // Copy problem to output OutputResult output_result; for (int32_T idx0{0}; idx0 < result.reflectivity.size(0); idx0++) { auto tmp = result.reflectivity[idx0]; auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); - std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); + std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); output_result.reflectivity.append(array); } for (int32_T idx0{0}; idx0 < result.simulation.size(0); idx0++) { - auto tmp = result.simulation[idx0]; - auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); - std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); - output_result.simulation.append(array); + auto tmp = result.simulation[idx0]; + auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); + std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); + output_result.simulation.append(array); } for (int32_T idx0{0}; idx0 < result.shiftedData.size(0); idx0++) { - auto tmp = result.shiftedData[idx0]; - auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); - std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); - output_result.shiftedData.append(array); + auto tmp = result.shiftedData[idx0]; + auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); + std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); + output_result.shiftedData.append(array); + } + + for (int32_T idx0{0}; idx0 < result.backgrounds.size(0); idx0++) { + auto tmp = result.backgrounds[idx0]; + auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); + std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); + output_result.backgrounds.append(array); + } + + for (int32_T idx0{0}; idx0 < result.resolutions.size(0); idx0++) { + auto tmp = result.resolutions[idx0]; + auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); + std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); + output_result.resolutions.append(array); } - for (int32_T idx0{0}; idx0 < result.layerSlds.size(0); idx0++) { + for (int32_T idx0{0}; idx0 < result.sldProfiles.size(0); idx0++) { py::list inner_list; - for (int32_T idx1{0}; idx1 < result.layerSlds.size(1); idx1++) { - auto tmp = result.layerSlds[idx0 + result.layerSlds.size(0) * idx1]; + for (int32_T idx1{0}; idx1 < result.sldProfiles.size(1); idx1++) { + auto tmp = result.sldProfiles[idx0 + result.sldProfiles.size(0) * idx1]; auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); inner_list.append(array); } - output_result.layerSlds.append(inner_list); + output_result.sldProfiles.append(inner_list); } - for (int32_T idx0{0}; idx0 < result.sldProfiles.size(0); idx0++) { + for (int32_T idx0{0}; idx0 < result.layers.size(0); idx0++) { py::list inner_list; - for (int32_T idx1{0}; idx1 < result.sldProfiles.size(1); idx1++) { - auto tmp = result.sldProfiles[idx0 + result.sldProfiles.size(0) * idx1]; + for (int32_T idx1{0}; idx1 < result.layers.size(1); idx1++) { + auto tmp = result.layers[idx0 + result.layers.size(0) * idx1]; auto array = py::array_t({tmp.f1.size(0), tmp.f1.size(1)}); std::memcpy(array.request().ptr, tmp.f1.data(), array.nbytes()); inner_list.append(array); } - output_result.sldProfiles.append(inner_list); + output_result.layers.append(inner_list); } for (int32_T idx0{0}; idx0 < result.resampledLayers.size(0); idx0++) { @@ -987,10 +420,6 @@ OutputResult OutputResultFromStruct5T(const RAT::struct5_T result) auto buffer = output_result.fitParams.request(); std::memcpy(buffer.ptr, result.fitParams.data(), output_result.fitParams.size()*sizeof(real_T)); - output_result.contrastParams.backgroundParams = py::array_t(result.contrastParams.backgroundParams.size(0)); - buffer = output_result.contrastParams.backgroundParams.request(); - std::memcpy(buffer.ptr, result.contrastParams.backgroundParams.data(), output_result.contrastParams.backgroundParams.size()*sizeof(real_T)); - output_result.contrastParams.scalefactors = py::array_t(result.contrastParams.scalefactors.size(0)); buffer = output_result.contrastParams.scalefactors.request(); std::memcpy(buffer.ptr, result.contrastParams.scalefactors.data(), output_result.contrastParams.scalefactors.size()*sizeof(real_T)); @@ -1003,10 +432,6 @@ OutputResult OutputResultFromStruct5T(const RAT::struct5_T result) buffer = output_result.contrastParams.bulkOut.request(); std::memcpy(buffer.ptr, result.contrastParams.bulkOut.data(), output_result.contrastParams.bulkOut.size()*sizeof(real_T)); - output_result.contrastParams.resolutionParams = py::array_t(result.contrastParams.resolutionParams.size(0)); - buffer = output_result.contrastParams.resolutionParams.request(); - std::memcpy(buffer.ptr, result.contrastParams.resolutionParams.data(), output_result.contrastParams.resolutionParams.size()*sizeof(real_T)); - output_result.calculationResults.sumChi = result.calculationResults.sumChi; output_result.calculationResults.chiValues = py::array_t(result.calculationResults.chiValues.size(0)); buffer = output_result.calculationResults.chiValues.request(); @@ -1023,123 +448,85 @@ OutputResult OutputResultFromStruct5T(const RAT::struct5_T result) return output_result; } -ProblemDefinition problemDefinitionFromStruct0T(const RAT::struct0_T problem) +ProblemDefinition problemDefinitionFromStruct(const RAT::b_ProblemDefinition problem) { ProblemDefinition problem_def; - problem_def.useImaginary = problem.useImaginary; - + stringFromRatBoundedArray(problem.TF.data, problem.TF.size, problem_def.TF); + problem_def.resample = pyArrayFromRatArray1d>(problem.resample); + problem_def.data = pyList1DFromRatCellWrap2D>(problem.data); + problem_def.dataPresent = pyArrayFromRatArray1d>(problem.dataPresent); + problem_def.dataLimits = pyListFromRatCellWrap2(problem.dataLimits); + problem_def.simulationLimits = pyListFromRatCellWrap2(problem.simulationLimits); + problem_def.numberOfContrasts = problem.numberOfContrasts; + stringFromRatBoundedArray(problem.geometry.data, problem.geometry.size, problem_def.geometry); + problem_def.useImaginary = problem.useImaginary; + problem_def.repeatLayers = pyArrayFromRatArray1d>(problem.repeatLayers); + problem_def.contrastBackgroundParams = pyListFromBoundedCellWrap>(problem.contrastBackgroundParams); + problem_def.contrastBackgroundTypes = pyListFromRatCellWrap02d(problem.contrastBackgroundTypes); + problem_def.contrastBackgroundActions = pyListFromRatCellWrap02d(problem.contrastBackgroundActions); + problem_def.contrastScalefactors = pyArrayFromRatArray1d>(problem.contrastScalefactors); + problem_def.contrastBulkIns = pyArrayFromRatArray1d>(problem.contrastBulkIns); + problem_def.contrastBulkOuts = pyArrayFromRatArray1d>(problem.contrastBulkOuts); + problem_def.contrastResolutionParams = pyListFromBoundedCellWrap>(problem.contrastResolutionParams); + problem_def.contrastResolutionTypes = pyListFromRatCellWrap02d(problem.contrastResolutionTypes); + problem_def.backgroundParams = pyArrayFromRatArray1d>(problem.backgroundParams); + problem_def.scalefactors = pyArrayFromRatArray1d>(problem.scalefactors); + problem_def.bulkIns = pyArrayFromRatArray1d>(problem.bulkIns); + problem_def.bulkOuts = pyArrayFromRatArray1d>(problem.bulkOuts); + problem_def.resolutionParams = pyArrayFromRatArray1d>(problem.resolutionParams); + problem_def.params = pyArrayFromRatArray1d>(problem.params); problem_def.numberOfLayers = problem.numberOfLayers; + problem_def.contrastLayers = pyList1DFromRatCellWrap2D>(problem.contrastLayers); + problem_def.layersDetails = pyListFromBoundedCellWrap>(problem.layersDetails); + // problem_def.customFiles is not set here since the object has been converted to function handles + stringFromRatBoundedArray(problem.modelType.data, problem.modelType.size, problem_def.modelType); + problem_def.contrastCustomFiles = pyArrayFromRatArray1d>(problem.contrastCustomFiles); + problem_def.contrastDomainRatios = pyArrayFromRatArray1d>(problem.contrastDomainRatios); + problem_def.domainRatios = pyArrayFromRatArray1d>(problem.domainRatios); problem_def.numberOfDomainContrasts = problem.numberOfDomainContrasts; - problem_def.numberOfContrasts = problem.numberOfContrasts; - - problem_def.modelType.resize(problem.modelType.size[1]); - memcpy(&problem_def.modelType[0], problem.modelType.data, problem.modelType.size[1]); - problem_def.geometry.resize(problem.geometry.size[1]); - memcpy(&problem_def.geometry[0], problem.geometry.data, problem.geometry.size[1]); - problem_def.TF.resize(problem.TF.size[1]); - memcpy(&problem_def.TF[0], problem.TF.data, problem.TF.size[1]); - - problem_def.contrastBackgroundParams = pyArrayFromRatArray1d(problem.contrastBackgroundParams); - problem_def.contrastBackgroundActions = pyArrayFromRatArray1d(problem.contrastBackgroundActions); - problem_def.resample = pyArrayFromRatArray1d(problem.resample); - problem_def.dataPresent = pyArrayFromRatArray1d(problem.dataPresent); - problem_def.oilChiDataPresent = pyArrayFromRatArray1d(problem.oilChiDataPresent); - problem_def.contrastQzshifts = pyArrayFromRatArray1d(problem.contrastQzshifts); - problem_def.contrastScalefactors = pyArrayFromRatArray1d(problem.contrastScalefactors); - problem_def.contrastBulkIns = pyArrayFromRatArray1d(problem.contrastBulkIns); - problem_def.contrastBulkOuts = pyArrayFromRatArray1d(problem.contrastBulkOuts); - problem_def.contrastResolutionParams = pyArrayFromRatArray1d(problem.contrastResolutionParams); - problem_def.backgroundParams = pyArrayFromRatArray1d(problem.backgroundParams); - problem_def.qzshifts = pyArrayFromRatArray1d(problem.qzshifts); - problem_def.scalefactors = pyArrayFromRatArray1d(problem.scalefactors); - problem_def.bulkIn = pyArrayFromRatArray1d(problem.bulkIn); - problem_def.bulkOut = pyArrayFromRatArray1d(problem.bulkOut); - problem_def.resolutionParams = pyArrayFromRatArray1d(problem.resolutionParams); - problem_def.params = pyArrayFromRatArray1d(problem.params); - - problem_def.contrastCustomFiles = pyArrayFromRatArray1d(problem.contrastCustomFiles); - problem_def.contrastDomainRatios = pyArrayFromRatArray1d(problem.contrastDomainRatios); - problem_def.domainRatio = pyArrayFromRatArray1d(problem.domainRatio); - - problem_def.fitParams = pyArrayFromRatArray1d(problem.fitParams); - problem_def.otherParams = pyArrayFromRatArray1d(problem.otherParams); - problem_def.fitLimits = pyArrayFromRatArray2d(problem.fitLimits); - problem_def.otherLimits = pyArrayFromRatArray2d(problem.otherLimits); - - return problem_def; -} - -py::list pyList1DFromRatCellWrap(const coder::array& values) -{ - py::list result; - - for (int32_T idx0{0}; idx0 < values.size(0); idx0++) { - result.append(pyArrayFromRatArray2d(values[idx0].f1)); - } - - return result; -} - -py::list pyList2dFromRatCellWrap(const coder::array& values) -{ - py::list result; - int32_T idx {0}; - for (int32_T idx0{0}; idx0 < values.size(0); idx0++) { - py::list inner; - for (int32_T idx1{0}; idx1 < values.size(1); idx1++) { - idx = idx0 + values.size(0) * idx1; - inner.append(pyArrayFromRatArray2d(values[idx].f1)); - } - result.append(inner); - } - - return result; -} - -template -py::array_t pyArray1dFromBoundedArray(const T& array) -{ - auto result_array = py::array_t({array.size[0]}); - std::memcpy(result_array.request().ptr, array.data, result_array.nbytes()); + problem_def.domainContrastLayers = pyList1DFromRatCellWrap2D>(problem.domainContrastLayers); + problem_def.fitParams = pyArrayFromRatArray1d>(problem.fitParams); + problem_def.fitLimits = pyArrayFromRatArray2d(problem.fitLimits); + problem_def.priorNames = pyListFromRatCellWrap01d(problem.priorNames); + problem_def.priorValues = pyArrayFromRatArray2d(problem.priorValues); - return result_array; -} - -template -py::array_t pyArray2dFromBoundedArray(const T& array) -{ - auto result_array = py::array_t({array.size[0], array.size[1]}); - std::memcpy(result_array.request().ptr, array.data, result_array.nbytes()); + problem_def.names.params = pyListFromRatCellWrap02d(problem.names.params); + problem_def.names.backgroundParams = pyListFromRatCellWrap02d(problem.names.backgroundParams); + problem_def.names.scalefactors = pyListFromRatCellWrap02d(problem.names.scalefactors); + problem_def.names.bulkIns = pyListFromRatCellWrap02d(problem.names.bulkIns); + problem_def.names.bulkOuts = pyListFromRatCellWrap02d(problem.names.bulkOuts); + problem_def.names.resolutionParams = pyListFromRatCellWrap02d(problem.names.resolutionParams); + problem_def.names.domainRatios = pyListFromRatCellWrap02d(problem.names.domainRatios); + problem_def.names.contrasts = pyListFromRatCellWrap02d(problem.names.contrasts); - return result_array; -} - -py::array_t pyArrayFromRatArray3d(coder::array array) -{ - auto result_array = py::array_t({array.size(0), array.size(1), array.size(2)}); - std::memcpy(result_array.request().ptr, array.data(), result_array.nbytes()); + problem_def.checks.params = pyArrayFromRatArray1d>(problem.checks.params); + problem_def.checks.backgroundParams = pyArrayFromRatArray1d>(problem.checks.backgroundParams); + problem_def.checks.scalefactors = pyArrayFromRatArray1d>(problem.checks.scalefactors); + problem_def.checks.bulkIns = pyArrayFromRatArray1d>(problem.checks.bulkIns); + problem_def.checks.bulkOuts = pyArrayFromRatArray1d>(problem.checks.bulkOuts); + problem_def.checks.resolutionParams = pyArrayFromRatArray1d>(problem.checks.resolutionParams); + problem_def.checks.domainRatios = pyArrayFromRatArray1d>(problem.checks.domainRatios); - return result_array; + return problem_def; } -BayesResults bayesResultsFromStruct8T(const RAT::struct8_T results) +OutputBayesResult OutputBayesResultsFromStruct(const RAT::BayesResults results) { - BayesResults bayesResults; + OutputBayesResult bayesResults; bayesResults.chain = pyArrayFromRatArray2d(results.chain); - bayesResults.predictionIntervals.reflectivity = pyList1DFromRatCellWrap(results.predictionIntervals.reflectivity); - bayesResults.predictionIntervals.sld = pyList2dFromRatCellWrap(results.predictionIntervals.sld); - bayesResults.predictionIntervals.reflectivityXData = pyList1DFromRatCellWrap(results.predictionIntervals.reflectivityXData); - bayesResults.predictionIntervals.sldXData = pyList2dFromRatCellWrap(results.predictionIntervals.sldXData); + bayesResults.predictionIntervals.reflectivity = pyList1DFromRatCellWrap1D>(results.predictionIntervals.reflectivity); + bayesResults.predictionIntervals.sld = pyList2dFromRatCellWrap>(results.predictionIntervals.sld); bayesResults.predictionIntervals.sampleChi = pyArray1dFromBoundedArray>(results.predictionIntervals.sampleChi); bayesResults.confidenceIntervals.percentile95 = pyArrayFromRatArray2d(results.confidenceIntervals.percentile95); bayesResults.confidenceIntervals.percentile65 = pyArrayFromRatArray2d(results.confidenceIntervals.percentile65); bayesResults.confidenceIntervals.mean = pyArrayFromRatArray2d(results.confidenceIntervals.mean); - bayesResults.nestedSamplerOutput.logZ = results.nestedSamplerOutput.LogZ; + bayesResults.nestedSamplerOutput.logZ = results.nestedSamplerOutput.logZ; + bayesResults.nestedSamplerOutput.logZErr = results.nestedSamplerOutput.logZErr; bayesResults.nestedSamplerOutput.nestSamples = pyArrayFromRatArray2d(results.nestedSamplerOutput.nestSamples); bayesResults.nestedSamplerOutput.postSamples = pyArrayFromRatArray2d(results.nestedSamplerOutput.postSamples); @@ -1147,7 +534,6 @@ BayesResults bayesResultsFromStruct8T(const RAT::struct8_T results) bayesResults.dreamOutput.outlierChains = pyArray2dFromBoundedArray>(results.dreamOutput.outlierChains); bayesResults.dreamOutput.runtime = results.dreamOutput.runtime; bayesResults.dreamOutput.iteration = results.dreamOutput.iteration; - bayesResults.dreamOutput.modelOutput = results.dreamOutput.modelOutput; bayesResults.dreamOutput.R_stat = pyArrayFromRatArray2d(results.dreamOutput.R_stat); bayesResults.dreamOutput.CR = pyArrayFromRatArray2d(results.dreamOutput.CR); bayesResults.dreamOutput.AR = pyArray2dFromBoundedArray>(results.dreamOutput.AR); @@ -1175,45 +561,77 @@ BayesResults bayesResultsFromStruct8T(const RAT::struct8_T results) return bayesResults; } -py::tuple RATMain(const ProblemDefinition& problem_def, const Cells& cells, const Limits& limits, const Control& control, - const Priors& priors) +const std::string docsRATMain = R"(Entry point for the main reflectivity computation. + +Parameters +---------- +problem_def : Rat.rat_core.ProblemDefinition + The project input for the RAT calculation. +control : RATapi.rat_core.Control + The controls object for the RAT calculation. + +Returns +------- +out_problem_def : Rat.rat_core.ProblemDefinition + The project input with the updated fit values. +results : Rat.rat_core.OutputResult + The results from a RAT calculation. +bayes_result : Rat.rat_core.OutputBayesResult + The extra results if RAT calculation is Bayesian. +)"; + +py::tuple RATMain(const ProblemDefinition& problem_def, const Control& control) { - RAT::struct0_T problem_def_struct = createStruct0(problem_def); - RAT::cell_7 cells_struct = createCell7(cells); - RAT::struct1_T limits_struct = createStruct1(limits); - RAT::struct2_T control_struct = createStruct2T(control); - RAT::struct4_T priors_struct = createStruct4(priors); - + RAT::b_ProblemDefinition problem_def_struct = createProblemDefinitionStruct(problem_def); + RAT::Controls control_struct = createControlsStruct(control); // Output - RAT::struct5_T results; - RAT::struct8_T bayesResults; - + RAT::Results results; + RAT::BayesResults bayesResults; // Call the entry-point - RAT::RATMain(&problem_def_struct, &cells_struct, &limits_struct, &control_struct, - &priors_struct, &results, &bayesResults); - + RAT::RATMain(&problem_def_struct, &control_struct, &results, &bayesResults); // Copy result to output - return py::make_tuple(problemDefinitionFromStruct0T(problem_def_struct), - OutputResultFromStruct5T(results), - bayesResultsFromStruct8T(bayesResults)); + auto out_problem_def = problemDefinitionFromStruct(problem_def_struct); + out_problem_def.customFiles = problem_def.customFiles.attr("copy")(); + return py::make_tuple(out_problem_def, + OutputResultFromStruct(results), + OutputBayesResultsFromStruct(bayesResults)); } -py::array_t makeSLDProfileXY(real_T bulk_in, - real_T bulk_out, - real_T ssub, - const py::array_t &layers, - real_T number_of_layers, - real_T repeats) +const std::string docsMakeSLDProfile = R"(Creates the profiles for the SLD plots + +Parameters +---------- +bulk_in : float + Bulk in value for contrast. +bulk_out : float + Bulk out value for contrast. +layers : np.ndarray[np.float] + Array of parameters for each layer in the contrast. +ssub : float + Substrate roughness. +number_of_repeats : int, default: 1 + Number of times the layers are repeated. + +Returns +------- +sld_profile : np.ndarray[np.float] + Computed SLD profile +)"; + +py::array_t makeSLDProfile(real_T bulk_in, + real_T bulk_out, + const py::array_t &layers, + real_T ssub, + int number_of_repeats=DEFAULT_NREPEATS) { coder::array out; coder::array layers_array = pyArrayToRatArray2d(layers); - RAT::makeSLDProfileXY(bulk_in, - bulk_out, - ssub, - layers_array, - number_of_layers, - repeats, - out); + RAT::makeSLDProfile(bulk_in, + bulk_out, + layers_array, + ssub, + number_of_repeats, + out); return pyArrayFromRatArray2d(out); @@ -1232,8 +650,12 @@ class Module } }; +template +using overload_cast_ = pybind11::detail::overload_cast_impl; + PYBIND11_MODULE(rat_core, m) { static Module module; + py::class_(m, "EventBridge") .def(py::init()) .def("register", &EventBridge::registerEvent) @@ -1246,19 +668,21 @@ PYBIND11_MODULE(rat_core, m) { py::class_(m, "DylibEngine") .def(py::init()) - .def("invoke", &DylibEngine::invoke, py::arg("params"), py::arg("bulkIn"), - py::arg("bulkOut"), py::arg("contrast"), - py::arg("domain") = DEFAULT_DOMAIN); - - py::class_(m, "PredictionIntervals") + .def("invoke", overload_cast_&, std::vector&, + std::vector&, int, int>()(&DylibEngine::invoke), + py::arg("params"), py::arg("bulkIn"), + py::arg("bulkOut"), py::arg("contrast"), + py::arg("domain") = DEFAULT_DOMAIN) + .def("invoke", overload_cast_&, + std::vector&>()(&DylibEngine::invoke), py::arg("xdata"), py::arg("param")); + + py::class_(m, "PredictionIntervals", docsPredictionIntervals.c_str()) .def(py::init<>()) .def_readwrite("reflectivity", &PredictionIntervals::reflectivity) .def_readwrite("sld", &PredictionIntervals::sld) - .def_readwrite("reflectivityXData", &PredictionIntervals::reflectivityXData) - .def_readwrite("sldXData", &PredictionIntervals::sldXData) .def_readwrite("sampleChi", &PredictionIntervals::sampleChi); - py::class_(m, "PlotEventData") + py::class_(m, "PlotEventData", docsPlotEventData.c_str()) .def(py::init<>()) .def_readwrite("reflectivity", &PlotEventData::reflectivity) .def_readwrite("shiftedData", &PlotEventData::shiftedData) @@ -1268,14 +692,56 @@ PYBIND11_MODULE(rat_core, m) { .def_readwrite("resample", &PlotEventData::resample) .def_readwrite("dataPresent", &PlotEventData::dataPresent) .def_readwrite("modelType", &PlotEventData::modelType) - .def_readwrite("contrastNames", &PlotEventData::contrastNames); - - py::class_(m, "ProgressEventData") + .def_readwrite("contrastNames", &PlotEventData::contrastNames) + .def(py::pickle( + [](const PlotEventData &evt) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(evt.reflectivity, evt.shiftedData, evt.sldProfiles, evt.resampledLayers, evt.subRoughs, evt.resample, + evt.dataPresent, evt.modelType, evt.contrastNames); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 9) + throw std::runtime_error("Encountered invalid state unpickling PlotEventData object!"); + + /* Create a new C++ instance */ + PlotEventData evt; + + evt.reflectivity = t[0].cast(); + evt.shiftedData = t[1].cast(); + evt.sldProfiles = t[2].cast(); + evt.resampledLayers = t[3].cast(); + evt.subRoughs = t[4].cast>(); + evt.resample = t[5].cast>(); + evt.dataPresent = t[6].cast>(); + evt.modelType = t[7].cast(); + evt.contrastNames = t[8].cast(); + + return evt; + })); + + py::class_(m, "ProgressEventData", docsProgressEventData.c_str()) .def(py::init<>()) .def_readwrite("message", &ProgressEventData::message) - .def_readwrite("percent", &ProgressEventData::percent); - - py::class_(m, "ConfidenceIntervals") + .def_readwrite("percent", &ProgressEventData::percent) + .def(py::pickle( + [](const ProgressEventData &evt) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(evt.message, evt.percent); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 2) + throw std::runtime_error("Encountered invalid state unpickling ProgressEventData object!"); + + /* Create a new C++ instance */ + ProgressEventData evt; + + evt.message = t[0].cast(); + evt.percent = t[1].cast(); + + return evt; + })); + + py::class_(m, "ConfidenceIntervals", docsConfidenceIntervals.c_str()) .def(py::init<>()) .def_readwrite("percentile95", &ConfidenceIntervals::percentile95) .def_readwrite("percentile65", &ConfidenceIntervals::percentile65) @@ -1303,120 +769,129 @@ PYBIND11_MODULE(rat_core, m) { .def_readwrite("storeOutput", &DreamParams::storeOutput) .def_readwrite("R", &DreamParams::R); - py::class_(m, "NestedSamplerOutput") + py::class_(m, "NestedSamplerOutput", docsNestedSamplerOutput.c_str()) .def(py::init<>()) .def_readwrite("logZ", &NestedSamplerOutput::logZ) + .def_readwrite("logZErr", &NestedSamplerOutput::logZErr) .def_readwrite("nestSamples", &NestedSamplerOutput::nestSamples) .def_readwrite("postSamples", &NestedSamplerOutput::postSamples); - py::class_(m, "DreamOutput") + py::class_(m, "DreamOutput", docsDreamOutput.c_str()) .def(py::init<>()) .def_readwrite("allChains", &DreamOutput::allChains) .def_readwrite("outlierChains", &DreamOutput::outlierChains) .def_readwrite("runtime", &DreamOutput::runtime) .def_readwrite("iteration", &DreamOutput::iteration) - .def_readwrite("modelOutput", &DreamOutput::modelOutput) .def_readwrite("AR", &DreamOutput::AR) .def_readwrite("R_stat", &DreamOutput::R_stat) .def_readwrite("CR", &DreamOutput::CR); - py::class_(m, "BayesResults") + py::class_(m, "OutputBayesResult", docsOutputBayesResult.c_str()) .def(py::init<>()) - .def_readwrite("predictionIntervals", &BayesResults::predictionIntervals) - .def_readwrite("confidenceIntervals", &BayesResults::confidenceIntervals) - .def_readwrite("dreamParams", &BayesResults::dreamParams) - .def_readwrite("dreamOutput", &BayesResults::dreamOutput) - .def_readwrite("nestedSamplerOutput", &BayesResults::nestedSamplerOutput) - .def_readwrite("chain", &BayesResults::chain); - - py::class_(m, "Calculation") + .def_readwrite("predictionIntervals", &OutputBayesResult::predictionIntervals) + .def_readwrite("confidenceIntervals", &OutputBayesResult::confidenceIntervals) + .def_readwrite("dreamParams", &OutputBayesResult::dreamParams) + .def_readwrite("dreamOutput", &OutputBayesResult::dreamOutput) + .def_readwrite("nestedSamplerOutput", &OutputBayesResult::nestedSamplerOutput) + .def_readwrite("chain", &OutputBayesResult::chain); + + py::class_(m, "Calculation", docsCalculation.c_str()) .def(py::init<>()) .def_readwrite("chiValues", &Calculation::chiValues) .def_readwrite("sumChi", &Calculation::sumChi); - py::class_(m, "ContrastParams") + py::class_(m, "ContrastParams", docsContrastParams.c_str()) .def(py::init<>()) - .def_readwrite("backgroundParams", &ContrastParams::backgroundParams) .def_readwrite("scalefactors", &ContrastParams::scalefactors) .def_readwrite("bulkIn", &ContrastParams::bulkIn) .def_readwrite("bulkOut", &ContrastParams::bulkOut) - .def_readwrite("resolutionParams", &ContrastParams::resolutionParams) .def_readwrite("subRoughs", &ContrastParams::subRoughs) .def_readwrite("resample", &ContrastParams::resample); - py::class_(m, "OutputResult") + py::class_(m, "OutputResult", docsOutputResult.c_str()) .def(py::init<>()) .def_readwrite("reflectivity", &OutputResult::reflectivity) .def_readwrite("simulation", &OutputResult::simulation) .def_readwrite("shiftedData", &OutputResult::shiftedData) - .def_readwrite("layerSlds", &OutputResult::layerSlds) + .def_readwrite("backgrounds", &OutputResult::backgrounds) + .def_readwrite("resolutions", &OutputResult::resolutions) .def_readwrite("sldProfiles", &OutputResult::sldProfiles) + .def_readwrite("layers", &OutputResult::layers) .def_readwrite("resampledLayers", &OutputResult::resampledLayers) .def_readwrite("calculationResults", &OutputResult::calculationResults) .def_readwrite("contrastParams", &OutputResult::contrastParams) .def_readwrite("fitParams", &OutputResult::fitParams) .def_readwrite("fitNames", &OutputResult::fitNames); - py::class_(m, "Checks") - .def(py::init<>()) - .def_readwrite("fitParam", &Checks::fitParam) - .def_readwrite("fitBackgroundParam", &Checks::fitBackgroundParam) - .def_readwrite("fitQzshift", &Checks::fitQzshift) - .def_readwrite("fitScalefactor", &Checks::fitScalefactor) - .def_readwrite("fitBulkIn", &Checks::fitBulkIn) - .def_readwrite("fitBulkOut", &Checks::fitBulkOut) - .def_readwrite("fitResolutionParam", &Checks::fitResolutionParam) - .def_readwrite("fitDomainRatio", &Checks::fitDomainRatio); - - py::class_(m, "Limits") + py::class_(m, "NameStore", docsNameStore.c_str()) .def(py::init<>()) - .def_readwrite("param", &Limits::param) - .def_readwrite("backgroundParam", &Limits::backgroundParam) - .def_readwrite("qzshift", &Limits::qzshift) - .def_readwrite("scalefactor", &Limits::scalefactor) - .def_readwrite("bulkIn", &Limits::bulkIn) - .def_readwrite("bulkOut", &Limits::bulkOut) - .def_readwrite("resolutionParam", &Limits::resolutionParam) - .def_readwrite("domainRatio", &Limits::domainRatio); - - py::class_(m, "Priors") + .def_readwrite("params", &NameStore::params) + .def_readwrite("backgroundParams", &NameStore::backgroundParams) + .def_readwrite("scalefactors", &NameStore::scalefactors) + .def_readwrite("bulkIns", &NameStore::bulkIns) + .def_readwrite("bulkOuts", &NameStore::bulkOuts) + .def_readwrite("resolutionParams", &NameStore::resolutionParams) + .def_readwrite("domainRatios", &NameStore::domainRatios) + .def_readwrite("contrasts", &NameStore::contrasts) + .def(py::pickle( + [](const NameStore &names) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(names.params, names.backgroundParams, names.scalefactors, names.bulkIns, names.bulkOuts, names.resolutionParams, + names.domainRatios, names.contrasts); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 8) + throw std::runtime_error("Encountered invalid state unpickling NameStore object!"); + + /* Create a new C++ instance */ + NameStore names; + + names.params = t[0].cast(); + names.backgroundParams = t[1].cast(); + names.scalefactors = t[2].cast(); + names.bulkIns = t[3].cast(); + names.bulkOuts = t[4].cast(); + names.resolutionParams = t[5].cast(); + names.domainRatios = t[6].cast(); + names.contrasts = t[7].cast(); + + return names; + })); + + py::class_(m, "Checks", docsChecks.c_str()) .def(py::init<>()) - .def_readwrite("param", &Priors::param) - .def_readwrite("backgroundParam", &Priors::backgroundParam) - .def_readwrite("qzshift", &Priors::qzshift) - .def_readwrite("scalefactor", &Priors::scalefactor) - .def_readwrite("bulkIn", &Priors::bulkIn) - .def_readwrite("bulkOut", &Priors::bulkOut) - .def_readwrite("resolutionParam", &Priors::resolutionParam) - .def_readwrite("domainRatio", &Priors::domainRatio) - .def_readwrite("priorNames", &Priors::priorNames) - .def_readwrite("priorValues", &Priors::priorValues); - - py::class_(m, "Cells") - .def(py::init<>()) - .def_readwrite("f1", &Cells::f1) - .def_readwrite("f2", &Cells::f2) - .def_readwrite("f3", &Cells::f3) - .def_readwrite("f4", &Cells::f4) - .def_readwrite("f5", &Cells::f5) - .def_readwrite("f6", &Cells::f6) - .def_readwrite("f7", &Cells::f7) - .def_readwrite("f8", &Cells::f8) - .def_readwrite("f9", &Cells::f9) - .def_readwrite("f10", &Cells::f10) - .def_readwrite("f11", &Cells::f11) - .def_readwrite("f12", &Cells::f12) - .def_readwrite("f13", &Cells::f13) - .def_readwrite("f14", &Cells::f14) - .def_readwrite("f15", &Cells::f15) - .def_readwrite("f16", &Cells::f16) - .def_readwrite("f17", &Cells::f17) - .def_readwrite("f18", &Cells::f18) - .def_readwrite("f19", &Cells::f19) - .def_readwrite("f20", &Cells::f20) - .def_readwrite("f21", &Cells::f21); - - py::class_(m, "Control") + .def_readwrite("params", &Checks::params) + .def_readwrite("backgroundParams", &Checks::backgroundParams) + .def_readwrite("scalefactors", &Checks::scalefactors) + .def_readwrite("bulkIns", &Checks::bulkIns) + .def_readwrite("bulkOuts", &Checks::bulkOuts) + .def_readwrite("resolutionParams", &Checks::resolutionParams) + .def_readwrite("domainRatios", &Checks::domainRatios) + .def(py::pickle( + [](const Checks &chk) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(chk.params, chk.backgroundParams, chk.scalefactors, chk.bulkIns, chk.bulkOuts, + chk.resolutionParams, chk.domainRatios); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 7) + throw std::runtime_error("Encountered invalid state unpickling Checks object!"); + + /* Create a new C++ instance */ + Checks chk; + + chk.params = t[0].cast>(); + chk.backgroundParams = t[1].cast>(); + chk.scalefactors = t[2].cast>(); + chk.bulkIns = t[3].cast>(); + chk.bulkOuts = t[4].cast>(); + chk.resolutionParams = t[5].cast>(); + chk.domainRatios = t[6].cast>(); + + return chk; + })); + + py::class_(m, "Control", docsControl.c_str()) .def(py::init<>()) .def_readwrite("parallel", &Control::parallel) .def_readwrite("procedure", &Control::procedure) @@ -1435,8 +910,9 @@ PYBIND11_MODULE(rat_core, m) { .def_readwrite("nMCMC", &Control::nMCMC) .def_readwrite("propScale", &Control::propScale) .def_readwrite("nsTolerance", &Control::nsTolerance) - .def_readwrite("calcSldDuringFit", &Control::calcSldDuringFit) - .def_readwrite("resampleParams", &Control::resampleParams) + .def_readwrite("numSimulationPoints", &Control::numSimulationPoints) + .def_readwrite("resampleMinAngle", &Control::resampleMinAngle) + .def_readwrite("resampleNPoints", &Control::resampleNPoints) .def_readwrite("updateFreq", &Control::updateFreq) .def_readwrite("updatePlotFreq", &Control::updatePlotFreq) .def_readwrite("nSamples", &Control::nSamples) @@ -1445,43 +921,183 @@ PYBIND11_MODULE(rat_core, m) { .def_readwrite("pUnitGamma", &Control::pUnitGamma) .def_readwrite("boundHandling", &Control::boundHandling) .def_readwrite("adaptPCR", &Control::adaptPCR) - .def_readwrite("checks", &Control::checks); - - py::class_(m, "ProblemDefinition") + .def_readwrite("IPCFilePath", &Control::IPCFilePath) + .def(py::pickle( + [](const Control &ctrl) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(ctrl.parallel, ctrl.procedure, ctrl.display, ctrl.xTolerance, ctrl.funcTolerance, + ctrl.maxFuncEvals, ctrl.maxIterations, ctrl.populationSize, ctrl.fWeight, ctrl.crossoverProbability, + ctrl.targetValue, ctrl.numGenerations, ctrl.strategy, ctrl.nLive, ctrl.nMCMC, ctrl.propScale, + ctrl.nsTolerance, ctrl.numSimulationPoints, ctrl.resampleMinAngle, ctrl.resampleNPoints, + ctrl.updateFreq, ctrl.updatePlotFreq, ctrl.nSamples, ctrl.nChains, ctrl.jumpProbability, + ctrl.pUnitGamma, ctrl.boundHandling, ctrl.adaptPCR, ctrl.IPCFilePath); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 29) + throw std::runtime_error("Encountered invalid state unpickling ProblemDefinition object!"); + + /* Create a new C++ instance */ + Control ctrl; + + ctrl.parallel = t[0].cast(); + ctrl.procedure = t[1].cast(); + ctrl.display = t[2].cast(); + ctrl.xTolerance = t[3].cast(); + ctrl.funcTolerance = t[4].cast(); + ctrl.maxFuncEvals = t[5].cast(); + ctrl.maxIterations = t[6].cast(); + ctrl.populationSize = t[7].cast(); + ctrl.fWeight = t[8].cast(); + ctrl.crossoverProbability = t[9].cast(); + ctrl.targetValue = t[10].cast(); + ctrl.numGenerations = t[11].cast(); + ctrl.strategy = t[12].cast(); + ctrl.nLive = t[13].cast(); + ctrl.nMCMC = t[14].cast(); + ctrl.propScale = t[15].cast(); + ctrl.nsTolerance = t[16].cast(); + ctrl.numSimulationPoints = t[17].cast(); + ctrl.resampleMinAngle = t[18].cast(); + ctrl.resampleNPoints = t[19].cast(); + ctrl.updateFreq = t[20].cast(); + ctrl.updatePlotFreq = t[21].cast(); + ctrl.nSamples = t[22].cast(); + ctrl.nChains = t[23].cast(); + ctrl.jumpProbability = t[24].cast(); + ctrl.pUnitGamma = t[25].cast(); + ctrl.boundHandling = t[26].cast(); + ctrl.adaptPCR = t[27].cast(); + ctrl.IPCFilePath = t[28].cast(); + + return ctrl; + })); + + py::class_(m, "ProblemDefinition", docsProblemDefinition.c_str()) .def(py::init<>()) - .def_readwrite("contrastBackgroundParams", &ProblemDefinition::contrastBackgroundParams) - .def_readwrite("contrastBackgroundActions", &ProblemDefinition::contrastBackgroundActions) .def_readwrite("TF", &ProblemDefinition::TF) .def_readwrite("resample", &ProblemDefinition::resample) + .def_readwrite("data", &ProblemDefinition::data) .def_readwrite("dataPresent", &ProblemDefinition::dataPresent) - .def_readwrite("oilChiDataPresent", &ProblemDefinition::oilChiDataPresent) + .def_readwrite("dataLimits", &ProblemDefinition::dataLimits) + .def_readwrite("simulationLimits", &ProblemDefinition::simulationLimits) .def_readwrite("numberOfContrasts", &ProblemDefinition::numberOfContrasts) .def_readwrite("geometry", &ProblemDefinition::geometry) - .def_readwrite("useImaginary", &ProblemDefinition::useImaginary) - .def_readwrite("contrastQzshifts", &ProblemDefinition::contrastQzshifts) + .def_readwrite("useImaginary", &ProblemDefinition::useImaginary) + .def_readwrite("repeatLayers", &ProblemDefinition::repeatLayers) + .def_readwrite("contrastBackgroundParams", &ProblemDefinition::contrastBackgroundParams) + .def_readwrite("contrastBackgroundTypes", &ProblemDefinition::contrastBackgroundTypes) + .def_readwrite("contrastBackgroundActions", &ProblemDefinition::contrastBackgroundActions) .def_readwrite("contrastScalefactors", &ProblemDefinition::contrastScalefactors) .def_readwrite("contrastBulkIns", &ProblemDefinition::contrastBulkIns) .def_readwrite("contrastBulkOuts", &ProblemDefinition::contrastBulkOuts) .def_readwrite("contrastResolutionParams", &ProblemDefinition::contrastResolutionParams) + .def_readwrite("contrastResolutionTypes", &ProblemDefinition::contrastResolutionTypes) .def_readwrite("backgroundParams", &ProblemDefinition::backgroundParams) - .def_readwrite("qzshifts", &ProblemDefinition::qzshifts) .def_readwrite("scalefactors", &ProblemDefinition::scalefactors) - .def_readwrite("bulkIn", &ProblemDefinition::bulkIn) - .def_readwrite("bulkOut", &ProblemDefinition::bulkOut) + .def_readwrite("bulkIns", &ProblemDefinition::bulkIns) + .def_readwrite("bulkOuts", &ProblemDefinition::bulkOuts) .def_readwrite("resolutionParams", &ProblemDefinition::resolutionParams) .def_readwrite("params", &ProblemDefinition::params) .def_readwrite("numberOfLayers", &ProblemDefinition::numberOfLayers) + .def_readwrite("contrastLayers", &ProblemDefinition::contrastLayers) + .def_readwrite("layersDetails", &ProblemDefinition::layersDetails) + .def_readwrite("customFiles", &ProblemDefinition::customFiles) .def_readwrite("modelType", &ProblemDefinition::modelType) .def_readwrite("contrastCustomFiles", &ProblemDefinition::contrastCustomFiles) .def_readwrite("contrastDomainRatios", &ProblemDefinition::contrastDomainRatios) - .def_readwrite("domainRatio", &ProblemDefinition::domainRatio) + .def_readwrite("domainRatios", &ProblemDefinition::domainRatios) .def_readwrite("numberOfDomainContrasts", &ProblemDefinition::numberOfDomainContrasts) + .def_readwrite("domainContrastLayers", &ProblemDefinition::domainContrastLayers) .def_readwrite("fitParams", &ProblemDefinition::fitParams) - .def_readwrite("otherParams", &ProblemDefinition::otherParams) .def_readwrite("fitLimits", &ProblemDefinition::fitLimits) - .def_readwrite("otherLimits", &ProblemDefinition::otherLimits); - - m.def("RATMain", &RATMain, "Entry point for the main reflectivity computation."); - - m.def("makeSLDProfileXY", &makeSLDProfileXY, "Creates the profiles for the SLD plots"); + .def_readwrite("priorNames", &ProblemDefinition::priorNames) + .def_readwrite("priorValues", &ProblemDefinition::priorValues) + .def_readwrite("names", &ProblemDefinition::names) + .def_readwrite("checks", &ProblemDefinition::checks) + .def(py::pickle( + [](const ProblemDefinition &p) { // __getstate__ + /* Return a tuple that fully encodes the state of the object */ + return py::make_tuple(p.TF, p.resample, p.data, p.dataPresent, p.dataLimits, p.simulationLimits, + p.numberOfContrasts, p.geometry, p.useImaginary, p.repeatLayers, + p.contrastBackgroundParams, p.contrastBackgroundTypes, p.contrastBackgroundActions, + p.contrastScalefactors, p.contrastBulkIns, p.contrastBulkOuts, p.contrastResolutionParams, + p.contrastResolutionTypes, p.backgroundParams, p.scalefactors, p.bulkIns, p.bulkOuts, + p.resolutionParams, p.params, p.numberOfLayers, p.contrastLayers, p.layersDetails, + p.customFiles, p.modelType, p.contrastCustomFiles, p.contrastDomainRatios, p.domainRatios, + p.numberOfDomainContrasts, p.domainContrastLayers, p.fitParams, p.fitLimits, p.priorNames, p.priorValues, + p.names.params, p.names.backgroundParams, p.names.scalefactors, p.names.bulkIns, + p.names.bulkOuts, p.names.resolutionParams, p.names.domainRatios, p.names.contrasts, + p.checks.params, p.checks.backgroundParams, p.checks.scalefactors, + p.checks.bulkIns, p.checks.bulkOuts, p.checks.resolutionParams, p.checks.domainRatios); + }, + [](py::tuple t) { // __setstate__ + if (t.size() != 53) + throw std::runtime_error("Encountered invalid state unpickling ProblemDefinition object!"); + + /* Create a new C++ instance */ + ProblemDefinition p; + + p.TF = t[0].cast(); + p.resample = t[1].cast>(); + p.data = t[2].cast(); + p.dataPresent = t[3].cast>(); + p.dataLimits = t[4].cast(); + p.simulationLimits = t[5].cast(); + p.numberOfContrasts = t[6].cast(); + p.geometry = t[7].cast(); + p.useImaginary = t[8].cast(); + p.repeatLayers = t[9].cast>(); + p.contrastBackgroundParams = t[10].cast(); + p.contrastBackgroundTypes = t[11].cast(); + p.contrastBackgroundActions = t[12].cast(); + p.contrastScalefactors = t[13].cast>(); + p.contrastBulkIns = t[14].cast>(); + p.contrastBulkOuts = t[15].cast>(); + p.contrastResolutionParams = t[16].cast(); + p.contrastResolutionTypes = t[17].cast(); + p.backgroundParams = t[18].cast>(); + p.scalefactors = t[19].cast>(); + p.bulkIns = t[20].cast>(); + p.bulkOuts = t[21].cast>(); + p.resolutionParams = t[22].cast>(); + p.params = t[23].cast>(); + p.numberOfLayers = t[24].cast(); + p.contrastLayers = t[25].cast(); + p.layersDetails = t[26].cast(); + p.customFiles = t[27].cast(); + p.modelType = t[28].cast(); + p.contrastCustomFiles = t[29].cast>(); + p.contrastDomainRatios = t[30].cast>(); + p.domainRatios = t[31].cast>(); + p.numberOfDomainContrasts = t[32].cast(); + p.domainContrastLayers = t[33].cast(); + p.fitParams = t[34].cast>(); + p.fitLimits = t[35].cast>(); + p.priorNames = t[36].cast(); + p.priorValues = t[37].cast>(); + + p.names.params = t[38].cast(); + p.names.backgroundParams = t[39].cast(); + p.names.scalefactors = t[40].cast(); + p.names.bulkIns = t[41].cast(); + p.names.bulkOuts = t[42].cast(); + p.names.resolutionParams = t[43].cast(); + p.names.domainRatios = t[44].cast(); + p.names.contrasts = t[45].cast(); + + p.checks.params = t[46].cast>(); + p.checks.backgroundParams = t[47].cast>(); + p.checks.scalefactors = t[48].cast>(); + p.checks.bulkIns = t[49].cast>(); + p.checks.bulkOuts = t[50].cast>(); + p.checks.resolutionParams = t[51].cast>(); + p.checks.domainRatios = t[52].cast>(); + + return p; + })); + + m.def("RATMain", &RATMain, docsRATMain.c_str(), py::arg("problem_def"), py::arg("control")); + + m.def("makeSLDProfile", &makeSLDProfile, docsMakeSLDProfile.c_str(), + py::arg("bulk_in"), py::arg("bulk_out"), py::arg("layers"), py::arg("ssub"), py::arg("number_of_repeats") = DEFAULT_NREPEATS); } diff --git a/pyproject.toml b/pyproject.toml index 4216b6e2..f2f9201c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,17 +2,93 @@ requires = [ 'setuptools>=61', 'wheel', - 'pybind11>=2.4', + 'pybind11>=2.4, <=2.13.6', ] build-backend = 'setuptools.build_meta' +[project] +name = "ratapi" +version = "0.0.0.dev15" +description = "Python extension for the Reflectivity Analysis Toolbox (RAT)" +readme = "README.md" +requires-python = ">=3.10" +dependencies = [ + "matplotlib>=3.8.3", + "numpy>=1.20", + "prettytable>=3.9.0", + "pydantic>=2.7.2", + "scipy>=1.13.1", + "strenum>=0.4.15 ; python_full_version < '3.11'", + "tqdm>=4.66.5", +] + +[project.urls] +Documentation = "https://rascalsoftware.github.io/RAT/" +Repository = "https://github.com/RascalSoftware/python-RAT" + +[project.optional-dependencies] +dev = [ + "pytest>=7.4.0,!=9.1.0", + "pytest-cov>=4.1.0", + "ruff>=0.4.10" +] +orso = [ + "orsopy>=1.2.1", + "pint>=0.24.4" +] +matlab_latest = ["matlabengine"] +matlab_2025b = ["matlabengine == 25.2.*"] +matlab_2025a = ["matlabengine == 25.1.2"] +matlab_2024b = ["matlabengine == 24.2.2"] +matlab_2024a = ["matlabengine == 24.1.4"] +matlab_2023b = ["matlabengine == 23.2.3"] +matlab_2023a = ["matlabengine == 9.14.3"] + +[tool.uv] +conflicts = [ + [ + { extra = "matlab_latest" }, + { extra = "matlab_2025b" }, + { extra = "matlab_2025a" }, + { extra = "matlab_2024b" }, + { extra = "matlab_2024a" }, + { extra = "matlab_2023b" }, + { extra = "matlab_2023a" }, + ], +] + [tool.ruff] line-length = 120 +extend-exclude = ["*.ipynb"] [tool.ruff.lint] -select = ["E", "F", "UP", "B", "SIM", "I"] -ignore = ["SIM108"] +select = ["E", # pycodestyle errors + "F", # pyflakes + "UP", # pyupgrade + "B", # flake8-bugbear + "SIM", # flake8-simplify + "I", # isort + "D"] # pydocstyle + +ignore = ["SIM103", # needless bool + "SIM108", # if-else block instead of ternary operator + "D105", # undocumented __init__ + "D107", # undocumented magic method + "D203", # blank line before class docstring + "D213", # multi line summary should start at second line + "UP038"] # non pep604 isinstance - to be removed + +# ignore docstring lints in the tests and install script +[tool.ruff.lint.per-file-ignores] +"tests/*" = ["D"] +"setup.py" = ["D"] [tool.ruff.lint.flake8-pytest-style] fixture-parentheses = false mark-parentheses = false + +[tool.ruff.lint.pydocstyle] +convention = "numpy" + +[tool.ruff.lint.isort] +known-first-party = ["ratapi.rat_core"] diff --git a/ratapi/__init__.py b/ratapi/__init__.py new file mode 100644 index 00000000..98683c7e --- /dev/null +++ b/ratapi/__init__.py @@ -0,0 +1,29 @@ +"""ratapi is a Python package for modelling, fitting and optimising reflectivity problems.""" + +from contextlib import suppress + +import ratapi.examples as examples +from ratapi import events, models +from ratapi.classlist import ClassList +from ratapi.controls import Controls +from ratapi.outputs import BayesResults, Results +from ratapi.project import Project +from ratapi.run import run +from ratapi.utils import convert, plotting + +with suppress(ImportError): # orsopy is an optional dependency + from ratapi.utils import orso as orso + +__all__ = [ + "examples", + "models", + "events", + "ClassList", + "Controls", + "BayesResults", + "Results", + "Project", + "run", + "plotting", + "convert", +] diff --git a/ratapi/classlist.py b/ratapi/classlist.py new file mode 100644 index 00000000..29637a5f --- /dev/null +++ b/ratapi/classlist.py @@ -0,0 +1,620 @@ +"""The ClassList class, which defines a list containing instances of a particular class.""" + +import collections +import contextlib +import importlib +import warnings +from collections.abc import Sequence +from typing import Any, Generic, TypeVar + +import numpy as np +import prettytable + +T = TypeVar("T") + + +class ClassList(collections.UserList, Generic[T]): + """List of instances of a particular class. + + This class subclasses collections.UserList to construct a list intended to store ONLY instances of a particular + class, given on initialisation. Any attempt to introduce an object of a different type will raise a ValueError. + The class must be able to accept attribute values using keyword arguments. In addition, if the class has the + attribute given in the ClassList's "name_field" attribute (the default is "name"), the ClassList will ensure that + all objects within the ClassList have unique values for that attribute. It is then possible to use this attribute + of an object in the .remove(), .count(), and .index() routines in place of the full object. Due to the requirement + of unique values of the ``name_field`` attribute, the multiplication operators __mul__, __rmul__, and __imul__ have + been disabled, since they cannot allow for unique attribute values by definition. + + We extend the UserList class to enable objects to be added and modified using just the keyword arguments, enable + the object ``name_field`` attribute to be used in place of the full object, and ensure all elements are of the + specified type, with unique ``name_field`` attributes defined. + + Parameters + ---------- + init_list : Sequence [T] or T, optional + 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: Sequence[T] | T = None, name_field: str = "name") -> None: + self.name_field = name_field + + # Set input as list if necessary + if init_list and not (isinstance(init_list, Sequence) and not isinstance(init_list, str)): + init_list = [init_list] + + # Set class to be used for this instance of the ClassList, checking that all elements of the input list are of + # the same type and have unique values of the specified name_field + if init_list: + self._class_handle = self._determine_class_handle(init_list) + self._check_classes(init_list) + self._check_unique_name_fields(init_list) + + super().__init__(init_list) + + def __str__(self): + # `display_fields` gives more control over the items displayed from the list if available + if not self.data: + return str([]) + try: + model_display_fields = [model.display_fields for model in self.data] + # get all items included in at least one list + # the list comprehension ensures they are in the order that they're in in the model + required_fields = list(set().union(*model_display_fields)) + table_fields = ["index"] + [i for i in list(self.data[0].__dict__) if i in required_fields] + except AttributeError: + try: + model_display_fields = [model.__dict__ for model in self.data] + table_fields = ["index"] + list(self.data[0].__dict__) + except AttributeError: + return str(self.data) + + if any(model_display_fields): + table = prettytable.PrettyTable() + table.field_names = [field.replace("_", " ") for field in table_fields] + rows = [] + for index, model in enumerate(self.data): + row = [index] + for field in table_fields[1:]: + value = getattr(model, field, "") + if isinstance(value, np.ndarray): + value = ( + f"{'Data array: [' + ' x '.join(str(i) for i in value.shape) if value.size > 0 else '['}]" + ) + elif field == "model": + value = "\n".join(str(element) for element in value) + else: + value = str(value) + row.append(value) + rows.append(row) + table.add_rows(rows) + output = table.get_string() + 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__] + table.add_rows( + [ + [index] + + list( + f"{'Data array: [' + ' x '.join(str(i) for i in v.shape) if v.size > 0 else '['}]" + if isinstance(v, np.ndarray) + else "\n".join(element for element in v) + if k == "model" + else str(v) + for k, v in model.__dict__.items() + ) + for index, model in enumerate(self.data) + ] + ) + output = table.get_string() + else: + output = str(self.data) + return output + + def __getitem__(self, index: int | slice | str | T) -> T: + """Get an item by its index, name, a slice, or the object itself.""" + if isinstance(index, (int, slice)): + return self.data[index] + elif isinstance(index, (str, self._class_handle)): + return self.data[self.index(index)] + else: + raise IndexError("ClassLists can only be indexed by integers, slices, name strings, or objects.") + + def __setitem__(self, index: int, item: T) -> None: + """Replace the object at an existing index of the ClassList.""" + self._setitem(index, item) + + def _setitem(self, index: int, item: T) -> None: + """Auxiliary routine of "__setitem__" used to enable wrapping.""" + self._check_classes([item]) + self._check_unique_name_fields([item]) + self.data[index] = item + + def __delitem__(self, index: int) -> None: + """Delete an object from the list by index.""" + self._delitem(index) + + def _delitem(self, index: int) -> None: + """Auxiliary routine of "__delitem__" used to enable wrapping.""" + del self.data[index] + + def __iadd__(self, other: Sequence[T]) -> "ClassList": + """Define in-place addition using the "+=" operator.""" + return self._iadd(other) + + def _iadd(self, other: Sequence[T]) -> "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"): + self._class_handle = self._determine_class_handle(self + other) + self._check_classes(other) + self._check_unique_name_fields(other) + super().__iadd__(other) + return self + + def __mul__(self, n: int) -> None: + """Define multiplication using the "*" operator.""" + raise TypeError(f"unsupported operand type(s) for *: '{self.__class__.__name__}' and '{n.__class__.__name__}'") + + def __rmul__(self, n: int) -> None: + """Define multiplication using the "*" operator.""" + raise TypeError(f"unsupported operand type(s) for *: '{n.__class__.__name__}' and '{self.__class__.__name__}'") + + def __imul__(self, n: int) -> None: + """Define in-place multiplication using the "*=" operator.""" + raise TypeError(f"unsupported operand type(s) for *=: '{self.__class__.__name__}' and '{n.__class__.__name__}'") + + def append(self, obj: T = None, **kwargs) -> None: + """Append a new object to the ClassList. + + This method can use the object itself, or can provide attribute values as keyword arguments for a new object. + + Parameters + ---------- + obj : T, optional + An instance of the class specified by self._class_handle. + **kwargs : dict[str, Any], optional + The input keyword arguments for a new object in the ClassList. + + Raises + ------ + ValueError + Raised if the input arguments contain a ``name_field`` value already defined in the ClassList. + + Warnings + -------- + 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, + stacklevel=2, + ) + if obj: + if not hasattr(self, "_class_handle"): + self._class_handle = type(obj) + self._check_classes([obj]) + self._check_unique_name_fields([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.", + ) + self._validate_name_field(kwargs) + self.data.append(self._class_handle(**kwargs)) + + def insert(self, index: int, obj: T = None, **kwargs) -> None: + """Insert a new object at a given index. + + This method can use the object itself, or can provide attribute values as keyword arguments for a new object. + + Parameters + ---------- + index: int + The index at which to insert a new object in the ClassList. + obj : T, optional + An instance of the class specified by self._class_handle. + **kwargs : dict[str, Any], optional + The input keyword arguments for a new object in the ClassList. + + Raises + ------ + ValueError + Raised if the input arguments contain a ``name_field`` value already defined in the ClassList. + + Warnings + -------- + 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, + stacklevel=2, + ) + if obj: + if not hasattr(self, "_class_handle"): + self._class_handle = type(obj) + self._check_classes([obj]) + self._check_unique_name_fields([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.", + ) + self._validate_name_field(kwargs) + self.data.insert(index, self._class_handle(**kwargs)) + + def remove(self, item: T | str) -> None: + """Remove an object from the ClassList using either the object itself or its ``name_field`` value.""" + item = self._get_item_from_name_field(item) + self.data.remove(item) + + def count(self, item: T | str) -> int: + """Return the number of times an object appears in the ClassList. + + This method can use either the object itself or its ``name_field`` value. + + """ + item = self._get_item_from_name_field(item) + return self.data.count(item) + + def index(self, item: T | str, offset: bool = False, *args) -> int: + """Return the index of a particular object in the ClassList. + + This method can use either the object itself or its ``name_field`` value. + If offset is specified, add one to the index. This is used to account for one-based indexing. + + """ + item = self._get_item_from_name_field(item) + return self.data.index(item, *args) + int(offset) + + def extend(self, other: Sequence[T]) -> 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"): + self._class_handle = self._determine_class_handle(self + other) + self._check_classes(other) + self._check_unique_name_fields(other) + self.data.extend(other) + + def union(self, other: Sequence[T]) -> None: + """Extend the ClassList by a sequence, ignoring input items with names that already exist.""" + if other and not (isinstance(other, Sequence) and not isinstance(other, str)): + other = [other] + + self.extend( + [ + item + for item in other + if hasattr(item, self.name_field) and getattr(item, self.name_field) not in self.get_names() + ] + ) + + def set_fields(self, index: int | slice | str | T, **kwargs) -> None: + """Assign the values of an existing object's attributes using keyword arguments.""" + self._validate_name_field(kwargs) + pydantic_object = False + + # Find index if name or object is supplied + if isinstance(index, (str, self._class_handle)): + index = self.index(index) + + # Prioritise changing language to avoid CustomFile validator bug + value = kwargs.pop("language", None) + if value is not None: + kwargs = {"language": value, **kwargs} + + if importlib.util.find_spec("pydantic"): + # Pydantic is installed, so set up a context manager that will + # suppress custom validation errors until all fields have been set. + from pydantic import BaseModel, ValidationError + + if isinstance(self.data[index], BaseModel): + pydantic_object = True + + # Define a custom context manager + class SuppressCustomValidation(contextlib.AbstractContextManager): + """Context manager to suppress "value_error" based validation errors in pydantic. + + This validation context is necessary because errors can occur whilst individual + model values are set, which are resolved when all of the input values are set. + + After the exception is suppressed, execution proceeds with the next + statement following the with statement. + + with SuppressCustomValidation(): + setattr(self.data[index], key, value) + # Execution still resumes here if the attribute cannot be set + """ + + def __init__(self): + pass + + def __enter__(self): + pass + + def __exit__(self, exctype, excinst, exctb): + # If the return of __exit__ is True or truthy, the exception is suppressed. + # Otherwise, the default behaviour of raising the exception applies. + # + # To suppress errors arising from field and model validators in pydantic, + # we will examine the validation errors raised. If all of the errors + # listed in the exception have the type "value_error", this indicates + # they have arisen from field or model validators and will be suppressed. + # Otherwise, they will be raised. + if exctype is None: + return + if issubclass(exctype, ValidationError) and all( + [error["type"] == "value_error" for error in excinst.errors()] + ): + return True + return False + + validation_context = SuppressCustomValidation() + else: + validation_context = contextlib.nullcontext() + + for key, value in kwargs.items(): + with validation_context: + setattr(self.data[index], key, value) + + # We have suppressed custom validation errors for pydantic objects. + # We now must revalidate the pydantic model outside the validation context + # to catch any errors that remain after setting all of the fields. + if pydantic_object: + self._class_handle.model_validate(self.data[index]) + + def get_names(self) -> list[str]: + """Return a list of the values of the ``name_field`` attribute of each class object in the list. + + Returns + ------- + 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)] + + def get_all_matches(self, value: Any) -> list[tuple]: + """Return a list of all (index, field) tuples where the value of the field is equal to the given value. + + Parameters + ---------- + value : str + The value we are searching for in the ClassList. + + Returns + ------- + : 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 + ] + + def _validate_name_field(self, input_args: dict[str, Any]) -> None: + """Raise a ValueError if the user tries to add an object with a ``name_field`` already in the ClassList. + + Parameters + ---------- + input_args : dict [str, Any] + The input keyword arguments for a new object in the ClassList. + + Raises + ------ + ValueError + Raised if the input arguments contain a ``name_field`` value already defined in the ClassList. + + """ + names = [name.lower() for name in self.get_names()] + with contextlib.suppress(KeyError): + name = input_args[self.name_field].lower() + if name in names: + raise ValueError( + f"Input arguments contain the {self.name_field} '{input_args[self.name_field]}', " + f"which is already specified at index {names.index(name)} of the ClassList", + ) + + def _check_unique_name_fields(self, input_list: Sequence[T]) -> None: + """Raise a ValueError if any value of the ``name_field`` attribute is repeated in a list of class objects. + + Parameters + ---------- + input_list : iterable + An iterable of instances of the class given in self._class_handle. + + Raises + ------ + ValueError + Raised if the input list defines more than one object with the same value of name_field. + + """ + error_list = [] + try: + existing_names = [name.lower() for name in self.get_names()] + except AttributeError: + existing_names = [] + + new_names = [getattr(model, self.name_field).lower() for model in input_list if hasattr(model, self.name_field)] + full_names = existing_names + new_names + + # There are duplicate names if this test fails + if len(set(full_names)) != len(full_names): + unique_names = [*dict.fromkeys(new_names)] + + for name in unique_names: + existing_indices = [i for i, other_name in enumerate(existing_names) if other_name == name] + new_indices = [i for i, other_name in enumerate(new_names) if other_name == name] + if (len(existing_indices) + len(new_indices)) > 1: + existing_string = "" + new_string = "" + if existing_indices: + existing_list = ", ".join(str(i) for i in existing_indices[:-1]) + existing_string = ( + f" item{f's {existing_list} and ' if existing_list else ' '}" + f"{existing_indices[-1]} of the existing ClassList" + ) + if new_indices: + new_list = ", ".join(str(i) for i in new_indices[:-1]) + new_string = ( + f" item{f's {new_list} and ' if new_list else ' '}{new_indices[-1]} of the input list" + ) + error_list.append( + f" '{name}' is shared between{existing_string}" + f"{', and' if existing_string and new_string else ''}{new_string}" + ) + + if error_list: + newline = "\n" + raise ValueError( + f"The value of the '{self.name_field}' attribute must be unique for each item in the ClassList:\n" + f"{newline.join(error for error in error_list)}" + ) + + def _check_classes(self, input_list: Sequence[T]) -> None: + """Raise a ValueError if any object in a list of objects is not of the type specified by ``self._class_handle``. + + Parameters + ---------- + input_list : iterable + A list of instances of the class given in ``self._class_handle``. + + Raises + ------ + ValueError + If the input list contains objects of any type other than that given in ``self._class_handle``. + + """ + error_list = [] + for i, element in enumerate(input_list): + if not isinstance(element, self._class_handle): + error_list.append(f" index {i} is of type {type(element).__name__}") + if error_list: + newline = "\n" + raise ValueError( + f"This ClassList only supports elements of type {self._class_handle.__name__}. " + f"In the input list:\n{newline.join(error for error in error_list)}\n" + ) + + def _get_item_from_name_field(self, value: T | str) -> T | str: + """Return the object with the given value of the ``name_field`` attribute in the ClassList. + + Parameters + ---------- + value : T or str + Either an object in the ClassList, or the value of the ``name_field`` for an object in the ClassList. + + Returns + ------- + instance : T 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. + + """ + try: + lower_value = value.lower() + except AttributeError: + lower_value = value + + return next((model for model in self.data if getattr(model, self.name_field).lower() == lower_value), value) + + @staticmethod + def _determine_class_handle(input_list: Sequence[T]): + """Determine the class handle from a sequence of objects. + + The ``_class_handle`` of the sequence is the type of the first element in the sequence + which is a subclass of all elements in the sequence. If no such element exists, the handle + is set to be the type of the first element in the list. + + Parameters + ---------- + input_list : Sequence[T] + A list of instances to populate the ClassList. + + Returns + ------- + class_handle : type + The type object of the first element which is a subclass of all of the other + elements, or the first element if no such element exists. + + """ + for element in input_list: + if all(issubclass(type(instance), type(element)) for instance in input_list): + class_handle = type(element) + break + else: + class_handle = type(input_list[0]) + + return class_handle + + # Pydantic core schema which allows ClassLists to be validated + # in short: it validates that each ClassList is indeed a ClassList, + # and then validates ClassList.data as though it were a typed list + # e.g. ClassList[str] data is validated like list[str] + @classmethod + def __get_pydantic_core_schema__(cls, source: Any, handler): + # import here so that the ClassList can be instantiated and used without Pydantic installed + from typing import get_args, get_origin + + from pydantic import ValidatorFunctionWrapHandler + from pydantic.types import ( + core_schema, # import core_schema through here rather than making pydantic_core a dependency + ) + + # if annotated with a class, get the item type of that class + origin = get_origin(source) + item_tp = Any if origin is None else get_args(source)[0] + + list_schema = handler.generate_schema(list[item_tp]) + + def coerce(v: Any, handler: ValidatorFunctionWrapHandler) -> ClassList[T]: + """If a sequence is given, try to coerce it to a ClassList.""" + if isinstance(v, Sequence): + classlist = ClassList() + if len(v) > 0 and isinstance(v[0], dict): + # we want to be OK if the type is a model and is passed as a dict; + # pydantic will coerce it or fall over later + classlist._class_handle = dict + elif item_tp is not Any: + classlist._class_handle = item_tp + classlist.extend(v) + v = classlist + v = handler(v) + return v + + def validate_items(v: ClassList[T], handler: ValidatorFunctionWrapHandler) -> ClassList[T]: + v.data = handler(v.data) + return v + + schema = core_schema.chain_schema( + [ + core_schema.no_info_wrap_validator_function(coerce, core_schema.is_instance_schema(cls)), + core_schema.no_info_wrap_validator_function(validate_items, list_schema), + ], + serialization=core_schema.plain_serializer_function_ser_schema(lambda x: x), + ) + + return schema diff --git a/ratapi/controls.py b/ratapi/controls.py new file mode 100644 index 00000000..9dd815b5 --- /dev/null +++ b/ratapi/controls.py @@ -0,0 +1,258 @@ +"""The Controls class for providing RAT algorithm settings.""" + +import contextlib +import os +import tempfile +import warnings +from pathlib import Path + +import prettytable +from pydantic import ( + BaseModel, + Field, + ValidationError, + ValidatorFunctionWrapHandler, + model_serializer, + model_validator, +) + +from ratapi.utils.custom_errors import custom_pydantic_validation_error +from ratapi.utils.enums import BoundHandling, Display, Parallel, Procedures, Strategies + +common_fields = [ + "procedure", + "parallel", + "numSimulationPoints", + "resampleMinAngle", + "resampleNPoints", + "display", +] +update_fields = ["updateFreq", "updatePlotFreq"] +fields = { + "calculate": common_fields, + "simplex": [*common_fields, "xTolerance", "funcTolerance", "maxFuncEvals", "maxIterations", *update_fields], + "de": [ + *common_fields, + "populationSize", + "fWeight", + "crossoverProbability", + "strategy", + "targetValue", + "numGenerations", + *update_fields, + ], + "ns": [*common_fields, "nLive", "nMCMC", "propScale", "nsTolerance"], + "dream": [*common_fields, "nSamples", "nChains", "jumpProbability", "pUnitGamma", "boundHandling", "adaptPCR"], +} + + +class Controls(BaseModel, validate_assignment=True, extra="forbid", use_attribute_docstrings=True): + """The full set of controls parameters for all five procedures that are required for the compiled RAT code.""" + + # All Procedures + procedure: Procedures = Procedures.Calculate + """Which procedure RAT should execute. Can be 'calculate', 'simplex', 'de', 'ns', or 'dream'.""" + + parallel: Parallel = Parallel.Single + """How the calculation should be parallelised. Can be 'single', 'contrasts' or 'points'.""" + + numSimulationPoints: int = Field(500, ge=2) + """The number of points used for reflectivity simulations where no data is supplied.""" + + resampleMinAngle: float = Field(0.9, le=1, gt=0) + """The upper threshold on the angle between three sampled points for resampling, in units of radians over pi.""" + + resampleNPoints: int = Field(50, gt=0) + """The number of initial points to use for resampling.""" + + display: Display = Display.Iter + """How much RAT should print to the terminal. Can be 'off', 'iter', 'notify', or 'final'.""" + + # Simplex + xTolerance: float = Field(1.0e-6, gt=0.0) + """[SIMPLEX] The termination tolerance for step size.""" + + funcTolerance: float = Field(1.0e-6, gt=0.0) + """[SIMPLEX] The termination tolerance for change in chi-squared.""" + + maxFuncEvals: int = Field(10000, gt=0) + """[SIMPLEX] The maximum number of function evaluations before the algorithm terminates.""" + + maxIterations: int = Field(1000, gt=0) + """[SIMPLEX] The maximum number of iterations before the algorithm terminates.""" + + # Simplex and DE + updateFreq: int = 1 + """[SIMPLEX, DE] Number of iterations between printing progress updates to the terminal.""" + + updatePlotFreq: int = 20 + """[SIMPLEX, DE] Number of iterations between updates to live plots.""" + + # DE + populationSize: int = Field(20, ge=1) + """[DE] The number of candidate solutions that exist at any time.""" + + fWeight: float = Field(0.5, gt=0.0) + """[DE] The step size for how different mutations are to their parents.""" + + crossoverProbability: float = Field(0.8, gt=0.0, lt=1.0) + """[DE] The probability of exchange of parameters between individuals at any iteration.""" + + strategy: Strategies = Strategies.RandomWithPerVectorDither + """[DE] The algorithm used to generate new candidates.""" + + targetValue: float = Field(1.0, ge=1.0) + """[DE] The value of chi-squared at which the algorithm will terminate.""" + + numGenerations: int = Field(500, ge=1) + """[DE] The maximum number of iterations before the algorithm terminates.""" + + # NS + nLive: int = Field(150, ge=1) + """[NS] The number of points to sample.""" + + nMCMC: int = Field(0, ge=0) + """[NS] If non-zero, an MCMC process with ``nMCMC`` chains will be used instead of MultiNest.""" + + propScale: float = Field(0.1, gt=0.0, lt=1.0) + """[NS] A scaling factor for the ellipsoid generated by MultiNest.""" + + nsTolerance: float = Field(0.1, ge=0.0) + """[NS] The tolerance threshold for when the algorithm should terminate.""" + + # Dream + nSamples: int = Field(20000, ge=0) + """[DREAM] The total number of function evaluations (number of algorithm generations times number of chains).""" + + nChains: int = Field(10, gt=1) + """[DREAM] The number of Markov chains to use in the algorithm.""" + + jumpProbability: float = Field(0.5, gt=0.0, lt=1.0) + """[DREAM] The probability range for the size of jumps in sampling. Larger values mean more variable jumps.""" + + pUnitGamma: float = Field(0.2, gt=0.0, lt=1.0) + """[DREAM] The probability that the scaling-down factor of jumps will be ignored and a larger jump will be taken.""" + + boundHandling: BoundHandling = BoundHandling.Reflect + """[DREAM] How steps past the space boundaries should be handled. Can be 'off', 'reflect', 'bound', or 'fold'.""" + + adaptPCR: bool = True + """[DREAM] Whether the crossover probability for differential evolution should be adapted during the run.""" + + # Private field for IPC file + _IPCFilePath: str = "" + + @model_validator(mode="wrap") + def warn_setting_incorrect_properties(self, handler: ValidatorFunctionWrapHandler) -> "Controls": + """Raise a warning if the user sets fields that apply to other procedures.""" + model_input = self + try: + input_dict = model_input.__dict__ + except AttributeError: + input_dict = model_input + + validated_self = None + try: + validated_self = handler(self) + except ValidationError as exc: + procedure = input_dict.get("procedure", Procedures.Calculate) + custom_error_msgs = { + "extra_forbidden": f'Extra inputs are not permitted. The fields for the "{procedure}"' + f" controls procedure are:\n " + f"{', '.join(fields.get('procedure', []))}\n", + } + custom_error_list = custom_pydantic_validation_error(exc.errors(include_url=False), custom_error_msgs) + raise ValidationError.from_exception_data(exc.title, custom_error_list, hide_input=True) from None + + if isinstance(model_input, validated_self.__class__): + # This is for changing fields in a defined model + changed_fields = [key for key in input_dict if input_dict[key] != validated_self.__dict__[key]] + elif isinstance(model_input, dict): + # This is for a newly-defined model + changed_fields = input_dict.keys() + else: + raise ValueError('The input to the "Controls" model is invalid.') + + new_procedure = validated_self.procedure + allowed_fields = fields[new_procedure] + for field in changed_fields: + if field not in allowed_fields: + incorrect_procedures = [key for (key, value) in fields.items() if field in value] + warnings.warn( + f'\nThe current controls procedure is "{new_procedure}", but the property' + f' "{field}" applies instead to the {", ".join(incorrect_procedures)} procedure.\n\n' + f' The fields for the "{new_procedure}" controls procedure are:\n' + f" {', '.join(fields[new_procedure])}\n", + stacklevel=2, + ) + + return validated_self + + @model_serializer + def serialize(self): + """Filter fields so only those applying to the chosen procedure are serialized.""" + return {model_field: getattr(self, model_field) for model_field in fields[self.procedure]} + + def __repr__(self) -> str: + fields_repr = ", ".join(repr(v) if a is None else f"{a}={v!r}" for a, v in self.model_dump().items()) + return f"{self.__repr_name__()}({fields_repr})" + + def __str__(self) -> str: + table = prettytable.PrettyTable() + table.field_names = ["Property", "Value"] + table.add_rows([[k, v] for k, v in self.model_dump().items()]) + return table.get_string() + + def initialise_IPC(self): + """Set up the inter-process communication file.""" + IPC_obj, self._IPCFilePath = tempfile.mkstemp() + os.write(IPC_obj, b"\x00") + os.close(IPC_obj) + return None + + def sendStopEvent(self): + """Send the stop event via the inter-process communication file. + + Warnings + -------- + UserWarning + Raised if we try to delete an IPC file that was not initialised. + + """ + if os.path.isfile(self._IPCFilePath): + with open(self._IPCFilePath, "wb") as f: + f.write(b"\x01") + else: + warnings.warn("An IPC file was not initialised.", UserWarning, stacklevel=2) + return None + + def delete_IPC(self): + """Delete the inter-process communication file.""" + with contextlib.suppress(FileNotFoundError): + os.remove(self._IPCFilePath) + self._IPCFilePath = "" + return None + + def save(self, filepath: str | Path = "./controls.json"): + """Save a controls object to a JSON file. + + Parameters + ---------- + filepath : str or Path + The path to where the controls file will be written. + """ + filepath = Path(filepath).with_suffix(".json") + filepath.write_text(self.model_dump_json()) + + @classmethod + def load(cls, path: str | Path) -> "Controls": + """Load a controls object from file. + + Parameters + ---------- + path : str or Path + The path to the controls object file. + + """ + file = Path(path) + return cls.model_validate_json(file.read_text()) diff --git a/RATapi/events.py b/ratapi/events.py similarity index 67% rename from RATapi/events.py rename to ratapi/events.py index 1f62264f..2383159c 100644 --- a/RATapi/events.py +++ b/ratapi/events.py @@ -1,12 +1,13 @@ +"""Hooks for connecting to run callback events.""" + import os -from typing import Callable, List, Union +from collections.abc import Callable -from RATapi.rat_core import EventBridge, EventTypes, PlotEventData, ProgressEventData +from ratapi.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 - been triggered. +def notify(event_type: EventTypes, data: str | PlotEventData | ProgressEventData) -> None: + """Call registered callbacks with data when event type has been triggered. Parameters ---------- @@ -21,8 +22,8 @@ def notify(event_type: EventTypes, data: Union[str, PlotEventData, ProgressEvent callback(data) -def get_event_callback(event_type: EventTypes) -> List[Callable[[Union[str, PlotEventData, ProgressEventData]], None]]: - """Returns all callbacks registered for the given event type. +def get_event_callback(event_type: EventTypes) -> list[Callable[[str | PlotEventData | ProgressEventData], None]]: + """Return all callbacks registered for the given event type. Parameters ---------- @@ -38,8 +39,8 @@ def get_event_callback(event_type: EventTypes) -> List[Callable[[Union[str, Plot return list(__event_callbacks[event_type]) -def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventData, ProgressEventData]], None]) -> None: - """Registers a new callback for the event type. +def register(event_type: EventTypes, callback: Callable[[str | PlotEventData | ProgressEventData], None]) -> None: + """Register a new callback for the event type. Parameters ---------- @@ -58,12 +59,14 @@ def register(event_type: EventTypes, callback: Callable[[Union[str, PlotEventDat def clear(key=None, callback=None) -> None: - """Clears all event callbacks or specific callback. + """Clear all event callbacks or specific callback. Parameters ---------- - callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None] - The callback for when the event is triggered. + key : EventTypes, optional + The event type of the callback to clear if given. + callback : Callable[[Union[str, PlotEventData, ProgressEventData]], None], optional + A callback for an event which will be cleared if given. """ if key is None and callback is None: diff --git a/ratapi/examples/__init__.py b/ratapi/examples/__init__.py new file mode 100644 index 00000000..b85aebed --- /dev/null +++ b/ratapi/examples/__init__.py @@ -0,0 +1,25 @@ +"""Usage examples for the Python RAT API.""" + +from ratapi.examples.absorption.absorption import absorption +from ratapi.examples.convert_rascal_project.convert_rascal import convert_rascal +from ratapi.examples.domains.domains_custom_layers import domains_custom_layers +from ratapi.examples.domains.domains_custom_XY import domains_custom_XY +from ratapi.examples.domains.domains_standard_layers import domains_standard_layers +from ratapi.examples.normal_reflectivity.DSPC_custom_layers import DSPC_custom_layers +from ratapi.examples.normal_reflectivity.DSPC_custom_XY import DSPC_custom_XY +from ratapi.examples.normal_reflectivity.DSPC_data_background import DSPC_data_background +from ratapi.examples.normal_reflectivity.DSPC_function_background import DSPC_function_background +from ratapi.examples.normal_reflectivity.DSPC_standard_layers import DSPC_standard_layers + +__all__ = [ + "absorption", + "domains_custom_layers", + "domains_custom_XY", + "domains_standard_layers", + "DSPC_custom_layers", + "DSPC_custom_XY", + "DSPC_standard_layers", + "DSPC_data_background", + "DSPC_function_background", + "convert_rascal", +] diff --git a/ratapi/examples/absorption/__init__.py b/ratapi/examples/absorption/__init__.py new file mode 100644 index 00000000..bf48e7ae --- /dev/null +++ b/ratapi/examples/absorption/__init__.py @@ -0,0 +1 @@ +"""An example of using absorption in a RAT project.""" diff --git a/ratapi/examples/absorption/absorption.ipynb b/ratapi/examples/absorption/absorption.ipynb new file mode 100644 index 00000000..696103bc --- /dev/null +++ b/ratapi/examples/absorption/absorption.ipynb @@ -0,0 +1,305 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "\n", + "import numpy as np\n", + "from IPython.display import Code\n", + "\n", + "import ratapi as RAT\n", + "from ratapi.models import Parameter" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Absorption (imaginary SLD) - effect below the critical edge\n", + "\n", + "RAT allows the use of an imaginary, as well as real part of the SLD. The effect of this is usually seen below the critical edge, and must sometimes be accounted for.\n", + "\n", + "The example used here is Custom Layers. It analyses a bilayer sample on a permalloy / gold substrate, measured using polarised neutrons, against D2O and H2O, leading to 4 contrasts in total. Absorption (i.e. imaginary SLD) is defined for Gold and the Permalloy, to account for non-flat data below the critical edge.\n", + "\n", + "For absorption with standard layers, an additional column appears in the layers block to accommodate the imagainary component of the SLD. For custom functions, we add an extra column to the output.\n", + "\n", + "For all calculation types, to activate this functionality it is necessary to set the 'absorption' flag when creating the project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem = RAT.Project(name=\"Absorption example\", calculation=\"normal\", model=\"custom layers\", geometry=\"substrate/liquid\", absorption=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now define our parameters, noting that each SLD parameter has both a real and imaginary component:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "parameter_list = [\n", + " Parameter(name=\"Alloy Thickness\", min=100.0, value=135.6, max=200.0, fit=True),\n", + " Parameter(name=\"Alloy SLD up\", min=6.0e-6, value=9.87e-6, max=1.2e-5, fit=True),\n", + " Parameter(name=\"Alloy SLD imaginary up\", min=1.0e-9, value=4.87e-8, max=1.0e-7, fit=True),\n", + " Parameter(name=\"Alloy SLD down\", min=6.0e-6, value=7.05e-6, max=1.3e-5, fit=True),\n", + " Parameter(name=\"Alloy SLD imaginary down\", min=1.0e-9, value=4.87e-8, max=1.0e-7, fit=True),\n", + " Parameter(name=\"Alloy Roughness\", min=2.0, value=5.71, max=10.0, fit=True),\n", + " #\n", + " Parameter(name=\"Gold Thickness\", min=100.0, value=154.7, max=200.0, fit=True),\n", + " Parameter(name=\"Gold Roughness\", min=0.1, value=5.42, max=10.0, fit=True),\n", + " Parameter(name=\"Gold SLD\", min=4.0e-6, value=4.49e-6, max=5.0e-6, fit=True),\n", + " Parameter(name=\"Gold SLD imaginary\", min=1.0e-9, value=4.20e-8, max=1.0e-7, fit=True),\n", + " #\n", + " Parameter(name=\"Thiol APM\", min=40.0, value=56.27, max=100.0, fit=True),\n", + " Parameter(name=\"Thiol Head Hydration\", min=20.0, value=30.0, max=50.0, fit=True),\n", + " Parameter(name=\"Thiol Coverage\", min=0.5, value=0.9, max=1.0, fit=True),\n", + " #\n", + " Parameter(name=\"CW Thickness\", min=1.0, value=12.87, max=25.0, fit=True),\n", + " #\n", + " Parameter(name=\"Bilayer APM\", min=48.0, value=65.86, max=90.0, fit=True),\n", + " Parameter(name=\"Bilayer Head Hydration\", min=20.0, value=30.0, max=50.0, fit=True),\n", + " Parameter(name=\"Bilayer Roughness\", min=1.0, value=3.87, max=10.0, fit=True),\n", + " Parameter(name=\"Bilayer Coverage\", min=0.5, value=0.94, max=1.0, fit=True)\n", + "]\n", + "\n", + "problem.parameters.extend(parameter_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the bulk in and bulk out parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem.bulk_in.set_fields(0, name=\"Silicon\", min=2.0e-6, value=2.073e-6, max=2.1e-6)\n", + "\n", + "problem.bulk_out.set_fields(0, name=\"D2O\", min=5.8e-06, value=6.21e-06, max=6.35e-06, fit=True)\n", + "problem.bulk_out.append(name=\"H2O\", min=-5.6e-07, value=-3.15e-07, max=0.0, fit=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use a different scalefactor for each dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "del problem.scalefactors[0]\n", + "problem.scalefactors.append(name=\"Scalefactor 1\", min=0.5, value=1, max=1.5, fit=True)\n", + "problem.scalefactors.append(name=\"Scalefactor 2\", min=0.5, value=1, max=1.5, fit=True)\n", + "problem.scalefactors.append(name=\"Scalefactor 3\", min=0.5, value=1, max=1.5, fit=True)\n", + "problem.scalefactors.append(name=\"Scalefactor 4\", min=0.5, value=1, max=1.5, fit=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Set the backgrounds and resolutions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "del problem.backgrounds[0]\n", + "del problem.background_parameters[0]\n", + "\n", + "problem.background_parameters.append(name=\"Background parameter 1\", min=5.0e-08, value=7.88e-06, max=9.0e-05, fit=True)\n", + "problem.background_parameters.append(name=\"Background parameter 2\", min=1.0e-08, value=5.46e-06, max=9.0e-05, fit=True)\n", + "problem.background_parameters.append(name=\"Background parameter 3\", min=1.0e-06, value=9.01e-06, max=9.0e-05, fit=True)\n", + "problem.background_parameters.append(name=\"Background parameter 4\", min=1.0e-06, value=5.61e-06, max=9.0e-05, fit=True)\n", + "\n", + "problem.backgrounds.append(name=\"Background 1\", type=\"constant\", source=\"Background parameter 1\")\n", + "problem.backgrounds.append(name=\"Background 2\", type=\"constant\", source=\"Background parameter 2\")\n", + "problem.backgrounds.append(name=\"Background 3\", type=\"constant\", source=\"Background parameter 3\")\n", + "problem.backgrounds.append(name=\"Background 4\", type=\"constant\", source=\"Background parameter 4\")\n", + "\n", + "# Make the resolution fittable\n", + "problem.resolution_parameters.set_fields(0, fit=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add the datasets:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data_path = pathlib.Path(\"../data\")\n", + "\n", + "data_1 = np.loadtxt(data_path / \"D2O_spin_down.dat\")\n", + "problem.data.append(name=\"D2O_dn\", data=data_1)\n", + "\n", + "data_2 = np.loadtxt(data_path / \"D2O_spin_up.dat\")\n", + "problem.data.append(name=\"D2O_up\", data=data_2)\n", + "\n", + "data_3 = np.loadtxt(data_path / \"H2O_spin_down.dat\")\n", + "problem.data.append(name=\"H2O_dn\", data=data_3)\n", + "\n", + "data_4 = np.loadtxt(data_path / \"H2O_spin_up.dat\")\n", + "problem.data.append(name=\"H2O_up\", data=data_4)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Add the custom file. We can see that we add an extra column for the output in our custom function." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem.custom_files.append(\n", + " name=\"DPPC absorption\",\n", + " filename=\"volume_thiol_bilayer.py\",\n", + " language=\"python\",\n", + " path=pathlib.Path.cwd().resolve(),\n", + ")\n", + "Code(filename='volume_thiol_bilayer.py', language='python')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, add the contrasts:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem.contrasts.append(\n", + " name=\"D2O Down\",\n", + " data=\"D2O_dn\",\n", + " background=\"Background 1\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"D2O\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " resolution=\"Resolution 1\",\n", + " resample=True,\n", + " model=[\"DPPC absorption\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"D2O Up\",\n", + " data=\"D2O_up\",\n", + " background=\"Background 2\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"D2O\",\n", + " scalefactor=\"Scalefactor 2\",\n", + " resolution=\"Resolution 1\",\n", + " resample=True,\n", + " model=[\"DPPC absorption\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"H2O Down\",\n", + " data=\"H2O_dn\",\n", + " background=\"Background 3\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"H2O\",\n", + " scalefactor=\"Scalefactor 3\",\n", + " resolution=\"Resolution 1\",\n", + " resample=True,\n", + " model=[\"DPPC absorption\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"H2O Up\",\n", + " data=\"H2O_up\",\n", + " background=\"Background 4\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"H2O\",\n", + " scalefactor=\"Scalefactor 4\",\n", + " resolution=\"Resolution 1\",\n", + " resample=True,\n", + " model=[\"DPPC absorption\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now run RAT and plot the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "controls = RAT.Controls(parallel=\"contrasts\", resampleMinAngle=0.9, resampleNPoints=150.0)\n", + "problem, results = RAT.run(problem, controls)\n", + "\n", + "RAT.plotting.plot_ref_sld(problem, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/RATapi/examples/absorption/absorption.py b/ratapi/examples/absorption/absorption.py similarity index 82% rename from RATapi/examples/absorption/absorption.py rename to ratapi/examples/absorption/absorption.py index 1593f78a..5d100aff 100644 --- a/RATapi/examples/absorption/absorption.py +++ b/ratapi/examples/absorption/absorption.py @@ -1,16 +1,27 @@ -import os +"""An example for using absorption in RAT.""" + import pathlib import numpy as np -import RATapi as RAT +import ratapi as RAT def absorption(): - """Custom layers model including absorption""" + """Run a custom layers model including absorption. + + RAT allows the use of an imaginary, as well as real part of the SLD. + The effect of this is usually seen below the critical edge, and must sometimes be accounted for. + + This is an example of a Custom Layers project using absorption. used here is Custom Layers. + It analyses a bilayer sample on a permalloy / gold substrate, + measured using polarised neutrons, against D2O and H2O, leading to 4 contrasts in total. + Absorption (i.e. imaginary SLD) is defined for Gold and the Permalloy, + to account for non-flat data below the critical edge. + """ problem = RAT.Project( name="Absorption example", - calculation="non polarised", + calculation="normal", model="custom layers", geometry="substrate/liquid", absorption=True, @@ -69,27 +80,27 @@ def absorption(): name="Background parameter 4", min=1.0e-06, value=5.61e-06, max=9.0e-05, fit=True ) - problem.backgrounds.append(name="Background 1", type="constant", value_1="Background parameter 1") - problem.backgrounds.append(name="Background 2", type="constant", value_1="Background parameter 2") - problem.backgrounds.append(name="Background 3", type="constant", value_1="Background parameter 3") - problem.backgrounds.append(name="Background 4", type="constant", value_1="Background parameter 4") + problem.backgrounds.append(name="Background 1", type="constant", source="Background parameter 1") + problem.backgrounds.append(name="Background 2", type="constant", source="Background parameter 2") + problem.backgrounds.append(name="Background 3", type="constant", source="Background parameter 3") + problem.backgrounds.append(name="Background 4", type="constant", source="Background parameter 4") # Make the resolution fittable problem.resolution_parameters.set_fields(0, fit=True) # Now add the data we need - data_path = os.path.join(pathlib.Path(__file__).parents[1].resolve(), "data") + data_path = pathlib.Path(__file__).parents[1] / "data" - data_1 = np.loadtxt(os.path.join(data_path, "D2O_spin_down.dat")) + data_1 = np.loadtxt(data_path / "D2O_spin_down.dat") problem.data.append(name="D2O_dn", data=data_1) - data_2 = np.loadtxt(os.path.join(data_path, "D2O_spin_up.dat")) + data_2 = np.loadtxt(data_path / "D2O_spin_up.dat") problem.data.append(name="D2O_up", data=data_2) - data_3 = np.loadtxt(os.path.join(data_path, "H2O_spin_down.dat")) + data_3 = np.loadtxt(data_path / "H2O_spin_down.dat") problem.data.append(name="H2O_dn", data=data_3) - data_4 = np.loadtxt(os.path.join(data_path, "H2O_spin_up.dat")) + data_4 = np.loadtxt(data_path / "H2O_spin_up.dat") problem.data.append(name="H2O_up", data=data_4) # Add the custom file @@ -97,7 +108,7 @@ def absorption(): name="DPPC absorption", filename="volume_thiol_bilayer.py", language="python", - path=pathlib.Path(__file__).parent.resolve(), + path=pathlib.Path(__file__).parent, ) # Finally add the contrasts @@ -150,7 +161,7 @@ def absorption(): ) # Now make a controls block and run the code - controls = RAT.Controls(parallel="contrasts", resampleParams=[0.9, 150.0]) + controls = RAT.Controls(parallel="contrasts", resampleNPoints=150) problem, results = RAT.run(problem, controls) return problem, results diff --git a/RATapi/examples/absorption/volume_thiol_bilayer.py b/ratapi/examples/absorption/volume_thiol_bilayer.py similarity index 89% rename from RATapi/examples/absorption/volume_thiol_bilayer.py rename to ratapi/examples/absorption/volume_thiol_bilayer.py index f5ac1bbc..2b9f7fd4 100644 --- a/RATapi/examples/absorption/volume_thiol_bilayer.py +++ b/ratapi/examples/absorption/volume_thiol_bilayer.py @@ -1,3 +1,6 @@ +"""Custom layer model file for the absorption example.""" + + def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): """VolumeThiolBilayer RAT Custom Layer Model File. @@ -20,6 +23,9 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): The second output parameter should be the substrate roughness. """ + # Note - The first contrast number is 1 (not 0) so be careful if you use + # this variable for array indexing. + subRough = params[0] alloyThick = params[1] alloySLDUp = params[2] @@ -89,11 +95,11 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): # Correct head SLD based on hydration thiolHeadHydr = thiolHeadHydr / 100 - sldHead = sldHead * (1 - thiolHeadHydr) + (thiolHeadHydr * bulk_out[contrast]) + sldHead = sldHead * (1 - thiolHeadHydr) + (thiolHeadHydr * bulk_out[contrast - 1]) # 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 - 1]) + sldHead = (thiolCoverage * sldHead) + ((1 - thiolCoverage) * bulk_out[contrast - 1]) SAMTAILS = [thickTail, sldTail, 0, goldRough] SAMHEAD = [thickHead, sldHead, 0, goldRough] @@ -110,7 +116,7 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): 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 - 1]) sldTail = sumbTail / vTail thickTail = vTail / bilayerAPM @@ -118,9 +124,9 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): 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 - 1]) + sldHead = (bilayerCoverage * sldHead) + ((1 - bilayerCoverage) * bulk_out[contrast - 1]) + sldMe = (bilayerCoverage * sldMe) + ((1 - bilayerCoverage) * bulk_out[contrast - 1]) BILTAILS = [thickTail, sldTail, 0, bilayerRough] BILHEAD = [thickHead, sldHead, 0, bilayerRough] @@ -128,11 +134,11 @@ def volume_thiol_bilayer(params, bulk_in, bulk_out, contrast): BILAYER = [BILHEAD, BILTAILS, BILME, BILME, BILTAILS, BILHEAD] - CW = [cwThick, bulk_out[contrast], 0, bilayerRough] + CW = [cwThick, bulk_out[contrast - 1], 0, bilayerRough] - if contrast == 1 or contrast == 3: + if contrast == 2 or contrast == 4: output = [alloyUp, gold, SAMTAILS, SAMHEAD, CW, *BILAYER] - else: + elif contrast == 1 or contrast == 3: output = [alloyDown, gold, SAMTAILS, SAMHEAD, CW, *BILAYER] return output, subRough diff --git a/ratapi/examples/bayes_benchmark/bayes_benchmark.ipynb b/ratapi/examples/bayes_benchmark/bayes_benchmark.ipynb new file mode 100644 index 00000000..bb9bba9f --- /dev/null +++ b/ratapi/examples/bayes_benchmark/bayes_benchmark.ipynb @@ -0,0 +1,365 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bayesian parameter estimation for low-dimensional examples\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Bayesian procedures available in RAT ([Nested Sampler (NS)](https://en.wikipedia.org/wiki/Nested_sampling_algorithm) and [DREAM](https://doi.org/10.1016/j.envsoft.2015.08.013)) estimate the parameters of our reflectivity model - that is, they find the maximum value of \n", + "$$P((X_1, X_2, ...) = (x_1, x_2, ...) | I)$$\n", + "where $P$ is a probability measure, $X_1, X_2, ...$ are our parameters, $x_1, x_2, ...$ are proposed values of these parameters, and $I$ is our background information on the model (e.g. our data), over a range of values of $x_1, x_2, ...$ between given minimum and maximum values. It can be shown that under some weak assumptions about our data, this probability is proportional to $\\exp(-\\chi^2/2)$, where $\\chi^2$ is the chi-squared measure of fit given by the least-squares solution. [1]\n", + "\n", + "If we want to calculate $\\chi^2$ directly for a sample of $N$ values between some given minimum and maximum values for each parameter, we would have to perform $N^P$ calculations, where $P$ is the number of parameters. Of course, for large numbers of parameters, this is infeasible, hence why algorithms such as NS and DREAM have been developed to do so more efficiently. However, for a small number of parameters, it is feasible for us to perform this direct calculation and compare it to the results of NS and DREAM. Here we will do so for an example of 2 and 3 parameters.\n", + "\n", + "*[1] D. S. Sivia, J. R. P. Webster,\n", + " \"The Bayesian approach to reflectivity data\",\n", + " Physica B: Condensed Matter,\n", + " Volume 248, June 1998, pages 327-337 \n", + " DOI: 10.1016/S0921-4526(98)00259-2 \n", + " URL: https://bayes.wustl.edu/sivia/98_20feb03.pdf*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Two-parameter example\n", + "We will start with a two-dimensional example on a simple project. This project represents a bare D2O substrate, and we will estimate the true values of the substrate roughness and background signal for this project." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "import ratapi as RAT\n", + "from ratapi.models import Parameter, Background, Resolution, Data, Contrast" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "project = RAT.Project(\n", + " name=\"Bare D2O Substrate\",\n", + " calculation=\"normal\",\n", + " model=\"standard layers\",\n", + " geometry=\"air/substrate\",\n", + " absorption=\"False\",\n", + " parameters=[Parameter(name=\"Substrate Roughness\", min=3.0, value=4.844363132849221, max=8.0, fit=True)],\n", + " background_parameters=[\n", + " Parameter(name=\"Background parameter 1\", min=5e-08, value=3.069003361230152e-06, max=7e-06, fit=True)\n", + " ],\n", + " scalefactors=[Parameter(name=\"Scalefactor 1\", min=0.07, value=0.10141560336360426, max=0.13, fit=False)],\n", + " bulk_in=[Parameter(name=\"Air\", min=0.0, value=0.0, max=0.0, fit=False)],\n", + " bulk_out=[Parameter(name=\"D2O\", min=6.3e-06, value=6.35e-06, max=6.4e-06, fit=False)],\n", + " resolution_parameters=[Parameter(name=\"Resolution parameter 1\", min=0.01, value=0.03, max=0.05, fit=False)],\n", + " backgrounds=[Background(name=\"Background 1\", type=\"constant\", source=\"Background parameter 1\")],\n", + " resolutions=[Resolution(name=\"Resolution 1\", type=\"constant\", source=\"Resolution parameter 1\")],\n", + " data=[\n", + " Data(name=\"Simulation\", data=np.empty([0, 3]), simulation_range=[0.005, 0.7]),\n", + " Data(\n", + " name=\"f82395c\",\n", + " data=np.array(\n", + " [\n", + " [4.8866e-02, 1.2343e-04, 1.3213e-06],\n", + " [5.1309e-02, 1.0063e-04, 1.0803e-06],\n", + " [5.3874e-02, 8.2165e-05, 8.8779e-07],\n", + " [5.6568e-02, 6.4993e-05, 7.2018e-07],\n", + " [5.9396e-02, 5.3958e-05, 6.0015e-07],\n", + " [6.2366e-02, 4.3590e-05, 5.0129e-07],\n", + " [6.5485e-02, 3.5780e-05, 4.1957e-07],\n", + " [6.8759e-02, 2.9130e-05, 3.5171e-07],\n", + " [7.2197e-02, 2.3481e-05, 3.0586e-07],\n", + " [7.5807e-02, 1.8906e-05, 2.6344e-07],\n", + " [7.9597e-02, 1.4642e-05, 2.2314e-07],\n", + " [8.3577e-02, 1.1589e-05, 1.8938e-07],\n", + " [8.7756e-02, 9.5418e-06, 1.6220e-07],\n", + " [9.2143e-02, 7.5694e-06, 1.3809e-07],\n", + " [9.6751e-02, 6.3831e-06, 1.2097e-07],\n", + " [1.0159e-01, 5.0708e-06, 1.0333e-07],\n", + " [1.0667e-01, 4.1041e-06, 8.9548e-08],\n", + " [1.1200e-01, 3.4253e-06, 7.9830e-08],\n", + " [1.1760e-01, 2.8116e-06, 7.1554e-08],\n", + " [1.2348e-01, 2.3767e-06, 6.3738e-08],\n", + " [1.2966e-01, 1.9241e-06, 5.6586e-08],\n", + " [1.3614e-01, 1.5642e-06, 5.2778e-08],\n", + " [1.4294e-01, 1.2922e-06, 4.9730e-08],\n", + " [1.5009e-01, 1.1694e-06, 5.1175e-08],\n", + " [1.5760e-01, 9.7837e-07, 5.0755e-08],\n", + " [1.6548e-01, 8.9138e-07, 5.3542e-08],\n", + " [1.7375e-01, 7.9420e-07, 5.4857e-08],\n", + " [1.8244e-01, 7.9131e-07, 5.8067e-08],\n", + " [1.9156e-01, 6.5358e-07, 5.7717e-08],\n", + " [2.0114e-01, 6.2970e-07, 5.7951e-08],\n", + " [2.1119e-01, 5.0130e-07, 5.5262e-08],\n", + " [2.2175e-01, 5.0218e-07, 5.6461e-08],\n", + " [2.3284e-01, 3.9299e-07, 5.0685e-08],\n", + " [2.4448e-01, 3.5324e-07, 5.0194e-08],\n", + " [2.5671e-01, 4.4475e-07, 5.6485e-08],\n", + " [2.6954e-01, 5.1338e-07, 6.2247e-08],\n", + " [2.8302e-01, 3.4918e-07, 4.9745e-08],\n", + " [2.9717e-01, 4.3037e-07, 5.5488e-08],\n", + " [3.1203e-01, 4.0099e-07, 5.3591e-08],\n", + " [3.2763e-01, 3.8397e-07, 5.1303e-08],\n", + " [3.4401e-01, 3.0995e-07, 4.5965e-08],\n", + " [3.6121e-01, 3.9357e-07, 5.0135e-08],\n", + " [3.7927e-01, 3.0997e-07, 4.3680e-08],\n", + " [3.9824e-01, 2.9656e-07, 4.2432e-08],\n", + " [4.1815e-01, 2.1909e-07, 3.6117e-08],\n", + " [4.3906e-01, 2.3153e-07, 3.6307e-08],\n", + " [4.6101e-01, 3.3428e-07, 4.3874e-08],\n", + " [4.8406e-01, 2.3441e-07, 3.7488e-08],\n", + " [5.0826e-01, 1.5496e-07, 3.0585e-08],\n", + " [5.3368e-01, 2.4708e-07, 3.9376e-08],\n", + " [5.6036e-01, 2.2157e-07, 3.8258e-08],\n", + " [5.8838e-01, 2.2798e-07, 4.6976e-08],\n", + " [6.1169e-01, 6.0272e-07, 2.3239e-07],\n", + " ]\n", + " ),\n", + " data_range=[0.048866, 0.61169],\n", + " simulation_range=[0.048866, 0.61169],\n", + " ),\n", + " ],\n", + " contrasts=[\n", + " Contrast(\n", + " name=\"Chain-d, acmw\",\n", + " data=\"f82395c\",\n", + " background=\"Background 1\",\n", + " background_action=\"add\",\n", + " bulk_in=\"Air\",\n", + " bulk_out=\"D2O\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " resolution=\"Resolution 1\",\n", + " resample=False,\n", + " model=[],\n", + " )\n", + " ],\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Firstly, we will run calculations using nested sampling and DREAM." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ns_controls = RAT.Controls(procedure=\"ns\", nsTolerance=1, nLive=500, display=\"final\")\n", + "_, ns_results = RAT.run(project, ns_controls)\n", + "\n", + "dream_controls = RAT.Controls(procedure=\"dream\", display=\"final\")\n", + "_, dream_results = RAT.run(project, dream_controls)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we will perform our direct calculation. The standard `'calculate'` procedure in RAT runs an Abelès calculation for the reflectivity of our model, and calculates the $\\chi^2$ statistic for how well this reflectivity fits the given data. We will take a sample of 30 values between the minimum and maximum value of our roughness and background parameters, and calculate $\\exp(-\\chi^2 / 2)$ on this roughness-background grid. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rough_param = project.parameters[0]\n", + "roughness = np.linspace(rough_param.min, rough_param.max, 30)\n", + "\n", + "back_param = project.background_parameters[0]\n", + "background = np.linspace(back_param.min, back_param.max, 30)\n", + "\n", + "controls = RAT.Controls(procedure=\"calculate\", display=\"off\")\n", + "\n", + "# function to calculate exp(-chi_squared / 2) for a given pair of roughness/background values\n", + "def calculate_posterior(roughness_index: int, background_index: int) -> float:\n", + " \"\"\"Calculate the posterior for an item in the roughness and background vectors.\n", + "\n", + " Parameters\n", + " ----------\n", + " roughness_index : int\n", + " The index of the roughness vector to use as the roughness parameter value.\n", + " background_index : int\n", + " The index of the background vector to use as the background parameter value.\n", + "\n", + " Returns\n", + " -------\n", + " float\n", + " The value of exp(-chi^2 / 2) for the given roughness and background values.\n", + " \"\"\"\n", + " project.parameters[0].value = roughness[roughness_index]\n", + " project.background_parameters[0].value = background[background_index]\n", + "\n", + " _, results = RAT.run(project, controls)\n", + " chi_squared = results.calculationResults.sumChi\n", + "\n", + " return np.exp(-chi_squared / 2)\n", + "\n", + "# we vectorise the calculation to make it faster by running it over a matrix of indices (x, y)\n", + "vectorized_calc_posterior = np.vectorize(calculate_posterior)\n", + "probability_array = vectorized_calc_posterior(*np.indices((30, 30), dtype=int))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can get the parameter values that best fit our model for each method:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# get the vector indices that produced the lowest chi-squared\n", + "best_indices = np.unravel_index(np.argmax(probability_array, axis=None), probability_array.shape)\n", + "print(\"Best values according to direct calculation:\\n\",\n", + " \"Roughness: \", roughness[best_indices[0]], \"\\n\",\n", + " \"Background: \", background[best_indices[1]])\n", + "\n", + "print(\"Best values according to Nested Sampler:\\n\",\n", + " \"Roughness: \", ns_results.fitParams[0], \"\\n\",\n", + " \"Background: \", ns_results.fitParams[1])\n", + "\n", + "print(\"Best values according to DREAM:\\n\",\n", + " \"Roughness: \", dream_results.fitParams[0], \"\\n\",\n", + " \"Background: \", dream_results.fitParams[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And finally, we will plot the posteriors created via each method to compare, as well as contour plots\n", + "for each method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from matplotlib import colormaps\n", + "import ratapi.utils.plotting as RATplot\n", + "\n", + "fig, axes = plt.subplots(3, 2, figsize=(6, 9))\n", + "\n", + "# plot NS and DREAM for each parameter\n", + "for i in [0, 1]:\n", + " RATplot.plot_one_hist(ns_results, i, axes=axes[0][i])\n", + " RATplot.plot_one_hist(dream_results, i, axes=axes[1][i])\n", + " # we want all 3 plots to have the same x-range\n", + " # so we will use the nested sampler x-range as our base\n", + " axes[1][i].set_xlim(*axes[0][i].get_xlim())\n", + " axes[1][i].set_title(\"\")\n", + "\n", + "# marginalise the probability array to get distributions for each parameter\n", + "roughness_distribution = np.sum(probability_array, axis=1)\n", + "background_distribution = np.sum(probability_array, axis=0)\n", + "\n", + "axes[2][0].hist(\n", + " roughness,\n", + " bins=25,\n", + " range=axes[0][0].get_xlim(),\n", + " weights=roughness_distribution,\n", + " density=True,\n", + " edgecolor=\"black\",\n", + " linewidth=1.2,\n", + " color=\"white\",\n", + " )\n", + "\n", + "axes[2][1].hist(\n", + " background,\n", + " bins=25,\n", + " range=axes[0][1].get_xlim(),\n", + " weights=background_distribution,\n", + " density=True,\n", + " edgecolor=\"black\",\n", + " linewidth=1.2,\n", + " color=\"white\",\n", + " )\n", + "\n", + "axes[0][0].set_ylabel(\"nested sampler\")\n", + "axes[1][0].set_ylabel(\"DREAM\")\n", + "axes[2][0].set_ylabel(\"direct calculation\")\n", + "fig.tight_layout()\n", + "\n", + "fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "contour_fig, axes = plt.subplots(1, 3, figsize=(9, 3))\n", + "\n", + "# plot NS and DREAM for each parameter\n", + "RATplot.plot_contour(ns_results, 0, 1, axes=axes[0])\n", + "RATplot.plot_contour(dream_results, 0, 1, axes=axes[1])\n", + "\n", + "axes[2].pcolormesh(roughness, background, probability_array.max() - probability_array.T, cmap=colormaps[\"Greys\"].reversed())\n", + "axes[2].contour(roughness, background, probability_array.max() - probability_array.T, colors=\"black\")\n", + "\n", + "axes[1].set_xlim(*axes[0].get_xlim())\n", + "axes[1].set_ylim(*axes[0].get_ylim())\n", + "axes[2].set_xlim(*axes[0].get_xlim())\n", + "axes[2].set_ylim(*axes[0].get_ylim())\n", + "\n", + "axes[0].set_title(\"NS\")\n", + "axes[1].set_title(\"DREAM\")\n", + "axes[2].set_title(\"direct\")\n", + "axes[1].set_ylabel(\"\")\n", + "axes[2].set_ylabel(\"\")\n", + "axes[2].set_xlabel(\"Substrate Roughness\")\n", + "fig.tight_layout()\n", + "fig.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/ratapi/examples/bayes_benchmark/bayes_benchmark.py b/ratapi/examples/bayes_benchmark/bayes_benchmark.py new file mode 100644 index 00000000..ee6ea96e --- /dev/null +++ b/ratapi/examples/bayes_benchmark/bayes_benchmark.py @@ -0,0 +1,366 @@ +"""An example script to compare different methods of Bayesian fitting. + +This example compares three Bayesian posteriors for a low-dimensional +example: a posterior generated by DREAM, one generated by NS, and +one calculated directly. + +The likelihood of the parameters being equal to a certain value is proportional +to exp(-chi^2 / 2) [1], so for a low-dimensional example we can calculate this directly +for a sample of parameter values. + +Citation: +[1] D. S. Sivia, J. R. P. Webster, + "The Bayesian approach to reflectivity data", + Physica B: Condensed Matter, + Volume 248, June 1998, pages 327-337 + DOI: 10.1016/S0921-4526(98)00259-2 + URL: https://bayes.wustl.edu/sivia/98_20feb03.pdf + +""" + +from dataclasses import dataclass +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np + +import ratapi as RAT +import ratapi.utils.plotting as RATplot +from ratapi.models import Background, Contrast, Data, Parameter, Resolution + +PWD = Path(__file__).parents[0] + + +# function to get our starting project +# this is the RasCAL-1 default project +# it is a bare D2O substrate +def get_project() -> RAT.Project: + """Create the project used as our example.""" + return RAT.Project( + name="Bare D2O Substrate", + calculation="normal", + model="standard layers", + geometry="air/substrate", + absorption="False", + parameters=[Parameter(name="Substrate Roughness", min=3.0, value=4.844363132849221, max=8.0, fit=True)], + background_parameters=[ + Parameter(name="Background parameter 1", min=5e-08, value=3.069003361230152e-06, max=7e-06, fit=True) + ], + scalefactors=[Parameter(name="Scalefactor 1", min=0.07, value=0.10141560336360426, max=0.13, fit=False)], + bulk_in=[Parameter(name="Air", min=0.0, value=0.0, max=0.0, fit=False)], + bulk_out=[Parameter(name="D2O", min=6.3e-06, value=6.35e-06, max=6.4e-06, fit=False)], + resolution_parameters=[Parameter(name="Resolution parameter 1", min=0.01, value=0.03, max=0.05, fit=False)], + backgrounds=[Background(name="Background 1", type="constant", source="Background parameter 1")], + resolutions=[Resolution(name="Resolution 1", type="constant", source="Resolution parameter 1")], + data=[ + Data(name="Simulation", data=np.empty([0, 3]), simulation_range=[0.005, 0.7]), + Data( + name="f82395c", + data=np.array( + [ + [4.8866e-02, 1.2343e-04, 1.3213e-06], + [5.1309e-02, 1.0063e-04, 1.0803e-06], + [5.3874e-02, 8.2165e-05, 8.8779e-07], + [5.6568e-02, 6.4993e-05, 7.2018e-07], + [5.9396e-02, 5.3958e-05, 6.0015e-07], + [6.2366e-02, 4.3590e-05, 5.0129e-07], + [6.5485e-02, 3.5780e-05, 4.1957e-07], + [6.8759e-02, 2.9130e-05, 3.5171e-07], + [7.2197e-02, 2.3481e-05, 3.0586e-07], + [7.5807e-02, 1.8906e-05, 2.6344e-07], + [7.9597e-02, 1.4642e-05, 2.2314e-07], + [8.3577e-02, 1.1589e-05, 1.8938e-07], + [8.7756e-02, 9.5418e-06, 1.6220e-07], + [9.2143e-02, 7.5694e-06, 1.3809e-07], + [9.6751e-02, 6.3831e-06, 1.2097e-07], + [1.0159e-01, 5.0708e-06, 1.0333e-07], + [1.0667e-01, 4.1041e-06, 8.9548e-08], + [1.1200e-01, 3.4253e-06, 7.9830e-08], + [1.1760e-01, 2.8116e-06, 7.1554e-08], + [1.2348e-01, 2.3767e-06, 6.3738e-08], + [1.2966e-01, 1.9241e-06, 5.6586e-08], + [1.3614e-01, 1.5642e-06, 5.2778e-08], + [1.4294e-01, 1.2922e-06, 4.9730e-08], + [1.5009e-01, 1.1694e-06, 5.1175e-08], + [1.5760e-01, 9.7837e-07, 5.0755e-08], + [1.6548e-01, 8.9138e-07, 5.3542e-08], + [1.7375e-01, 7.9420e-07, 5.4857e-08], + [1.8244e-01, 7.9131e-07, 5.8067e-08], + [1.9156e-01, 6.5358e-07, 5.7717e-08], + [2.0114e-01, 6.2970e-07, 5.7951e-08], + [2.1119e-01, 5.0130e-07, 5.5262e-08], + [2.2175e-01, 5.0218e-07, 5.6461e-08], + [2.3284e-01, 3.9299e-07, 5.0685e-08], + [2.4448e-01, 3.5324e-07, 5.0194e-08], + [2.5671e-01, 4.4475e-07, 5.6485e-08], + [2.6954e-01, 5.1338e-07, 6.2247e-08], + [2.8302e-01, 3.4918e-07, 4.9745e-08], + [2.9717e-01, 4.3037e-07, 5.5488e-08], + [3.1203e-01, 4.0099e-07, 5.3591e-08], + [3.2763e-01, 3.8397e-07, 5.1303e-08], + [3.4401e-01, 3.0995e-07, 4.5965e-08], + [3.6121e-01, 3.9357e-07, 5.0135e-08], + [3.7927e-01, 3.0997e-07, 4.3680e-08], + [3.9824e-01, 2.9656e-07, 4.2432e-08], + [4.1815e-01, 2.1909e-07, 3.6117e-08], + [4.3906e-01, 2.3153e-07, 3.6307e-08], + [4.6101e-01, 3.3428e-07, 4.3874e-08], + [4.8406e-01, 2.3441e-07, 3.7488e-08], + [5.0826e-01, 1.5496e-07, 3.0585e-08], + [5.3368e-01, 2.4708e-07, 3.9376e-08], + [5.6036e-01, 2.2157e-07, 3.8258e-08], + [5.8838e-01, 2.2798e-07, 4.6976e-08], + [6.1169e-01, 6.0272e-07, 2.3239e-07], + ] + ), + data_range=[0.048866, 0.61169], + simulation_range=[0.048866, 0.61169], + ), + ], + contrasts=[ + Contrast( + name="Chain-d, acmw", + data="f82395c", + background="Background 1", + background_action="add", + bulk_in="Air", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=[], + ) + ], + ) + + +@dataclass +class CalculationResults: + """Data class for results from a direct calculation.""" + + x_data: list[np.array] + distribution: np.array + + +def bayes_benchmark_2d(grid_size: int) -> (RAT.outputs.BayesResults, CalculationResults): + """Bayes benchmark for a 2-dimensional example. + + Parameters + ---------- + grid_size : int + The number of points to sample for each fit parameter. + + Here we estimate the substrate roughness and background using two different methods: + nested sampling (the 'ns' procedure in RAT) and through a direct calculation of chi-squared + over a range of parameter values. + + Returns + ------- + RAT.BayesResults + The BayesResults object from a nested sampler calculation. + CalculationResults + Results from the direct calculation. + + """ + problem = get_project() + + ns_controls = RAT.Controls(procedure="ns", nsTolerance=1, nLive=500, display="final") + _, ns_results = RAT.run(problem, ns_controls) + + dream_controls = RAT.Controls(procedure="dream", display="final") + _, dream_results = RAT.run(problem, dream_controls) + + # now we get the parameters and use them to do a direct calculation + rough_param = problem.parameters[0] + roughness = np.linspace(rough_param.min, rough_param.max, grid_size) + + back_param = problem.background_parameters[0] + background = np.linspace(back_param.min, back_param.max, grid_size) + + controls = RAT.Controls(procedure="calculate", display="off") + + def calculate_posterior(roughness_index: int, background_index: int) -> float: + """Calculate the posterior for an item in the roughness and background vectors. + + Parameters + ---------- + roughness_index : int + The index of the roughness vector to use as the roughness parameter value. + background_index : int + The index of the background vector to use as the background parameter value. + + Returns + ------- + float + The value of exp(-chi^2 / 2) for the given roughness and background values. + + """ + problem.parameters[0].value = roughness[roughness_index] + problem.background_parameters[0].value = background[background_index] + + _, results = RAT.run(problem, controls) + chi_squared = results.calculationResults.sumChi + + return np.exp(-chi_squared / 2) + + vectorized_calc_posterior = np.vectorize(calculate_posterior) + + print("Calculating posterior directly...") + probability_array = vectorized_calc_posterior(*np.indices((grid_size, grid_size), dtype=int)) + + return ns_results, dream_results, CalculationResults(x_data=[roughness, background], distribution=probability_array) + + +def bayes_benchmark_3d(grid_size: int) -> (RAT.outputs.BayesResults, CalculationResults): + """Bayes benchmark for a 3-dimensional example. + + Here we estimate the substrate roughness and background using two different methods: + nested sampling (the 'ns' procedure in RAT) and through a direct calculation of chi-squared + over a range of parameter values. + + Parameters + ---------- + grid_size : int + The number of points to sample for each fit parameter. + + Returns + ------- + RAT.BayesResults + The BayesResults object from a nested sampler calculation. + CalculationResults + Results from the direct calculation. + + """ + problem = get_project() + problem.scalefactors[0].fit = True + + ns_controls = RAT.Controls(procedure="ns", nsTolerance=1, nLive=500, display="final") + _, ns_results = RAT.run(problem, ns_controls) + + dream_controls = RAT.Controls(procedure="dream", display="final") + _, dream_results = RAT.run(problem, dream_controls) + + # now we get the parameters and use them to do a direct calculation + rough_param = problem.parameters[0] + roughness = np.linspace(rough_param.min, rough_param.max, grid_size) + + back_param = problem.background_parameters[0] + background = np.linspace(back_param.min, back_param.max, grid_size) + + scale_param = problem.scalefactors[0] + scalefactor = np.linspace(scale_param.min, scale_param.max, grid_size) + + controls = RAT.Controls(procedure="calculate", display="off") + + def calculate_posterior(roughness_index: int, background_index: int, scalefactor_index: int) -> float: + """Calculate the posterior for an item in the roughness, background, and scalefactor vectors. + + Parameters + ---------- + roughness_index : int + The index of the roughness vector to use as the roughness parameter value. + background_index : int + The index of the background vector to use as the background parameter value. + scalefactor_index : int + The index of the scalefactor vector to use as the scalefactor parameter. + + Returns + ------- + float + The value of exp(-chi^2 / 2) for the given roughness and background values. + + """ + problem.parameters[0].value = roughness[roughness_index] + problem.background_parameters[0].value = background[background_index] + problem.scalefactors[0].value = scalefactor[scalefactor_index] + + _, results = RAT.run(problem, controls) + chi_squared = results.calculationResults.sumChi + + return np.exp(-chi_squared / 2) + + vectorized_calc_posterior = np.vectorize(calculate_posterior) + + print("Calculating posterior directly...") + probability_array = vectorized_calc_posterior(*np.indices((grid_size, grid_size, grid_size), dtype=int)) + + return ( + ns_results, + dream_results, + CalculationResults(x_data=[roughness, background, scalefactor], distribution=probability_array), + ) + + +def plot_posterior_comparison( + ns_results: RAT.outputs.BayesResults, dream_results: RAT.outputs.BayesResults, calc_results: CalculationResults +): + """Create a grid of marginalised posteriors comparing different calculation methods. + + Parameters + ---------- + ns_results : RAT.BayesResults + The BayesResults object from a nested sampler calculation. + dream_results : RAT.BayesResults + The BayesResults object from a DREAM calculation. + calc_results : CalculationResults + The results from a direct calculation. + + """ + num_params = calc_results.distribution.ndim + fig, axes = plt.subplots(3, num_params, figsize=(3 * num_params, 9)) + + def plot_marginalised_result(dimension: int, axes: plt.Axes, limits: tuple[float]): + """Plot a histogram of a marginalised posterior from the calculation results. + + Parameters + ---------- + dimension : int + The dimension of the array to marginalise over. + axes : plt.Axes + The Axes object to plot the histogram onto. + limits : tuple[float] + The x-axis limits for the histogram. + + """ + # marginalise to the dimension + # note we don't need to normalise here as np.histogram normalises for us + sum_axes = tuple(i for i in range(0, num_params) if i != dimension) + distribution = np.sum(calc_results.distribution, axis=sum_axes) + distribution /= np.sum(calc_results.distribution) + + # create histogram + axes.hist( + calc_results.x_data[dimension], + bins=25, + range=limits, + weights=distribution, + density=True, + edgecolor="black", + linewidth=1.2, + color="white", + ) + + # row 0 contains NS histograms for each parameter + # row 1 contains direct calculation histograms for each parameter + for i in range(0, num_params): + RATplot.plot_one_hist(ns_results, i, axes=axes[0][i]) + RATplot.plot_one_hist(dream_results, i, axes=axes[1][i]) + # we want all 3 plots to have the same x-axis + axes[1][i].set_xlim(*axes[0][i].get_xlim()) + axes[1][i].set_title("") + plot_marginalised_result(i, axes[2][i], limits=axes[0][i].get_xlim()) + + axes[0][0].set_ylabel("nested sampler") + axes[1][0].set_ylabel("DREAM") + axes[2][0].set_ylabel("direct calculation") + + fig.tight_layout() + fig.show() + + +if __name__ == "__main__": + ns_2d, dream_2d, calc_2d = bayes_benchmark_2d(30) + ns_3d, dream_3d, calc_3d = bayes_benchmark_3d(30) + + plot_posterior_comparison(ns_2d, dream_2d, calc_2d) + plot_posterior_comparison(ns_3d, dream_3d, calc_3d) diff --git a/RATapi/examples/convert_rascal_project/Model_IIb.m b/ratapi/examples/convert_rascal_project/Model_IIb.m similarity index 100% rename from RATapi/examples/convert_rascal_project/Model_IIb.m rename to ratapi/examples/convert_rascal_project/Model_IIb.m diff --git a/RATapi/examples/convert_rascal_project/Model_IIb.py b/ratapi/examples/convert_rascal_project/Model_IIb.py similarity index 83% rename from RATapi/examples/convert_rascal_project/Model_IIb.py rename to ratapi/examples/convert_rascal_project/Model_IIb.py index ae36ba5f..2e15d5d1 100644 --- a/RATapi/examples/convert_rascal_project/Model_IIb.py +++ b/ratapi/examples/convert_rascal_project/Model_IIb.py @@ -1,7 +1,13 @@ +"""A custom model file for a monolayer volume model.""" + from math import cos, radians def Model_IIb(params, bulk_in, bulk_out, contrast): + """Calculate layer parameters for a monolayer volume model at two deuterations.""" + # Note - The first contrast number is 1 (not 0) so be careful if you use + # this variable for array indexing. Same applies to the domain number. + # converted from matlab file Model_IIb.m Roughness, APM, thickHead, theta = params @@ -46,7 +52,7 @@ def Model_IIb(params, bulk_in, bulk_out, contrast): vTail = 2 * (16 * vCH2) + 2 * (vCH3) # make SLDs - thisMask = deut[contrast] + thisMask = deut[contrast - 1] if thisMask[0] == 0: thisWater = (H2O * 0.9249) + (D2O * 0.0871) @@ -54,7 +60,7 @@ def Model_IIb(params, bulk_in, bulk_out, contrast): thisWater = D2O # Calculate mole fraction of D2O from the bulk SLD - d2o_molfr = (1 / D2O - H2O) * ((bulk_out[contrast] / 0.036182336306) - H2O) + d2o_molfr = (1 / D2O - H2O) * ((bulk_out[contrast - 1] / 0.036182336306) - H2O) thisWater = (d2o_molfr * D2O) + ((1 - d2o_molfr) * H2O) if thisMask[1] == 0: diff --git a/RATapi/examples/convert_rascal_project/R1monolayerVolumeModel.mat b/ratapi/examples/convert_rascal_project/R1monolayerVolumeModel.mat similarity index 100% rename from RATapi/examples/convert_rascal_project/R1monolayerVolumeModel.mat rename to ratapi/examples/convert_rascal_project/R1monolayerVolumeModel.mat diff --git a/ratapi/examples/convert_rascal_project/__init__.py b/ratapi/examples/convert_rascal_project/__init__.py new file mode 100644 index 00000000..0648853e --- /dev/null +++ b/ratapi/examples/convert_rascal_project/__init__.py @@ -0,0 +1 @@ +"""An example of converting between RAT and RasCAL-1.""" diff --git a/RATapi/examples/convert_rascal_project/convert_rascal.ipynb b/ratapi/examples/convert_rascal_project/convert_rascal.ipynb similarity index 71% rename from RATapi/examples/convert_rascal_project/convert_rascal.ipynb rename to ratapi/examples/convert_rascal_project/convert_rascal.ipynb index d437a732..aebd749a 100644 --- a/RATapi/examples/convert_rascal_project/convert_rascal.ipynb +++ b/ratapi/examples/convert_rascal_project/convert_rascal.ipynb @@ -4,22 +4,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Convert between RasCAL1 and RAT" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "RasCAL1 (R1) project structs can be converted to RAT `Project` classes, and vice versa.\n", - "This is done via the functions `r1_to_project_class` and `project_class_to_r1`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### RasCAL1 to RAT\n", + "### RasCAL-1 to RAT\n", + "\n", + "RasCAL-1 (R1) project structs can be converted to RAT Projects, and vice versa. This is done via the functions `r1_to_project` and `project_to_r1`.\n", + "\n", "Converting from R1 to a `Project` is very simple. We use the example R1 project in the file `R1monolayerVolumeModel.mat`, which is a project for analysing a monolayer of DSPC with various deuterations (tail-deuterated, head-deuterated, fully deuterated, hydrogenated)" ] }, @@ -27,7 +15,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Simply give the file path to the function `r1_to_project_class`, and it returns a RAT `Project` that you can use exactly like any other." + "Simply give the file path to the function `r1_to_project`, and it returns a RAT `Project` that you can use exactly like any other." ] }, { @@ -36,9 +24,9 @@ "metadata": {}, "outputs": [], "source": [ - "from RATapi.utils.convert import r1_to_project_class\n", + "from ratapi.utils.convert import r1_to_project\n", "\n", - "project = r1_to_project_class(\"R1monolayerVolumeModel.mat\")\n", + "project = r1_to_project(\"R1monolayerVolumeModel.mat\")\n", "print(project)" ] }, @@ -46,7 +34,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Note that there are various features of RAT which do not feature in R1, such as `prior_type`, `mu` and `sigma` for parameters. These are given sensible default values (again e.g. for parameters, `prior_type = uniform`, `mu = 0.0`, `sigma=inf`), but you may change these if you would like to use these new features:" + "Note that there are various features of RAT which do not feature in RasCAL-1, such as `prior_type`, `mu` and `sigma` for parameters. These are given sensible default values (again e.g. for parameters, `prior_type = uniform`, `mu = 0.0`, `sigma=inf`), but you may change these if you would like to use these new features:" ] }, { @@ -100,7 +88,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### RAT to RasCAL1\n", + "### RAT to RasCAL-1\n", "\n", "To demonstrate the other way around, we will use the DSPC lipid bilayer model project from another tutorial." ] @@ -111,7 +99,7 @@ "metadata": {}, "outputs": [], "source": [ - "from RATapi.examples import DSPC_standard_layers\n", + "from ratapi.examples import DSPC_standard_layers\n", "lipid_bilayer_project = DSPC_standard_layers()[0]\n", "print(lipid_bilayer_project)" ] @@ -120,7 +108,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "`project_class_to_r1` takes parameters `project` and `filename`, which are the `Project` object and filename for the produced .mat file respectively. This .mat file can then be loaded into RasCAL-1.\n", + "`project_to_r1` takes parameters `project` and `filename`, which are the `Project` object and filename for the produced .mat file respectively. This .mat file can then be loaded into RasCAL-1.\n", "\n", "Alternatively, if one sets `return_struct=True`, the struct is returned as a Python dictionary instead of being saved.\n", "\n", @@ -133,21 +121,21 @@ "metadata": {}, "outputs": [], "source": [ - "from RATapi.utils.convert import project_class_to_r1\n", + "from ratapi.utils.convert import project_to_r1\n", "from pprint import pp # for printing the struct\n", "\n", "# save to a file called lipid_bilayer.mat\n", - "project_class_to_r1(lipid_bilayer_project, filename=\"lipid_bilayer.mat\")\n", + "project_to_r1(lipid_bilayer_project, filename=\"lipid_bilayer.mat\")\n", "\n", "# return as a Python dictionary\n", - "struct = project_class_to_r1(lipid_bilayer_project, return_struct=True)\n", + "struct = project_to_r1(lipid_bilayer_project, return_struct=True)\n", "pp(struct)" ] } ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -165,5 +153,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/ratapi/examples/convert_rascal_project/convert_rascal.py b/ratapi/examples/convert_rascal_project/convert_rascal.py new file mode 100644 index 00000000..15179b35 --- /dev/null +++ b/ratapi/examples/convert_rascal_project/convert_rascal.py @@ -0,0 +1,49 @@ +"""An example of how to convert a RasCAL-1 project to RAT.""" + +import pathlib +from pprint import pp + +import ratapi as RAT + + +# convert R1 project to Project class +def convert_rascal(mat_filename="lipid_bilayer.mat"): + """Convert a project from RasCAL-1 and a project to RasCAL-1. + + We convert a RasCAL-1 monolayer volume model to RAT, and the DSPC Standard Layers + example to RasCAL-1. + + Parameters + ---------- + mat_filename : str + The filename of the output of the RAT project converted to RasCAL-2. + + Returns + ------- + project, struct + A RasCAL-1 monolayer volume model converted to a RAT project, and the + struct of the DSPC standard layers example converted to a RasCAL-1 struct. + + """ + project_path = pathlib.Path(__file__).parent / "R1monolayerVolumeModel.mat" + project = RAT.utils.convert.r1_to_project(project_path) + + # change values if you like, including ones not supported by R1 + project.parameters["Head Thickness"].prior_type = "gaussian" + project.parameters["Theta"].mu = 2.0 + project.parameters["Area per molecule"].sigma = 50.0 + + # convert DSPC standard layers example to a struct and save as file + lipid_bilayer_project = RAT.examples.DSPC_standard_layers()[0] + RAT.utils.convert.project_to_r1(lipid_bilayer_project, filename=mat_filename) + + # convert and return as a Python dictionary + struct = RAT.utils.convert.project_to_r1(lipid_bilayer_project, return_struct=True) + + return project, struct + + +if __name__ == "__main__": + project, struct = convert_rascal() + print(project) + pp(struct) diff --git a/RATapi/examples/data/D2O_spin_down.dat b/ratapi/examples/data/D2O_spin_down.dat similarity index 100% rename from RATapi/examples/data/D2O_spin_down.dat rename to ratapi/examples/data/D2O_spin_down.dat diff --git a/RATapi/examples/data/D2O_spin_up.dat b/ratapi/examples/data/D2O_spin_up.dat similarity index 100% rename from RATapi/examples/data/D2O_spin_up.dat rename to ratapi/examples/data/D2O_spin_up.dat diff --git a/RATapi/examples/data/DSPC_D2O.dat b/ratapi/examples/data/DSPC_D2O.dat similarity index 100% rename from RATapi/examples/data/DSPC_D2O.dat rename to ratapi/examples/data/DSPC_D2O.dat diff --git a/RATapi/examples/data/DSPC_SMW.dat b/ratapi/examples/data/DSPC_SMW.dat similarity index 100% rename from RATapi/examples/data/DSPC_SMW.dat rename to ratapi/examples/data/DSPC_SMW.dat diff --git a/RATapi/examples/data/H2O_spin_down.dat b/ratapi/examples/data/H2O_spin_down.dat similarity index 100% rename from RATapi/examples/data/H2O_spin_down.dat rename to ratapi/examples/data/H2O_spin_down.dat diff --git a/RATapi/examples/data/H2O_spin_up.dat b/ratapi/examples/data/H2O_spin_up.dat similarity index 100% rename from RATapi/examples/data/H2O_spin_up.dat rename to ratapi/examples/data/H2O_spin_up.dat diff --git a/ratapi/examples/data/__init__.py b/ratapi/examples/data/__init__.py new file mode 100644 index 00000000..9fc1b9dd --- /dev/null +++ b/ratapi/examples/data/__init__.py @@ -0,0 +1 @@ +"""Data files used by the examples.""" diff --git a/ratapi/examples/data/c_PLP0011859_q.ort b/ratapi/examples/data/c_PLP0011859_q.ort new file mode 100644 index 00000000..7a7bf1fd --- /dev/null +++ b/ratapi/examples/data/c_PLP0011859_q.ort @@ -0,0 +1,441 @@ +# # ORSO reflectivity data file | 1.1 standard | YAML encoding | https://www.reflectometry.org/ +# # handwritten test file header created to test RAT orsopy integration! +# # example data from refnx: https://refnx.readthedocs.io/en/latest/getting_started.html#fitting-a-neutron-reflectometry-dataset +# data_source: +# owner: +# name: null +# affiliation: null +# measurement: +# instrument_settings: null +# data_files: null +# experiment: +# title: +# probe: neutron +# instrument: None +# start_date: 1970-01-01T00:00:00 +# sample: +# name: film on silicon +# model: +# stack: Si | SiO2 30 | film 250 | D2O +# materials: +# film: +# sld: 2.0e-6 +# roughness: 3 +# reduction: +# software: null +# timestamp: null +# data_set: 0 +# columns: +# - {name: Qz, unit: 1/angstrom, physical_quantity: normal momentum transfer} +# - {name: R, unit: '', physical_quantity: specular reflectivity} +# - {error_of: R, error_type: uncertainty, value_is: sigma} +# - {error_of: Qz, error_type: resolution, value_is: sigma} +# # Qz (1/angstrom) R () sR sQz +0.00806022 0.709581 0.0850676 0.000331422 +0.00813662 0.862281 0.11237 0.000334619 +0.00826375 0.908647 0.0790047 0.000339939 +0.00837067 0.773292 0.0792728 0.000344412 +0.00845033 1.05797 0.125959 0.000347744 +0.00853083 1.01566 0.113295 0.000351111 +0.00861217 0.734717 0.0611566 0.000354512 +0.00869437 0.769216 0.0617058 0.000357949 +0.00877743 1.11574 0.11273 0.000361421 +0.00886136 0.972303 0.089716 0.000364929 +0.00894616 0.751214 0.0549393 0.000368473 +0.00903185 0.797649 0.0567122 0.000372053 +0.00911844 0.922189 0.0685841 0.000375671 +0.00920593 0.975755 0.0729395 0.000379325 +0.00929432 0.819504 0.0521617 0.000383017 +0.00938364 0.78832 0.0479473 0.000386748 +0.00947389 0.794701 0.0460224 0.000390516 +0.00956508 0.8744 0.0515164 0.000394323 +0.00965721 0.839662 0.0474285 0.00039817 +0.0097503 0.800872 0.0439958 0.000402055 +0.00984436 1.1171 0.073733 0.000405981 +0.00993939 0.888411 0.049541 0.000409947 +0.0100354 0.779129 0.0389873 0.000413953 +0.0101324 0.799968 0.0389974 0.000418001 +0.0102304 0.843124 0.041598 0.00042209 +0.0103294 0.961332 0.0492536 0.00042622 +0.0104868 0.880544 0.0299083 0.000432781 +0.0106327 0.755735 0.0320851 0.000438868 +0.0107359 0.971231 0.0453485 0.00044317 +0.0108401 0.895549 0.0390542 0.000447516 +0.0109454 0.862589 0.0358072 0.000451906 +0.0110518 0.890992 0.0361257 0.000456342 +0.0111593 0.900348 0.0367924 0.000460822 +0.0112679 0.845927 0.0321881 0.000465348 +0.0113776 0.943152 0.0365533 0.000469921 +0.0114884 0.995631 0.0390116 0.00047454 +0.0116004 0.969594 0.0363623 0.000479205 +0.0117135 0.905181 0.032041 0.000483919 +0.0118278 0.893381 0.0306119 0.00048868 +0.0119433 0.919602 0.0314677 0.00049349 +0.0120599 0.918998 0.0306097 0.000498349 +0.0121777 0.781056 0.0235542 0.000503257 +0.0122968 0.864915 0.0272025 0.000508215 +0.012417 0.843516 0.0255015 0.000513223 +0.0125385 0.998418 0.0319722 0.000518283 +0.0126612 0.88126 0.0260273 0.000523393 +0.0127852 0.883569 0.0255862 0.000528556 +0.0129105 0.93767 0.0274651 0.000533771 +0.013037 1.0192 0.0305107 0.000539039 +0.0131648 0.845526 0.0226269 0.00054436 +0.0132939 0.873804 0.0232468 0.000549735 +0.0134243 0.865953 0.0224906 0.000555165 +0.0135561 0.877982 0.0224491 0.00056065 +0.0136892 0.947545 0.0248985 0.00056619 +0.0138237 0.888154 0.0220962 0.000571787 +0.0139595 0.891362 0.0218148 0.00057744 +0.0140967 0.888456 0.0215092 0.00058315 +0.0142353 0.913717 0.0222586 0.000588919 +0.0143753 0.810364 0.0188289 0.000594745 +0.0145168 0.738548 0.0168827 0.000600631 +0.0146597 0.68651 0.0159742 0.000606576 +0.014804 0.58224 0.0135021 0.000612582 +0.0149498 0.446855 0.0100626 0.000618648 +0.015097 0.392461 0.00915549 0.000624775 +0.0152458 0.320517 0.00731959 0.000630965 +0.0153961 0.281006 0.00639909 0.000637217 +0.0155479 0.2401 0.00544239 0.000643532 +0.0157012 0.220881 0.00502437 0.000649911 +0.0158561 0.192033 0.00431441 0.000656354 +0.0160126 0.179849 0.00405159 0.000662863 +0.0161707 0.160069 0.00356202 0.000669437 +0.0163303 0.153129 0.00346777 0.000676078 +0.0164916 0.13422 0.003016 0.000682786 +0.0166545 0.12833 0.00288853 0.000689562 +0.016819 0.124794 0.00286182 0.000696406 +0.0169853 0.109127 0.0024831 0.000703319 +0.0171532 0.104429 0.00235392 0.000710302 +0.0173228 0.094683 0.00209162 0.000717355 +0.0175881 0.0896911 0.00143938 0.000728391 +0.0178419 0.0809144 0.00187278 0.000738945 +0.0180185 0.0746544 0.00171422 0.000746287 +0.0181968 0.0703661 0.00163423 0.000753704 +0.018377 0.0690445 0.0016053 0.000761195 +0.0185589 0.0627055 0.00146146 0.000768762 +0.0187427 0.0593915 0.00140007 0.000776405 +0.0189284 0.0575477 0.00136095 0.000784125 +0.0191159 0.0513833 0.00122668 0.000791923 +0.0193054 0.0492267 0.00117824 0.0007998 +0.0194967 0.0452174 0.00107962 0.000807755 +0.01969 0.0424556 0.00102225 0.000815792 +0.0198852 0.0412613 0.000994781 0.000823909 +0.0200824 0.0352333 0.00087779 0.000832108 +0.0202815 0.0335271 0.000836747 0.000840389 +0.0204827 0.0332684 0.000833959 0.000848754 +0.0206859 0.0316644 0.000789886 0.000857204 +0.0208912 0.02916 0.000749613 0.000865738 +0.0210985 0.0265201 0.000706383 0.000874359 +0.021308 0.0251829 0.000671389 0.000883066 +0.0215195 0.0238757 0.000642693 0.000891861 +0.0217331 0.0228929 0.000633068 0.000900745 +0.021949 0.0208646 0.000593128 0.000909718 +0.0221669 0.0208771 0.00059201 0.000918781 +0.0223871 0.0182228 0.000529205 0.000927936 +0.0226095 0.0177346 0.000525152 0.000937183 +0.0228341 0.0158714 0.000481877 0.000946523 +0.023061 0.0143255 0.000451619 0.000955957 +0.0232902 0.0142776 0.000452249 0.000965486 +0.0235217 0.0126624 0.000419845 0.000975112 +0.0237555 0.0122128 0.000413786 0.000984834 +0.0239917 0.0104608 0.000374532 0.000994654 +0.0242302 0.0106133 0.000381052 0.00100457 +0.0244712 0.00987903 0.000364128 0.00101459 +0.0247145 0.00837203 0.000331393 0.00102471 +0.0249603 0.00767048 0.000307705 0.00103493 +0.0252086 0.00734489 0.000304978 0.00104526 +0.0254594 0.00679865 0.000289868 0.00105569 +0.0257127 0.0059163 0.000267178 0.00106622 +0.0259685 0.00534498 0.000251536 0.00107686 +0.0262269 0.00512265 0.000247412 0.0010876 +0.026488 0.00475031 0.000237953 0.00109846 +0.0267516 0.00430715 0.00022385 0.00110942 +0.0270179 0.00401817 0.000220051 0.0011205 +0.0272868 0.00353915 0.000204653 0.00113168 +0.0275585 0.00381819 0.000207944 0.00114298 +0.0278329 0.00286475 0.000181921 0.0011544 +0.02811 0.0027958 0.000176691 0.00116592 +0.02839 0.0026215 0.000175002 0.00117757 +0.0286727 0.00248477 0.000169456 0.00118933 +0.0289583 0.00242009 0.000170925 0.00120121 +0.0292467 0.00235926 0.00017006 0.0012132 +0.0295381 0.00197856 0.000160021 0.00122532 +0.0298323 0.0019472 0.000158282 0.00123757 +0.0301296 0.00173593 0.000152731 0.00124993 +0.0304298 0.00189459 0.000160305 0.00126242 +0.030733 0.00169668 0.000152574 0.00127504 +0.0310392 0.00179369 0.000159245 0.00128778 +0.0313486 0.00178686 0.000155202 0.00130065 +0.031661 0.00187201 0.000158395 0.00131365 +0.0319766 0.00168818 0.000149984 0.00132678 +0.0322953 0.00173237 0.000154325 0.00134004 +0.0326173 0.0015376 0.000145396 0.00135344 +0.0329424 0.00154134 0.000149756 0.00136697 +0.0332708 0.00170033 0.000157208 0.00138064 +0.0336026 0.00214224 0.000172887 0.00139445 +0.0339376 0.00194402 0.000168689 0.0014084 +0.0342205 0.001914 0.000107714 0.00141748 +0.0346645 0.00198641 0.000143828 0.00143727 +0.0350219 0.00184974 0.000127974 0.00145177 +0.035385 0.00193264 0.000122708 0.00146643 +0.0357162 0.00218899 0.000149598 0.00148083 +0.0360773 0.00231432 0.000150345 0.00149568 +0.0364677 0.00183177 0.000104159 0.00151093 +0.0368263 0.00179715 0.000101292 0.00152596 +0.0371616 0.00227874 0.000141733 0.0015409 +0.0375421 0.00218339 0.00012946 0.00155639 +0.0379404 0.001799 9.62498e-05 0.00157213 +0.0383128 0.00182808 9.73464e-05 0.00158778 +0.038684 0.00194985 0.00010826 0.00160356 +0.0390692 0.00204214 0.000112245 0.00161957 +0.0394734 0.00165946 8.39554e-05 0.00163584 +0.0398633 0.00162031 8.07338e-05 0.00165215 +0.0402658 0.00158862 7.61769e-05 0.00166867 +0.0406608 0.00158251 7.82912e-05 0.0016853 +0.0410701 0.0014299 7.03445e-05 0.00170214 +0.0414781 0.00133612 6.49882e-05 0.00171913 +0.0418744 0.0017219 9.20006e-05 0.00173625 +0.0423049 0.00140489 6.78817e-05 0.00175363 +0.0427317 0.00114648 5.31515e-05 0.00177115 +0.0431546 0.00103013 4.8728e-05 0.00178884 +0.0435835 0.00101864 4.85163e-05 0.0018067 +0.0440155 0.00106025 5.14888e-05 0.00182475 +0.0444549 0.000911561 4.51767e-05 0.00184298 +0.0448983 0.000779536 3.74676e-05 0.00186138 +0.045347 0.000595757 2.86778e-05 0.00187998 +0.0457947 0.000647645 3.28669e-05 0.00189877 +0.0462512 0.000526839 2.66621e-05 0.00191774 +0.0467124 0.000436546 2.24095e-05 0.00193691 +0.0471783 0.000369605 1.92965e-05 0.00195626 +0.0476469 0.000331564 1.80855e-05 0.00197583 +0.0481208 0.000254584 1.44062e-05 0.00199557 +0.0485994 0.00020908 1.31243e-05 0.00201553 +0.0490828 0.000192937 1.26159e-05 0.00203569 +0.049571 0.000130922 9.99222e-06 0.00205605 +0.050064 0.000109823 9.08051e-06 0.00207663 +0.0505619 9.56548e-05 8.37009e-06 0.00209741 +0.0510655 7.92572e-05 7.69913e-06 0.00211839 +0.0515734 7.95605e-05 6.89856e-06 0.0021396 +0.0520864 7.22495e-05 6.10273e-06 0.00216102 +0.0526045 7.82513e-05 6.39136e-06 0.00218266 +0.0531279 8.63712e-05 6.56186e-06 0.00220452 +0.0536565 0.000133162 8.78984e-06 0.0022266 +0.0541905 0.000143632 8.17884e-06 0.00224891 +0.0547298 0.000158682 8.56534e-06 0.00227144 +0.0552745 0.000190007 9.75524e-06 0.00229421 +0.0558247 0.00023542 1.14172e-05 0.00231721 +0.0563804 0.000233932 1.03452e-05 0.00234044 +0.0569417 0.00024339 1.05955e-05 0.0023639 +0.0575087 0.000270858 1.12513e-05 0.00238761 +0.0580813 0.000310966 1.23355e-05 0.00241156 +0.0586597 0.000348327 1.35786e-05 0.00243575 +0.0592439 0.000332957 1.27559e-05 0.0024602 +0.059834 0.000354659 1.32236e-05 0.00248489 +0.06043 0.000354467 1.30661e-05 0.00250983 +0.0610319 0.000385515 1.40893e-05 0.00253502 +0.06164 0.000332509 1.20176e-05 0.00256048 +0.0622541 0.000333087 1.19715e-05 0.00258619 +0.0628744 0.000330307 1.19723e-05 0.00261217 +0.0635009 0.000322469 1.16291e-05 0.00263842 +0.0641337 0.000274462 9.94879e-06 0.00266493 +0.0647728 0.000279243 1.02537e-05 0.00269171 +0.0654184 0.000238938 8.96085e-06 0.00271877 +0.0660704 0.000233028 8.72665e-06 0.00274611 +0.066729 0.000186343 7.23614e-06 0.00277372 +0.0673942 0.000164949 6.6195e-06 0.00280162 +0.068066 0.000133244 5.54157e-06 0.00282981 +0.0687446 0.000115376 4.97162e-06 0.00285828 +0.06943 8.25033e-05 3.95115e-06 0.00288705 +0.0701223 6.71923e-05 3.57018e-06 0.00291611 +0.0708215 5.03322e-05 2.92623e-06 0.00294547 +0.0715278 3.33612e-05 2.5097e-06 0.00297513 +0.0722411 2.29052e-05 2.11638e-06 0.0030051 +0.0729338 1.87944e-05 1.86053e-06 0.00303317 +0.0736683 1.55344e-05 1.79821e-06 0.00306431 +0.0744015 1.82452e-05 1.95184e-06 0.00309508 +0.0751405 2.23562e-05 1.801e-06 0.00312604 +0.0758721 2.77362e-05 1.89014e-06 0.00315615 +0.0766402 3.93101e-05 2.30095e-06 0.00318888 +0.0773964 4.59669e-05 2.3324e-06 0.00322041 +0.0781061 5.54131e-05 2.45926e-06 0.00324807 +0.0788682 6.72605e-05 2.72957e-06 0.00327954 +0.0797953 7.65064e-05 2.77309e-06 0.00331828 +0.0807289 7.79472e-05 2.85741e-06 0.00335684 +0.0815334 8.50542e-05 2.9904e-06 0.00339073 +0.0823318 9.68569e-05 3.2227e-06 0.00342487 +0.0831605 9.4624e-05 3.16621e-06 0.00345952 +0.0840252 8.58564e-05 2.82446e-06 0.00349469 +0.0848648 8.10144e-05 2.66254e-06 0.00353001 +0.0857342 7.65592e-05 2.54978e-06 0.00356583 +0.0865553 7.38543e-05 2.48584e-06 0.00360169 +0.0874372 6.24971e-05 2.19092e-06 0.00363822 +0.0883163 5.49543e-05 2.00127e-06 0.00367507 +0.0891108 5.69454e-05 2.08158e-06 0.00371178 +0.0900416 4.2292e-05 1.72971e-06 0.00374959 +0.0909546 3.36754e-05 1.45891e-06 0.00378764 +0.0918504 2.54564e-05 1.24963e-06 0.00382594 +0.0927435 2.09221e-05 1.15976e-06 0.00386459 +0.0936289 1.53112e-05 1.06014e-06 0.00390356 +0.0945527 1.26565e-05 9.57753e-07 0.0039431 +0.0955178 9.33124e-06 8.62139e-07 0.0039832 +0.0964771 8.90152e-06 7.82897e-07 0.00402366 +0.0974189 1.07915e-05 8.93847e-07 0.0040644 +0.0984259 1.21368e-05 9.11308e-07 0.00410584 +0.0994201 1.5408e-05 9.07777e-07 0.0041476 +0.100425 1.93803e-05 9.60253e-07 0.00418981 +0.101434 2.09116e-05 1.04089e-06 0.00423243 +0.102499 2.51925e-05 1.07837e-06 0.0042757 +0.103498 2.8188e-05 1.13217e-06 0.00431908 +0.104546 2.9981e-05 1.17853e-06 0.0043631 +0.105608 3.05628e-05 1.15049e-06 0.0044076 +0.106682 2.81903e-05 1.09907e-06 0.00445257 +0.107758 2.69263e-05 1.0374e-06 0.00449797 +0.108831 2.54192e-05 1.01256e-06 0.0045438 +0.109916 2.2827e-05 9.3671e-07 0.00459012 +0.11104 1.76917e-05 7.9045e-07 0.00463704 +0.112117 1.54751e-05 7.6254e-07 0.00468423 +0.113244 1.17258e-05 6.68805e-07 0.00473208 +0.114319 1.05027e-05 6.59805e-07 0.00478019 +0.115464 8.12153e-06 5.84703e-07 0.00482905 +0.116645 4.98884e-06 5.26719e-07 0.00487853 +0.117762 4.90999e-06 5.36096e-07 0.00492824 +0.118925 5.30434e-06 5.24084e-07 0.00497863 +0.120129 5.68905e-06 4.91234e-07 0.00502965 +0.121346 6.44471e-06 5.06107e-07 0.00508123 +0.122586 7.45619e-06 5.05803e-07 0.0051334 +0.123823 8.24842e-06 5.0256e-07 0.00518608 +0.125091 1.06749e-05 5.84539e-07 0.00523939 +0.126361 1.13162e-05 5.72228e-07 0.00529323 +0.127643 1.1044e-05 5.76255e-07 0.00534765 +0.128932 1.06258e-05 5.65534e-07 0.00540265 +0.13021 9.33766e-06 5.25472e-07 0.00545814 +0.131547 8.9228e-06 5.00068e-07 0.00551441 +0.132854 6.43611e-06 4.44688e-07 0.00557113 +0.134162 6.18113e-06 4.55625e-07 0.00562844 +0.135515 4.68568e-06 4.03478e-07 0.00568647 +0.136824 4.66754e-06 3.80929e-07 0.00574496 +0.138204 4.2625e-06 3.76301e-07 0.00580426 +0.139589 3.8843e-06 3.57158e-07 0.00586419 +0.140989 3.69948e-06 3.79662e-07 0.00592478 +0.14243 3.65993e-06 3.54338e-07 0.00598611 +0.143851 4.55939e-06 3.66569e-07 0.00604802 +0.145263 4.58088e-06 3.47062e-07 0.00611055 +0.14675 4.82929e-06 3.50392e-07 0.00617393 +0.148225 4.93092e-06 3.5333e-07 0.00623794 +0.14971 4.781e-06 3.61256e-07 0.00630265 +0.151225 4.64484e-06 3.39711e-07 0.00636812 +0.152736 4.36508e-06 3.32459e-07 0.00643425 +0.154261 3.80706e-06 3.25378e-07 0.00650113 +0.155825 3.54415e-06 3.05388e-07 0.00656881 +0.157366 2.63269e-06 2.77355e-07 0.00663715 +0.158941 2.12968e-06 2.57061e-07 0.0067063 +0.160511 2.50908e-06 2.68417e-07 0.00677617 +0.162137 2.60626e-06 2.68354e-07 0.00684694 +0.163755 2.46796e-06 2.61811e-07 0.00691843 +0.165404 2.43769e-06 2.45708e-07 0.00699078 +0.167035 2.81846e-06 2.62635e-07 0.00706385 +0.168736 3.20191e-06 2.67722e-07 0.00713789 +0.17041 3.02096e-06 2.54866e-07 0.00721266 +0.172119 2.39855e-06 2.32464e-07 0.00728832 +0.173839 2.45824e-06 2.38546e-07 0.00736483 +0.175574 2.03366e-06 2.23196e-07 0.00744222 +0.177336 1.68404e-06 2.04828e-07 0.00752051 +0.179087 1.29383e-06 2.00765e-07 0.00759963 +0.180907 1.43967e-06 1.88207e-07 0.00767979 +0.182715 1.5402e-06 1.99998e-07 0.0077608 +0.184535 1.33849e-06 1.86482e-07 0.00784273 +0.186383 1.61599e-06 1.86369e-07 0.00792563 +0.188247 1.49347e-06 1.88386e-07 0.00800949 +0.190126 2.05968e-06 1.9207e-07 0.00809433 +0.192038 1.69015e-06 1.7677e-07 0.00818019 +0.193954 1.48837e-06 1.79274e-07 0.00826701 +0.1959 1.40382e-06 1.74728e-07 0.00835488 +0.19786 1.34689e-06 1.70569e-07 0.00844376 +0.199845 9.4771e-07 1.61779e-07 0.00853372 +0.201833 1.08955e-06 1.73502e-07 0.00862469 +0.203863 1.24635e-06 1.65466e-07 0.0087168 +0.205904 1.22737e-06 1.6449e-07 0.00880998 +0.207959 1.16896e-06 1.58456e-07 0.00890425 +0.210042 1.16172e-06 1.52198e-07 0.00899967 +0.21214 1.21689e-06 1.58854e-07 0.00909622 +0.214257 1.31757e-06 1.54607e-07 0.00919392 +0.216399 1.03279e-06 1.47292e-07 0.00929281 +0.21857 1.03066e-06 1.51473e-07 0.00939292 +0.220781 5.94535e-07 1.51172e-07 0.00949429 +0.222988 7.27996e-07 1.42928e-07 0.00959682 +0.225216 7.80631e-07 1.48525e-07 0.0097006 +0.227467 1.06339e-06 1.4993e-07 0.00980565 +0.229741 6.52697e-07 1.29668e-07 0.00991199 +0.232037 1.07438e-06 1.48453e-07 0.0100196 +0.234356 8.68763e-07 1.46862e-07 0.0101286 +0.236698 9.21868e-07 1.45082e-07 0.0102389 +0.239064 6.47149e-07 1.36809e-07 0.0103506 +0.241454 5.36393e-07 1.35688e-07 0.0104637 +0.243867 6.33717e-07 1.30403e-07 0.0105782 +0.246304 6.2927e-07 1.36557e-07 0.0106942 +0.248766 6.33292e-07 1.22453e-07 0.0108116 +0.251253 1.03705e-06 1.35409e-07 0.0109304 +0.253764 8.25286e-07 1.43161e-07 0.0110508 +0.256301 6.26825e-07 1.19257e-07 0.0111727 +0.258863 5.25259e-07 1.22741e-07 0.0112962 +0.26145 5.21832e-07 1.30918e-07 0.0114212 +0.264064 3.91659e-07 1.2137e-07 0.0115479 +0.266703 4.72439e-07 1.39973e-07 0.0116762 +0.269369 5.59536e-07 1.39151e-07 0.0118061 +0.272062 6.6407e-07 1.44867e-07 0.0119377 +0.274782 4.59378e-07 1.51466e-07 0.012071 +0.277529 3.66961e-07 1.43546e-07 0.0122061 +0.280303 5.31531e-07 1.48308e-07 0.012343 +0.283105 4.28914e-07 1.36145e-07 0.0124816 +0.285935 5.52006e-07 1.41983e-07 0.0126221 +0.288793 5.70264e-07 1.529e-07 0.0127644 +0.29168 5.04731e-07 1.36429e-07 0.0129086 +0.294596 6.61923e-07 1.40793e-07 0.0130548 +0.297541 7.60132e-07 1.60721e-07 0.0132029 +0.300516 4.68527e-07 1.34887e-07 0.0133529 +0.30352 4.4286e-07 1.47134e-07 0.0135051 +0.306554 4.89979e-07 1.4043e-07 0.0136592 +0.309619 3.60163e-07 1.33728e-07 0.0138155 +0.312714 2.90563e-07 1.48062e-07 0.0139739 +0.315841 5.19963e-07 1.51562e-07 0.0141344 +0.318998 4.66665e-07 1.56256e-07 0.0142972 +0.322187 3.88883e-07 1.57011e-07 0.0144622 +0.325408 4.46778e-07 1.55512e-07 0.0146295 +0.328662 3.23885e-07 1.52586e-07 0.0147991 +0.331947 3.78736e-07 1.5818e-07 0.0149711 +0.335266 3.88199e-07 1.53911e-07 0.0151455 +0.338618 4.42877e-07 1.49098e-07 0.0153224 +0.342003 2.47787e-07 1.46321e-07 0.0155017 +0.345423 2.85769e-07 1.35135e-07 0.0156836 +0.348876 4.75964e-07 1.53664e-07 0.0158681 +0.352364 4.49639e-07 1.53956e-07 0.0160552 +0.355887 2.47147e-07 1.44322e-07 0.0162449 +0.359445 2.16764e-07 1.49181e-07 0.0164375 +0.363039 5.20585e-07 1.57369e-07 0.0166327 +0.366669 5.24697e-07 1.54541e-07 0.0168309 +0.370335 3.64403e-07 1.55024e-07 0.0170319 +0.374037 4.59752e-07 1.65308e-07 0.0172358 +0.377777 5.35922e-07 1.82043e-07 0.0174427 +0.381554 4.26807e-07 1.77003e-07 0.0176527 +0.385369 4.03666e-07 1.8111e-07 0.0178658 +0.389222 2.55454e-07 1.59729e-07 0.018082 +0.393113 9.26972e-08 1.65402e-07 0.0183015 +0.397044 1.10672e-07 1.80888e-07 0.0185242 +0.401014 4.52163e-07 1.73191e-07 0.0187503 +0.405023 3.78066e-07 1.51597e-07 0.0189798 +0.409073 3.09136e-07 1.57195e-07 0.0192128 +0.413163 3.41774e-07 1.44818e-07 0.0194493 +0.417294 3.44924e-07 1.59581e-07 0.0196894 +0.421466 2.5184e-07 1.59757e-07 0.0199332 +0.42568 4.01737e-07 1.53814e-07 0.0201807 +0.429936 3.17279e-07 1.6913e-07 0.0204321 +0.434235 5.50631e-07 1.61142e-07 0.0206873 +0.438577 5.0851e-07 1.6499e-07 0.0209465 +0.442962 6.02593e-07 1.73835e-07 0.0212097 +0.447391 4.38454e-07 1.6535e-07 0.0214771 +0.451865 3.38757e-07 1.87639e-07 0.0217487 +0.456383 4.35846e-07 1.97826e-07 0.0220245 +0.460946 3.85579e-07 1.76143e-07 0.0223047 +0.465555 3.83415e-07 1.88454e-07 0.0225894 diff --git a/RATapi/examples/data/c_PLP0016596.dat b/ratapi/examples/data/c_PLP0016596.dat similarity index 100% rename from RATapi/examples/data/c_PLP0016596.dat rename to ratapi/examples/data/c_PLP0016596.dat diff --git a/RATapi/examples/data/c_PLP0016601.dat b/ratapi/examples/data/c_PLP0016601.dat similarity index 100% rename from RATapi/examples/data/c_PLP0016601.dat rename to ratapi/examples/data/c_PLP0016601.dat diff --git a/RATapi/examples/data/c_PLP0016607.dat b/ratapi/examples/data/c_PLP0016607.dat similarity index 100% rename from RATapi/examples/data/c_PLP0016607.dat rename to ratapi/examples/data/c_PLP0016607.dat diff --git a/ratapi/examples/data/d2o_background_data.dat b/ratapi/examples/data/d2o_background_data.dat new file mode 100644 index 00000000..93b2fd38 --- /dev/null +++ b/ratapi/examples/data/d2o_background_data.dat @@ -0,0 +1,82 @@ +0.011403 1.90034798968076e-06 -9.65035874608547e-07 +0.011973 1.81361996101478e-06 -4.67852140773275e-09 +0.012572 1.5763144199176e-06 -1.36151693657437e-06 +0.013201 2.66861902156408e-06 5.28737972088124e-07 +0.013861 1.19184137102607e-06 6.5429177234931e-07 +0.014554 1.75409120253422e-06 -4.50039804064594e-07 +0.015281 1.51534921649628e-06 3.54060605152339e-07 +0.016045 1.76294603973655e-06 2.30273872099416e-07 +0.016848 1.66691808740296e-06 1.02729272466451e-06 +0.01769 2.2391873415575e-06 2.02710446930881e-07 +0.018575 1.47947093349392e-06 9.31566506641381e-07 +0.019503 1.58967045467121e-06 6.58308695637623e-09 +0.020479 2.05056480300655e-06 -4.18637528083399e-07 +0.021502 2.54199126843229e-06 6.96150360898885e-08 +0.022578 1.07273638130851e-06 -5.94598550176916e-08 +0.023706 2.89987639289405e-06 8.05335897612554e-07 +0.024892 1.56081284721073e-06 5.50847432744533e-08 +0.026136 2.32386636321661e-06 -5.72991095509919e-07 +0.027443 2.52478251612625e-06 -2.38750704688337e-08 +0.028815 2.66154668842285e-06 1.05087573637142e-06 +0.030256 1.74132051718101e-06 -2.3192582338868e-07 +0.031769 2.01215747485553e-06 -4.26893410009117e-07 +0.033357 1.91881656322323e-06 8.87192534478923e-07 +0.035025 1.69716945696631e-06 1.80981995646851e-07 +0.036777 2.13585488200451e-06 -1.90164659296111e-07 +0.038615 2.17932170608953e-06 -4.91062265460096e-07 +0.040546 1.82384243860966e-06 -1.08387392818395e-06 +0.042573 2.06617996409986e-06 2.22697399577916e-07 +0.044702 3.33679088859971e-06 -1.53613977488785e-07 +0.046937 1.99621696227773e-06 3.55134601922439e-07 +0.049284 2.3551514683307e-06 -1.06523727035749e-06 +0.051748 1.76873031859355e-06 1.15746760150783e-06 +0.054336 1.73606104969994e-06 4.89763150040874e-07 +0.057052 1.82710646654775e-06 -1.15330099931726e-06 +0.059905 2.28227888686718e-06 9.45647703159621e-07 +0.0629 1.59923042799896e-06 -3.70062237263438e-07 +0.066045 1.07352660741589e-06 3.41777294345909e-07 +0.069348 2.02660800872659e-06 2.75569910736786e-07 +0.072815 1.78179239147256e-06 -6.0256088120987e-07 +0.076456 2.14000373613308e-06 -2.18911980741668e-06 +0.080279 2.04230294359047e-06 5.284442372682e-07 +0.084292 2.36455952978407e-06 -1.73629847921614e-07 +0.088507 2.45037654782291e-06 -3.78287083788833e-07 +0.092932 1.33718085273407e-06 4.35130166728242e-07 +0.097579 1.23771058575749e-06 -4.51744576618967e-07 +0.10246 2.25121666653143e-06 6.36952833032752e-07 +0.10758 2.15319571282475e-06 2.20717968415214e-07 +0.11296 1.53041976734067e-06 -6.93055107868105e-07 +0.11861 2.61870106321507e-06 7.69463958198665e-07 +0.12454 2.01650595727752e-06 4.79607176188218e-07 +0.13077 2.06178415911062e-06 1.10173268381594e-06 +0.1373 2.13696968977538e-06 -6.14098124528528e-07 +0.14417 2.3770829041412e-06 -6.16219383494697e-07 +0.15138 2.7622487528669e-06 3.50660742020884e-07 +0.15895 1.86901211887215e-06 6.33626529015099e-07 +0.16689 1.13465824611353e-06 7.62493241842828e-07 +0.17524 2.50673214999504e-06 1.05207422581854e-07 +0.184 1.53613195077685e-06 -8.87137577093779e-08 +0.1932 2.62184014311179e-06 6.22256875962273e-07 +0.20286 1.70525565120706e-06 1.67162600924891e-06 +0.213 2.74574086739327e-06 8.07667338780613e-07 +0.22365 1.59701095264287e-06 1.67629565660922e-07 +0.23484 1.4437004736234e-06 -3.59611249006791e-07 +0.24658 2.47846978404969e-06 4.99800504594724e-07 +0.25891 1.31847420553136e-06 -2.87283586089481e-07 +0.27185 2.34029248136207e-06 2.90756508518823e-07 +0.28544 2.21891181128286e-06 7.22598553179947e-07 +0.29972 1.92836622666398e-06 8.39418345516717e-07 +0.3147 1.82923374769972e-06 5.70510331434857e-07 +0.33044 3.02890531703209e-06 1.20234742176368e-06 +0.34696 1.8127324822871e-06 1.58096394623758e-06 +0.36431 1.90489840127358e-06 -1.41813181395574e-06 +0.38252 1.53063379469415e-06 -1.32294734328625e-06 +0.40165 1.59326881780842e-06 -6.38112989285387e-07 +0.42173 1.7081906242357e-06 -1.49834166690205e-06 +0.44282 2.85476268526193e-06 -1.85680046178151e-07 +0.46496 1.80479009111448e-06 -1.69120607911057e-07 +0.48821 1.6549673183601e-06 3.00340803829798e-07 +0.51262 1.77588964903545e-06 3.28929520936145e-07 +0.53825 2.35718817504981e-06 -4.48934854489947e-07 +0.56516 1.34213437585845e-06 -5.50651590195596e-07 +0.59342 2.31356104763158e-06 7.347220470815e-07 diff --git a/ratapi/examples/domains/__init__.py b/ratapi/examples/domains/__init__.py new file mode 100644 index 00000000..ed955f76 --- /dev/null +++ b/ratapi/examples/domains/__init__.py @@ -0,0 +1 @@ +"""Examples for how to use RAT with domains models.""" diff --git a/RATapi/examples/domains/alloy_domains.py b/ratapi/examples/domains/alloy_domains.py similarity index 63% rename from RATapi/examples/domains/alloy_domains.py rename to ratapi/examples/domains/alloy_domains.py index f7d9ed4c..90da84fd 100644 --- a/RATapi/examples/domains/alloy_domains.py +++ b/ratapi/examples/domains/alloy_domains.py @@ -1,7 +1,15 @@ +"""Custom model file for the domains custom layers example.""" + + def alloy_domains(params, bulkIn, bulkOut, contrast, domain): - """Simple custom model for testing incoherent summing. + """Calculate custom model layers for a permalloy/gold model with domains. + + Simple custom model for testing incoherent summing. Simple two layer of permalloy / gold, with up/down domains. """ + # Note - The first contrast number is 1 (not 0) so be careful if you use + # this variable for array indexing. Same applies to the domain number. + # Split up the parameters subRough = params[0] alloyThick = params[1] @@ -18,9 +26,9 @@ def alloy_domains(params, bulkIn, bulkOut, contrast, domain): gold = [goldThick, goldSLD, goldRough] # Make the model depending on which domain we are looking at - if domain == 0: + if domain == 1: output = [alloyUp, gold] - else: + elif domain == 2: output = [alloyDn, gold] return output, subRough diff --git a/RATapi/examples/domains/domains_XY_model.py b/ratapi/examples/domains/domains_XY_model.py similarity index 58% rename from RATapi/examples/domains/domains_XY_model.py rename to ratapi/examples/domains/domains_XY_model.py index fd1823a4..6a288ba2 100644 --- a/RATapi/examples/domains/domains_XY_model.py +++ b/ratapi/examples/domains/domains_XY_model.py @@ -1,9 +1,16 @@ -import math +"""Custom model file for the domains custom XY example.""" + +from math import sqrt import numpy as np +from scipy.special import erf def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): + """Calculate the SLD profile for a domains custom XY model.""" + # Note - The first contrast number is 1 (not 0) so be careful if you use + # this variable for array indexing. Same applies to the domain number. + # Split up the parameters for convenience subRough = params[0] oxideThick = params[1] @@ -16,13 +23,13 @@ def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): z = np.arange(0, 141) # Make the volume fraction distribution for our Silicon substrate - [vfSilicon, siSurf] = makeLayer(z, -25, 50, 1, subRough, subRough) + [vfSilicon, siSurf] = make_layer(z, -25, 50, 1, subRough, subRough) # ... and the Oxide ... - [vfOxide, oxSurface] = makeLayer(z, siSurf, oxideThick, 1, subRough, subRough) + [vfOxide, oxSurface] = make_layer(z, siSurf, oxideThick, 1, subRough, subRough) # ... and also our layer. - [vfLayer, laySurface] = makeLayer(z, oxSurface, layerThick, 1, subRough, layerRough) + [vfLayer, laySurface] = make_layer(z, oxSurface, layerThick, 1, subRough, layerRough) # Everything that is not already occupied will be filled will water totalVF = vfSilicon + vfOxide + vfLayer @@ -33,13 +40,13 @@ def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): oxSLD = vfOxide * 3.41e-6 # Layer SLD depends on whether we are calculating the domain or not - if domain == 0: + if domain == 1: laySLD = vfLayer * layerSLD - else: + elif domain == 2: laySLD = vfLayer * domainSLD # ... and finally the water SLD. - waterSLD = vfWater * bulk_out[contrast] + waterSLD = vfWater * bulk_out[contrast - 1] # Make the total SLD by just adding them all up totalSLD = siSLD + oxSLD + laySLD + waterSLD @@ -50,8 +57,9 @@ def domains_XY_model(params, bulk_in, bulk_out, contrast, domain): return SLD, subRough -def makeLayer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): - """This produces a layer, with a defined thickness, height and roughness. +def make_layer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): + """Produce a layer, with a defined thickness, height and roughness. + Each side of the layer has its own roughness value. """ # Find the edges @@ -59,12 +67,9 @@ def makeLayer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): right = prevLaySurf + thickness # Make our heaviside - 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]) + erf_left = erf((z - left) / (sqrt(2) * Sigma_L)) + erf_right = erf((z - right) / (sqrt(2) * Sigma_R)) - VF = np.array((height / 2) * (erf_a - erf_b)) + VF = np.array((0.5 * height) * (erf_left - erf_right)) return VF, right diff --git a/ratapi/examples/domains/domains_custom_XY.ipynb b/ratapi/examples/domains/domains_custom_XY.ipynb new file mode 100644 index 00000000..0a153e9d --- /dev/null +++ b/ratapi/examples/domains/domains_custom_XY.ipynb @@ -0,0 +1,179 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "from IPython.display import Code\n", + "\n", + "import ratapi as RAT\n", + "from ratapi.models import Parameter" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Simple example of a layer containing domains using a custom XY model\n", + "\n", + "Domains custom XY models operate in the same way as domains custom layer models, in that there is an additional input to the custom model specifying the domain to be calculated:\n", + "\n", + "This is then used within the function to calculate the correct SLD profile for each contrast and domain. In this example, we simulate a hydrogenated layer on a silicon substrate, containing domains of a larger SLD, against D2O, SMW and water.\n", + "\n", + "Start by making the project and adding the parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem = RAT.Project(calculation=\"domains\", model=\"custom xy\", geometry=\"substrate/liquid\")\n", + "\n", + "parameter_list = [\n", + " Parameter(name=\"Oxide Thickness\", min=10.0, value=20.0, max=50.0, fit=True),\n", + " Parameter(name=\"Layer Thickness\", min=1.0, value=30.0, max=500.0, fit=True),\n", + " Parameter(name=\"Layer SLD\", min=-0.5e-6, value=-0.5e-6, max=0.0, fit=True),\n", + " Parameter(name=\"Layer Roughness\", min=2.0, value=5.0, max=7.0, fit=True),\n", + " Parameter(name=\"Domain SLD\", min=1.0e-6, value=1.0e-6, max=5.0e-6, fit=True)\n", + "]\n", + "\n", + "problem.parameters.extend(parameter_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now set the SLDs of the bulk phases for our samples." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem.bulk_in.set_fields(0, name=\"Silicon\", value=2.073e-6, max=1.0, fit=False)\n", + "\n", + "problem.bulk_out.append(name=\"SLD SMW\", min=2.0e-6, value=2.073e-6, max=2.1e-6)\n", + "problem.bulk_out.append(name=\"SLD H2O\", min=-0.6e-6, value=-0.56e-6, max=-0.5e-6)\n", + "\n", + "problem.scalefactors.set_fields(0, min=0.8, value=1.0, max=1.1, fit=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The custom file takes the parameters and build the model as usual, changing the SLD of the layer depending on whether we are calculating the layer (domain = 0), or the domain (domain = 1)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Code(\"domains_XY_model.py\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, add the custom file to the project, and make our three contrasts." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem.custom_files.append(name=\"Domain Layer\", filename=\"domains_XY_model.py\", language=\"python\", path=pathlib.Path.cwd().resolve())\n", + "\n", + "# Make contrasts\n", + "problem.contrasts.append(\n", + " name=\"D2O\",\n", + " background=\"Background 1\",\n", + " resolution=\"Resolution 1\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"SLD D2O\",\n", + " domain_ratio=\"Domain Ratio 1\",\n", + " data=\"Simulation\",\n", + " model=[\"Domain Layer\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"SMW\",\n", + " background=\"Background 1\",\n", + " resolution=\"Resolution 1\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"SLD SMW\",\n", + " domain_ratio=\"Domain Ratio 1\",\n", + " data=\"Simulation\",\n", + " model=[\"Domain Layer\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"H2O\",\n", + " background=\"Background 1\",\n", + " resolution=\"Resolution 1\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"SLD H2O\",\n", + " domain_ratio=\"Domain Ratio 1\",\n", + " data=\"Simulation\",\n", + " model=[\"Domain Layer\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, run the simulation and plot the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "controls = RAT.Controls()\n", + "problem, results = RAT.run(problem, controls)\n", + "\n", + "RAT.plotting.plot_ref_sld(problem, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/RATapi/examples/domains/domains_custom_XY.py b/ratapi/examples/domains/domains_custom_XY.py similarity index 77% rename from RATapi/examples/domains/domains_custom_XY.py rename to ratapi/examples/domains/domains_custom_XY.py index e069540f..38d4f031 100644 --- a/RATapi/examples/domains/domains_custom_XY.py +++ b/ratapi/examples/domains/domains_custom_XY.py @@ -1,10 +1,21 @@ +"""An example of using domains with a Custom XY model.""" + import pathlib -import RATapi as RAT +import ratapi as RAT def domains_custom_XY(): - """Simple example of a layer containing domains using a custom XY model""" + """Calculate an example of a layer containing domains using a custom XY model. + + Domains custom XY models operate in the same way as domains custom layer models, + in that there is an additional input to the custom model + specifying the domain to be calculated. + + This is then used within the function to calculate the correct SLD profile + for each contrast and domain. In this example, we simulate a hydrogenated layer + on a silicon substrate, containing domains of a larger SLD, against D2O, SMW and water. + """ problem = RAT.Project(calculation="domains", model="custom xy", geometry="substrate/liquid") problem.parameters.append(name="Oxide Thickness", min=10.0, value=20.0, max=50.0, fit=True) @@ -24,7 +35,7 @@ def domains_custom_XY(): name="Domain Layer", filename="domains_XY_model.py", language="python", - path=pathlib.Path(__file__).parent.resolve(), + path=pathlib.Path(__file__).parent, ) # Make contrasts diff --git a/ratapi/examples/domains/domains_custom_layers.ipynb b/ratapi/examples/domains/domains_custom_layers.ipynb new file mode 100644 index 00000000..3016e977 --- /dev/null +++ b/ratapi/examples/domains/domains_custom_layers.ipynb @@ -0,0 +1,141 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "from IPython.display import Code\n", + "\n", + "import ratapi as RAT\n", + "from ratapi.models import Parameter" + ] + }, + { + "attachments": { + "33c727cd-f7da-4589-aef2-f96e0f70c4d2.png": { + "image/png": "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mZmZmZmZmRVgIo+ZmZmZmZmZWQEm8piZmZmZmZmZFWAij5mZmZmZmZlZASbymJmZmZmZmZkVYCKPmZmZmZmZmVkBJvKYmZmZmZmZmRVgIo+ZmZmZmZmZWQEm8piZmZmZmZmZFWAij5mZmZmZmZlZASbymJmZmZmZmZkVYCKPmZmZmZmZmVkBJvKYmZmZmZmZmRVgIo+ZmZmZmZmZWQEm8piZmZmZmZmZFWAij5mZmZmZmZlZASbymJmZmZmZmZkVYCKPmZmZmZmZmVkBJvKYmZmZmZmZmRVgIo+ZmZmZmZmZWQEm8piZmZmZmZmZFWAij5mZmZmZmZlZASbymJmZmZmZmZkVYCKPmZmZmZmZmVkBJvKYmZmZmZmZmRVgIo+ZmZmZmZmZWQEm8piZmZmZmZmZFWAij5mZmZmZmZlZASbymJmZmZmZmZkVYCKPmZmZmZmZmVkBJvKYmZmZmZmZmRVgIo+ZmZmZmZmZWQEm8piZmZmZmZmZFWAij5mZmZmZmZlZASbymJmZmZmZmZkVYCKPmZmZmZmZmVkBJvKYmZmZmZmZmRVgIo+ZmZmZmZmZWQEm8piZmZmZmZmZFWAij5mZmZmZmZlZASbymJmZmZmZmZkVYCKPmZmZmZmZmVkB9v8BDmqwDDoJKuwAAAAASUVORK5CYII=" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Analysing Domains Samples Using Custom Layers Models\n", + "\n", + "For custom models, all the work with calculating the reflectivity from the different domains is done within the custom model itself. To do this, there is an additional input into the custom model file which denotes the domain to be calculated:\n", + "\n", + "The final 'domain' input is always either 0 or 1, denoting which domain is being calculated. Then, within the custom model, we can calculate the layers structure for whichever domain structure is required in this pass through the function:\n", + "\n", + "We will make a simple example of a permalloy layer on silicon, which has spin up and spin down domains, each with different SLDs\n", + "\n", + "![image.png](attachment:33c727cd-f7da-4589-aef2-f96e0f70c4d2.png)\n", + "We start by setting up the project:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem = RAT.Project(calculation=\"domains\", model=\"custom layers\", geometry=\"substrate/liquid\")\n", + "\n", + "# Make some parameters\n", + "parameter_list = [\n", + " Parameter(name=\"Alloy Thickness\", min=100.0, value=150.0, max=200.0, fit=True),\n", + " Parameter(name=\"Alloy SLD up\", min=9.0e-6, value=11.0e-6, max=13.0e-6, fit=True),\n", + " Parameter(name=\"Alloy SLD down\", min=5.0e-6, value=7.0e-6, max=10.0e-6, fit=True),\n", + " Parameter(name=\"Alloy Roughness\", min=5.0, value=7.0, max=11.0, fit=True),\n", + " Parameter(name=\"Gold Thickness\", min=100.0, value=150.0, max=200.0, fit=True),\n", + " Parameter(name=\"Gold SLD\", min=4.0e-6, value=4.5e-6, max=5.0e-6, fit=True),\n", + " Parameter(name=\"Gold Roughness\", min=5.0, value=7.0, max=11.0, fit=True)\n", + "]\n", + "\n", + "problem.parameters.extend(parameter_list)\n", + "\n", + "# Set the bulk SLD\n", + "problem.bulk_in.set_fields(0, name=\"Silicon\", value=2.073e-6, max=1.0)\n", + "\n", + "# Add the custom file\n", + "problem.custom_files.append(name=\"Alloy domains\", filename=\"alloy_domains.py\", language=\"python\", path=pathlib.Path.cwd().resolve(),\n", + ")\n", + "\n", + "# Make a contrast\n", + "problem.contrasts.append(\n", + " name=\"D2O Contrast\",\n", + " data=\"Simulation\",\n", + " background=\"Background 1\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"SLD D2O\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " resolution=\"Resolution 1\",\n", + " resample=False,\n", + " domain_ratio=\"Domain Ratio 1\",\n", + " model=[\"Alloy domains\"],\n", + ")\n", + "\n", + "print(problem)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the project, we are using a custom function which we have called 'alloy_domains':" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Code(\"alloy_domains.py\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that the main difference between this and a 'normal' custom function is the extra 'domain' input, which we then use to select which domain we compute using the 'if / else' instruction at the end of the function\n", + "\n", + "To run this, we make a controls block as usual, and send it to RAT." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "controls = RAT.Controls()\n", + "problem, results = RAT.run(problem, controls)\n", + "\n", + "RAT.plotting.plot_ref_sld(problem, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/RATapi/examples/domains/domains_custom_layers.py b/ratapi/examples/domains/domains_custom_layers.py similarity index 73% rename from RATapi/examples/domains/domains_custom_layers.py rename to ratapi/examples/domains/domains_custom_layers.py index 7ebf0132..92b5e037 100644 --- a/RATapi/examples/domains/domains_custom_layers.py +++ b/ratapi/examples/domains/domains_custom_layers.py @@ -1,10 +1,18 @@ +"""An example of using domains with custom layer models.""" + import pathlib -import RATapi as RAT +import ratapi as RAT def domains_custom_layers(): - """An example custom layers domains project involving incoherent summing on a permalloy layer""" + """Calculate an example custom layers domains project involving incoherent summing on a permalloy layer. + + For a custom layers model, rather than being forced to define our layers as [Thick SLD Rough…. etc], + we can parameterise however we like and then use a function to calculate the parameters for each layer. + So for example, if the volume of lipid tails are known (from the literature), + then all we need is the Area per molecule to calculate the layers. + """ problem = RAT.Project(calculation="domains", model="custom layers", geometry="substrate/liquid") # Make some parameters... @@ -24,7 +32,7 @@ def domains_custom_layers(): name="Alloy domains", filename="alloy_domains.py", language="python", - path=pathlib.Path(__file__).parent.resolve(), + path=pathlib.Path(__file__).parent, ) # Make a contrast diff --git a/ratapi/examples/domains/domains_standard_layers.ipynb b/ratapi/examples/domains/domains_standard_layers.ipynb new file mode 100644 index 00000000..300207d3 --- /dev/null +++ b/ratapi/examples/domains/domains_standard_layers.ipynb @@ -0,0 +1,200 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ratapi as RAT\n", + "from ratapi.models import Layer, Parameter" + ] + }, + { + "attachments": { + "f38e04ec-f12b-4e68-b486-6cf8bffef1bd.png": { + "image/png": "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k7gQTWsVBTiKdSVWbZX36//4J1k4JOC4TgOq+Pj4mjVrTp8+nb6gXMZx6wIO98YOJy1UpD0FFQg4XnnllaFDh0JU0bD75Zdfrl+/PmnB3NzcpKQkjPyeeOIJ0o4Q3A8++OCqVaseeughIAPoPCi8Bx54AInLli2DMjh69Ojf//733r17h4WFTZgwgeTgu+++m5GRAQH3xRdfzJo167///W+/fv2QjQUfARS81NatWzF4bdSo0bZt22jIRbWqCqCbWgAVg7g/deoUfQI0Ef6dPHky5XnttdcGDRqE4TXgCP5FNrTt9u3bBw8ePGDAgPT09J9++mn06NF333032pCwFxqnb9++aE8qBBrirbfemjZtGuLQfwBeyHD//ff/5S9/UQSzNiMYWuzSrl27hx9+WLSjkL6pgoMVMMnOnTvRaPi4BA6ys7OhRCdOnEga66mnngoODgbLgaPwFmCMjz76CE0Htunfv/977733+++/P/vss2AwgBV639mzZ4MJIyMj0f5kbYIWnDNnDiJZWVnjxo0DmEYGSNUdO3ZQHdB6JFt5EUybNm3efPNNPA7pVdM4hI756quvAr6vWLECfIU2PHDgAMNiihDCIE5gmwReB4mM78mKw/iDbqHZGRTOK2DQFCiHCkEimy2RGf+iI7Rq1app06b/93//RxlEsHjtgENvVLfwAGeAm/07dVaNHFaHXDR6XYzoVmunTp3ATuiY4gI1Sbci4ND2Kag4o6REP336TIvFVnrP0rUCjjFjxkBB8jTw4cOHwXmQaBggIoJf582bBwVQt25djOAhgDAGQjrG09CRkIAY4nz44YePPPIIUAKkNqT8sGHDoCahJJBt06ZNKPbee+997rnnEIGiRWJsbCzURr169WhsxNsrSCxiCIU8a9asqdylGx6imQlytkaNGmfPniVFBb2Fl3rppZcw3AzTaMaMGRDBeIX169fjFapXr46me/vttwEImjVrhvQXXnghOjoaEdz+8ccfP/roo0Bjf/3rX9GSaHN8gscff5yaC0CkVq1aQDDAHJDszz//PGkCWvnB8h2gp3HjxvgKDC/wNenXqjlYz8nJwevzmgNQ165dExISwF1BQUHADQsWLADAQp7vvvsOv955552IA3VB3SKCJh05ciSG4z4+PqmpqQcPHgTABVZYuXIlGJKQGT5KYmIiXj8lJQX5fX19wXIo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" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Domains Samples Using Standard Layers\n", + "\n", + "Domains standard layers projects proceed in much the same way as a normal standard layers problem, except that there is an additional grouping step between layers and contrasts.\n", + "\n", + "Layers are grouped into 'Domain Contrasts'. The model for the actual experimental contrast is built from these domain contrasts rather than from layers. There are exactly two domains for each contrast, with the the ratio of them controlled by a fittable 'domain ratio' parameter.\n", + "\n", + "![image.png](attachment:f38e04ec-f12b-4e68-b486-6cf8bffef1bd.png)\n", + "\n", + "In this we will set up a simple example of a simulated system consisting of two layered domains to illustrate this process.\n", + "\n", + "Start by making the project, specifying that this is a domains calculation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem = RAT.Project(calculation=\"domains\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Define the parameters we need to define our two domains:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "parameter_list = [\n", + " Parameter(name=\"L1 Thickness\", min=5.0, value=20.0, max=60.0, fit=True),\n", + " Parameter(name=\"L1 SLD\", min=3.0e-6, value=4.1e-6, max=5.0e-6, fit=False),\n", + " Parameter(name=\"L1 Roughness\", min=2.0, value=5.0, max=20.0, fit=True),\n", + " Parameter(name=\"L1 Hydration\", min=10.0, value=20.0, max=30.0, fit=True),\n", + " #\n", + " Parameter(name=\"L2 Thickness\", min=5.0, value=60.0, max=100.0, fit=True),\n", + " Parameter(name=\"L2 SLD\", min=2.1e-6, value=3.0e-6, max=5.0e-6, fit=False),\n", + " Parameter(name=\"L2 Roughness\", min=2.0, value=5.0, max=20.0, fit=True),\n", + " Parameter(name=\"L2 Hydration\", min=10.0, value=20.0, max=30.0, fit=True),\n", + " #\n", + " Parameter(name=\"L3 Thickness\", min=5.0, value=200.0, max=300.0, fit=True),\n", + " Parameter(name=\"L3 SLD\", min=3.0e-6, value=7.0e-6, max=8.0e-6, fit=False),\n", + " Parameter(name=\"L3 Roughness\", min=2.0, value=5.0, max=20.0, fit=True),\n", + " Parameter(name=\"L3 Hydration\", min=10.0, value=20.0, max=30.0, fit=True)\n", + "]\n", + "\n", + "problem.parameters.extend(parameter_list)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now group these into layers as usual:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "layers = [\n", + "Layer(name=\"Layer 1\", thickness=\"L1 Thickness\", SLD=\"L1 SLD\", roughness=\"L1 Roughness\", hydration=\"L1 Hydration\", hydrate_with=\"bulk out\"),\n", + "Layer(name=\"Layer 2\", thickness=\"L2 Thickness\", SLD=\"L2 SLD\", roughness=\"L2 Roughness\", hydration=\"L2 Hydration\", hydrate_with=\"bulk out\"),\n", + "Layer(name=\"Layer 3\", thickness=\"L3 Thickness\", SLD=\"L3 SLD\", roughness=\"L3 Roughness\", hydration=\"L3 Hydration\", hydrate_with=\"bulk out\")\n", + "]\n", + "\n", + "problem.layers.extend(layers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If we look at the project, there are two extra groups as compared to a normal standard layers - Domain Contrasts and Domain Ratios" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(problem)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, make a couple of Domain Contrasts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem.domain_contrasts.append(name=\"Domain 1\", model=[\"Layer 1\"])\n", + "problem.domain_contrasts.append(name=\"Domain 2\", model=[\"Layer 2\", \"Layer 3\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now make a contrast as with standard models, but this time also including the default domain ratio (\"Domain Ratio 1\"). Note that the model for each experimental contrast **must** have **exactly** two domain contrasts." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "problem.contrasts.append(\n", + " name=\"Domain Test\",\n", + " background=\"Background 1\",\n", + " resolution=\"Resolution 1\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " resample=False,\n", + " bulk_in=\"SLD Air\",\n", + " bulk_out=\"SLD D2O\",\n", + " domain_ratio=\"Domain Ratio 1\",\n", + " data=\"Simulation\",\n", + " model=[\"Domain 1\", \"Domain 2\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can run our simulation as usual, and plot the results:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "controls = RAT.Controls()\n", + "problem, results = RAT.run(problem, controls)\n", + "\n", + "RAT.plotting.plot_ref_sld(problem, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/RATapi/examples/domains/domains_standard_layers.py b/ratapi/examples/domains/domains_standard_layers.py similarity index 82% rename from RATapi/examples/domains/domains_standard_layers.py rename to ratapi/examples/domains/domains_standard_layers.py index b1d08778..9a251233 100644 --- a/RATapi/examples/domains/domains_standard_layers.py +++ b/ratapi/examples/domains/domains_standard_layers.py @@ -1,7 +1,19 @@ -import RATapi as RAT +"""An example using domains with standard layers.""" + +import ratapi as RAT def domains_standard_layers(): + """Calculate an example for using standard layers with domains. + + Domains standard layers projects proceed in much the same way as a normal standard layers problem, + except that there is an additional grouping step between layers and contrasts. + + Layers are grouped into ‘Domain Contrasts’. The model for the actual experimental contrast + is built from these domain contrasts rather than from layers. There are exactly + two domains for each contrast, with the the ratio of them controlled by + a fittable ‘domain ratio’ parameter. + """ problem = RAT.Project(calculation="domains") # Define the parameters we need to define our two domains diff --git a/ratapi/examples/extras/two_contrast_example.py b/ratapi/examples/extras/two_contrast_example.py new file mode 100644 index 00000000..86811056 --- /dev/null +++ b/ratapi/examples/extras/two_contrast_example.py @@ -0,0 +1,215 @@ +"""The example project with two contrasts from the user guide.""" + +import numpy as np + +import ratapi as RAT + + +def two_contrast_example(): + """Generate the two-contrast example project from the user guide.""" + problem = RAT.Project(name="DSPC monolayers") + parameters = [ + RAT.models.Parameter(name="Tails Thickness", min=10, value=20, max=30, fit=True), + RAT.models.Parameter(name="Heads Thickness", min=3, value=11, max=16, fit=True), + RAT.models.Parameter(name="Tails Roughness", min=2, value=5, max=9, fit=True), + RAT.models.Parameter(name="Heads Roughness", min=2, value=5, max=9, fit=True), + RAT.models.Parameter(name="Deuterated Tails SLD", min=4e-6, value=6e-6, max=2e-5, fit=True), + RAT.models.Parameter(name="Hydrogenated Tails SLD", min=-0.6e-6, value=-0.4e-6, max=0, fit=True), + RAT.models.Parameter(name="Deuterated Heads SLD", min=1e-6, value=3e-6, max=8e-6, fit=True), + RAT.models.Parameter(name="Hydrogenated Heads SLD", min=0.1e-6, value=1.4e-6, max=3e-6, fit=True), + RAT.models.Parameter(name="Heads Hydration", min=0, value=0.3, max=0.5, fit=True), + ] + + problem.parameters.extend(parameters) + H_Heads = RAT.models.Layer( + name="Hydrogenated Heads", + thickness="Heads Thickness", + SLD="Hydrogenated Heads SLD", + roughness="Heads Roughness", + hydration="Heads Hydration", + hydrate_with="bulk out", + ) + + D_Heads = RAT.models.Layer( + name="Deuterated Heads", + thickness="Heads Thickness", + SLD="Deuterated Heads SLD", + roughness="Heads Roughness", + hydration="Heads Hydration", + hydrate_with="bulk out", + ) + + D_Tails = RAT.models.Layer( + name="Deuterated Tails", thickness="Tails Thickness", SLD="Deuterated Tails SLD", roughness="Tails Roughness" + ) + + H_Tails = RAT.models.Layer( + name="Hydrogenated Tails", + thickness="Tails Thickness", + SLD="Hydrogenated Tails SLD", + roughness="Tails Roughness", + ) + + problem.layers.extend([H_Heads, D_Heads, H_Tails, D_Tails]) + + problem.background_parameters.set_fields(0, name="Backs Value ACMW") + problem.background_parameters.set_fields(0, value=5.5e-6) + problem.background_parameters.append(name="Backs Value D2O", min=1e-8, value=2.8e-6, max=1e-5) + + problem.backgrounds.append(name="Background D2O", type="constant", value_1="Backs Value D2O") + problem.backgrounds.set_fields(0, name="Background ACMW", value_1="Backs Value ACMW") + + problem.bulk_out.append(name="SLD ACMW", min=-0.6e-6, value=-0.56e-6, max=-0.3e-6, fit=True) + + d13acmw20 = np.array( + [ + [5.1793e-02, 1.8087e-05, 7.9683e-07], + [5.4383e-02, 1.4582e-05, 6.3691e-07], + [5.7102e-02, 1.3621e-05, 5.5407e-07], + [5.9957e-02, 1.2409e-05, 4.8014e-07], + [6.2955e-02, 1.0992e-05, 4.1824e-07], + [6.6103e-02, 1.0619e-05, 3.7541e-07], + [6.9408e-02, 1.0162e-05, 3.4945e-07], + [7.2878e-02, 1.0716e-05, 3.3763e-07], + [7.6522e-02, 8.3468e-06, 2.8040e-07], + [8.0348e-02, 7.5250e-06, 2.5702e-07], + [8.4365e-02, 6.4395e-06, 2.2528e-07], + [8.8584e-02, 6.0544e-06, 2.0545e-07], + [9.3013e-02, 5.9517e-06, 1.9417e-07], + [9.7664e-02, 5.6433e-06, 1.8108e-07], + [1.0255e-01, 4.8172e-06, 1.6076e-07], + [1.0767e-01, 4.8066e-06, 1.5520e-07], + [1.1306e-01, 4.1559e-06, 1.4115e-07], + [1.1871e-01, 4.1418e-06, 1.3926e-07], + [1.2465e-01, 3.4580e-06, 1.2273e-07], + [1.3088e-01, 3.2376e-06, 1.1791e-07], + [1.3742e-01, 3.0976e-06, 1.1948e-07], + [1.4429e-01, 2.7478e-06, 1.1518e-07], + [1.5151e-01, 2.5492e-06, 1.1573e-07], + [1.5908e-01, 2.7500e-06, 1.2812e-07], + [1.6704e-01, 2.1813e-06, 2.0450e-07], + [1.7539e-01, 1.8609e-06, 5.4900e-07], + [1.8416e-01, 1.9405e-06, 1.5660e-07], + [1.9337e-01, 1.7421e-06, 2.3280e-07], + [2.0304e-01, 1.8050e-06, 3.9820e-07], + [2.1319e-01, 1.5801e-06, 1.4110e-07], + [2.2385e-01, 1.6724e-06, 7.7900e-08], + [2.3504e-01, 1.4150e-06, 4.0820e-07], + [2.4679e-01, 1.4340e-06, 5.3180e-07], + [2.5913e-01, 1.3102e-06, 2.6000e-07], + [2.7209e-01, 1.3702e-06, 2.8540e-07], + [2.8569e-01, 1.2468e-06, 2.3230e-07], + [2.9998e-01, 1.2956e-06, 5.3240e-07], + [3.1497e-01, 1.2947e-06, 3.9940e-07], + [3.3072e-01, 1.2488e-06, 2.1390e-07], + [3.4726e-01, 1.4620e-06, 3.3640e-07], + [3.6462e-01, 1.3056e-06, 2.1600e-07], + [3.8285e-01, 1.4553e-06, 2.3170e-07], + [4.0200e-01, 1.1579e-06, 2.6740e-07], + [4.2210e-01, 1.1753e-06, 3.0940e-07], + [4.4320e-01, 1.0066e-06, 5.2040e-07], + [4.6536e-01, 1.1043e-06, 3.1870e-07], + [4.8863e-01, 1.2969e-06, 4.1670e-07], + [5.1306e-01, 1.2495e-06, 2.0890e-07], + [5.3871e-01, 1.3898e-06, 4.7560e-07], + [5.6565e-01, 1.1225e-06, 3.0470e-07], + [5.8877e-01, 8.3346e-07, 3.8944e-07], + ] + ) + + d70d2o20 = np.array( + [ + [5.1793e-02, 1.4943e-04, 3.2517e-06], + [5.4383e-02, 1.1882e-04, 2.5846e-06], + [5.7102e-02, 9.2164e-05, 2.0507e-06], + [5.9957e-02, 7.7813e-05, 1.7070e-06], + [6.2955e-02, 6.1143e-05, 1.3983e-06], + [6.6103e-02, 4.8033e-05, 1.1343e-06], + [6.9408e-02, 4.1379e-05, 1.0006e-06], + [7.2878e-02, 3.5090e-05, 8.6919e-07], + [7.6522e-02, 3.0350e-05, 7.5890e-07], + [8.0348e-02, 2.4115e-05, 6.5226e-07], + [8.4365e-02, 2.0755e-05, 5.7445e-07], + [8.8584e-02, 1.7500e-05, 4.9617e-07], + [9.3013e-02, 1.5011e-05, 4.3754e-07], + [9.7664e-02, 1.3632e-05, 3.9907e-07], + [1.0255e-01, 1.2997e-05, 3.7469e-07], + [1.0767e-01, 1.1656e-05, 3.4282e-07], + [1.1306e-01, 1.0820e-05, 3.2299e-07], + [1.1871e-01, 9.5831e-06, 3.0088e-07], + [1.2465e-01, 8.9996e-06, 2.8102e-07], + [1.3088e-01, 8.6498e-06, 2.7363e-07], + [1.3742e-01, 7.9412e-06, 2.7158e-07], + [1.4429e-01, 7.4042e-06, 2.6829e-07], + [1.5151e-01, 6.8321e-06, 2.6877e-07], + [1.5908e-01, 5.6809e-06, 2.6232e-07], + [1.6704e-01, 5.6646e-06, 2.8607e-07], + [1.7539e-01, 4.7762e-06, 2.7767e-07], + [1.8416e-01, 4.1971e-06, 2.7353e-07], + [1.9337e-01, 4.1815e-06, 2.9140e-07], + [2.0304e-01, 3.2725e-06, 2.3160e-07], + [2.1319e-01, 2.3244e-06, 4.2270e-07], + [2.2385e-01, 2.2892e-06, 1.4970e-07], + [2.3504e-01, 1.9198e-06, 8.1460e-07], + [2.4679e-01, 1.4828e-06, 1.0840e-07], + [2.5913e-01, 1.1450e-06, 4.7440e-07], + [2.7209e-01, 1.3047e-06, 1.8840e-07], + [2.8569e-01, 9.6081e-07, 3.9385e-07], + [2.9998e-01, 8.2280e-07, 2.3955e-07], + [3.1497e-01, 6.3219e-07, 3.5324e-07], + [3.3072e-01, 6.1254e-07, 5.0846e-07], + [3.4726e-01, 7.4092e-07, 2.2312e-07], + [3.6462e-01, 6.3584e-07, 4.2866e-07], + [3.8285e-01, 7.7287e-07, 2.9493e-07], + [4.0200e-01, 9.4637e-07, 2.3347e-07], + [4.2210e-01, 7.0576e-07, 3.3494e-07], + [4.4320e-01, 7.8969e-07, 2.3371e-07], + [4.6536e-01, 5.8374e-07, 3.2624e-07], + [4.8863e-01, 5.6711e-07, 6.0419e-07], + [5.1306e-01, 4.7782e-07, 3.4822e-07], + [5.3871e-01, 6.3813e-07, 4.3279e-07], + [5.6565e-01, 4.6186e-07, 1.8863e-07], + [5.8877e-01, 5.6129e-07, 4.3960e-07], + ] + ) + + problem.data.append(name="H-tail / D-head / ACMW", data=d13acmw20) + problem.data.append(name="D-tail / H-head / D2O", data=d70d2o20) + + problem.contrasts.append( + name="D-tail/H-Head/D2O", + background="Background D2O", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_out="SLD D2O", + bulk_in="SLD Air", + data="D-tail / H-head / D2O", + ) + + problem.contrasts.append( + name="H-tail/D-Head/ACMW", + background="Background ACMW", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_out="SLD ACMW", + bulk_in="SLD Air", + data="D-tail / H-head / D2O", + ) + + problem.contrasts.set_fields(0, model=["Deuterated Tails", "Hydrogenated Heads"]) + problem.contrasts.set_fields(1, model=["Hydrogenated Tails", "Deuterated Heads"]) + + problem.background_parameters.set_fields(0, fit=True) + problem.background_parameters.set_fields(1, fit=True) + problem.scalefactors.set_fields(0, fit=True) + problem.bulk_out.set_fields(0, fit=True) + + return problem + + +if __name__ == "__main__": + problem = two_contrast_example() + controls = RAT.Controls() + problem, results = RAT.run(problem, controls) + + RAT.plotting.plot_ref_sld(problem, results, True) diff --git a/ratapi/examples/languages/__init__.py b/ratapi/examples/languages/__init__.py new file mode 100644 index 00000000..99fd5e1f --- /dev/null +++ b/ratapi/examples/languages/__init__.py @@ -0,0 +1 @@ +"""A benchmark for using RAT custom files in three different languages.""" diff --git a/RATapi/examples/languages/custom_bilayer.cpp b/ratapi/examples/languages/custom_bilayer.cpp similarity index 87% rename from RATapi/examples/languages/custom_bilayer.cpp rename to ratapi/examples/languages/custom_bilayer.cpp index ad25b18f..2cf0ca81 100644 --- a/RATapi/examples/languages/custom_bilayer.cpp +++ b/ratapi/examples/languages/custom_bilayer.cpp @@ -13,6 +13,8 @@ extern "C" { LIB_EXPORT void custom_bilayer(std::vector& params, std::vector& bulkIn, std::vector& bulkOut, int contrast, std::vector& output, double* outputSize, double* rough) { + // Note - The first contrast number is 1 (not 0) so be careful if you use + // this variable for array indexing. double subRough = params[0]; double oxideThick = params[1]; double oxideHydration = params[2]; @@ -65,9 +67,9 @@ extern "C" { // Manually deal with hydration for layers in // this example. - double oxSLD = (oxideHydration * bulkOut[contrast]) + ((1 - oxideHydration) * oxideSLD); - double headSLD = (headHydration * bulkOut[contrast]) + ((1 - headHydration) * SLDhead); - double tailSLD = (bilayerHydration * bulkOut[contrast]) + ((1 - bilayerHydration) * SLDtail); + double oxSLD = (oxideHydration * bulkOut[contrast-1]) + ((1 - oxideHydration) * oxideSLD); + double headSLD = (headHydration * bulkOut[contrast-1]) + ((1 - headHydration) * SLDhead); + double tailSLD = (bilayerHydration * bulkOut[contrast-1]) + ((1 - bilayerHydration) * SLDtail); // Make the layers // oxide... @@ -77,7 +79,7 @@ extern "C" { // Water... output.push_back(waterThick); - output.push_back(bulkOut[contrast]); + output.push_back(bulkOut[contrast-1]); output.push_back(bilayerRough); // Heads... diff --git a/RATapi/examples/languages/custom_bilayer.m b/ratapi/examples/languages/custom_bilayer.m similarity index 100% rename from RATapi/examples/languages/custom_bilayer.m rename to ratapi/examples/languages/custom_bilayer.m diff --git a/RATapi/examples/languages/custom_bilayer.py b/ratapi/examples/languages/custom_bilayer.py similarity index 73% rename from RATapi/examples/languages/custom_bilayer.py rename to ratapi/examples/languages/custom_bilayer.py index dc978e31..bed82ca3 100644 --- a/RATapi/examples/languages/custom_bilayer.py +++ b/ratapi/examples/languages/custom_bilayer.py @@ -1,7 +1,13 @@ +"""A custom bilayer model for the custom file languages benchmark.""" + import numpy as np def custom_bilayer(params, bulk_in, bulk_out, contrast): + """Calculate the layer parameters for a custom bilayer model.""" + # Note - The first contrast number is 1 (not 0) so be careful if you use + # this variable for array indexing. + sub_rough = params[0] oxide_thick = params[1] oxide_hydration = params[2] @@ -51,13 +57,13 @@ def custom_bilayer(params, bulk_in, bulk_out, contrast): tailThick = vTail / lipidAPM # 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) + oxSLD = (oxide_hydration * bulk_out[contrast - 1]) + ((1 - oxide_hydration) * oxide_SLD) + headSLD = (headHydration * bulk_out[contrast - 1]) + ((1 - headHydration) * SLDhead) + tailSLD = (bilayerHydration * bulk_out[contrast - 1]) + ((1 - bilayerHydration) * SLDtail) # Make the layers oxide = [oxide_thick, oxSLD, sub_rough] - water = [waterThick, bulk_out[contrast], bilayerRough] + water = [waterThick, bulk_out[contrast - 1], bilayerRough] head = [headThick, headSLD, bilayerRough] tail = [tailThick, tailSLD, bilayerRough] diff --git a/RATapi/examples/languages/run_custom_file_languages.py b/ratapi/examples/languages/run_custom_file_languages.py similarity index 80% rename from RATapi/examples/languages/run_custom_file_languages.py rename to ratapi/examples/languages/run_custom_file_languages.py index 0e9ae47d..2f6025ae 100644 --- a/RATapi/examples/languages/run_custom_file_languages.py +++ b/ratapi/examples/languages/run_custom_file_languages.py @@ -5,9 +5,9 @@ import setup_problem -import RATapi as RAT +import ratapi as RAT -path = pathlib.Path(__file__).parent.resolve() +path = pathlib.Path(__file__).parent project = setup_problem.make_example_problem() controls = RAT.Controls() @@ -16,7 +16,7 @@ start = time.time() project, results = RAT.run(project, controls) end = time.time() -print(f"Python time is: {end-start}s\n") +print(f"Python time is: {end - start}s\n") RAT.plotting.plot_ref_sld(project, results) @@ -26,7 +26,7 @@ start = time.time() project, results = RAT.run(project, controls) end = time.time() -print(f"Matlab time is: {end-start}s\n") +print(f"Matlab time is: {end - start}s\n") RAT.plotting.plot_ref_sld(project, results) @@ -36,6 +36,6 @@ start = time.time() project, results = RAT.run(project, controls) end = time.time() -print(f"C++ time is: {end-start}s\n") +print(f"C++ time is: {end - start}s\n") RAT.plotting.plot_ref_sld(project, results) diff --git a/RATapi/examples/languages/setup_problem.py b/ratapi/examples/languages/setup_problem.py similarity index 86% rename from RATapi/examples/languages/setup_problem.py rename to ratapi/examples/languages/setup_problem.py index dff7a1d6..dbf300db 100644 --- a/RATapi/examples/languages/setup_problem.py +++ b/ratapi/examples/languages/setup_problem.py @@ -1,13 +1,14 @@ -import os +"""A custom example problem for the languages benchmark.""" + import pathlib import numpy as np -import RATapi as RAT +import ratapi as RAT def make_example_problem(): - """Custom Layers example for Supported DSPC layer. + """Generate a Custom Layers example for Supported DSPC layer. Example of using custom layers to model a DSPC supported bilayer. """ @@ -39,10 +40,10 @@ def make_example_problem(): # and H2O. Load these datafiles in and put them in the data block # Read in the datafiles - data_path = os.path.join(pathlib.Path(__file__).parents[1].resolve(), "data") - D2O_data = np.loadtxt(os.path.join(data_path, "c_PLP0016596.dat"), delimiter=",") - SMW_data = np.loadtxt(os.path.join(data_path, "c_PLP0016601.dat"), delimiter=",") - H2O_data = np.loadtxt(os.path.join(data_path, "c_PLP0016607.dat"), delimiter=",") + data_path = pathlib.Path(__file__).parents[1] / "data" + D2O_data = np.loadtxt(data_path / "c_PLP0016596.dat", delimiter=",") + SMW_data = np.loadtxt(data_path / "c_PLP0016601.dat", delimiter=",") + H2O_data = np.loadtxt(data_path / "c_PLP0016607.dat", delimiter=",") # Add the data to the project - note this data has a resolution 4th column problem.data.append(name="Bilayer / D2O", data=D2O_data) @@ -54,7 +55,7 @@ def make_example_problem(): name="DSPC Model", filename="custom_bilayer.py", language="python", - path=pathlib.Path(__file__).parent.resolve(), + path=pathlib.Path(__file__).parent, ) # Also, add the relevant background parameters - one each for each contrast: @@ -83,11 +84,11 @@ def make_example_problem(): ) # And add the two new constant backgrounds - problem.backgrounds.append(name="Background SMW", type="constant", value_1="Background parameter SMW") - problem.backgrounds.append(name="Background H2O", type="constant", value_1="Background parameter H2O") + problem.backgrounds.append(name="Background SMW", type="constant", source="Background parameter SMW") + problem.backgrounds.append(name="Background H2O", type="constant", source="Background parameter H2O") # And edit the other one - problem.backgrounds.set_fields(0, name="Background D2O", value_1="Background parameter D2O") + problem.backgrounds.set_fields(0, name="Background D2O", source="Background parameter D2O") # Finally modify some of the other parameters to be more suitable values for a solid / liquid experiment problem.scalefactors.set_fields(0, value=1.0, min=0.5, max=2.0, fit=True) diff --git a/RATapi/examples/non_polarised/DSPC_custom_XY.py b/ratapi/examples/normal_reflectivity/DSPC_custom_XY.py similarity index 86% rename from RATapi/examples/non_polarised/DSPC_custom_XY.py rename to ratapi/examples/normal_reflectivity/DSPC_custom_XY.py index fd350d78..72511977 100644 --- a/RATapi/examples/non_polarised/DSPC_custom_XY.py +++ b/ratapi/examples/normal_reflectivity/DSPC_custom_XY.py @@ -1,13 +1,14 @@ -import os +"""An example of analysing a Custom XY model.""" + import pathlib import numpy as np -import RATapi as RAT +import ratapi as RAT def DSPC_custom_XY(): - """Custom XY Example for Supported DSPC layer. + r"""Calculate a 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 @@ -20,7 +21,7 @@ def DSPC_custom_XY(): We can define our lipid in terms of an Area per Molecule, almost in its entirety, if we recognise that where the volume is known, the thickness of the layer is simply given by the layer volume / APM: - $d_{\textrm{layer}} =\frac{V_{\textrm{layer}} }{{\textrm{APM}}_{\textrm{layer}}}$. + .. math:: d_{\textrm{layer}} =\frac{V_{\textrm{layer}} }{{\textrm{APM}}_{\textrm{layer}}}. We can then define the Volume Fraction of this layer with a roughened Heaviside of length dlayer and a height of 1. Then, the total volume occupied will be given by the sum of the volume fractions across the interface. Of course, @@ -28,11 +29,11 @@ def DSPC_custom_XY(): 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$$ + .. math:: {\textrm{VF}}_{\textrm{wat}} =1-\\sum_n {\textrm{VF}}_n where VFn is the Volume Fraction of the n'th layer. """ - # Start by making the class and setting it to a custom layers type: + # Start by making the class and setting it to a custom XY type: problem = RAT.Project(name="Orso lipid example - custom XY", model="custom xy", geometry="substrate/liquid") # We need to add the relevant parameters we are going to need to define the model @@ -59,10 +60,10 @@ def DSPC_custom_XY(): # Water and H2O. Load these datafiles in and put them in the data block # Read in the datafiles - data_path = os.path.join(pathlib.Path(__file__).parents[1].resolve(), "data") - D2O_data = np.loadtxt(os.path.join(data_path, "c_PLP0016596.dat"), delimiter=",") - SMW_data = np.loadtxt(os.path.join(data_path, "c_PLP0016601.dat"), delimiter=",") - H2O_data = np.loadtxt(os.path.join(data_path, "c_PLP0016607.dat"), delimiter=",") + data_path = pathlib.Path(__file__).parents[1] / "data" + D2O_data = np.loadtxt(data_path / "c_PLP0016596.dat", delimiter=",") + SMW_data = np.loadtxt(data_path / "c_PLP0016601.dat", delimiter=",") + H2O_data = np.loadtxt(data_path / "c_PLP0016607.dat", delimiter=",") # Add the data to the project - note this data has a resolution 4th column problem.data.append(name="Bilayer / D2O", data=D2O_data) @@ -74,7 +75,7 @@ def DSPC_custom_XY(): name="DSPC Model", filename="custom_XY_DSPC.py", language="python", - path=pathlib.Path(__file__).parent.resolve(), + path=pathlib.Path(__file__).parent, ) # Also, add the relevant background parameters - one each for each contrast: @@ -91,11 +92,11 @@ def DSPC_custom_XY(): problem.background_parameters.append(name="Background parameter H2O", min=0.0, 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") - problem.backgrounds.append(name="Background H2O", type="constant", value_1="Background parameter H2O") + problem.backgrounds.append(name="Background SMW", type="constant", source="Background parameter SMW") + problem.backgrounds.append(name="Background H2O", type="constant", source="Background parameter H2O") # And edit the other one - problem.backgrounds.set_fields(0, name="Background D2O", value_1="Background parameter D2O") + problem.backgrounds.set_fields(0, name="Background D2O", source="Background parameter D2O") # Finally modify some of the other parameters to be more suitable values for a solid / liquid experiment problem.scalefactors.set_fields(0, value=1.0, min=0.5, max=2.0, fit=True) diff --git a/ratapi/examples/normal_reflectivity/DSPC_custom_layers.ipynb b/ratapi/examples/normal_reflectivity/DSPC_custom_layers.ipynb new file mode 100644 index 00000000..b90c4aa3 --- /dev/null +++ b/ratapi/examples/normal_reflectivity/DSPC_custom_layers.ipynb @@ -0,0 +1,349 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "4b988c4a-3a09-4b75-8a87-8ba8402635ba", + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "\n", + "import numpy as np\n", + "from IPython.display import Code\n", + "\n", + "import ratapi as RAT\n", + "from ratapi.models import Parameter" + ] + }, + { + "cell_type": "markdown", + "id": "793d9c50-698e-438b-87f7-85e3a9f11d6b", + "metadata": {}, + "source": [ + "# Custom Layers Example for Supported DSPC layer\n", + "\n", + "Example of using Custom layers to model a DSPC supported bilayer.\n", + "Start by making the project and setting it to a custom layers type:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a60cd45-0e1d-448a-b4bd-4c02bd6a3475", + "metadata": {}, + "outputs": [], + "source": [ + "problem = RAT.Project(name=\"Orso lipid example - custom layers\", model=\"custom layers\", geometry=\"substrate/liquid\")\n", + "problem.show_priors()" + ] + }, + { + "cell_type": "markdown", + "id": "9cc56e51-3d52-460a-bbb1-6d68571887c6", + "metadata": {}, + "source": [ + "For a custom layers model, rather than being forced to define our layers as \\[Thick SLD Rough.... etc\\], we can parameterise however we like and then use a function to calculate the \\[d $\\rho$ $\\sigma$\\] arrangement for each layer. So for example, if the volume of lipid tails are known (from the literature), then all we need is the Area per molecule, because then:\n", + "\n", + "$$\n", + "d = \\frac{V}{APM},\n", + "$$\n", + "where d is the thickness and V is the volume.\n", + "\n", + "Likewise, the SLD is:\n", + "$$\n", + "\\rho = \\frac{\\sum_{i}n_{i}b_{i}}{V},\n", + "$$\n", + "\n", + "as usual.\n", + "\n", + "In this folder there is a pre-prepared Python custom model for a DSPC on a Silicon substrate. We can display it here to see what we mean:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9038b77f-e3fc-4946-87fe-af4addf8ee84", + "metadata": {}, + "outputs": [], + "source": [ + "Code(filename='custom_bilayer_DSPC.py', language='python')" + ] + }, + { + "cell_type": "markdown", + "id": "002b67c8-1091-4544-9325-58227a012e4e", + "metadata": {}, + "source": [ + "We need to add the parameters we are going to need to define the model (note that Substrate Roughness always exists as parameter 0 as before, and that we are setting a Gaussian prior on the Head Hydration here)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "70494ef9-6cc5-47dc-9d02-6506645de46b", + "metadata": {}, + "outputs": [], + "source": [ + "parameter_list = [\n", + " Parameter(name=\"Oxide Thickness\", min=5.0, value=20.0, max=60.0, fit=True),\n", + " Parameter(name=\"Oxide Hydration\", min=0.0, value=0.2, max=0.5, fit=True),\n", + " Parameter(name=\"Lipid APM\", min=45.0, value=55.0, max=65.0, fit=True),\n", + " Parameter(name=\"Head Hydration\", min=0.0, value=0.2, max=0.5, fit=True, prior_type='gaussian', mu=0.3, sigma=0.03),\n", + " Parameter(name=\"Bilayer Hydration\", min=0.0, value=0.1, max=0.2, fit=True),\n", + " Parameter(name=\"Bilayer Roughness\", min=2.0, value=4.0, max=8.0, fit=True),\n", + " Parameter(name=\"Water Thickness\", min=0.0, value=2.0, max=10.0, fit=True)\n", + "]\n", + "\n", + "problem.parameters.extend(parameter_list)\n", + "problem.parameters.set_fields(0, min=1.0, max=10.0)" + ] + }, + { + "cell_type": "markdown", + "id": "a11897b0-244b-46c2-8bcd-a3d65bd8fc5c", + "metadata": {}, + "source": [ + "Need to add the relevant Bulk SLD's. Change the bulk in from air to silicon, and add two additional water contrasts:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "453fe3d2-162a-42bb-91ee-b1d020ffd29e", + "metadata": {}, + "outputs": [], + "source": [ + "# Change the bulk in from air to silicon:\n", + "problem.bulk_in.set_fields(0, name=\"Silicon\", min=2.07e-6, value=2.073e-6, max=2.08e-6, fit=False)\n", + "\n", + "problem.bulk_out.append(name=\"SLD SMW\", min=1.0e-6, value=2.073e-6, max=3.0e-6, fit=True)\n", + "problem.bulk_out.append(name=\"SLD H2O\", min=-0.6e-6, value=-0.56e-6, max=-0.3e-6, fit=True)\n", + "\n", + "problem.bulk_out.set_fields(0, min=5.0e-6, fit=True)" + ] + }, + { + "cell_type": "markdown", + "id": "d767523b-70ab-42a9-b28f-cd013a8b177e", + "metadata": {}, + "source": [ + "Now add the datafiles. We have three datasets we need to consider - the bilayer against D2O, Silicon Matched water and H2O. Load these datafiles in and put them in the data block:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa4c1b96-3a1b-4aa6-8d61-68f24b0cb482", + "metadata": {}, + "outputs": [], + "source": [ + "# Read in the datafiles\n", + "data_path = pathlib.Path(\"../data\")\n", + "D2O_data = np.loadtxt(data_path / \"c_PLP0016596.dat\", delimiter=\",\")\n", + "SMW_data = np.loadtxt(data_path / \"c_PLP0016601.dat\", delimiter=\",\")\n", + "H2O_data = np.loadtxt(data_path / \"c_PLP0016607.dat\", delimiter=\",\")\n", + "\n", + "# Add the data to the project - note this data has a resolution 4th column\n", + "problem.data.append(name=\"Bilayer / D2O\", data=D2O_data, data_range=[0.013, 0.37])\n", + "problem.data.append(name=\"Bilayer / SMW\", data=SMW_data, data_range=[0.013, 0.32996])\n", + "problem.data.append(name=\"Bilayer / H2O\", data=H2O_data, data_range=[0.013, 0.33048])" + ] + }, + { + "cell_type": "markdown", + "id": "e60cd052-54f9-41b4-ab8b-6d4dde1c50fa", + "metadata": {}, + "source": [ + "Add the custom file to the project:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e649c26-b32b-4c79-8ae7-fa701c87e6c2", + "metadata": {}, + "outputs": [], + "source": [ + "problem.custom_files.append(name=\"DSPC Model\", filename=\"custom_bilayer_DSPC.py\", language=\"python\", path=pathlib.Path.cwd().resolve())" + ] + }, + { + "cell_type": "markdown", + "id": "19a57f11-3d3c-49c5-b7a6-52bf449a3878", + "metadata": {}, + "source": [ + "Also, add the relevant background parameters - one each for each contrast:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5d51954f-469a-4044-9a7d-1b6e30474a6b", + "metadata": {}, + "outputs": [], + "source": [ + "problem.background_parameters.set_fields(0, name=\"Background parameter D2O\", min=1.0e-10, max=1.0e-5, value=1.0e-07, fit=True)\n", + "\n", + "problem.background_parameters.append(name=\"Background parameter SMW\", min=1.0e-10, value=1.0e-7, max=1.0e-5, fit=True)\n", + "problem.background_parameters.append(name=\"Background parameter H2O\", min=1.0e-10, value=1.0e-7, max=1.0e-5, fit=True)\n", + "\n", + "# And add the two new constant backgrounds\n", + "problem.backgrounds.append(name=\"Background SMW\", type=\"constant\", source=\"Background parameter SMW\")\n", + "problem.backgrounds.append(name=\"Background H2O\", type=\"constant\", source=\"Background parameter H2O\")\n", + "\n", + "# And edit the other one\n", + "problem.backgrounds.set_fields(0, name=\"Background D2O\", source=\"Background parameter D2O\")\n", + "\n", + "# Finally modify some of the other parameters to be more suitable values for a solid / liquid experiment\n", + "problem.scalefactors.set_fields(0, value=1.0, min=0.5, max=2.0, fit=True)" + ] + }, + { + "cell_type": "markdown", + "id": "a69a6d51-202a-4834-a6be-5c30f67d9107", + "metadata": {}, + "source": [ + "We need to use the data resolution (i.e. the fourth column of our datafiles). Do do this, we need to add a 'Data' resolution object to our resolutions table" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1e4d313-8450-459b-b60e-868fe82f06b0", + "metadata": {}, + "outputs": [], + "source": [ + "problem.resolutions.append(name=\"Data Resolution\", type=\"data\")" + ] + }, + { + "cell_type": "markdown", + "id": "ddde7088-1382-4f56-9e05-6f1683ec2260", + "metadata": {}, + "source": [ + "Now add the three contrasts as before:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efc7b351-2112-40c4-862b-a47e4570d173", + "metadata": {}, + "outputs": [], + "source": [ + "problem.contrasts.append(\n", + " name=\"Bilayer / D2O\",\n", + " background=\"Background D2O\",\n", + " resolution=\"Data Resolution\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_out=\"SLD D2O\",\n", + " bulk_in=\"Silicon\",\n", + " data=\"Bilayer / D2O\",\n", + " model=[\"DSPC Model\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"Bilayer / SMW\",\n", + " background=\"Background SMW\",\n", + " resolution=\"Data Resolution\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_out=\"SLD SMW\",\n", + " bulk_in=\"Silicon\",\n", + " data=\"Bilayer / SMW\",\n", + " model=[\"DSPC Model\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"Bilayer / H2O\",\n", + " background=\"Background H2O\",\n", + " resolution=\"Data Resolution\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_out=\"SLD H2O\",\n", + " bulk_in=\"Silicon\",\n", + " data=\"Bilayer / H2O\",\n", + " model=[\"DSPC Model\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "89f110e4-c3f8-488d-91d5-4f5fb5fbe9d7", + "metadata": {}, + "source": [ + "Note that the model is simply the custom file we've just added to the project.\n", + "\n", + "Look at the complete model definition before sending it to RAT:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee889e55-8357-4363-860d-fb1c13bb8e8b", + "metadata": {}, + "outputs": [], + "source": [ + "print(problem)" + ] + }, + { + "cell_type": "markdown", + "id": "861b6e03-773a-46c3-b3fd-0df47c99d27e", + "metadata": {}, + "source": [ + "To run it, we need to make a controls block" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "154a33df-06b9-4035-aa4c-a0e095c1bb06", + "metadata": {}, + "outputs": [], + "source": [ + "controls = RAT.Controls()\n", + "print(controls)" + ] + }, + { + "cell_type": "markdown", + "id": "384f0a34-1a2b-40f7-a945-6d44db9391ab", + "metadata": {}, + "source": [ + ". . . and send this to RAT" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5d9a782-0fb1-40b6-b1fa-86307abe32a6", + "metadata": {}, + "outputs": [], + "source": [ + "problem, results = RAT.run(problem, controls)\n", + "RAT.plotting.plot_ref_sld(problem, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/RATapi/examples/non_polarised/DSPC_custom_layers.py b/ratapi/examples/normal_reflectivity/DSPC_custom_layers.py similarity index 86% rename from RATapi/examples/non_polarised/DSPC_custom_layers.py rename to ratapi/examples/normal_reflectivity/DSPC_custom_layers.py index 1b88ebd3..8de14903 100644 --- a/RATapi/examples/non_polarised/DSPC_custom_layers.py +++ b/ratapi/examples/normal_reflectivity/DSPC_custom_layers.py @@ -1,16 +1,14 @@ -import os +"""Example of using custom layers to model a DSPC supported bilayer.""" + import pathlib import numpy as np -import RATapi as RAT +import ratapi as RAT def DSPC_custom_layers(): - """Custom Layers example for Supported DSPC layer. - - Example of using custom layers to model a DSPC supported bilayer. - """ + """Calculate a Custom Layers example for a supported DSPC layer.""" 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 @@ -39,10 +37,10 @@ def DSPC_custom_layers(): # Water and H2O. Load these datafiles in and put them in the data block # Read in the datafiles - data_path = os.path.join(pathlib.Path(__file__).parents[1].resolve(), "data") - D2O_data = np.loadtxt(os.path.join(data_path, "c_PLP0016596.dat"), delimiter=",") - SMW_data = np.loadtxt(os.path.join(data_path, "c_PLP0016601.dat"), delimiter=",") - H2O_data = np.loadtxt(os.path.join(data_path, "c_PLP0016607.dat"), delimiter=",") + data_path = pathlib.Path(__file__).parents[1] / "data" + D2O_data = np.loadtxt(data_path / "c_PLP0016596.dat", delimiter=",") + SMW_data = np.loadtxt(data_path / "c_PLP0016601.dat", delimiter=",") + H2O_data = np.loadtxt(data_path / "c_PLP0016607.dat", delimiter=",") # Add the data to the project - note this data has a resolution 4th column problem.data.append(name="Bilayer / D2O", data=D2O_data, data_range=[0.013, 0.37]) @@ -54,7 +52,7 @@ def DSPC_custom_layers(): name="DSPC Model", filename="custom_bilayer_DSPC.py", language="python", - path=pathlib.Path(__file__).parent.resolve(), + path=pathlib.Path(__file__).parent, ) # Also, add the relevant background parameters - one each for each contrast: @@ -75,11 +73,11 @@ def DSPC_custom_layers(): ) # And add the two new constant backgrounds - problem.backgrounds.append(name="Background SMW", type="constant", value_1="Background parameter SMW") - problem.backgrounds.append(name="Background H2O", type="constant", value_1="Background parameter H2O") + problem.backgrounds.append(name="Background SMW", type="constant", source="Background parameter SMW") + problem.backgrounds.append(name="Background H2O", type="constant", source="Background parameter H2O") # And edit the other one - problem.backgrounds.set_fields(0, name="Background D2O", value_1="Background parameter D2O") + problem.backgrounds.set_fields(0, name="Background D2O", source="Background parameter D2O") # Finally modify some of the other parameters to be more suitable values for a solid / liquid experiment problem.scalefactors.set_fields(0, value=1.0, min=0.5, max=2.0, fit=True) diff --git a/ratapi/examples/normal_reflectivity/DSPC_custom_xy.ipynb b/ratapi/examples/normal_reflectivity/DSPC_custom_xy.ipynb new file mode 100644 index 00000000..0c0472c9 --- /dev/null +++ b/ratapi/examples/normal_reflectivity/DSPC_custom_xy.ipynb @@ -0,0 +1,284 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "956a341a-2a40-466c-b5c4-f8ea334ee81c", + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "\n", + "import numpy as np\n", + "from IPython.display import Code\n", + "\n", + "import ratapi as RAT\n", + "from ratapi.models import Parameter" + ] + }, + { + "attachments": { + "bf3e4c3d-0fc8-4565-8f2d-f4f8386d582c.png": { + "image/png": "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" + } + }, + "cell_type": "markdown", + "id": "2c6e70fd-f282-47e6-b310-8f4a3e305b7e", + "metadata": {}, + "source": [ + "# Custom XY Example for Supported DSPC layer.\n", + "\n", + "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 Shekhar et al, *J. Appl. Phys.*, **110**, 102216 (2011).)\n", + "\n", + "In this type of model, each 'layer' in the sample is described by a roughened Heaviside step function (really, just two error functions back to back). So, in our case, we will need an oxide, a (possible) intervening water layer, and then the bilayer itself.\n", + "\n", + "We can define our lipid in terms of an Area per Molecule, almost in it's entirity, if we recognise that where the volume is known, the thickness of the layer is simply given by the layer volume / APM\n", + "$$\n", + "d = \\frac{V}{APM}.\n", + "$$\n", + "We can then define the Volume Fraction of this layer with a roughened Heaviside of length dlayer and a height of 1. Then, the total volume occupied will be given by the sum of the volume fractions across the interface. Of course, this 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\n", + "$$\n", + "VF_{water} = 1 - \\sum_{n}VF_{n},\n", + "$$\n", + "where $VF_{n}$ is the Volume Fraction of the n'th layer.\n", + "![image.png](attachment:bf3e4c3d-0fc8-4565-8f2d-f4f8386d582c.png)\n", + "Start by making the class and setting it to a custom XY type:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d53c3ea9-b06f-4bf1-b7cc-da2264ca7322", + "metadata": {}, + "outputs": [], + "source": [ + "problem = RAT.Project(name=\"Orso lipid example - custom XY\", model=\"custom xy\", geometry=\"substrate/liquid\")" + ] + }, + { + "cell_type": "markdown", + "id": "f73d2471-a59c-4394-bd9f-7bed3f7f6057", + "metadata": {}, + "source": [ + "We need to add the relevant parameters we are going to need to define the model (note that Substrate Roughness always exists as parameter 0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ba58003-096e-45cb-b384-f82d66259fed", + "metadata": {}, + "outputs": [], + "source": [ + "parameter_list = [\n", + " Parameter(name=\"Oxide Thickness\", min=10.0, value=15.0, max=30.0, fit=True),\n", + " Parameter(name=\"Oxide Hydration\", min=0.1, value=0.2, max=0.4, fit=True),\n", + " Parameter(name=\"Water Thickness\", min=0.0, value=5.0, max=20.0, fit=True),\n", + " Parameter(name=\"Lipid APM\", min=40.0, value=50.0, max=90.0, fit=True),\n", + " Parameter(name=\"Lipid Coverage\", min=0.9, value=1.0, max=1.0, fit=True),\n", + " Parameter(name=\"Bilayer Roughness\", min=3.0, value=5.0, max=8.0, fit=True)\n", + "]\n", + "\n", + "problem.parameters.extend(parameter_list)\n", + "\n", + "problem.parameters.set_fields(0, min=1.0, max=10.0)" + ] + }, + { + "cell_type": "markdown", + "id": "b1fe7c6e-2200-4c83-9485-ec3590e950d5", + "metadata": {}, + "source": [ + "Need to add the relevant Bulk SLDs. Change the bulk in from air to silicon, and add two additional water contrasts:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0ef585b-4893-440b-9e63-6dcc8102d4c6", + "metadata": {}, + "outputs": [], + "source": [ + "# Change the bulk in from air to silicon\n", + "problem.bulk_in.set_fields(0, name=\"Silicon\", min=2.07e-6, value=2.073e-6, max=2.08e-6, fit=False)\n", + "\n", + "problem.bulk_out.append(name=\"SLD SMW\", min=1.0e-6, value=2.073e-6, max=3.0e-6, fit=True)\n", + "problem.bulk_out.append(name=\"SLD H2O\", min=-0.6e-6, value=-0.56e-6, max=-0.3e-6, fit=True)\n", + "\n", + "problem.bulk_out.set_fields(0, min=5.0e-6, value=6.1e-6, fit=True)" + ] + }, + { + "cell_type": "markdown", + "id": "643dd278-57d7-4756-b568-824e0b3cb2d5", + "metadata": {}, + "source": [ + "Now add our datafiles:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "372cf5bc-5ec5-4e96-8ade-05a8b0baa3a2", + "metadata": {}, + "outputs": [], + "source": [ + "# Read in the datafiles\n", + "data_path = pathlib.Path(\"../data\")\n", + "D2O_data = np.loadtxt(data_path / \"c_PLP0016596.dat\", delimiter=\",\")\n", + "SMW_data = np.loadtxt(data_path / \"c_PLP0016601.dat\", delimiter=\",\")\n", + "H2O_data = np.loadtxt(data_path / \"c_PLP0016607.dat\", delimiter=\",\")\n", + "\n", + "# Add the data to the project - note this data has a resolution 4th column\n", + "problem.data.append(name=\"Bilayer / D2O\", data=D2O_data)\n", + "problem.data.append(name=\"Bilayer / SMW\", data=SMW_data)\n", + "problem.data.append(name=\"Bilayer / H2O\", data=H2O_data)" + ] + }, + { + "cell_type": "markdown", + "id": "7f4a1730-f6af-40f4-b1dc-1d76eeaaa08e", + "metadata": {}, + "source": [ + "Add the custom file to the project. We can view the code first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60a4b771-7967-4b46-bd3c-1c7cb4eaa24b", + "metadata": {}, + "outputs": [], + "source": [ + "Code(\"custom_XY_DSPC.py\")\n", + "problem.custom_files.append(name=\"DSPC Model\", filename=\"custom_XY_DSPC.py\", language=\"python\", path=pathlib.Path.cwd().resolve())" + ] + }, + { + "cell_type": "markdown", + "id": "c4157f30-47c0-476c-b9d3-736f0af21e79", + "metadata": {}, + "source": [ + "Add and modify the remaining parameters - backgrounds, scalefactors, and resolutions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57303283-9319-4b1c-817b-04d6441a2992", + "metadata": {}, + "outputs": [], + "source": [ + "problem.background_parameters.set_fields(0, name=\"Background parameter D2O\", fit=True, min=1.0e-10, max=1.0e-5, value=1.0e-07)\n", + "\n", + "problem.background_parameters.append(name=\"Background parameter SMW\", min=0.0, value=1.0e-7, max=1.0e-5, fit=True)\n", + "problem.background_parameters.append(name=\"Background parameter H2O\", min=0.0, value=1.0e-7, max=1.0e-5, fit=True)\n", + "\n", + "# And add the two new constant backgrounds\n", + "problem.backgrounds.append(name=\"Background SMW\", type=\"constant\", source=\"Background parameter SMW\")\n", + "problem.backgrounds.append(name=\"Background H2O\", type=\"constant\", source=\"Background parameter H2O\")\n", + "\n", + "# And edit the other one\n", + "problem.backgrounds.set_fields(0, name=\"Background D2O\", source=\"Background parameter D2O\")\n", + "\n", + "# Finally modify some of the other parameters to be more suitable values for a solid / liquid experiment\n", + "problem.scalefactors.set_fields(0, value=1.0, min=0.5, max=2.0, fit=True)\n", + "\n", + "# Also, we are going to use the data resolution\n", + "problem.resolutions.append(name=\"Data Resolution\", type=\"data\")" + ] + }, + { + "cell_type": "markdown", + "id": "d941b284-13b0-4866-90c7-765fb2dc4ed1", + "metadata": {}, + "source": [ + "Now add the three contrasts as before:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6815648e-ad4a-4193-ba39-83f5f15781b1", + "metadata": {}, + "outputs": [], + "source": [ + "problem.contrasts.append(\n", + " name=\"Bilayer / D2O\",\n", + " background=\"Background D2O\",\n", + " resolution=\"Data Resolution\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_out=\"SLD D2O\",\n", + " bulk_in=\"Silicon\",\n", + " data=\"Bilayer / D2O\",\n", + " model=[\"DSPC Model\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"Bilayer / SMW\",\n", + " background=\"Background SMW\",\n", + " resolution=\"Data Resolution\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_out=\"SLD SMW\",\n", + " bulk_in=\"Silicon\",\n", + " data=\"Bilayer / SMW\",\n", + " model=[\"DSPC Model\"],\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"Bilayer / H2O\",\n", + " background=\"Background H2O\",\n", + " resolution=\"Data Resolution\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " bulk_out=\"SLD H2O\",\n", + " bulk_in=\"Silicon\",\n", + " data=\"Bilayer / H2O\",\n", + " model=[\"DSPC Model\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ca0e6c93-e617-482c-b8bd-41dc0df4f586", + "metadata": {}, + "source": [ + "## Running the Model\n", + "\n", + "We do this by first making a controls block as previously. We'll run a Differential Evolution:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "821571d9-3593-4ac6-a5db-4d83998ff4db", + "metadata": {}, + "outputs": [], + "source": [ + "controls = RAT.Controls(procedure=\"de\", parallel=\"contrasts\", display=\"final\")\n", + "problem, results = RAT.run(problem, controls)\n", + "RAT.plotting.plot_ref_sld(problem, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/ratapi/examples/normal_reflectivity/DSPC_data_background.py b/ratapi/examples/normal_reflectivity/DSPC_data_background.py new file mode 100644 index 00000000..11a14730 --- /dev/null +++ b/ratapi/examples/normal_reflectivity/DSPC_data_background.py @@ -0,0 +1,220 @@ +"""A standard layers example with a data background.""" + +import pathlib + +import numpy as np + +import ratapi as RAT + + +def DSPC_data_background(): + """Calculate a Standard Layers fit of a DSPC floating bilayer with a data background.""" + problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") + + # Set up the relevant parameters + problem.parameters.append(name="Oxide Thickness", min=5.0, value=19.54, max=60.0, fit=True) + problem.parameters.append(name="Oxide SLD", min=3.39e-06, value=3.39e-06, max=3.41e-06, fit=False) + problem.parameters.append(name="SAM Tails Thickness", min=15.0, value=22.66, max=35.0, fit=True) + problem.parameters.append(name="SAM Tails SLD", min=-5e-07, value=-4.01e-07, max=-3e-07, fit=False) + problem.parameters.append(name="SAM Tails Hydration", min=1.0, value=5.252, max=50.0, fit=True) + problem.parameters.append(name="SAM Roughness", min=1.0, value=5.64, max=15.0, fit=True) + problem.parameters.append(name="CW Thickness", min=10.0, value=17.12, max=28.0, fit=True) + problem.parameters.append(name="CW SLD", min=0.0, value=0.0, max=1e-09, fit=False) + + 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) + problem.parameters.append( + name="SAM Heads Hydration", + min=10.0, + value=45.45, + max=50.0, + fit=True, + prior_type="gaussian", + 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) + problem.parameters.append(name="Bilayer Roughness", min=2.0, value=6.014, max=15.0, fit=True) + problem.parameters.append(name="Bilayer Tails Thickness", min=14.0, value=17.82, max=22.0, fit=True) + problem.parameters.append(name="Bilayer Tails SLD", min=-5.0e-07, value=-4.61e-07, max=0.0, fit=False) + problem.parameters.append(name="Bilayer Tails Hydration", min=10.0, value=17.64, max=50.0, fit=True) + problem.parameters.append(name="Bilayer Heads Hydration", min=10.0, value=36.15, max=50.0, fit=True) + problem.parameters.append(name="CW Hydration", min=99.9, value=100.0, max=100.0, fit=False) + problem.parameters.append(name="Oxide Hydration", min=0.0, value=23.61, max=60.0, fit=True) + + 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="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="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 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] + problem.bulk_in.append(name="Silicon", min=2.0e-06, value=2.073e-06, max=2.1e-06, fit=False) + + del problem.bulk_out[0] + problem.bulk_out.append(name="D2O", min=5.50e-06, value=5.98e-06, max=6.4e-06, fit=True) + problem.bulk_out.append(name="SMW", min=1.0e-06, value=2.21e-06, max=4.99e-06, fit=True) + + # Set the scalefactors - use one for each contrast + del problem.scalefactors[0] + problem.scalefactors.append(name="Scalefactor 1", min=0.05, value=0.10, max=0.2, fit=False) + problem.scalefactors.append(name="Scalefactor 2", min=0.05, value=0.15, max=0.2, fit=False) + + # Now deal with the backgrounds + # SMW has a constant background + del problem.backgrounds[0] + del problem.background_parameters[0] + 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="SMW Background", type="constant", source="Background parameter SMW") + + data_path = pathlib.Path(__file__).parents[1] / "data" + + # load in background data for D2O + d2o_background = np.loadtxt(data_path / "d2o_background_data.dat") + problem.data.append(name="D2O Background Data", data=d2o_background) + + # add background parameter for the offset + problem.background_parameters.append( + name="D2O Data Offset", + min=-1e-8, + value=0, + max=1e-8, + fit=True, + ) + + # add the background with data and offset + problem.backgrounds.append( + name="D2O Data Background", + type="data", + source="D2O Background Data", + value_1="D2O Data Offset", + ) + + # Now add the data + d2o_dat = np.loadtxt(data_path / "DSPC_D2O.dat", delimiter=",") + problem.data.append(name="dspc_bil_D2O", data=d2o_dat) + + smw_dat = np.loadtxt(data_path / "DSPC_SMW.dat", delimiter=",") + 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", + ] + + # Then make the two contrasts + problem.contrasts.append( + name="D2O", + bulk_in="Silicon", + bulk_out="D2O", + background="D2O Data 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, + ) + + controls = RAT.Controls() + problem, results = RAT.run(problem, controls) + + return problem, results + + +if __name__ == "__main__": + problem, results = DSPC_data_background() + RAT.plotting.plot_ref_sld(problem, results, True) diff --git a/ratapi/examples/normal_reflectivity/DSPC_function_background.py b/ratapi/examples/normal_reflectivity/DSPC_function_background.py new file mode 100644 index 00000000..e6a87b69 --- /dev/null +++ b/ratapi/examples/normal_reflectivity/DSPC_function_background.py @@ -0,0 +1,219 @@ +"""A standard layers example with a function background.""" + +import pathlib + +import numpy as np + +import ratapi as RAT + + +def DSPC_function_background(): + """Calculate a standard Layers fit of a DSPC floating bilayer with a function background.""" + problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") + + # Set up the relevant parameters + problem.parameters.append(name="Oxide Thickness", min=5.0, value=19.54, max=60.0, fit=True) + problem.parameters.append(name="Oxide SLD", min=3.39e-06, value=3.39e-06, max=3.41e-06, fit=False) + problem.parameters.append(name="SAM Tails Thickness", min=15.0, value=22.66, max=35.0, fit=True) + problem.parameters.append(name="SAM Tails SLD", min=-5e-07, value=-4.01e-07, max=-3e-07, fit=False) + problem.parameters.append(name="SAM Tails Hydration", min=1.0, value=5.252, max=50.0, fit=True) + problem.parameters.append(name="SAM Roughness", min=1.0, value=5.64, max=15.0, fit=True) + problem.parameters.append(name="CW Thickness", min=10.0, value=17.12, max=28.0, fit=True) + problem.parameters.append(name="CW SLD", min=0.0, value=0.0, max=1e-09, fit=False) + + 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) + problem.parameters.append( + name="SAM Heads Hydration", + min=10.0, + value=45.45, + max=50.0, + fit=True, + prior_type="gaussian", + 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) + problem.parameters.append(name="Bilayer Roughness", min=2.0, value=6.014, max=15.0, fit=True) + problem.parameters.append(name="Bilayer Tails Thickness", min=14.0, value=17.82, max=22.0, fit=True) + problem.parameters.append(name="Bilayer Tails SLD", min=-5.0e-07, value=-4.61e-07, max=0.0, fit=False) + problem.parameters.append(name="Bilayer Tails Hydration", min=10.0, value=17.64, max=50.0, fit=True) + problem.parameters.append(name="Bilayer Heads Hydration", min=10.0, value=36.15, max=50.0, fit=True) + problem.parameters.append(name="CW Hydration", min=99.9, value=100.0, max=100.0, fit=False) + problem.parameters.append(name="Oxide Hydration", min=0.0, value=23.61, max=60.0, fit=True) + + 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="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="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 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] + problem.bulk_in.append(name="Silicon", min=2.0e-06, value=2.073e-06, max=2.1e-06, fit=False) + + del problem.bulk_out[0] + problem.bulk_out.append(name="D2O", min=5.50e-06, value=5.98e-06, max=6.4e-06, fit=True) + problem.bulk_out.append(name="SMW", min=1.0e-06, value=2.21e-06, max=4.99e-06, fit=True) + + # Set the scalefactors - use one for each contrast + del problem.scalefactors[0] + problem.scalefactors.append(name="Scalefactor 1", min=0.05, value=0.10, max=0.2, fit=False) + problem.scalefactors.append(name="Scalefactor 2", min=0.05, value=0.15, max=0.2, fit=False) + + # Now deal with the backgrounds + # SMW has a constant background + del problem.backgrounds[0] + del problem.background_parameters[0] + 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="SMW Background", type="constant", source="Background parameter SMW") + + problem.custom_files.append( + name="D2O Background Function", + filename="background_function.py", + language="python", + path=pathlib.Path(__file__).parent, + ) + + problem.background_parameters.append(name="Fn Ao", min=5e-7, value=8e-6, max=5e-5) + problem.background_parameters.append(name="Fn k", min=40, value=70, max=90) + problem.background_parameters.append(name="Fn Const", min=1e-7, value=8e-6, max=1e-5) + + problem.backgrounds.append( + name="D2O Function Background", + type="function", + source="D2O Background Function", + value_1="Fn Ao", + value_2="Fn k", + value_3="Fn Const", + ) + + # Now add the data + data_path = pathlib.Path(__file__).parents[1] / "data" + + d2o_dat = np.loadtxt(data_path / "DSPC_D2O.dat", delimiter=",") + problem.data.append(name="dspc_bil_D2O", data=d2o_dat) + + smw_dat = np.loadtxt(data_path / "DSPC_SMW.dat", delimiter=",") + 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", + ] + + # Then make the two contrasts + problem.contrasts.append( + name="D2O", + bulk_in="Silicon", + bulk_out="D2O", + background="D2O Function 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, + ) + + controls = RAT.Controls() + problem, results = RAT.run(problem, controls) + + return problem, results + + +if __name__ == "__main__": + problem, results = DSPC_function_background() + RAT.plotting.plot_ref_sld(problem, results, True) diff --git a/ratapi/examples/normal_reflectivity/DSPC_standard_layers.ipynb b/ratapi/examples/normal_reflectivity/DSPC_standard_layers.ipynb new file mode 100644 index 00000000..3110cfe5 --- /dev/null +++ b/ratapi/examples/normal_reflectivity/DSPC_standard_layers.ipynb @@ -0,0 +1,337 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "1ca14405-4a7c-4588-93cd-46534c374a36", + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "\n", + "import numpy as np\n", + "\n", + "import ratapi as RAT\n", + "from ratapi.models import Layer, Parameter" + ] + }, + { + "attachments": { + "e72d4765-3d29-4d8b-a0c5-2b9ba546588c.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQAAAAECCAYAAAARugltAACAAElEQVR42uy9Z3Dd15Xl69cf5lV11euZ19Ntu9t2P4+n7W7bSgxgFoNIMSdJFHMSCeYkijmTAAEQYM45k2DOGZmZkkgxSKIky0m2RFKSJXfPm6n+8mrOO791zrm4BO8FLizApnShqlsUARC4+J+z09prr/2tb33N/vuH2p3Gf79ul//v+3U6m0q/6nYxP6jb5Y9///P2bSv7cxsPWPLz+n2yG9Tpv+CfvlXz35/hP/N/NBiY9cMGA3IaNxi4sHm9/pk/+fnLc/9TzXOp4v+Kv0b/lZSUFNdp0//Lf6jV0fxDrU7G/Zn46x/tv/nO0+1N59RZv7t498vis9c/Ls57K/aLzxXcul989MpvijuNW38lpfeC/1G394L/ndIn6+O2o9ZcXHX4zeKiWw+K82/ef+j78P98rOjOg+IT135bvOnEreIle64WrzjwRnFuwXvFBf5zeW/dK/fnJ9tLz9s+mzNv/r44fUtxcfPBy67V67PgXoN+OabhgEWmfr/sP9j/v/HK3D3FRy792p7Ng5rnVwWvb12+fNl8XV5XrlwxjToNNt99uoPpPWi0GT52ohk6ekJCrxH2azv0HGL+68/bmA6D5pj8W5+bi+/90RS/8wdT/Pajr/PvfmnO3XxgUjMOmrp9FppWw1eZ7lO2mRZDV5i6vXNMsyErTMb2S+bsjfvm/N0vI//uwt0/mpNvfGLStl4wL0/dYf/danuBF5tnBy0zHcZtMK+k7TcrDt2wP/cL+zO+iPmzk/HFczv15j0zJPOQafLKMtOg/yLTZPAK8+zQNabp0LWmSepK02jgEr1emrzNbDn7rju/mmf3lV5kAObr8rIZgGnYcZAcwPiJU8z89DSTNm9eQq/M+emm39Cx5ttPtTM/avaKNc7tZvPJ28ZGeZN/8545d+OTyMtGZ3Pm+sdmWOZB83T3+abH1G1mT+H7+rrcwvfM+CXHTbPBS83TL883Pe3nDl/6tSm89cAU3n5g1h19y7QbvcbU6ZlhbNZgGg9aoQv87BAcwVL78UzTqP9CYyOZOXL518ZGvYd+djK+eK42qpve03eY2va54TBbvZprOs0+a7rMKzJd04pN5znnTIfpJ/QsebbPDVmu8+O5V+pn2bPlnHRe/sV5J+uz/9o6gLGvTTbz5s01c+bMSeiVnjbP9EkdIwfwr62G2KiebUgvZ63LM8eu/MYU3S69CMV3PjWTV5wyz3TPMM8PX2kOXfilufDO57o4JW9/Zi7e/YPZePyWaTl0uRzEC69tMvuKf2E/dtO0sBezbq9Ma/CrTNvJh03nufm6wF3mFepCt5l0UBe8do/5pveMnebEtY+S+gLy4rmOXXTM1LLPstHApaa9NfSu6faZpRXpublXcAR5pvmIjXICPadtN6fe+H3CThRnf/jir8yMtefMgNm7zbjFx8zSvVfNmTc/fuj8axzAN9gB/O3PWpvOQ+aaqavPmYY2Ej/VLd28NGmzWZR7xZx8/SNdkgU7Lpj6fXPkIJbYC7Iz764ZkXXQDJiTax3DabPxxC05iX0lvzAD5+aaWj0yTOsRq8xz1iGk9M40zYZv0EUNhh952QvNxW4/7bhpbNNcot3sDfm6fMkc/Q+UfGia24yKZ95uytFHn1vUq6t9hp3ss208aLnOp+trG5V1VfQM862TwJF3n7zVOvb5kRcZWbdJWyKOIP8rOgF+n0czjBoH8Ng4gP/7p8+bnmOzzNVf/LtZe+SGedleiNr2EtTrs8B0HLtOl6Fu7yx7uRaaxdYpcLmapbp0n4yAP7l4g9P2KnPgYo3KPmyjfpZSfiJ/Jxl/UfxLbJ1AuylH9DPbjVqj9DdZswCMBeeb0ifLNBu2XpE+3nOLfn7Pj99jHUa2qWOfO+XA+mPxnQDP9tQbvzPdbbnG+XV6db3OPn2Ldcaj10YcweicI+bsdZcphIyhbHlYfobxwBw8/0uViP1m7zKv2j+X7bv20PeM98JJkMmEUpKv/3PciaRzAICATbpPNFtOv6MoTq0/b1OR6TFlm+r6utaIWw5dYRbuvmw2n7rto3qWeW3ZCbPm8Jv2UI/p68gcuk/Zag6c/1BR44UJm/R1rV/bay9oSYWXuEtaoepZyoWMbedNkX0vyegA+L2nrjqjlL7l2B3lOs7oLIAyAUeME8CBByfAmZY1HAyTM67dI9O0siXd9rPvqJTjZx+/+lszZ0OBcBmcwEsTN5tNPsObs7HArDjwhjn/9ucVGiNGm1v4voLIMyFY4FisgyLIbDl9xzqoT2M6J/7tmTd/b3IL3tfvQNDZce5dc8K+N5xafjXiREmJAfz3ZoNUhxMBuARcBtK/PYUfWKO/Yw7aVPGsdQwd7GFi6GMWHrVf90CHUfz2p/aC3FbqSeTgQq069KacQYqN6KT3iV7iluN26eJPW302aR1AsX3245eesMaZbp5/bY+r/St0nkWmw8zTKhmI4GRjGB2OOXP7eTn1AA5iyCsPviFn0XjgIjn18+98rgjL1/B5DHOrNVDO8MmX0mw5t1J3o8nAxabNyNUqD7gP8coDDBQMiCCA4b8yb48NFtfNjHXnlOFxhygR1x+/+dA5E/FPvv47s2DnResktpgWqUuVfQpDemWx6TBmrZmw7KTZb0ukijKIGgeQoAP4+yfbmSfaDDf1+y9S9KCGJ4pzEfHEIY0cueCQIkKv6dvliaNTQS7OKXtwfA31P4fF5aJs6GgvZpe0xNLYVjaNBQx8zRoAPz9ZM4CZ6/JspMwwLUZvSdB5Fpu2kw4p4+o9Y4ei6PQ150yD/jk6j6GZB8zugvdksETS1iNX6eMTl580x23ZRjbXd9YuM3bRUWE8AIMX3v3cHLJ/pqbvEzZEVtHZlgqNBizUvx2z8IicQFlD5GdzZwan7TNPWOeBIZ+20RyngnPhbg2Ys1uZAN9r7qZCfQ/+zd6iD+R0MHhejV5ZpqyQV6NXbObZJ9vUsg6l7ajVyloKqwErSkoM4MXh6dYb35ZXxjvzgAHjjl7+jYwbr8uhEwFo/xXEaDXhELgQo3MOy1HgTIgyIP+JXGJq3RYjN+vg0zYXJW0GgDFssJER42g4cInpNPtchTgAzrPF6K2mXp8s0zx1mU2bb6ozk73rkv0+i2ydn26d8hKl83yeTA1jP2iNEYPj80RqPo6hk0Uszr2s90O3J2vHBRv5VwmcBBDGsdTpFcqD2zLs0Hng/VMqcP5tbbbAfSGjjM4w9DUb3NcQ4Wetyze78t9TFgkQ3HjwCtN6wj4PHBc5oHN2nrLJZ1NX6X5xR7edeafK28ZJ6QC6j84wVz74N7PllEv7OFzAIQ6QQ+aQiAKkZuXVX0SY4AQAAQH1mo/YVC6KHYyfw278Ckh2tn0ft6stxfu6dAIG2TQeYyALUAYVx4nybNtM3G+NcqFA19o9HCdg1cE3ldoTKYek71f7lvPAiRPx9xBtp26V4QMGrjt6w+RYhwH3oJ41zGfs9+lnswIyBs48pN1E+K1n3lb34EkbLCgzXl18XN8P4164+1IEh1h54A2Vj7QXyTBCm5HfEaeAo6ds4efxnslgmg5Z40Hj4jKOz7c9rSMgUJApgiVw3/Ju3KtxAF/FAbw8KsNelj9EjG7FgddF6CFapHhkPtsafyIpF07g9Bu/N4v3XDGthq3QZWgz+VB8J+AvdnN7qHj2lydtUc2azFwAMiycMaUURtFi1BbTeW6BnmH0q4v92POv7ZVzJnMau/CoevoAt2RfGFyo+0HjMdxcT+CCePVktzTV6ZRvpOik4Zxd9s5Lpv2YNcoMmts6HMfPeUxaccrk2P+/8v6X5tCFX5nBtjzg55A18nUEDzIOznHKytM2Qr8tzIDvQwYJCFi7l2szAgJetGVG+pYiAY44J1iNlIzltz2LlRXBiuTZgDdVZSmQ1A4gtF+4CHhWarKtp99WW64yqRaXpfjOZ6pDuQxEJ1K6shdYhznrrDw6h9nYXh4AqsIk5gFElwLU4xhWfSK3TX1bjt1pa/2Dapli+E2HrlG7MLTszl13BJ7M7RfkFMjihszfL7YmToCMoOQdIm+xMjSygu3n3nmIPaga3n4t9T//FgOn7gYLAOBtYp3ShKUnvGP5TCAxoCPOPkUdo+X23M/K0ZCm896G2u9Dm3Hm+jyVF097gHKydRKcNW1jsRlHb0sI9OyaVmJajdupDIl/W5XZYtI7gOg+LKmfer9vPUoN5tK4uu6+DjHW19DK4WLWEa8gW4Sg58fn6gK3tVlBS3uIjV5xdGBSU7KGGuMvBQNJn2FHEh1xAtT4vOrz6rtA2RnIeOY2h/SHM+AZ8ixpwWFszw5aLENZtv+aGWdrf7IyDBmjjMcVIEvgc5QFZIANrSOg+0OEx/BenLhJBDDAQu4C4B4ZBpnB0cu/Ni+qAzDflgfHIt8rtBlnrc/XeyArAF+CUIYDwLlVXC76tue0Y8p6KGNqHMBXxgAyH3EA5THIjl/9yKaaearrhmUeUC0Hj7+s8ebLCXws4Ih5AC7tQy/VpItM/9m7zbpjb8UEF5M1+i/f/7oidIonYcH0c4j4GoFkROZ69nPt7XPFEMsaMin9kcu/0fk08tlAeD07aIlZYTOtRBiXZA7gADhyHDptwxcmbFRa39R+HwyYrkHIMPieZAuUBXQNAjmsLDMwy2Yp8Etw/mQr3IU2lXEAU50D6DltW40D+GoOoLXpMnSeHEBFLC9n/L81fWxUEhOwR0aE4EGtx6EqG4j6PmQCAD6HLv5SrSMuTf1+2aYBUchG/YHW+0MtJp2sDMvsm8wEhHTVsH+O0nSypnb2sqsb4PESAFPafoE4hSEB9pU1hHyfqVHGzbDlGIYJ+k/9rQzOM+0CQl8e246PhxYf3SFatTghwL4OY9YJe1h9+E31/GsLpV8T8z1FOxZKzG6TNkeYpy1Gba5ECbBLmQgAZOGtGgzgK/EAfvr8UDNg7l6zv/jDmOyscAEAiECGMfiXJm1RlCJFBDAMrb+Bc/codQ3ZAIdD1Og/Z7eivdJZ+3XhRUpLPThl1WmHNSQ5+g8/v9O49TJswL8u8wriI+LWETQbtk6GAACn2Y0YWE2BL9OK/Iu/F9iftSv/rpxy35m7FMkxWHr2FRkU75PvgWOhRKlvHYHLLtL1Cn36ijKMUDqQAZKl0PbsMONkuU6A37vjrLMqHblLZDI1DuArMgH/uflgU6tnlnl+xEozf2uJUvHoi5TnXxB9iPiQO8gELrz7B6V9OIcVSllXCFnm83h3Prf68HV1E2hPMdkGeNN2yhHTfvpx03rifvPc6K2mQf/Fth50Y8akk/lJOhJMjQxfnmdB+xTjL5cD4EFUBqlon5JyrzlyvULDg8UJ2NrUOl7qdCH01oAxQkoGKLiJGBVfA3OPMWSAPzIMav7cgvcSNkrhTPbFv2X6semwtabjzDPO6cWZfmyK07PPiOnHvBoi0FefBuw4eLYZs+i4T8WyxdTaee6uUsgiP/ILFZSLAsMPsIfaDp42UYD/v3T3D6KPBvCHKDZ/a7FmB4hmzUZssJ77TFQHwB2omwY8ZmvcZfr+IMrJ2AIMGRa8C9D0dlOPJpgOFwtYFanGlgwtrLMtD9wjckPTbT18pc573KJjwhBo2+GocQScGe01ssGKzoLPl80wyjrwABrzilXm4QDIBGgPAgbi0ChxiPQRnogtgegkgX8QTAA4IQ/l1xCBvjoI2GvsAnPx7pfijdPq4RJwGagXGf6g/0u916j/IrNkz1XxukOLBwCn3ei1QnaZ5T93/ZMIGxBCEWkaU21OB6AoLpON1I95BGpfOOLJ1g3ASCiBWg5bbp/BYjnLLgkPAp18aBAo4gTuPHh0CtBG7G42Q3vKpurDsw5G6nqMGLowVPDAIyCaA+KGskwTepUs0fh6skWcDENFoTwsW6rQTYKrgBPAwHFmDQcsUfsT9l9Dmz06inCW3v9ua/w1VOAqmgZs0WuyOXLFpfRibtmoAFhHJA91He0fjJ+DbCKCygIxsaBvwhQEFyD1J4XnQo1acEhf02hAYpdZswCvunYQbaGkq/+tIdJ7bzbYyXyR6lZMn354EKiNdco8O84NBw5GgxPA2DBeDAaaLpkW5R6ZgGi6N0tpujgEpjHFI7DfZ2jGfrPffp0IXm/+XiVGoqO5bqjobdNl/AbdBYIBfAHuFxThsqIjfN9j9h4yqQimwRBSowE5akHSEekzY4dZvOeyRplrhoGqeBrw+ZGrleZzITgUDoj2HnX/CPuCn747/64uVi1rpDPW5Sn9Im2lnmwzYpUuDKk/ABAjnBz4s0PWms6qZRO4yDNOmfr9FoqCTFmRTKUAvyu/M90UnkEHG9W7/AmDQHwvMjcMroF1CiOzDwnsw/gd9TZbxKwN1pHvzHvXjLLZGkg8/4YzJuJzB1bZM+04bp0yBUA6pj5xDJSAAL98XXl1fqE1fpiAGC4OByeAUeNYwInINOEq8H2iz5nvCXYEwQjuAvMpZCOdXt0gXYG1R284PYGbNQ6giroAbc0TbYebev0cHZNZdHr6MMZCTcfhE0Fo8XAhBtk/ObR83xricjEoIiDHHjZOglqePnVztXZKEopmnefmKdVrZrMPomF+kmEBPGOem1hxY7Yn1hNnEGjUFvesBy9VhL5oMzmo240HLlY/nmwObEGCIbZE4IxpNQL6hQEgyj7Kr55TtwvbYZiIrgKYDqUA2QGALl+Do3dg4XsxpcMwTkBgSEp8bzoMRG0AOzKCVE8hJtWHvqzR4psOJyArGZ55UMNLpPyOM5Ktu8l7pwRAsUqtzJoSoOqmAedtLhH487S9MBw6lyBflF6XFiIB9oz0/jY+Qu4I6VuIPjqo3o6thl5dIpGMr4EHjvotUQM2WbKBgTxDZgAwTKK0m6QsvyWG4IrwmQFOwAPqMKk/URR+BXU+jqG2n6Cbt7lQRkgZx9dj3JtO3hKxi+xNRCH7uTBHQFuSGl5gnz3zRbmXNU5MIACvwJGEbCBgBGSFlIc4H2YO+Bj3qNCzAXnRbSK1d8DvPpUXZJ28B7og3AM6RDwDxE7Icuj9Q4jCcZBx8ntUNXnsKzuA8+fPS64b2W4M9MKFC+bixYuRz/P/fP7SpUv6fDBk/s7H+fq/xDQgkmBueGONLgEel9QPEBDVH6n3DlhkL9e1uKO6wWBxAk4SLEsH1kn1bMUYAPp3OA4mzc7YS5SM3QCcLs8vqAFz8bvEGARiOAj0H+MHbJ225qzIOSmeZ8Gsv6bubCZHNMaxANKSWXUdv1EOgZT6nM/gMFBASBwCzoR2L5OBrp//aeR8of66mf5cnRVfB/cD0JFIftL+DMpG7hAsxX3FHwh4BNgFP+LfBlrwppNOSAYnQGAhY+CeQXCiHIx0iiIdoxJ1BiBH8bMpD/jdqrIc+NZXNf6jR4+atLQ0k5mZac6cOWO2bdtmlixZIsPm8+vXr5cBrlixwhQWFupjeXl5ZunSpfr4vn37EnYC1TENCAg4ZeUZscuI+E8JBJyvdBJvX1F/N8+PBE+yFzBQWQH3yid3FKlLQLcA744CcbLqAYR2IAaGE6AtC/231au7RZVtM/GALQ+2CRlP6eNGrjF8njnPDA0A6nQMk3KC+p+aHsOlZ4+gC5EZ8g8dm2gnK86+/R6aIxi3TuBviyGuo1Dg8R7KAJzFORvtF+y4GJk3IGuBhwDl2xn/Wo0IQyPm42ASOKeWw1ZopoBhIcoMQGONoFvD5640GbwytoBsmelRCFDwBuBNFD0O04AYIwbfqFEj06JFC9O8eXOzaNEivcaMGWOuXr1qBgwYYP71X//VdOzY0fz0pz81Xbp0UUaQnp5uGjRoYOrXr2/++Z//2Rw6dCghJ1Adw0DhEuCpAQXx5jxkAKJEkVc3UfZAvWQuKOlcm0kHXBuwTDngxlrzRQOt29u1sJg9T2ZaML87NTNgG5ERkk/ZOQqeKxFw+YHXH9L9wxjcFOEyGToGTM3PIBBEK5w6KTyGGe88i3w2QC2e4jNBnEjGthJNbIIv4HDoGjH8AwmIsWKwBjIS8Abk5ChBWnkQkEjPzye7AARsOWylyglKSVJ/9AD4nSoqewIBip0I6nzY3+XwpV9VWbb4JzsADHnHjh3m+9//vtm7d69544039PENGzYoG9i6dav5p3/6J7N7925z/fp1c/jwYfO9733PrF692pw7d84UFRUpI/jud7+r7ICS4C85DRiGNsKcePRlEZX01v1S1dYYWQH1IKAPXG3xAWxaShSjzifa4wg6z8k3bacc1raboPu2dN+1pKYDRzvR8zZ9py2GASKH1aBv9kMOAONmSGcnxhyVBgdBTro3ZANEcpzBM35mAyJX4e2K6b4YPbLvqw+5qL9GIGBpe5BefMmdz/Q5sgsMGcfCbgICSHuf0k9cfkrZA/eBMjMyZmwdQ2gJov+H7JfuRgJKyJRAcAQodyoTnKo1A8CIO3ToIEOfOnWqjHjixImmU6dOKgtSUlKUCfD1YARNmjQxkydPVu3PC2fAvz1w4MBfLAOomP55X0gzwA1tJwx8jU0RuTCxGGBECupRwKk6vq7ViqvU1cIHSHG5JHjyZfSta8aBSyW1bTnWZ+ZOgWUYPSw4aLDUwJQAAIWUTMxSOObeg4eQeIwcgwSFh+CD2Cpkn8oaS36U3BflAU5EIODQ5cpSMO4QJKQs/ebvHdmoGx2jve5u0DHy94evCVwDtAHBJDBk7kSXBDofIXNsNmyDyoCq1JD4yhgAf86dO9f84Ac/MMOGDTMzZ840L7zwgjXOeaZu3brm2rVrEQfQsGFDM336dH3s5MmT5oknnjDjxo1LKPpX9Tjwpfe+TGhSjQNnPPXpqPYRRtzPRilS97IGHAQm8PxcQmrFMAhEROv86gbpwyX7IFBZg8P4IVZh4DhK0H6BqX6ZCtkTQFmz4W5wqLl3AoVlniGOIIBusWi6YbAnaD84uu798nUKbHTnLKnrySrAK8gOzr75sTlx9SMzIsuBgB1Gr1UmUhaky/PvS6PF6AD2yNRdgAKciAZidAbQ2JYUtAQfiwzg9OnTwgFu376tyF6nTh0za9Ys1fpbtmxReZCbm2tef/11s2vXLv2d0iA/P980bdrU9OvXTxnCnxMEhAfwZLsRJp0hoJv34x4+xk96LjlpWweCOm88cVOAXQAMqfdo70Tvl+NgSAeJPpBBGvXP0ew3EY1DBzSau7HAHLv62xoHEPWsIcEQ3QDFWKH26ERgYUQWDGEVnABtPtp2iaLihf5sAOUYrKFkoL6H01HejsDw/fna0DokmvP/vAcZv03/wQDKA41xSICAPaRDmaWpQicKUlRh9GdWgsADaawqF8l8JQxg06ZN5plnnjHt27c3P/nJT5QJzJgxQ38nyvfo0UMgX+vWrc2Pf/xjk5qaqo8PGTLE/NVf/ZXAw5YtW5r58+c/1Dr8czABIQIx509bhbo/moTDhWTPH6kmD32hzQLU1731wMtH/VKtK2o6av3Z6/NNPqne22jQv6luQEC0WQpKCksq22TQCn2sVncn8AiglOyiIDhgamsHqC10ewHLMwh1UArUOiOramcNUOXAnYpHcfeX/EJ7HMEIyOY4v7DWDREXUvt4BizpOC8dhhbAi1EgIHx+GX8CaTlOH30B5k3AilgeSxbQtRwRVLoElEDcmymrzjweXQBeYABE+qysLEV2jJi2IFE/lAc4iZycHLN9+3Z9jNf+/fvVHly1apVe/D18fXU7gL/7eRvTuNsE03HcBl0E2jRotQM+FYX+8OVfy6NT9wH+OOMvTRul4X/9Exvlz4hgwmVCeXZh7mWtESM6NR2+zrS3XhtaMCmsWn8IW0w+bFM/hw+Q8pL65ifxhuCglkNLLFESlQhBE/ZHJgJx1KjvFsZZ8Bm9uAODZ6afkV4yPABHjJgSr5fNClBoLm8qMN+XePT6CR67rOHDN4jOQgIeEW+GgI/DOmTdvOThbNbDhKi7J1EiqPOKJA1OW5T7QnuRoJF/8zFSBMLoqeFDBMeQQ0qPwZb9PC8+z8fCKxHjr+rdgEcu/1bGTSrGJXpxwmabmhdqHyAPGvUfJMBAe+kLA+7QUwbFpTfMIcA+g+xBBAnZABRV+tZdPJmjrBy4NN9nnVEnAI9O6pvMuoA4U8g4tbpXbjMQA1eAgpLX6usmA0cuOCzDjH6ewQD7ztypdhxgHaBdGOdFW5ChL848yH6lbSmOZAPx2rOihvvZ/vAzwscAIslKIBU5BeLY9OFD4gRsExOwYf9FEotl5yH6kYwCNx+5SWUC96TLqxvUanzsmIBfS03AUW4vAIcCmAMwQ/+XWi60j1AC4hLQuyVChAWSfA1fi3MgqsBDB5RxKrFZSvkrGgbq6vu6jMFy4fg+ycoDcKvBjms1WKvxuZVaDVavrxMFyd51UXJrT9mzYX5jx7l3/PYdV7bNXl8gRw+an+sXdwgM9IAhf4eKDQekkd8YjWOG+0+5lwjGEAx86uqzei9BSwI+gBsm+v0jsx5klWAYwzMPaCoyWjuSF5gRnQdoymAX1VEuJuUw0JNtR1gv70BA0nuQXKI8BBKGPpj158DgmNf3IOB0W/fBIUdIAmPHIVA+hIlCLh6pP8y1xIQeCyOIdvrW4qRlAqoE2HFBa9XBSRJaDZZeoi4Bzw7uPfwBzor2mlh69ryGZhzQ0g6MGg4BakDQgwHQ4BKwHIS5Adh9YAPFfkeksgEkymDpWUPm30drBJTHIwD4rdUjUyUJAQReQMAZRlqHcibGajFwI7LM16wThMwUNkzxJyAy24XDLsOaacAqBgHp64cNL4EAhCFCIwXx59IQZaAER4OAILmUAhwsBwUo5FSAcxIXtmDFtU15SX3hFiTrbkDpAtrnCTOOsWDmIyqiUdMehFsh8RWbQQG8QrNliAdxFgxXtG4byZ/yYi+QZzg3IjKpfp0yIGDW9vNiI5LRkSUQCMJOQdB+NglBAopV03M3GD0mywATYlUZ94n3w8dxSHyf/r51HLABXojSQC+uFzpFCMh6EdkUP/E4YZmjPlfHrEjSOQBAwCYvTzCdXnUXgYlARCOY+CuKGhJp70HAYTaSqM4r2xa6/okoobD5OHi8NvVoh5mnKrEcNFdabxBXktUBBCENyFOhDdhBnYA4GnnMUIzY6AavbIotEHDQUkVuzo4XiDytVtp8PNtdpPI21Q6DOJCNAPugC9PTDyAgYq+Ag2GSD8YeQQLs4Lkhy2J2CjBmvo5pvTo9s5QRQhkOo+V8H0rEFydu1n1iAxHkJD5OxqmZAV86trF1P6Cf9COFAZSONIcx4qp2An9xB1B08aJef24Q8OiVj+TlSfUwYBBiCDpEezx+2BXnRoHvxWwLaVW4LQtg9QWVYDbYdE2Q3UXKy+GTqiYzEMilpgwjnRd7khFp+xy1aXmuEwrtNOecRFVxEFqqMWq1ANh5mwod+NonW4Qc0mlS+ZDNldgzApij5RsEXDXO6w0Uo6KDQLrtloouNvNs1MbQSb05f0RGwpZgZvtDv5+fA0mI+0K2wbRh4W0HAq489KaWeQICklXQ+kN7QINDNrjwXl26v9D+XvuiJiCLoqYCi1VSIi5bx+sMFH6TQMCiCxfMzSVLzI1Vq0zhn3kWACYgF4/an55uvYdAQIx/t1K4imovLhFccy6WNtCkrvLLHosqGAU+rK8n9aUGTfYdAWRVJ679zmMpTlsBqTBS/SapK2UEddWxyRRoyzMv8pEaoDaAgDD2gj6/AwHvC9PByeM0ylKDA3MTAwX4I10PICDju7T6Lr/3hbgg7mekK/Pg8+AODPxwb3ACpPe0g8GMCCB8ry7jN4pAxM/hPpFl1I7oR2Sb1q/tK1dAhs+xWYryknJnTwym4dfWAWD0786YYf7X979vruzbZworyASqehYgL/Rkr30kSS9AHICh2TYTOFEJph4HQuSB5kt0QrHGkTvKpLHesyMIis477R8GR5IVAIzlTDEU2JUYW+kuhQWamiR1Jw1X3z3qbPh36Di4+n6+ojUDOKDvCLuQZgPMkTHEy7SCGMzSvdd0jnV7u7KOLJBe/3kb7VHlHRkGjrqXdowwfshM49TOzFDdTr3fYawDAfka3g/OBCcAcUibgYeuTZj34DYEZ5iZ6/K+WctBMfrfv/SS+SIlxZQUFJhiLxry5xwGClLPAQMo27cNn8/3fd5Y/eGwOIJWE04A5haem56/DtKmeLSuWo7doQEhDhNuAZc5mTcDRzvRsJKr07h1MuJAoQ6TgKTAR2OsZAs4AivcWPxBGh9AwKD4jLZeoqvB2BNAOk828uRLafr3WTvO6/OUBbzPOR5jgAVKGYDCUC0v303qz8/C2HFYnV519GGyPT7HuDnYj6J/WmJS6GgjwBzEIX2jVoMVnT9vSvLyzJfPPGM+6tnTFF6+/GfhASS+G/CejBQKJkIO1Kl44ehtQNEtLZwAqSYGLpVgG+mpW0llSWnx/ICFqlft901mFmC0hn765mLp4uE8SXeZlKNNCjvwWY3B5kg/AbCNpSyxR7Kd5DcRG2yA2p0MqyKOfrz2JGXBiAUHhTHgUBAcYX8EtT8vnMVlW0qCG5Ex4LTIMorvfBq1NdoxS2EZUlrSOmaGBMIYo+EJ7wacfkLlD/qA37jdgICAV3Nzzf/63vfMO9ZYC69cqVYH8MLwNHPh3S8qND6MHyMFQOLwAGLcRKDrHiDnXFBmiCQwvKg76Us3iJoEJJKBN7jllp/W7Ab0z4tWGek2DpMNQSgEdxYo5iYBEVAhm0JBqW6vDJGnyovoD08Efho557AfMOj9VST3Hbb8AtLSKnxSgiPLRfYhnScjZDS3earDJ1gPH6s+5+cDBtIubuh/TzKbVq/uSjwDmHhAGQClxDdyOShGfzsry/zHd79rXt+2LSYoWFW7AX/eepiZtPKMoni8h8nFgK+N18f4aeOAE9A6Ig2j5QPyzKEGxeBQS4ItQBem1gv93fCC2UXraa00Be4ndfrPs6eubux3KCKg0sWj4LGMwCkpuW06ONLKTAKyGxAuAAQhEH+wAc4I7KYigyIbAOALICH3AUwCFqLadNb4wY9wGBXNEFASABKq9Td0tRxdxR2jIrcT0WaVdKq+sbsBSf9/PWiQ+bef/cxcOHNGXYLq2g34jDVgx69+P2ZNSfuICB+EIBB7jMYHKAOIRBzKwDm7NUwUWIWD0/fpgFM07bW8NJUdskbbX0LLkMhX3hhqMoiAAKpRD9PzrhAQC5OAw9ZFJMJWHKhYVIXzpcSgjACkI1qT0nMGpNRs+Y03SBQdxTFg1IJwHm1Hr1EpR10/Uzsj7lW8Vsw7PbgGYAWk9M9bpxef+FSkLgAtUfQQYaAequLhsceLCOQBwM+bNDGfdOjgHEAUKFhVm4Ge6z3FvDhpq0AbPDmof5AECxcmLJMEjWZpRFgKGr6Ov0Mm0Ty4RCd3qtYcPG+vV7hdIhXbsOZarR57eVlu+dzobU470KaDOIFkxAGUYdnyimhMJgUBpmtlJwFB0q0TXpR7Ja4BUwLQzpOMuDV8MAHahEyAvuD3OvI5BonIBiqKrmGtOGAkYCHrvSqbyYEf0LoMg0zch5hKyLPzlBVp2Mk+IwJSVStIPXZMQIz+0pEj5n/+8Ifm/fHjTUEUHlCVRKCzN+6JfRZ6svRnoZRykDC3QJ2p9fkaSCFcHGb4B9r0nbSf4Qwow1ymAPpxGTFsetaSeU6PJWpRpI+1sZeYi0/6i5JtQZI5Aa0Gs9EMxJ7n5bTxCiu1GxADCtjBuEVHnQFHy4T5xRtEW+pnZvBxCDhvzo6sbZI910AdBuRVq/DWo9OEsd6/E5S5FxPUDGVhodeTjOVImEPgdyATgD/CchTITtT7bJUmewzZ4uwN+dVyRx5LKjClwI2VK81/fOc75vrq1ZHOQFVtB+6UOteUeFnw2RsLlErSpsERIA/dzK+Rpk1HiQDZA5IJESSAgIBBjA+XiHr6rmk3ao1bT9UvW9r2FYM7Rea5UVuVLSAukozLQYmiiKdUZjloZBKwT46yBzT76B5wXvTekWILe/9A8V+2Rg14h5Y/BsTn4QxwZmEtlwaJ/IwATnyVDQT53rgB72B9JurUGPihA4HiELv94PEHYtJDrWXvBBg/pxR1/P/SSUBebCWCikyZk0iJ8Y2aBQAU/GDcOPP//uhH5uKxY8oMqgoD+JdWQ0zP6TuVwl3wNE3qOC4UwxwY96jsQwIJOQBAn17Tdph1x96SLLVUa8XhXiCNAGYHuET8nfZVIrsBcRDtpx5Ti4kIdcJvo0kmB4BxdfWj2KD8ia0G8zWxddacF1Ob1OXItLm1YEudOMvuS5LrxjHwfIns4A0N+7slIER9wFjm9rkD9OzhEHAenG+R5/BDPjp+5TcVAoVOEPYTtR7D+jECBu8J4BAZslMxAEcWmaAqTHbC14VpQLJDBswgM0VvokqeYSBUhy9eNPfatTOfNW2qv5ecP18lDuDHLVJN7V4LRPCgXcfDJRKc9CovGD4Ph5ZLUIqhXhW19LYjAa0/+pbkqCCKQANmWQWpHCh14rsB85X+kgZLGSjJwEBANfgVZEEo3or3Xx6FmknA2efEqcDZAubBy0CcU1ueF7stz0RyzgVD7GCNn04Dcx/MAkDUGpS2V8al+h9OhnUMGCGUX1p5dHuo08EJGFCCu78a2bE4gG0QAiGTw7mgJsV8Aevm6BxQ5tWyDqGTfS9878D85C5BTUZxuqnNYup7XCi8KCf5Hek20MEIG4uSZhqQqH/h9Gnz7z/9qfl1aqopsllBVZQAXYbMNRNXnNFeeNX/07ZpO6vTpv9cr1kbCnSYXKhYuvIcIowwnENtX6dxgKDZiQ4DIREGWAh19HBSLge9p+wLKm0dOc/NUv+NR6GGVdl02FqHntuyjf47QC5OAJyGaMooL1N2OG9aZgh+AvLy/dneA0lIQzzWYUxeeTrCGiRlh6UnKS8P6pEV9J+9S0EAoJCskEBQtnPDv2F7NK3hNn59F+PJ3CNGiDFy1o495XkEpPSBUdjOvie6ILBDW47dLvFPJkrJiACRIZGBL5HhbDh+K/kUgYouXTJvbN0qfsCdnByT8uLwrwwC9hidaS7c/UL1Y4gEpIREiRybOpIKkpZSWy7T4o4HcfvY/EnKiSOpZx0Kwp+dK7EbkEhGqnoqSXcDYjyoMoG70N9H/w6AlG6Jc5L5mgp8/rV9HhTLEN5CDe86NUvkqHECMDbdJKAbCya1x8jCPkFGhkv82LUj+Xyqlpyb0vP1v6TGH0QIRZwJmYCiuDVEMgruBA4niIjw/oM+Ieg+/BG+DzwD9Cb4GmjKzJlwr7hrCMxAeeb3oU0MBhImAQMXgkySjAdpMO4JToCyteAb2wYsBw94d9Ys8x8/+IF5vmFn8/e1O3/1WQB7Obh8jHtOWnFa/Vx6xBKRsK9nBznjr6jtkueJP8iGQ/Os13eBGwkurwzgkH0/m/QXqfFkHgfmd8dgwAPq+Sk5SiNSfYweCnV9vyWIRaoM3vBvMFRqe/rjRGk+h/Y+jhmj21v0vuk8foMTbbUl2rkb92L+bLgbjPnydTgLdB7CgJc2D9vvxfftIf0+JwLDrsGMrSXCjrTa2xoooDDvhyWhdYQBOHUgNCV25t9VVpC90xGBHFU8y2FGc/Pjt0B91whlaX72GFtmFN1+kFwOIEwO3uvV0xT/9d+a/6d2RzN6wpQq2g14XygvKSFjm+jTMQiyqUw7qCIngDYAgA2Hri23kw/FYLUFodACCYeSyuLVHbkjyceBb91XBKfFqnrYl1T1+2S5l6dS97OGR6peEEXvpdUH4v5Ut/mi2g616T/8/K5+xv+FCRu1jjtuS08I+yeK3gBxcDpwIIh78P34M3wdCsZkjZzzU34FWYqMv0BOAoo4xg8uBGMU5wD2oIGi7ef1HrhnamH2zUkM/KTzMeOE5Olaj1gpncKqui9fGwfA0FBRfr754L/92Kz+ux+aEZOmVc9uQK8qE3q8at9E9XfjkXbUKrr+iZmw/GRk1pvJP/HaVRIUKp1jqgv1Fy5JWHFVsyDEGTL1OrVyQ6+JR28c9R9SYJ5ZI5s6S0bb/kl2FrImSjScB1N2PFNauoCAYQ03BK2KUfxPIkaPpBd3ABCP1P8ptRFzJTbq0vnfKjMAQwDdp61Inc/SjjATgNAI9GOyFSYctYLcvi+0AeF9NB20WNlNorsByRjJFnCK6x+H3YB/iVfBhQvm5da9zPt/9X+aAy+9ZGbMn19tuwF5wIcv/Vr1/UuTtqg1BN8b8Q6BQPGkou2LYRGtBKOXayMKK6CUzto/HbKbKaSYGrFmN6DLwvaj22+NlZqYZwUZxqXGxW41mDUA6uTmXg4sLFYNWZqbBPzU1tzv65yQfCfiHrbRMjqTi97pGJx+2UWjBVG7AQHsqPuJ9ux8QKvAqQV9FsEZMHZYhTiKMKwT2RR10+2RyNnlREsoM2hLut2Aq77euwH/EpqAtToNMd1/mGI+/7/+xqweMcLMTEurcgfAoYHKu4WP8+XViTxcguaeOhxaP2VlntWXtoYNqywQgxr0Ld10y+FTOx5LoLecTBgAq7m53BhFZykqFcdsA/In9FicKAQuHEe0AYuz70FAtWwfQuvvC6EH7H1x4iYNehHxNQ8Sp8VX5Md5cShwBMguyFKW73tdfX04IOAHfBwhkX1l3k90QAGQ1P7Dnm43IKPirEFLdDdgY8bKbUZCVyopM4BABPrbOl3M/pRG5t4Pvm8ypk0zs+bNq7QDuHj3y5gML6ICiK3bLZ8hIhA9WOYBSAMhaGDYfB6ENzI/wBZhPwEI0pviFWXCq75fGoJE1HLNs9+vEQLxhsG6b6Ijiz5QSyp/JuDhgSAAQIG1dyoeCKJF6Hb7ubo9KAMz7MVMxgnf4ouVoeTZe4FaUJgf4DzhFAiAtN+vcxgsKwc3CqAz4+UqE+29aDPpQGK7Aacc0e8L/gCD8i++G/Av6QC+80xHM+a1Kea9n//MvPX005VyAOwF+HmbYWbW+oLIBcwrs97bjQA7T09EJ82jb+t2Bt5SP5kaE4IGXp3PQfxooho1Q/veiFIcGj1dVG7p6VLDpXiaJ4oyyS4GEowic9t5J4Fta/2EB4ImuoEgVw4sEQAbb76f5yzjt+eFwQ9QPf+uMrXUtH1OB9AacbdJm1X3x1sNFrQDGcohAAD4ceZwQSoy/kfAzjXn/G7AZba0OVvubkBHflopCTlA0qokBH1tZcFHT5xmFk6ZbB58+9vmZPv2ZnoFeEDZvQApfXOUpm86cTsiBcWLtg7GD5gEeLT//IeKMAhQMPl14e7n6sWyX47LRBSgbcTXcxkhswQ9wId6ul7Sms22ZBFkBWQMhUmOAVAfj4usBttb+dVgA9x6MCL6kPT9olRH4ypkdDh1jBQ0HsJPWOtGHZ/nRT0oCYjktOhmrstXCzA/DusPR3DGsw9J+cEEAmcgSIGX59z5WnYQkAmQhQAGah9CUANOL46UQBCDCBx1emToPVJyVGXH6Gu9F2C2NfoNqanmj//5P5tNgwaZGenpCe0FaNpjonlh4mb1/TlwgJsFOy9qqQQXCUIIxsnH3GBQRoSIgS7d4Uu/krOY5BF/arp6fZzxq54rp6fLIZMd4Czoe7thk3tJ7QDo0cOGq9xqsFNypJRUOGjO7CmNZe9SO05EnztODQhQkDMCeEXXARxg6b6r6tkzEUh/Xl0E64iI6GR33AkMu7zWbwAUg2YkuBEdARxKIOzEq9X5HNmEcwJOCr358A1SCQIAZUcgvX9wBwINZLEDfqlIzWKQKCYgkf94x47m07//e5MzcWLcciAaA+g1boF9kI6HDnmHBxwIQAyTYPzsm6vnBzPoABBB+H8uB3Uko8McBl0Caf8NXKJULqGJtnkFanFR0wnRvZXcJCD64pVSyWUgyBoI/4baG0OFYw/+AhjHOTH9l7GtRAAdIC7p+vYzb6v0omR42tfxlHOk9JCB0O/nXFEbIqugTEgkQyMlp3TQWLiXjcMhDZm/T9OHOKJ4G4WOWwfEiPlDylFhGtD+HugHMihER6o6QONvxGagWWlp5nrt2ua9f/kX/X323LnxBUF+1tq07DPVHLHel+hDNIc0QmTnxegmvXkuABeF2j5QgSEHcbGkT28vHwskmA7kIjZLcLV1QLNbjN4qJJuSI5llwYmipLWAaQhfsD69wtVgtsQCZwkDQQNm5yol50U2wWwFTp2UH4eAk4fyS/eGf8PZ4hjQd6AOp+TDeIne137xR3UGcCIo/p70233LM35AYrpDfC+wAaYMcQD8fDJIWodkeqEsCKUCQiWD5u3RYplo2ThhGyygRWQm/64pseVKdRHFvhkOwEb99OnTze++/31T1Ly5SgGcAC3C4AyiMYD/1vQV09FGjmX7X9ehlCq8fiFCRzN/geZsLJSToFvAK6jBTFl5Rrx/LgmoLOg+uu0Jpa9l9wIuOZbUa8EiU4H2mUKPpR5uP+1YKYZSdiBoTp4XB80U/sJwDSUaTgAOPrU93RmARbAFKNqIt+w4+26Er4/jpv53W4GuKXPACWC0GOtqP5tARkj2t/X0nZjAoDoYeXfVjiQgANCF9B5QkOlA7RCwTmhIxn7V/SGKM4UqlSKb/jew6T9EJ0BQ0n5aoaFzRLZJdlFdWNE3Zjcgxr5y1Cjz5X/5L2Zn796R0mDVyJHOQQQH4EVB6yEzbS8DtR4enOhBO0obZr0YyOk3Hq3PQ+1HmcAFdPzxBabpkDUJCjy6KIYMFJcYCmmyLwYJ2gBQeF09vFB4AC1BhoF4Zh1nnxVIiIPAUTCiy5gvMuyIiiDYQv0PMBe0G/kTh0BtTgcAI522+kyE+hsAPdJ/6N+Qi2Ss9n0wKIbewFN+SIg2YfQkYKFnH3JfcBSIjUIHlyjsWy69B1tA8MNNHGao3qcNCCZRp5dji6ICxLBTID053UOngkyrk+eBg8HR5N+sKQHKHQfG6Pf06GHuf+c75tZTTxnzrW+Zo506KSOIjAP/9Hnz4vA0W+NfFnWTA+fCkQKGC4Dxn4xK2eJFLUZLAZa4WPD/XQ+7uELjJ4Vl2AUvX5W0zq87GxAnzPy8i36lLMowEMRzptyieyOtf4+4b7NlG4AqUZxSYsm+q3qmxb72fmVurtJxIn0smS/+ThYImEjkx6mDAxD5Efio3y9bjoAOAiUhjoDSEV0B7gs/m24ApQPkMYaG2B6NZiT3hKwyDBJxz/gZ2iMJ6PnIEtTS9h+EqKZDnRowcwWJKhMlrQMgCyDi/9vf/I2Mn9e1evXMNOsYHloMMjrDXP3Fv6s3DG+bw2a2vPngZVKNOZHgwg7IPEQcuN7Uf6RxrgVYVO4UIKkehwrPwE0T1hCCiKhw7MFjOoxZ50VTo1mU2WLRhVHcsvRdzmywN0gcCHX4/K3FMlImLoMwSEXtOeS/UXmiPbfh2E1FcXAepy6Uoff1/IiVAhVpG2L8sBG17cerAIEzkBXwPhAb4XsTUBhk4vN0jGgHJzIERLsT5wcguObI9ZouQDwHQJq/MTXV/M+//uuI8fP61Y9+5DCA9LRHqMChVURtRo+fV9B2K3s5Q9TQarDbpbMAhbdcOwdSkHjstn5D4bbL3MKHe7qa6DoVqV/Dzvpk5wEESjUCmcqmemVGFJPZnBthUfbJ0tw+gzqxQLkwvjth+Qk922gQEKRfy0QTeNaUDHSHiPhEXbIAtyX4tybdOhScA1kGADEp/b6iD3xKn6lJPWYHaEOCP1D/PxPJKD9SlgBASctPm48TJD3hLHBiwzMP1DiAeA4AsC9ryhRztHNn8/E//mPEAYAJZE+aZNLmp5e7G9D1dO89MuTDxVpi0z4owdBAh2Uc1N8BkPKjhkZISaU+izqQvbgscqCORcKa3i5DLJQJ9T19dc2RG0lv/MGhAojV8/RpsqjWttZvN/WYjARn2mrcLjHhpJ5rjYq6OpYhhJqePj+DQERlhDeI6sGJF/m14PFENSQcakuKlz0wSFkIdZt/Q5nAuYMp8D3z7XuASxAWiRKh+ZpQfqw88IbuRFggyrgxG34rMwUYaMDVsRfwG1cC4ATAAdJmzDAHunUzv/vBD8z/tk5g3dChZm7G/IgD6DaSWYAvKiTg0P5Ls3UdLZlaPTJFPOEw3bz3VqWU0bMABy98qJ4tbZ16EXXXrKgll9lKHVf6PQNJvw3YGknWjgvqqBDlMfTOEX38MixKWw+jt6iWq42ijNkWxwFPw5SfwMA7bgWbBry8eCsv8JtYA10h4yObYDlobfQdrHEj6gGAp1Fxb+C7UIMevUb3w23sefh7Fd/+VO1mDJd14TgvN+a8MiGwOGBGsAFxfnBRqloa/BvlAMo6gnkzZ5p91hGsGzLEzPMZALMAP2s9zEaG/EgEikdQgQnI4QYUGBkqDppDJ8VkcQh9/MBBDxth6TGH1dZlU1lejL3CXa8uqeevS+pP3U5kpBvT6lUPiM0rXxkHJ0DExQHTritMICJyljhrWIO1e7gBINJzMBhWvRXcejQj4GyQ+CZqB91ARGAhDXHGtBbVJbC1PmWBGIFxuP98PU4gMgU4cKmt7U8nnAFAeiIDQEugJgOohCgojiBwAh6aBWjuZgEAdgLbK5pogSGjAtuYCTVruNR1l7zIIy8uLmIQdfxSkckrTvspwt+avtobmCmeOtyAdlOPKJVFGKTNxP0iDBHFyBBIfZN1IIhnTiTmOZDeJ7ojD63Axq+4ZZyNVQ5cdlE+jiMN+wdDKg7gyzgwjgcglvMFPMyNMcwTnDrEMND9On6lGCWc4x+4DoAWhVYALkpgdNZuBRRk41qO3ZkAb8Q5CIRQGZVesPNClZeN32gHEG8WoFmPSebFUOPZ6I6KLLJcoc6jvgvLQiBznLORgL4/vWH6ztSBpIBkBS0EOGVqXxykEYBA5ryd1FNRaZsn6v9JdcPGYBxNMmIBGC09eZ5Xy3G7ElZS5gW+QkmFQbI8A9AOA3s0it8XsNvRGjugHmk80mBa2W3LAdp2bIAiPUcTUhOFMdZ8cT4iDe27aqP9DtFzARrpNGD8ZR0HTkcS8mXAYwIHYCfdDYBA3ZF4TsADhOKL2IDxUjUMAiWlA9AswNgF9iJ8IuNmJjuotEyxUZ1LAT+ANJELs6/oFzpoLlvgDJA5oEaDs6As6DB2rVs6yY54mzVQs5V3ofkcq59I60hDk3UIiK05lRoC8nMAKgPss2NpBzRfdjOSYiPcEdau5/tBnFE5R3RupOs4ifNSDX4Q4RCQytMq5Cw0UTh/n74uDPiEzCJkAyz/gAMQdkdER/7wtQCDlA50ecANAotQ24bsn3AL3P7IxabtpIOlykeRl8t0oIuneHk5cKOk2wtQHQ6AvQAdBs+2D9PJR285dUd7AdzGGKclR50IGwy0l6jOBSJlRBUm1P91/UponEBuwXtqAUEJRgcwkcUgHDpocDjcZMsCyADmbMh3LdEEdQDCC4Yc2RNceohUAKucWevhq1RWkcEBvuFgOKfWXqsfY4RHwAvHHd7HWfsn2R3ZHG07WIFFXhMQdmg0VRsyTr7vGkUTcwKRCenv+lIOStef3Beox6f83sJ8v3aee1W3lysF6Xy0ZC/ga3utM9ytjhFZJJ+Dn8KwVHWViknnAMAAftIy1bw0ybHJEPvg4EjtAXhoHWVuP+83A+1T6kj7j+ii6S0bHUg52dZKVsCB8zHahHhrDbMksuLK04HBC5g/TzY6MNGVHjs1OGy/cglU0evUpp8QvoJx0ZcHkzlkHfUQ0YhdlobRMLoNcYcMgQGvvcUfKAugXHvGj4ED3gVdQc6WcoHsjkyQLgBUb1iHDBLFEwkJ2QGAIQEiYAT8P/cmrAcLMwXKKgAYbSmCI2JbUOgY1eudGXlR4nCfoDfDM0m+1WDV6AB+3GKwecZeFvjkeH68a1n+OL1+ygMuU/RmoJBeMn6Kd+dwAYhaDV+hyyx0N6GR1tKBoPFLTiTdQFBgPzINhxMk6nWhN16BMg7RMqWP02CgrUaqHS3swQQdEZ/ODZN5GD8EnA4eBMTAwWsEAgqVz9F7gK5LeRAEPnhvwzIPKiOkC8AY8Qmth3sQ0wGMX3pCZSAdHgBF7tFpb+SIyjJf0mzQUknLhRYl2QUkJUhO3B2WogAcoyvBbAklAs6B3weOQXWMjSedA/ivP29tnu87zYxeeCyye230wiMOBb7ttsWyHRaEGe8dLT/9cAr7QKk/2EFYFqHpwIT33BdpEITLPyNJR4KJajxDojWlACxJuiXB4B2LsiiijOPIQBka7AG/kfJyv2x1ZMjCwtYfwLIDntXJ/wdVX9D/M1Eg4PwtJSofOD/AQFLt0BFybcrfqhxo0D9HKT3OhWyA913g90lwX8hEanu5crpKxXc+80Sxe9IYIJsAR6JMYQIQsBGyUWvJiGdq+g9AEJ2I8HtDGe8484zKncAcDUtPahzAV10NNibTXH7/j+rhN+y3MLIJCEWYtM3FupBcCtJKQJ94qV9Y7ogToKVEGidEO8HloHh5nBBtxmRlBRLVyKaCE2jQb5HNBjZoUKb1hL1ql+EY0ArgGbNOCxLQhXc/t9H/itsD4JWAMGqpAd8qBfkYLgoDO1JiDpLgbzmyEGn/4PR9nsOfZVLT98qZ8PkCnxk6afC1ciLcE5wCGAKlY+AJcI7MHqD5z5oynBRCH6wVC7MlAMyUHgSKICH3rI36ncpRQe4cZkd6Zuh3PPdWTQbwlR0AVOAL736hQ0axBUNvFAUCchlS0938dkVtF0cyuSvWGIfrlIHOVNgFgCIMM5BRVvCF/CSWBYPMQwaGsfI8tBikT6kyDoBf65GrtHQFgw3kH7Im2rM4D6Ir/xanznAOz9RtbM7Sv5VEV4zoiZEDAi7Ze8W1BD0IiMHyJ733y+99qTr8tWUn5QDCLklS87AmHh0B7lLIKMgIyQpI/cES4BJcuvuFpgkpT0j7wT4qVJHCCSCAYr8WxwH5qSqzgKR1AGEWgIfJheLw6OtzaTikYPxBZ74sWahsv5mXqKM95ts6dY3IP0rlog430FvZDgSQRURDsCLZ9QAC+YpnCCYTFmcE9iToPMIpDOSQ5kc7S84PEJB5/NCqJbpiiAEEZPNzeRlWaPnBBek2cYt4IWQTTWxk53sFZSDSfVp8AMUAisjHYdyAxgDKQRKMQSBKG7IDJhif9mIj/J2SYOyiY+I/AAIn0v7smlYi7ghZwLAqHghKegcQHQkCCBgIHFBE4YwzoopW3F6/ByDm4gevAiNMwB44klUYOhOA1HNw2UGw6WGTznIBRmQdEuCU7PsBCjRR+WuNzpJF1Qs7Fdif5xF/ygOAVlR3iMbRzji0yIiyMDExSmjaPaduM1uk5vMgwffh9gwC3lH68bNI78NqsGPIyNn6njuAJgBcgONehRh8gOyRtD9wEIq92Mg4zzeBJ0KHgc6RhD4m7EuwY1Q6ENS3igeCahxAOWkpE2XNtWsuXdGFaAD4REspFiLLx0g1XTngLi5ILukbfV2knwT62EtFeslFS/bdAEGzv6t4+o4cQ2SU82SnwoyTWrTafMQmPT/Sb0g/ZdWUJdnmDR0HgXFSo5c1Fs6IjC6eEUX39+nMUP9TGhDZ4XogIVZ4635kopD3T9bI/XjhtU36uQVlyEE4gsV7riqjoFzAyVHa8Dsm2jKODARN317jAL6qA+g+OlMYQHkRiXSNKARBCKYYlw4ElxQTwQrq/rLTaFyMUzaik8a21kRgdkTUQiuv7b8HyCE9LKjZDOTbgZ8IIWfpRRObNdEFCIy4aAq1jMBGQTAWHAVpdnEMtd28qPHu6M+FjAHAkYwORL28YbDozA6jZqZfYiN9ndgIpQCfpzxwIh/ZGvGON6GIw4BzgPNP8dOhIo0lmAE8/2quMoBRVTwQlJxMwEGzbd39WcwHST3O4Uqw0T5w1kGHYRP4AESqQPagRRgMGeNnuIXasK4f9gkOJKSxvPh8zu5LXjsuuR0AzxXpbowBViTlUnkt1JAKo7fQ1M9wUKtXNCLLGR08/6EMF6l30HzOhhIBvkf+zfKdsbb52FQeEJJs4CnP8gsgIMY/b1NhhYCxcwJXlUlyP9gK1GnOuQpXoaljNHStyobQqqxxAH8qEejJduZfnks1o3KOqmaPjiIcIEATAx8Y+aicw5F14UV+dTgtHUgfwci5wHyO3i5Ooy794MErNcKJui0dAS42LS3AwbA3ECmy6pJ6/jq9qJ0Bt1iGkRgg5kaC60mjAaHNHarN40XFcLb9bQb3pK3lwWjg4jtWoEPrie6Os18+UEjpwHIO5ONpK2LI7CWgAxC9Yq6ijIJ7x++NQfO7RBt6rBFo+CIpNstAZ0IDQW/VbAb6ykzAWj2zTNvRa5QOAsSBLlMzDhD3P10sMh4QqT7GjWY8ctPBIbDbLcVLg3OBmg5eIsN+bvTWyHbbgPpHJgHnFmgrUMgGUIxJ1v4/BoXRgZwT0SteChpdDx+LdAhq93Bqu0fjbFvGWCYuP6UaHtk2gNySdz7Tz569IV8R/Wk/JrwhAYFWiY14wRC6BvD6w7+RxFwFikNBKIQsk5Zi2InIneny0GowPxDknR2tUcRTasaBq4IJ2G+6jfJutx+vFyZsFCsMIQ/+LtbVydvy7PR7qf0CCDhmoQMBL7zzuVDien4mgEPC+IPBx0vngsADzqPzuPW6SMlYCmCYGBA1MQIZTiKrMPG9gNYgMCDX7pvvnADTgFE1OBGbZS5hozNOHJFPl9E5Rw6hhzl9vgfgHPgNxlsR7VY4Q1QZhxPYX/IL/XvKChiBQT48HsgMoOjKgSyVQFCAuRtQxAFCwTtgipJZkmnWUIGrahx43AJ7+J9reQSccAwYAUkuwXNDVygSYPwBsR2cvlfDHPw/rZ52o9cK1eXQoaG61WB+13uCq8GeHbJKnHatCk/CLADjwGBR2AXdx6i7JJoBTDmqZ95z+nZx/ZnJENtv/Eaz9siNCEUX42beg+iPNiDzB+uO3tDZMulH9GbrTpAjD2UdnZ6FuZcTBmpxJqsOvylcKAQV7sqAObvlgGKtBuM9unHyu+blKWHsN0pGzv4/sw7gFrzXmmGgKssA2pgWvSab/ed/aS6994UuwfL918zU1We0OsotjrwWoWvSWw4z5lw2lldwSdwUX56+Vjz2ERsTFrWIXgwyc925pCQCaRnIG78zL07cLMNLuCfOXsBXc2Uw1PP04Unnod/iBHAMOGtot6gMQxNGzx/6MKAfn3/ixXnKCpAVCws/MEaGiSgJOFvAWzI81+f/tFzjh43o0nm3zgtmKQIjYA5NXlmiexUtNS9n8JbjLfBeATSjmY/aiWB/fvcp25RVlFTjoFhSYgCsBms7Zp1ZaGt7HoJWg9kXq8FI3UhL8eJcougpPbEGbbSeuTZP7SCkndTuC6vB0iqzGmyvJgHVzkrS1WDRi0EbD16uDKqiLgCAKug5xoahIqgSBDymrj4r5h8MQIycz6P1wJniaIKuA+AuPXu+B+eM2CZZH+UB7V+Ge3AEZIUAwnxOQSDGajAYpPxMwN25GwudbLxN1QELwR6eHbRYTghuCO9T6kI3Pta5axiNFN9mj8w7UO8jAgJYjI5kfU8Vx1FU1wLZpHMAiII+0Wa4qQ8V1z58Uiz41dTisMY6aWw0Q9RSJsdibZGhRgTE6eDTSzw2Y6qVWQ0WloPSPkpWKnBYCYZxgojT6nJO4OG9gEFaDaCwyeAVMmwMk8EguPsg8Qi7MCAELZhnShpPyw2jw9gA+kD+Yfrh8CFhUX619wIvpOw4fIwckJD9A8zzAwiTipPtkWlEVoNZQ+bvncauF1OQzkKQDUcbgM+jI8nPAFOivARYJqIzdMaMAuxAhp1UOkZNQHa2JWL7qcdMs+FuhwSsxk0nb9VgAFWFAbw0It1ejtcjQpGgyXhxwBb+jvHTGSivTQfSSzuHS6WNs/YCQfVNaDXYrLP2Z7ltLziSZF4N5nYqvKvnzxwFi1UAwjraSA8yjgZAu2nH1D0JJKAu1uAZ+AH5J7I6ld/FJmfnJX0/J976mTlvHQK1P04aevCewlIGZ+D/wxrkvENGQd2OYWPElAZjFh5ROo6RvzRps8nZdVH/Zv/5DyNqUfD9KR2Z6+A+4DigNYelnhg9ICUDS2EtGNyQNpMOlb8azAYUsgKcI86jOgDjpKUCsxqMgyFt4+EC4DBVRrQ49UZiFF0yAS4DtN46fq6b6a54TsDp2+drAywXGVagWw1WsxaMrgurs2BOqu01wHUHMHrSYbgCfBxAligfZvIxVAQ+cAIYMRkdWA3GgjyYVm3bjyPxHquWD04eHEhThdYJdLVGjBIQP6fEZmdrj94QfsDniNyUB7R9yQ66eeNHAQhnEAhgfI7/p7NE/Q/QCE7Be9FyGOvQElEFpjtCdokToMNQ0waswlkA17f9VJcIRBpjzovB0AspX5FfCpFXZhqNNFPyT6wGsykqvO3IgosoUQsyBNJc0joumxN4qNkOFFiBvKh3idZhNyAGjDgLU3CrD78ZmbyMbieSdgO0tfQofCObjfH/dfyasYrk10M2AMkGTIHMEEPljNAcILWnVAGvIOrDXWBCcaA1aERFpTlgM0fUgOgygDlMsvU/0uG1emZKRRj1Z0aZyQAaDlhSia5HiZwF2cmwmtVg1TMMFIw+VnoVNN2p5bgAG4/fUnSRRlyUE9hT4MoB7bazlxaxD8RBAPvgfFPPIXaBkwDY4fvUrAYrfX4Y3yxbZ1PPB4GNUlQ8W0CdSFsxBqgCS4/NP3RzkNnCaXAe6ZuLHxHwLJ8y7Cb8KAuI+HQLiNy8P7gfji36mwgFmem+Wn5dOc5Ag0Z+hPzQhV+pRAEEBAdApBQZc8qcLgmKoD40CThzZ40DqBpFoCxz6b0vEx4PfXHiJl0GxwHPifD5Q+QIjgIRCpSCiRAN/YrrsBpMCq/W+7+6+Li+Z2FN5C9VVcp/T4ZPlEvpky0DQSOQVmnzkZs1JBR69FB/j9jUPBY+kx+1nYkBHqJ2WUZenn+VR1AKg0Q4/LBolBIRJl6QHgNfAGRM8WvNSM/LgrmaIbDpP9OC4AiUDwyGQfphBiCxzUClk4AIz9asBqsCHkDzXpPN3uIP/RxA/GiAvHRnOOOIPdoUn1QP5JkLgUNgVVP0RhntoLP/7qTfHKSxzyhhCy45FGLAQ1dK1ER+JiM7aKlqhgwdVWV1U0D+00scaDr7nLYqgQmABQConS5HraksSy+6e0NnR1mEL+viK/06oBeiDsAgho4Bd5u0RfyA15Y5o+Zc07YUxTXMPD8OzOAY/X5IZwCA7acnqh1ZIslwMCNmEKo6cCQtD6CNTRPx8OEilgWGSPMgkNASpPbCqPHwEIdQgKEFCNEDFlpYLxZSWRxFc6G9CwRgsQWGy0IEE9I9cLEyhWTeDRgyLNGvuzsVJbojsYGxIn2cNiDaCkRD6vpE9RTCMwYnoINABsfSF/YChsUd5Tkp/j0GzABQPWn+z1dXgDOFSKTWYAKKR4jNMnMAZ0AqyPGGgKJ5D9NPChAlo9Q6+RoH8NV5AE+2HS76KV51eOZBCXvyYMNYKMY8LGO/DhlxR4xfG2XuOGkw+sQgv8wQsFYKsIgFFRg/ToPZdrw8swG0sOjzIhHWdtIhpbRhFTbjrMnqALSG+8zbypJwkB1nnkpoLwDpcBivVjlgn3l5C0IDtkP0pA0n2vYAxwHhBboPyh+29sTNKOzncTgY4dyNBdoNgbZAQZyloLGyO+4OnQVKRJwYLT66Qg+3Aks3IrManXKBe8rAWUE1iMckJQbQbeR8syj3qpDiJ15KEyhHRMaoqfEmLj+pVK35kGUiYEBZJQIssDUgF+CEp47ycS4WHp2o3nbUGrfDPnVlZLa9qx/pjN4NyAYYvDopJUqyyUgE4nd28xaBRVmU0HJQygParWRXGDDtulBSxRMckfGDxg91Gg6Adeg8vDhhc4QHMjrniBsmKicbCJhPGCSKJzLKn9yN0OKMdiz8HcqxygFbztDi4z5on8TcfGVBGD7AcQhSsBnZUlUdwrFJ6QB6jsky1z78d10cdPmo0Wtpf/tipwzbPUMtHIwfj039XwoCulo+W+u978sRwBJr4PvN9K07KJrF7/G+YGtb9AH4ekoJMoxkywSgP8O5gA5NpyTh3YD2uTI+ywQdAB1OlIUblHMYZTQuwN9p44l1Z8+HiH3l/S91Zrxw5JB3WP5Ctsf68JANhPOgxVgZPgNsUtB6SkN2F3I36E5EO4tCv3GYhZ84QBB+siBk40QQU7noth9TIrGLsGYYqCpBwJ6TzZ6iX4g6yoNdfei66nYMm0tFZKBHT3pJCYBzoHYbnXNYM+W1PQgI2wsnQjTj0NXfH7czwb0AbiKQcmB5Eu4F4JkBpkkdd8z2hHcDBgfAs4bcgxMhimM0U1ae8bLhTtyVEgPVHjoI0HwxROY/Fu6+JEPlfXAHYGP29iIwDbUO/g05AFiAGTZLOf/25xVGX7ICskP6/LXFRXCoP3gBmSZDY9HZBe8R/IHWJpuJmkUwo2z9iQAqWBMOrbgaM8TkBQFHrVVKH4aBhN6//jsZPcQgogMMQbIBcAL1/j0ISDsIskgAAbedfVuTZbSw2k9PXNgCZwEoOHnF6aQbCMLhMXgTlmMkqgXAEg3qYrInJ8N1X1FWwzu2nEMfYNyiY2bSilOayMNRT151Wmh+Bz/nIW0/a+gg+jiDYr8glDKQ/RCKujbzg4+AkCcfj14qEgsoxKFQSvLzKDmgKgMy9vJAMt+HexOdXQAMct8mrjhpS4LFUROBWRKVBUhGoIaR4pphoCoFAUeIu4+nBuFH9YcHLHqpr/EY+yUtJCvAGRREjXIWv/2p1oaTFZAdcOngooP4V7jo4aGJwH1KgccuPJp0DiD/LSe/JtafTc8TkQQLa9VD/Y+x4sQZ695y+m1RqzFsLXjpli4Sz6SVp7SDD3yGs8KpI9PN2dXVNqAF+nd0cpgGRRgG7UfOmX2AROantH58p5xCWekvBzJ+IkPHAQ1O26vuRpAFJ3DgEBp64JGsgrICijFkMDIUsiDuTrNh6wQcw39gJRiMQe7os68sqbbtUckLAu65JnIHICBUTRB50nlAwAkeBAQHcDJRD2JyyAF6AAy5aE4BOMe0mXwoYannFqPcRCCtpGQEAgu9liJZgIZjrBPoEg2c+qjvnmepnFpQatYMvo2YLOoIiztZGc7zFEp/7C1xOZxgSLpKOIcNfKZzBjfAAHEMgHIAstFqQGSGLOXknmC8OHpS9rIcAiYP+TxLRY75tWKQkDD0Ii2b/UxMUhaJ0CGi3GTPBPfO7URcp+m/EBiCI6R71Hz4Rjkp3p8k5GragFVDBWY3IKj/yAWlICCgSxjdxPiZ5qpIKJIWFD3pRr7PT5uvIoZXVy9r1dADPoCNyTgRGAwImbU6GqvOkf5/uymHRf5hGlDtU+tUMZIUzwactS5fGdNyafYvV4TuOXW70H1NAer1uYyPDb+k/KT7ZUU5MGLmP1jUkeJFXuD6u8Uj92XEDPGQ/pMRci8cG3GnlIdoC05fczby3sGNcEC0J8k4YO6Bc5A5hKWzAJYEF84dRSh+31In92jJ03WeKxXr9MpQ2XmiigHjJB8Gcik/ii6jrVeGIMKFYoW0E4FwqVyRVwWORToh/eNA+HqcRz0tfDjgD7QopvHzZ7MRbiKQC5d/837STgTm+WEeIrYGeDT1l61uCi/apdoM1NsN1QDmFfg6mnPhuSPKQgRmQAduPuxCnAHpNh9nNgD6dUzRUE/GojVHDY+RE9H5GOk8Bkwqf+aN30twpNWwlU55CA1Ie1ccvTdH2QTIPp2koC8A+CgQcOgKUYVLbOnIUFALf08kC24dXZcKZMGZCGS2BEdDV6NGFryKh4FC/Y/Hx/ujBUBkxzCpB0FjEXoEKwg4QSymF0wzKf5K6GGHVIAdpbV00QU93iD0wGXaevpO0k8EhmgMIQu59LYjV3sKtZsGZPSWLIH5f9G3ywBwYAmk1RgVqT6ZHCkzxoeU9vZz75S/GzDyfX4jjACjP/X6R4q4RGuAuBDF6STgrLpN2qySACwB4ybyAxqSTQIaMmpOhkK2UM/PgoD28/MoWXB0iIEkvBhkfK4cAHJjNYtBqmk1WPRUIA8ZdJnUnv5/2P8Ob4CLChBYlu2F0wCZDtx/9gPA9uLwWr26S/RPat06WjO1SpemZiKwdK0XSDojthhSqUDmAnsGOXpezFdQ08eibnNmqPjAmAPtR9yVbU6Bpp0oO1Erxa67lWJwAsKI8XNDlqljUOC5H8wUhPHxPUXvRzoAc2wQcHyE+5GFsst8/Y9DYjoQrb+61gG0rQReROAgaKA/UOMAqnkakIwA4ye9A4GljuRicTFBekGu6UGzQDJ6qQj/j3wzjiJMAtazqWt46WPWMSBg4S5yjfGX8vQdjgIphtQfFBzZNBwo/y9WnDUaUHlYfLGMOrDuqJPJFqKZeWVXh5XXnXh48/AvZbS8ryA4su3MOzpvMgLawrARCRJwCcouew3ODef0oieUub0QC0zrifsT3w04xU0EVvVIcFISgZr1nGRyCz+IuVuOS4Rxay21rfFgjxV7ngBjq4CGbiGF6/cGNJsUURfFH3CTQculFPzcmG0irkD5pNVDKgizMHqKMNnXgrNfj8vNc4MUBB02goh7A2EoBt18CYja+nqVrdnjAbSRTC6GgwBvoDUXfnZFgBoOhH9DGdhKUd51DNALoE2IehC4QffJW7XnIB5XoMhvFAZXqCOdgSzdj0RFQWgNghkhNFqV9yZpiUCtR67RoYLkFnihR3qzILnUkHjqBTsuavCHC8PXhZbOnI2Fila1xCM4KOPH+4sBNnCp2lkMeYQpNg4ZIKfd5MOadaf+Qz3mcJy59uTSA7zrduwFmaw4i1UCeNpi9BY5i05+y08i/HgH1H4iFJ5dAiD0gK/gOkcq4P+Xdnse6GuZGQjSYWSD3AFSejKFQj/iHXfE/OZ9ZQzjlx6XE6EcZLipPOaomwg8Id4Kd25TFWtIJjURqJZ0+XaKZAGQBKIMYszHQZBBkon4TG+hXMvHqClxBICDjhbs0GmUXjB+9gHGI7TwcdpaYAM4i9fsRUhmDIDfnXLome7pCdKBi+RYwzBQs8FL5MQriohu8KjYzfTbDIISDXBPw0Q2cqMKXVbqLZYRhzKPSI/zYI6Aki+oBYsbYoMF/JB4W4EUaGxGiTIwdyBIyEVLxz2shHxKX8PXwlCsEQSpIiLQykPXNRuO2AcXg9rSscgyhDgDBqEERHqH5+Vz1Hn0byH/cKnYOMtIsFpB9vPhICtCdCF90DemxIB8lIxZAIZAStz1tQ1q+wFyJUahLjatJ+xXuSDxUOt442ECIcsAbNXyjb5uiy/DNRCQOvs5jwZ+rj+iCGRfp2NIwkfjBPy8sDQWo0SgBDJZ+7FrtXsAtB4Nw7K4QvTvPjhtn1tCYoMR2Q/PgLYgdGdKHoRA3ETgfGWYVb0YNKm7AK9/+D9k5Iyk0qoB2GtjU9GJK05pAjBsCEapFtSfdh2tJtX/ntLJQdL75SISlRLdb9cVHsBwpx84d1NBUrIAucgYIhx+ev1BGz8RQIyo2MA7ZZxvw34LlQmUrelB4tkcTMqP82Y+IIzxYsBa+b3shDICzhRKMAxBhogg8ZAVFt1+kACP4RMZPMGD94QoKYg/2cbAObn6PmU1C4Qt2D8Bl52s2AL9Tk4NeYmmA+mAADyDN1B+VAdZLOkcwN890dbU7TzW1vp3nBd/2xkfBx/m/NGSZysMFFIefFD7IaUjcuAowqIHWIBsBkoU0AmlAB5fg0ArTyXlZqCIA0h1KrlEvUQHglAGYn6ASEs9DUKP4dGCC6VFyKo0cuynOY9f+a1Se85aNF0fxWH10e4LSD6iLmFDNCSxgpuxdwSGj4EL8DM62OgPqzO34H1xAZqlutYf33NfSakOZFAyZlgIhmI9vw7M6Ue6vYB8jKxlwc4LnoRWPVliUoKA/73ZIHlaCBlhyo9owZ8Af6T5sLU2xpjC4sLsK/7AaQTYQ5cunCjAmyq1Giw4AMqJZHQAGM/xKy46Uw65EiAxUgwgK90ADBXHjCYfkRI8hpYcrD6cOfsaiOxs1oHEhfY/Rs3ZYpQYF+AdTp8OT7/Zu/T1LCwFJAzlQba9E3lROwSisQV+Fg6IzgSlRpgs5U+GfV6auEWSZzgYWoGBQ4CeJL9DSi+3Gbj5iA3qGIGFaBDIZgA4NeYQEDGpmQasQhCwdqfRpokGM5ycM0AO6SCHyRooPo4Hj7eUsdALhlL/14msBku8BADMghTEBRCIdSc5gUAi61jRdTO8Ay1KKAOARs2zY+Y+054dO/02WGeNMyEzI6WGlo0xM98PRgDDUIs9ejtuB6UDDlycjh0X/BToA/X5ySR4b+g91PNCL/2tc3Cy3y4ak2WwzAQD5WsIHGH675Tf4IOMOP+fOn9fRGQGYyZj4N7gXAgEIfuJHgTqMO1E5I4wShy2DNU4gCrCAFYfvqG0kIMACHSCDDmKItT65YFA0fvgmRtwxA5GWg8mAAKGQaDFArB25d2tFq23r0UZcNOpAsOSw4ikDBSnDdjFTwgCjNXr60DbsIUHCnaQ4J61Pk/gHukzI7pgNKTxLs3OEdhH6YFAB1FeUuTWyOgG0ZY9dz2sLv+NE4s5/KZXiZqvP6EBgx2RUbBXkLIB/gcEIPAEAgrK0SD2/GycBcxCMIIICahPtoC/tlMOVzgzAhmKDIP1YyeqQTkqqacBmfRivJPDJxLA/YZuysfLpnuxyCUYLocCa5DefqNXlqlnW95qMEgukIIAAOk2sCY6mVeD8QzBUYjMGGir8blOHdi3wcKzxGliDPX8ohCGbzK3nddIMBnbwLm55uil3ygboA2HARMx0QKgTUunISj4aiOUjdY4eeb/Ww5drpofgyYL3GBT967jN2qACDFYuCHQiutLEThdEZmUH6dAGQIfgZ/P53BI4XNkGUiK43ACUBgWnkAPT2Q1GPMkTYeuUbbCXa1ZDVaFswCBpsmDwJDDIom8GGug8fB8DQcZPQue750AqDGHhGy1tO0hAqVFEYHY+DrtmHk21e15w+GwQjpZo39Zx8rCFNJ1IjKOlLFqxmAZqnLiGIudiKY1PmS6JJX19qdK/TFwwDak3DDgQNPFMDvaaMy4MKpOZVH0oNkPIIyBU6tj3ERbaQ1CO7blAU6DM0dfAB0CAgXnB0eEsgCUntVgAHqUBbR2GRMO8wGUI6T+ZA5aDTZwiet6JNj2DINA7B+s2QxUTcNAsXcCOuCHIRA04Tl02oK0DqNVgjgULsLLk7ZEVGaI8qi7MAQEuCMqsN8Ow9gxraZk3gr8qOz2PRki6TQRlM4KIClGT4pOSo+Rbjv78GQfNTmrwekIBKkvFogy0dfOYwJs9cX44iHpGDjAHKvJaAlSGlCn83M5L9qDnC+YEF9Lne/Wwz3Q1h9KSH4+kT6MjcMuZB4Bo2WFOe8fJaKG/bIruRqsdDMQ7eoaIlAVlgAV1VNctLmbCm16usAZ9SuuXwygQxSADRh6+Kr1bJZAm5ALp9Vgkd12C6QaTO33yry9ujzJiPwnQg3WvoDTb0t1eYY1yHmbijRu6/T/H8REw0P9DxaAk6YkeOKleTJeojnGW5Gz5S5A86ascBOEn4rtF6YBUQ5O21Jsy4xfm5I7n4kiznq4QAKjw1CWM1DgRUWmrDotybg6f+pqsCk1DqBKeQB1Oo8xGdsv+Fr/fhzjv2+ytp93Nd3ARTJsKKDsh0cnkLQSDvuaIzciESnQPBkgopVU2t8tdQRcJOivu/LfqxkFjsPb5xniUBmzxQhh75GK01Zzqj6xNzjjjKHlgvpD+lliHQd/z6+E0bjtw/ciAYD3AKAXCGBkgnxviGDSLOjvSEhx9xL4MmPVoesqBSKrwaCMV3IQaFIVDwIlNQ+gdq8FUn5RKl+WpaUtsR9K8AHvz9QX0SHMgiM9jZgoWQHoNW0jLguv9C0lLoXtk6XZANpb1LGlQo+LldoyX7C9ErPqyTQajF5er+nbpYxL5GNWwAlnZuu5kRVEl2CPbgp2BJ/CBKb9EgEpcQoo+ZBNwPugrCAAUC4QJBI5Q94TgQGeAoNPMEHROSyvFAjbgaADQ0cHX6jBAKoiA+g0xrQavkrtFZBfJ/x5P/Ii3eSgMH5qwYdBwI+VvnOgrIiq7/vE1Jxpm4uVMeAUWti6n8GfhxSB6O/OOBXpAnCZd+a9W4MFBOP3K7zInHg+AKpsDcKBogvA/sB6fXNUm3M+OOL8PzEljrcOvrzM4OyNjyVaAghJ5wfiT2VS8qBBSKuQ34/ggO7hQ6vB0kpXg1H7A4gS/aUEVLMarGowgO6jM83xq7/TXjhaN9TrtHE4UIwfsAlAqZ01UFLIeZuLBPK0tmk94pO0rQJtGEAQo3d87hzV+W7TTUk5/ewCe/gbpRALVzyZNQGjDZJOgBSC+y00rcbtMp1nn3OtQL8lmOfn9uUtU0ag3vjVjyrlBMKWYFqFnGEwzEQ2Nef5jCBkGH+K44ZEBqmnhXYWZGgylN8VenMQQW035YgcHs8h6EY6GnPNarAqcQAvDk83F+9+qV1wUHGl/e7XfsESA+SD7w9Sz4RXbe2tX6Cecx0PArbzmQMXASYhrLR6IbVLq1gVuNOsM34V1EKzgywgiduBGNJG+ywdoSpH034PL8wsQ6TSSPUKZXA4Y2bsE3ECcPDBfRAOxaGTgdHVYUEJmV1VlmPlZRj8HGjmfabv0J2RQIj9vRv0X2zq91uou1ZLW6QXmdELj2h2obruR/JhAE+2Mz9pmWof7DGh8dT2MPomWUfAbDjAHhNaEEiI/Bh/a1suoOsOU2zpvqvaAqR9czbyM2xC9EAUgiwADkCiMk9hxRXodTJOBEa34cBUwEZI9xPZEtx2igfh7Iv++4GS8pH+PD/iC8uTqCqx0UHO2QPMwegEcCzLA6ls1M33m4TJLtzOR59hxMgE+Dxa/4DCgIsEIvQoyGzgEdDyLG9rcY0D+BNBwH9uMdjUtak6LaO1HsUv9kMaHBxRfbGNCtTyAD2osEjo0QNMPDgYZFwiKbVm7Bfpo742A52p9GYgVlkla1swzMZ3Hl85XQBtCR7ihEE4A0hAtPvirQqnXGO+IyyBZf8fkZUSjmyulncKyI5DBw6dBvgDiToBnAe9f5wMd4vvSzmJYyHDKJulBDVk6Q+88fuIVBkO8dLdP7huSDUvjU1CTcDW5vl+003/OXsih87QB9JUHAYMsu3W89Ky4fNQg8u2XsK+eGSfg4IQ2QBYQHtRgYsSngiklqXMSNYMAEMjs2peybHgsCS0vkRBXK2ME4C+W3aZJue36cRt1d3MXzD8Ez0BigMikwv6AuA86AiA2sP32FPwftyR4Ie0B2ydDiMU/Ij3BKuQjgEZRu8ZO5VpFsRwApCGMH5GieGdUJbO2pAfyTqDk6hxAFWoCpx/61PVj6RdYb8fSCsjwixlrN0zS/9fXhrI5RED0KZsXEAyBqdrV5zYduDU1ar3ltoIkaztwOAAnpMwSOV0AdBgoN06c32eugIYG5F3Ye7lUg2H207Lj24PGg+k1mE1eAABoRSjCwmmQyZHiw8yF/chKEMjKeYyg9itRyI4vH8owYjJEERYEErLkvdEKclWIDkff9Yij735sTgOzB44KnSGskL+lEiqvZewDTWcVNMFqDom4IV3v1BkIGJA1wzjoyyVpJYfX4HxP8QZsGkiaZ90AV9ZZsuA0+U6AaJ/6wl7hXhzMek05L11L2lLAFJx0mUcaKK6AIxeQ6klA0DTj+9Dy1YTd9aQAM9gaqK+rK6ODHO71J4g8mCUgIAMggHiHrrwKw0SwQKE+OMWiW7XPUhRWzLL9Jq2TfMFYaAouqvAzwZPoJbnPInqYUHo8asfaW4grDGnfczHcRpD0p2T4dUkdaX0ABiIEm9k6Fo5AWYUWDd27PJv/uS2Z40DiDMLEGo9vDUpF3RPLlRlACC+BykaVE1tcx26xk0FRrWvpBDsL3abSQfV4gEAnJeki0HLOtFXlxxT1KP9VZEDCD3yBv1d+5XUH5YmRvfashMR/cYgz4XhMfoNbwAGH3+n20D2B80bY2c+g7VbfI9i+wLXITKTLTBgFL1ElMwRh4ER84I+rH0G1rhZJsq/CQpTAX84bSM9uw+gk/OeeR/MPXAHGA5iR0DgBJTemyK1BAkq4BzcL75vzW7AahgGCiIPYpDF4ZtHi0DGcgJcQjoEoNmwAJniQgAUoUfAQea/mw1bL7CLgycS/SlI8zdRFwDKrdutiK7C/rg4CtkTPXNaqCl9SuczEHgl7caZgp6Pzj4ioyfSg7JrV+CiozLi0MIlUuP0ia58HMOkAwQLNDAAye44dwRg2AqFU0EzAmwAI3YjvtlyNIB94AmjbLRnJZkyDJt9LN5zVb8nAiFwACQr3sMNOcEMFW4UbzTYt4wbD1qhTICSoqhmN2D1rAYrr5+79uhbUpUBNYYNhsHHpBDbC8OMeIpkpx0u4MQ/FkU20KIiE/Trkt34o58dbMq6vd1wDViKditqt0KJIiPIP3JgGD/ZAvJejN7SQsSAMUJAtPPvfq5I7pB1R9hC/gtHES3d5VbAPdDXUQZQ/1MCMkUIwLv60HUZOqIlfD8CAyPByIm5zCJDmQYYAcZ/yn4f6n9AQPgdzwYQ0P5cwEHpC7zzmQRK+BwcACeCUnHGwxox7g+ZSpAdr3EA1TwNGNB+0VOtIQMO1fI6gEhH4QjCRYrOBAB2SBvH2LqQmhBOO4gwXAFGTo9qGUVi7LNkwgKIunREoncrIov1HFTg0VtFoQ6tV1icLu1/IHVdjeX6rs6onMO29n9PBlvsh7PoAPA5tj7F6uoABEbX/5xx7+nblRVwdulbigQChujL10IgghbMTAcfGzA7V1gDDoLPg/pDDycTkDahLR+yd15S5tFq+AqvC5DYVCDlQaNBy3WXtmih7P3HywFcvHjRXL16Va/z58/rdenSpcdSE7BWx9G2jiuQoZaHvvOQackEUQcknwB7EJVkKwwILXVdWQUhLtgxW6vBFwed1hYY9gbY1BPqL3U/1M5kFwMp26oDh2FhRoiO0bsV9f99nDGi7BM9DBSkuanZqdU5G545ugDDbfpPhKYVN2NtXrnTdGF1GNmA/n3aXp25Mjfag9PIOBwIiCPgRQCg7AAEJiN4wYOAEeUhmznwXt3n54uDQMbCYNOzldIFKFb5SOmA1FhVdY2qxAFcuHDBrF+/3nTv3t306dPHHDhwwOzZs8cMGjTI5OXlyXAfJyLQj5q9omlAhB6i08Gyxk+9BUjUerhb4+3wAScIymhmQ79IZLQ93DNaMebqRsoE0smwUDJovdf3wB8RDGeA1FRRzTSgF9i8o7rZTf0tVIsPjjw4CjsBof4SwXnmkva6/eCRMWKiOFp9GBjz99TqZG1Ec4w/bP8pj6YbRrqJ7soi7M/B4HhvZAY4Exw7gGIAAckCQnkBgFz2THEEsBAp+0QnR8ZcGc4KLyRblJCQLMNQPIMwvPZYOAAi/ZEjR8zPfvYzM3z4cDN06FCzYsUKfWz69OmmoKDgsXIALAdt0Wuy6TZ5my4H0ZwDPXntd5HtslwAan6iNp6fy3Dh3T94ENC9hP5uP+/qPDTpbGSnV8shAwpJxWbYOtNuymHJP3HQgFdtJx00TbwsGE4CJ5DM04DU4FtPv61ngXNsNny9WoEh6jlwrEj1PzTh+r48YEQ7lvMME52IrSIkQjR3mM19OW8MEbYedXTY9RB/DLhUFyCsiaPzQBQGGyAbpGQgM8H46SIUVqALEEBAOYEEdQHCMhQCCPqFYAlV1Q78VlVE/9zcXPO9733PrFy50ly/ft1cvnzZ7Ny50/Tt21cO4HHDAHqNXWAvwic6UGr7Z7yeGyo09InZFdjK67lR/+cLBLwhKilUUYw232sDoCfPzvZAJtKeAPs9GWgJlzji4f1oMHUf7a4wEozjyH8rGdeDuQ4A0250TtyMfGEcgygq3QlgDc7tbbip5xZ7j9/DU3v8PwNHnDPnBDYDig8VPGRuFXUqCjTJd1Ndg8YeBGSalHJhMcafQDanbMfeH1p6dRUk1kdNicYRBp3n5kZwPOgPVmXpWCUlAFnA6NGjzbe//W3TqVMnc/r0aZUEtWrVeuxKALcbMMNc/cW/6UGSsrnWXYZb8DBwkZ/GylT9x8GDAxDVQYjd+qeFurRo0UEeCfoBGhDqu0Cpa7nIrt8WTEpHp4D12MnIBQh7+yBQwQKkVZrIglAEQ4m69N3BYApvlS/8gdFhuM8NWS5nD+24sV8Oi8OmPt9X9EFC5VhwFOg4YPRwAGg/VsYo+TkMLyE3RolJMNDoc3pxRP68i9cE4J60HLtdGeWzgxa7n3XrMXQAgH9kAnXr1pUT2Lp1q0lJSXnsHAAg4DMdRtm034GAF21qD1WUNg7pHGOivNCX51DZFUgmAIqMI0DKG314gYD2Y5BCOBDqssAEFJ01kYm2SYcUBbpN2qxWVLK1BHF61PNkQqD8iS4HbTPJ9eODRDjzGjy/WKKf4Wxa2KhPOUdGB0gHQ5CxYFqyT9izpATBmAtuPUhstNhnGPwOBXGGfIIqUXnvi3KgLmrHqats1rhPnIDOc86ZDjNPmdav7TWNGXumg2BLTTgLj50mIMZ/6NAhs3nzZpUDI0eONA0bNjRbtmyRM3isQUCbhjHpxwAQh8XBURtymfi7AwGzhCxTpwaSEPXg5BWnZfBkBCDXcLxTvMpLoivCKAWIfEQk+PDJVgbQoiMNh/vuRFSKE5oB6DjrrLIwgD4cM5GccV4NAr39acSRBrFQJg3BeyDtFPkZgVD/MwQGFZzvwVkPsyn2gfO/fEjxuTKOmX/HYA+CoSwRYX8BXIVYjoD3ssFmJvAOwITq+cEmloaE5aC8WEMHd6A61oN9qyraf9u3bzdPPfWUDP6JJ54w69atUwbQokULk5+f//iBgL2nmG5THAhIew8CChel0Es64xCoDev76TBAwOgJM2nS27/TdqL+42vEYrMXSFRW1IAScACkdzAGEX6QbHUSOgDYkNIBGLczwQygSKuzU2xJxhAWoi3gKJRnAHP0+VHi5Xz4kzYgThrSUJB0A3PRDgi/w4/3AqCLo//5i/NUzrmNvm4Z7IZjb5kSeycSKWn43mwkcnMlaZHdhGSO4EtlS72gHIyQaadXHUs08CAYSiNLcSPq1TMu/q2qMswzZ86YvXv3mrNnz8opFBYW6mOPIxGo19gsc/r6J5F139KOtxGEywO5BIln6jMHAp4o98BhiWkaMOwITF0txLqi1k64yCjBdLYlR3Wsffo6tP+W77umiT5IPhLJrHCMukQYC2UDNFsMnXQeQwe34RxQbSazeHHiJkV2SjpwGlqNnDNZA4y60TmHI5EV9iAtRHr/GCC1NnJjgMGMfC/WnED8Lb0EDnj6PaZt033i+xNYBs3bo6iOMwB4ZPIzuobn/8ETeC9NBy8pVZDuk6UdAjgBOkyVxRn+7EQgjJNyIDraV1Xkrw4m4MW7X+jQkPXG49MzruN7ufTu+TuDJSDM5QJM9vKQvuP11ae2h82gSsX0ziIv9zzfDLWpaX4SkoJ4rjg+RDJ55tTAL5STPfFMaYfBqeDrG1jnCQbjZMTvy4Fj7ERRsjvOkAWuOHXAxhYCATOUrTUeGEDAHDMy+5Cm/C5YJ4CjIOrn3XBcAXAft/IrW0YaZgPyYqgNgSHBBGT6kAzivN8UzFTi4DTHMOQ9wxtQZ8J+H4RJJBfeM0NpPyKo0KCZCOT/wZTcSPJi/X4FNbLgVTsLoA0uNm1jWSQ1IosleXGxEuXq45m5ABOXn3Jsr9RV8Vc/pTluOxOBTlc+R/hCsnIBMAJaq1xyCFM4gYCAB0S8q1fKxfihB4O1MOSDEVM3U0aA24Q5f3rtyHUv3XtNmI4TA3Ga/Bg0kZq6HNoxEV4goM344AxgYKHccwzDj0Xsapa6VE6F7IJ+f4jeWkNmfy6pOmcPMLz//If6POAy6f1576DGLjrmOSJORRrjRyMA7AH+AzyRrkFFOvAf5uSrrAzbkJFML6wZBqraYaCgJR+EHXhFK8AE1ZYIqhvDKfD1RA9qTWUS1nMzytllbqE/1JL/v707f5KDuvIF//6F6RcTMz3x5oeJmYgX0e5nG0mIfbFBbBIG29iAWWy0GLFIQixGYLFqRSAQi5BA7EgIsQokQFJVqcRmwMZsBmNwt+12Gyy6bXe/ePPTxETk3M+596aySrWkUGnCdCYRGYVqyazKe++553zP9/s9BcB6oRBaboxFtQl7OpgSXDOsy29/Id4PrsqYf8QvzD8FUsQgY9b448uY6AC818HxL7MbqhuQiT19BZ0nvAkQMAV0h1cPvZK9et/OIGAwBxc9Hm1gB/GHAQL+urn+Jvs66FLw0658sCkl/sG162NWgOyPSEwwF5BwSHBGUIIFnco3WJ8yDPuHRiSQf0rAs7ORLL2D8mc4/kNMRU57pk4JHm1ydTcA7IUaMG/IgeaNZr7pCDisN69/rQnmDEUftiEEgf3KRlHb6lszetAhAPrFbPi0YfLh/7TjFYF1NqD349BIzRcWRDyj4QcGuSpPVYLbPJUOf3X7cTCPD7efDAICZikAw+orfTx3cQYBKTQ3xpSgT3djIvpYdQQVBKTV0CZWw8sG8T3oDYCFso+vloBR+QQ+Otx4JZSCMhpkJXsgKwaXpwzjxXge5UieWLwk04FHaxv7GgOUaXnaFIbjX50Y6Is2FwAG0A5IpU0k7RP5ATnjT1sSPWMpXO497y4JdjtdceeWmCOQZwLuGg1mU5yTbg+3154Op+gENaAbGW+fJVeUSMVrkQbAJCcKO9lYfd/d4kBAWv1xAQIuihtfva59ZnCn9Qs/vmFpup/E7ey11fFe76Gt78c6ViHXBTc8GfU/3ojbXFnAAgx+gUima6SvX01GUJXhAA779IWPBUDpeeanfaNUgS+p+10M7blI7whdxLhiQtsNAJ8zAPzN32VTUDZNI6GqbooN/R8FmivCEw4hB4XWPx1mt4pN93yIgHYOQIPDPyBtiNCNF2owEMkGQPpZnVLE7WMwtuo/aiYAKZdCH9CcrZgZlqGgSzeplP3R/o+affHaq0fldvi9327dceEWfE+sYzs9dGvi0N8IBCxrowVsziPil6C0rngDVJygVZvv60oNGoEIUqW0lDlQgEL5v5qyG2Ill0CMib/08bZt5HdNCX6oGwD21hZ80nkrG3c+9fMhlYC1LpXKW1DtphgJFmn/J42lD73cNBOVLj5SiB7KBXLRM+Y/HDd/2D2ldFDaD7k+6OysBvQ1m2RLsZ/uHv5dkt46lpuhipQXDRZJCE+AVgAOsF9ps0Hu60HYVgBdNb+bGDFrxYbXhx2qsUsVuHs20CroseaUoMqLTBVf3rh2TV+UB9X3D05QUX4XRQwwHTRbwPMYBnL0ubfnErBMj24/APSHo5TfgY9hNwDsRQD4r0fNCCag9su8lVsilW/lgbvFccyhtUw7gUKVLVjpn1Bkh1+AUINKH91K0k2AEteaSReta0ye/3wQfrD+gFk2slaQQGCz20hdDOCTpqlnBM2zlzcmXfJoi0def1NUxWuReaaD4L3OswB2DiwlSottqCyrHnx4gO6PwJ5Lik9H7vKkPWJ02X7p1naAufjKFCD9LMXrvAHKw+E0BT7P+ntSCgLwA1mNVnA7DMgoAeasi9c2R2KsWIEdWQJMnnp1Ssl25F4wB5eUUuED5Bnx/xqccGCLB8GPRWY1Zc47QghDSD1jG0hJAB9Q70+etTo28OHnrooDP3i8VW1nkQgLEAKFerfTTUFDrLPxrVBmovgGjyL4AEO3UbXGDv/hnQEWChq4/e3ciD3Ng/xMaAAAcWYAGD9OnDO4vz+4JAwL7wdfakyZc1eAgEqMgwsI6PAPJvmMFARcGkoVmeHoIqj8N9MLCAA3j6GNfEeCgOTAP/3H/9G4ad2r0bdF9HDYpVbspCDResbkv1BmVFM1fwYBF0cax1++ElmQgHxexmBw5ZSrt4y4oN9c0B++ADY85Dlm2HewLbiH4awAvKNmPzzqjRhjs1MmcND3Mw/AbfzoKGq+asoBP6j23GTB+vL+XWnE9cYfLlOJIR6v/z4uCb/z5FmrQhkaLj1t3sqVNYh34m/GAXDATx5mFiJvxCPPuycwA0Qn3Y1uG/Dzjgf/0rGNg741t3EPKe8Hf4qWEsT+6HNzb7Y6yDj8OgDHnJ+jrkUm2z29+MR9NbzaH4760GJOmbM6aldIbbtaAHJgP3NTGWTRyXMBHCTciMllpPqo7186FLIAabSb2AF2sw41wSf6+Q7/4scjkPve+557Nxx8Hdzv8yNIz6F1Z50fLT37kX7nOu9PRlGByNaSIcrFIh4b6rAGByHtL1lIqP3SXohx8gOMUPoak6/YlP7O1fG7wZ32JNB0A8AwGMD/cfg5jSNn3BZ9ZwAOtx90UT1c4BFDRynhSXPXRPsGe6wCQj7yfq/1v1vEv7Wc3CbYaiftwWgwxJZLV2zu2NmAbmb2WswugaVZR9HXlibgaxfcHwIsWZRMINpsq3uaU4FaRUcL7u+PteQpKKt75cM/x+eBwMDHG9a+HP19WZ7nY95ZJb+j4ReDyxkCJReIVjFugE7BUM9TR5ZRAwI9AZyGgWD+kUfzADygjAiXqWIBykC6VOC9NQWdfEHjsKm3xC0ufb8rPNZ2BosMBmCxlAM2gx6v26M1RRfZN6bMAedb9LapDg4J554OB320Oxz0rTwa7GsxGmz58BTqYUaDoQWjccNS3OKCsJteEK+mnG5NgK8AoU5/tP/jsG6T+WHuke8KCFVUNK7MCED+0vHZ1iZZy2uRAce4+XQ5aEXKKpUosryhpMVZQfib8DSAI+0SAy0NMRAvQo7HQOd9QRfvUCLQosbdKfKSXzrkjBrZg0kh9YxnFOLGcRfeGWPCh3rje0rtytBCr9+GAersSV8XQ1AJgIPeyUAgJP678+7PFmmXPTH6+2dYRgoUMoaJ6X2XyUm7cfSPJw3+9vUB8CLqIPZg6SHnmO+XTThuLcSuBZFaU2MC9+oEXxp+alA40IHFhNQtPhJl2x7B7XcZHFBIS1esfCFq9v3KnL8wM31nIJXcv5Ui9BBovnXkeaUWT73+0diT+2p/dPRcALc4HnedE79/MWQw2EFa5hYZqTbPoNDOSB/JNqWh1deuHZNHNFebc19JPb9ogiCtPb3/2v4bDhH3NdqAiWVmH/0AY1edGROGdAasqezMWjpISoB7N2dRENSeZTivf1x9/66mIhyfX0t7Q+oO6IXuyywQuB7f8fGQ2EBvzJj8KG5+3QHUYfp9e0PgMF/QgRbsKQ+rpbm9JWjU7pFsQVdAh8jHMKVNr438hIL8V2kI8kXWAojE3lQHfX5KIaX9k2evDqHH2jIuvF1UFw/ArRFA4MXrGycXX7ehEGy8gGhjpVtoRrqhet/Z2fEkIIfipJSRjS/OwACx1hl5rR55R1+0NoK1Q37OtY/EQckKu23hCFR5Giy03ObAXK8TxK6UlgP6tPTU/8+98c8h/9Xp+XLRE/iZcH9Oz6OvDxuoX/O99kwN2MoMqDxmXwSWdGP7nOdu8kbSA74Uk4fT68tM/L23bngjbMYd/kNnrAyF6IlXbQkcRCl5/LxnAv0PJWC6mASB7nDQfSAGarWHzkqr3cdAB021sseG6WUve/iVkGy6mSja8tSXvl2jra7rDZVb7udmNPqRfVTbfeEMQtP7jWYbjLv03hwy9dbGpLnrgxMg3ZcxkQrLECaUQZwOo8PldhcApPnq5RADvZsPXw0IdXovzAdHv3W6b8P+6RcAAD8aSURBVDYV+bBx3tInmu1ct/iWEiT8XoENhOnLDUEBF1Q8r+eBOUTWmEpG8l8goLLkysAYfhqfIwLCKREEwqQkBTu6EIeb0k9XY4CDdMswWZ0loiJ6CGzCbhdgX6oBh6nvdAuoAPMo70+abaDBqC70WBlhE0vjzAaA6AoI2n5AKl/TYXik91cd2/4bjhBEaKMWrrZYIQTik1eksw4MBuCKx14Pym5l/iHHkNnGiO5L1kRZ1Wrdpp4XnB2g7UOm8X8MsM/Al1D4pTWSKVyRSsTtQfPe2bjk1s0B9soGlAakw0bEjQ/Djpvjlpc9eB03fYCA6WsGl9647tUoUQQHXQafpwbMUuDRacBEQ4KTicJ9f22uwF+0AHBqm2rAytxi2IHxd0SK2MddcGdsjDpCfHCm4N+EQDoEWQ66C9W1gaWT6l23UPfm310NaM6CG9YBq4AYERDSlHl6DrPe++BD4KC7lanzat1vnXD0ZQsCCeLXSO95DSaA3xNm3ZlLi7RmbniUYwfYa6jjlR9IPAKOwGM/OOTB7ktBYs7yjZEBVCWp3x/QjD0qCPn7sB5jjHwboOeUq56PNiEMA87xVzMY5IsWAP7zl45pHH3WFWkhfjeq46sbSQ2I+WehvfkW3gYTwWcufqKpTW8FBjnAbNjxcdwOE6sSsCC7UOGr7+qNjdANAANpthff8mye42c8WDq0wDDGKtqDgYqnm9X47nDZHeK9c0s7HAw4AHJuZixP/7/4wZfafr+3l+EdOgbSeo5BFRuotf0jBWOgzZcZ8hZ0qGUPREi1BNFi1EqsisJTL38g2pLYpocAPNvgPNSSAEdABsRwpEsF3hs14JFTG0fNvCMWaqhbvGn4mRbZjW0jQXIZgxD8IHhgDtKf++jGrwYhcAJacMSN/WPUdSa42MgHp43sRhlXxoIZVjHWxI4v4s0Pdzkv3Y7jo8ZeFkSY7I+/LQAxVlnHXvZ44AKA0xPnrI6DPlTnpDr9UGWqv+EETDd7CyOvr1h+hT34KG09h8wekHar2yembE7Qr0xBweCVlEnKDmQBLgb2ZK0lRp01qP4XRLSXj2D+eeZ/oOGgXywi0PGNLx07M9Ipt7ievwjeavVlY6j1tYgsKhcai4gk9GIhCyGv0GV/5ZR8w6hBLTwGGBCptgQDxLpma0Z25z/fOP5HTwUWMOH0PEpMEOjkTMB7JlUeV6b0QMJPKqKpwT6K3j8OS9iTMoGRRnrJKvpaBneEFuCnv4+gbziIMgxOEIj+OyMHAh8F9ToQ5thUw19xx5boFJkrAc+R5usEDOfuXGcU2Et5gtQNMR48uh1tTEMybObgc26NDDQHtG4JsFdEoFs2vBHssP1KDceuSVqOkScdhfoCcdw2Iryoa+NAh7n5WAA9XjThmGV/zvKoOSG1iCBurKE3cn/cbGSgdegIE4pOFAM5lN7zSWGPlecpjlQP+9qU+S8EuCrVnnr9+kDoR0PFvc5zP/3nCPYOn0PswKrVAXkBGI4yMVgw8VoyFestI/BRoHdJ1MPfM4rJjI+ySa/t57n/ntzGFCnvjd/dpaSr0BUD7dVswIWN13/932NBKboshBYPkwkAD2eXKhrR359786Y4rHk24MLYrERBwJxXP/xzgD825PgyGwDHf0RFW1F4EXkoB5QUncgEzESYN+IQHT5jVdsaAJ4KfmZceP6vHrGbEkYj6WNmdy4KrgZG3pybNgbBRpCXeVy1uqf4/o+cDWALWnftRrwCIN/c9P9mCLQDzNUyESU5SsS0b5oTgncLBPnCUA4pH/29SwtHodsF2AstwFdOOL/xI0Kg0udl9MlpFlrsgNsoWjeGfrj1/ZtqS6rq30HoKKm/fq9FlVJmOfCt2eTxutGjunJAYPnWpfcOsJbqpPRf8EP+yd547U0GOv6KZ5ttwjr4Q62+/b2dQwYZWgE4js7A7SmTU8LVG11K7vUFddnAaLLi7Bi0swSDT6I93DNIgVhdpofDGur3MhKZECKgG4PzgORUg1ymO28NDoDxcYBR8yPGeoZkR4KAZgPud9qSxqmX3x/pvPaONxUjUGT2gAEQjNg4aMHqLuWBjQMMxDpz60v/GFAqISZ83tmAKZA82aGzAS9K6XCeDbh+D2YDPh9llu4M+q5gbHrPXc++FYexptpVmVeFQDev/8kAZycfveehIeAsnEqDk1MWaB/UQ9bK+tuT2YD0HTID+oOglA8aOtrTEgQy+WhJXB5YkGjO+AGHpn/bU76mFfncECa03QDwOWYDHnXmvMbpP14bGweoArnVl6/y0J/86i+p5n+zOcTBDTLUbEAKrzxwYnF6nlu6swE/RwbAJdcB+PqsB9qeDnxcypwcCk5O1s3hsAY6CPNWvpBq8d/F+lDZkWlrBc5YuKFp/z33lmcb19+3vfHAll9ESk8O7pAyIuX6rDQwzUcAARpqCfa3UaKFI3R6TeCwzERACcvwtL66B3QGrXhFz1u5/am9aIzZ4VOXD1ADenx3Xm4btgaNbgDYSwzgtNlLGlvf+mN4vFXxj5R/wX07IgW8cd0rzUkyNcUfbizYY/0fBx6wazbgHXswG3BTzAb02ps7dDbg7Y//NPf4lU4lBR4VA5j9UNMHACdgx3v/EgffesFU+DgKCkqDGNV19brIsEwBHlcOZnUF4tyM6BV1dUrvPY+A/ODW9xvPvPrb2AcOZ5UXjwQUMjbB/bCfuBGTE/s9KtaQJxgPVPaFecgvPotMlKlM+BoUzoixZQhoLprn98Ht39FU4Jd++eeI2AAdzj5qsYrsuk3cBJe3MbjDcygXagdAPWciUDuzAVGEtbTcDh3bCkw3sADqPSfyGakMCNxk3saUNS0P7GS/JlD7YWRvWrEO60Fn5aBuDbn90P87iNYXr8PtL+vjQiRwG8/GJ1DGgJNw97PvxLpD9Tk8+x6HkVHscEChzBGwmMuRO6NMFJhcEvc+914EI5bg8CP8hGpaUjMYJCdBDekJZ6QSoCacnmdWMqCRJXZnA475bMCdEbmlWQAhHQCRGlLc7uCOWnPKFmI24LTbizFI/zCzAfsbx1z6WLAE8cYNoejUAOAg3PHEzyLwRlvsonUDZwOW/4/DnwIrdiBADNVa4NyvuOUAYaXpQDmkG7fmyqd+Fim+OltAkDEYEOKwWncHykw/N3T1BVyz+d2mOWidDRgjzJmNnJmBwhhB9t4uO/laKmACKikxCJUVrVgDXABDMRuJ3hjByr47+6p1mQPx/ZvCAn3Kj5+LTMgjC6AeK9OkFoVGgnvSWGYCXTFQS59XOmbBt5TUbABz7L3PCnV4eEmwTEA2IWJbNMo/7b5KZFEWIH6od6X+0j069k6eDVjfO3JsN6DaHgDGWAUDUN/frW9Sbp2rQLbt8BDvGMgqG4iM7fYXQgmYCVv/2njlwz/FbQsAVIcL8gPt3/P6Prjlg0jZxxeCDu/HnpbD7SM3aDoQrWB6AxN+lW0AZMNIUZgFGUNJOUgB/wCclXDUX/YPDkC4SKVgQRFYwT+HPQe63XkjggIasGxRidENAPtQDTi4VUN1Bs11UFmHt26K4YKA22lCcZOBCRxx3t0BDkJ4pXWhFEybmX/dUCaWHTkRyGSfh1+OyT4Tz1halIA3RklVW34OCzmvnnuTep3eP61EN69sgIjn2jW9wd9g+AGcRb/m9TjSugn8eTbh8gg0D7zwfuACRoDxfHz943+PQHHyxffELe61/K6yRtwCFGVtukeLmlF5EliDGREIRwRFKePYkep9IGRVNjKFCR7AKKXP5PnPxaXivcA+7O3OBdh3AaAeyAtvfDozx1LUF911BJA/ADZDTxTK3QH9ZRZX1SasKgKBO8ekGhApxcy47lSgQW3BlFY7QN5jvPsDmnMVlzRRcek6041gAJYDXWc4nnLZfXE48wTfG4J37/Ar50YrsWrvfnUK8qdf+VAEcg+HW+nAjMPa6v0jfgkEsAPgnkEvM9MBh/I7/F7fR6+LUSo7EAw4/9AmOLzTFmwobeN7254NeFTKHJULF6UA0qUC740ceNaSxqsf/tuwRA8Hc9aNGyPKxyDQdPurAxk0trYO1XU1Hatc74tXbA5q8cFnLxvY0ikbGhJtsIjN3j30u/v2kwIHmBpimZWNo+esjToYNoBjgTdhIMjk2avilq+qQOug/qfO8x6jzDrIMUl3MBGnvN5ggHdb8Sd8Ltb10ygxGIdm9ufSaCWq/wmAoPLagzgEQD4lCScpXQfiIeVBTfsrhTibli5tLH5gR25dmg142R7MBrw8T04CmnYDwOedC/D3xzYOOHlOY/Uzbwdy3DOES+uVhZ2GHGLxKnkEb50WQJooI2A46dBr40CiMfpEaCQVll/aVVxsbGJ1rZFX4QCTbpWsBOyagbRaawP1vO8Hp0MOJAWEtY4Gq16KBEEyMyh+DP4s7+O2kg04vA5ybdUONnP1EQDoEWPh3hs4GqwGhfzxD3FrW7Mvn3J92hOrIhvw/FUgxu3HtF97AmP0sRd/PeCAVuMSZiM6FKEd+UHu+cOJ2g0ARssJAN+5/L5uANjbuQCHT1sRtN6n06GubC86fqBRrs+WhjFkT3qjzQig+7eIFvuW4j4j2rtlgDxuHIdfB+CEec/sGgXWnGvX15h85eZwCKIElE2gGnc6AFhTeHr66IFHTfzs8GQqo8FCR7EqMoHzUopNmdnX5miwzaHIezLYgR46PjAEpUcrst+aFURZl7KNs69ZF1mhsgLZJyzG088RhE0sHoX2zFC/SwWUAYbWPisClxYCVLvjwdcHgMjerDsb8PNqAf7+uMb4E2c1jph+a0Rs/VmEDYISkZ6Lj8UB+pF7Ap3UnZNm3hHMM+IV0dcgkcr4ogRk+hHtv5B39g8bxU+8eltBdBfF5u10U5DaasWjkBIfPWfd6JRgoNiVm7O/QgrU2nechEYSVPUUii78wLpbM5yAyhlA94bYY+YN5zOg/tcNmBy6/kVNj0AlQj38o2V1gEX0ZPuuEqBGn4WQZwNWP8QbizFpNwB8bjnw4sbadOArWg+xRfu1oNpJDv/6MAO5IwuBUvonMAS5JH3/9AWPRauQgMdzhKrr7PbsnU4um9f3A4dshk4OAsGg+8nvAr03BWdKu6PB0kMgraPBtOg45QxF3PJvPHqH32HNfP/3A3NwI0+/fkNhES6OjA62MBT1N2zg0+fJw10WMxY91vjmxfdEWxIw3K5JR8WLvodBmrIYfpG53BnaRVoA0EXKXpJ3j6kgqCMDwLfPW9h47eP/Hj1jLR4EDROAvnPZfWEdpYYL5lbaLBcsfarxzGu/i0W/+u7eqN183sGHEq8y1RY6PX1l+2OtYijIPVHvBrusg4eC7D4arK/90WAX5tFgMWmXb2AK4jEkpLg8x9jxIjq69p7eCObceOA6MRqsuPqEPHfDa9HfNyjG4BDtv5EmBe/CGnb5GY6mAhxMIxf8ZSFudbgG3sM3ijtwzYJOmLexlI2Lg/CUvSi6rsB7VQJ8+fjzG8vXv96kcNYbOLfx/iWYYzYCVqBbvjrKWFTUYXWjbAAIFT1d5JU9UAHGXMC5j0T05zTbqWPB6nv+9Cv/GO5IQNIpV+3BaLCZa1L2tTjKMuPbZXNKAig8hL5Kd7H0TH/S3zdfTz/f+652X/7Iq2HIYh8I8rNv3Jip4Om5TABuVwkYI77ShaD1N/umZ+L3ydnd8IFAEHnwhfdDyVg5AQKBveRx2A/vDPahctHYMIe/OxtwDEDA//PIqY0J6bawUfRuvanVA47mH7NMZB7Ks79Sh9Ws48InLveq9ygApM3L1EJKZyZcJ2cAdTTYaVc8EAevrbZYGQ3GUstoMAfZIQPgwgP03PXoCX2+HxqNGyM7QDSS8R0xtczuS49a4rFye650BLQOlXwzFj0egWH0w59pxd++9J4ycmyX2AjnQ+twqJKir+w54rOjiytSK29EK1lppOWMwtydDThGbcADvzU3TEGh+Ew96vBF9E0L4CYJbvkvPhtxvvvZV+fhoEgrh067rS0jkArq8AsU9Y0V6/TZAA6d21YAOGTqbeF/N2wQKNoANXG4AhnrnYLAj257Plh2VH+Ym9mUNY9xt8aYgA4/sM7nMfhIg+vsQIFA8BBEYAMEPUbDKwUEl+Fu8ZAApwwClRiWRLTjZzy/1xKMTojW4UsDjEOqEA2197ACIrdyRnQacFBWpNKk/72d+wwn6ti5AOt6PwpjSdRKevHWzWQYxGggSwSBn/wusgjyUT9v2u9oCHb0c6/clF73pvg5baROZwQGSPfG7zMfP63B4eeuytz4OhqseCvGdKUUHPArBE80Xzf3MQWsBcYJ5Pj5Wreo21p1bk+GLjG7LwUExC43cmX2rXn2nWDuRQmR1lFPPzQGxYwDeFhlx4Odf+BI8CDPOy3tJwBdTJgu48mYxYxrThva1vSSwCbUiagDZLQDcUY8+EUeOv2OmHlIOHQdJuPb3QAwtsNBP/y3OMSisLrvOylyk366KQarAGNOfNkwfS1y0Gwk+Un8jM2C53/c5U/lIDCMv5sOwCHnZKcXLLMuD2DXe0y2a5R2HIpzVgSBivmHzoCgyTVIhuDrgidFncOGhwG0zXTbVTHl2Tr5GlWe1p4WbhzSdJiVHE2yT4vz765BsQuD5+/fOkFSerMD3ewxlKRIeZUHxD3wILc1PoJWI+v4MJgNMPCzUBzSfggEuCc6CMDk/c/I2BHl6MktqscIetf2hTqw6iL8rfsiU+x4LYCFbAUBB6daQCRYgJsGOMj6a334xn3WDBThIrz4iSLrXN44JmUChjxWwK/af1G40XnbwJxqbJKuHmBgKfDky/8QVNddgqBlzcfEMl0JCGsSTyXcVP/+716enZb9nMyMHLj6PXy1pOdKt6He86oINRXolJQNuLGtt/qd42+9xRl04AJ4PaWjz8kstCCBjdJ9ykOdiekLNwQQCOT1exx3/somd+CAmB953y6T2GH4DjwSXBb2y1i6AXe1AMNoAQYDfhbu62XoA1GQOu+IaSsiTRTtt5d2kHJAP/mgslEPmboi2jcivI8Ofp1iK9NwW/R2b//djFV46UnlDyx6gIGjwW5vLFv3SmPrm5/sxrar9bU024Ek0oHkCwjWjlDoyTbe82rSgVeAvx9twvQzSglZRlUCWuPAF1IZgktwy6OvF5vwGyJbcMOHUCj9HejjeazYB0E4MhPw0OocNQoBiJw8qM/p71j68EtjngV0IAh4XGPiyXNSffhWROZh7b6MBXvuvbCEmnD60kBzbc46jjo2VbopUFjrUBGbB8efemxiUbFN/N7ieISi7cylgVp7ru5U4IGB9s6nfh4gnNsupv/y/p96a6T8B8dosKVRD6u3H976yyGZcLXtRx/Azcn30mdo1UbAbYsu/GkECm3Jmkms7/1VUMAh/YxGzk3Znuf1/EbHrXzyZ3HrO/zAPmUCMhF+yfgWXMHr61jIAL8+66E2KcD9gS3BRqbHKPmuKejeuwIffk7jsHSL8wTEyMrp/MBbAIAjnRPxtQZzTZk5A3rMZ87fZSpqRtz24jCLiBLDQaIzcHu0+6T+yoKvX3B/bGobXJspp7E7O/7m9z4cOf2WbJSRbkbvFyOQ6hEIA5h00SONQ6feFtwJCD1u/nCHoeftSgTahbiH+m8QUWck/IV5CDwBruDmvy+tuawjnITLz3kNabnJQG57JUF/8SmoAiAZCyERoBnir3M0gQrw0j1QAc57JqsAU/nR23UF3nsi0IRvzGocOSMvinoSh7ve+hYVMnzqvPsD/AEe2ThPv5znAqohpXMWXkSWmukzwwaAPXke4LIAsPC3B6vZYAGMQfYXBGbcGjr2Ts0E6m1LWBVB8fx7A+Vv2oENav0By6gsBQE8DGBeuwfCgXSDY3Oy9brunr5mB2ao53CQ3eKyvIorCO7VjMQ+UQLWDgCcYDBF16XieR7c+kFgAs36P10Ox176WNsZACB0fDghre1mAGODASxuPLDll8H0E7k5thgjDTTi/vr9a9aFkwveNcUebYCUEPI8ZfZdjTkpc0Agsrj6+Pq4ed57rleptiqHe7ipQOTBHGwZSXSyH2D221sUU5JGq4lrAJVZeZ/diNZrNAGO11n55JtB+AmiTnEFRvnlP2CNh/JniJu+OAWPL6axanhsP8GD2cdXAxO6pen9P9zrP1SCgOfBG8n28e2pAF0mggeLsb6uKehYaAEWNF4PLcDvo8fqcFd1F5BOZmDkEwQYU696u1vAWv+TkiKNMIeA/ioF1P1fa8Ph5eQYbvFCdAyqB32nBYGYCpxuTC6+3vNwUl7QZk2cAmy4N5+WPRsCaR+GTdkbmMDHkWU4rEbBYQQ6vEeGwGtBDPukCM1DRYae4mONZQNuYsFj/zN2kYyUMKOtXw4C78fsAQ7DB6a1nzL/uZH3SjPg5QxJqdkFAcdgNNh/O+68FE3zPDe9YvU+5p8eMXBHS0+66OYXsQWINZveDoaYHnOkfSkIOLwYbNJLrSvpv+m27dZ27KCyIKi34+jAyirAnKlIKL2ZRdnXtjFGbQ1SbzqETDp6ikdg6w0eqrvCAZh6XU7TlXDbS4p/dqg5l0YGh733+CAzj9YDrOTQj5+Zsgal47mplOAAPPhQ9hasYHvhjdQgEq5FP/tD4/ylT4aXATWjAz7Ufsmkp54YCQ405Dcx1mPBOloL8NVTq2f8R83Fqv3h7PDzyzjgNgfbJ5+rai+ZAxMJqLSsAdoLwTaZBoOtHTFLqyDo0hWdJwjKIqDfRBouExpdE986GuyFeK/d/tB+mZdAjWRDkLM9sJx8iNX7MjYH1uHT4sPjgOXEjMCUIQj0QEjfZx3hMjmYfDrQKWjQqLCeQRThqgpc9fTPI10HCuL5PxO/02dNXwF77viYSbCocej020NG3nQ/imDQGxmR9l91kBJoet/pEoHGRAtw0Lcvbpx8yb1xeMlDb1j7SvjJWSSBQIuONBSxBxtsqOGOgkaozNA5y1gqGv8Trtzc9pDLKgiyiTstA/AebkqHkLmGHj8XpXZBsWMvfSIOht6+Q3jtmr54/79aDjCm3UPbPojDb41RhrVrZXlEXrj/Xtf7HtLgVMYJ+IhCvv8H1zxS2okfx0HeVg7u6EDjzsbVa3qDwtsqNoIbhKbgnT+WDsUfAxjUPQAIhjdEuEevCWzosBl3NolPh6fsxuHfsY8uiI4FAXve3hnAn9RQLemGkN6hlZ5yWZb7Srs2jzDzfXsZCBEgYEGKj7l4Q3tDLkMQlH3h3RKdKAjyN8uepMMGYo4eOLcXI5A7m0xBPnsO3upn3go34ZgYxLaLEOg72akHSw+QR/wVhz8F9zrYFWeDdNdzeEjrYQSyAwQezyUgAAp3jGDk6vLQWaAl8Zo6QsBCuEHVmEwtmoJKJ6c+1IpuukcP4I1k1qPfUxu6XR5DNwC0SQV++Zd/icPtVrAhBAI3fmWOAQHXR5voj6OSWAQBNM8we5x2+6izAXfVsdkVCHGlEynB3lsHQorrEExqTgUaxhknva9hAnJGHvWNb6F2FwTqnADArANr6IbDjMl56+NvxI0KK/B1r33v5nejLx9DRdJzCETKgxeKTsDvtmHHxzGv7++/fX1oAq4vopzd6OJpD5g8fFBxeVICCCBxa7/5SQyXxSnRfTAHUrbha6jgWnu1dXx4qvcBnHAkY8FhRHmOxOIQSslIujyAMdQCRE2fNo5UdGEKBPr60koCD22evjYjrs1iKqwsQkpvk54Uzi7bh6z94QQIQYZJZF/AziUDOTwYlnXwh/aY4KgODmPQMAHtieEZ1Rmnkq/c3LX+p94LpV1Qdz9tzhng3ejgu/0h/XmewydlytOnIeRSFtT6f120BD9rgnm0CdZofNziS8L6++EYFJrJRp6PH2EoDdNzwBP8Tep8BxZfhPtQuEaTDJtPmLIO3BOU8Jgidc6KPEWqBLrWR4jHpt3WGH/qotA6bB5jPUB3MEiLEKTyyStzLKilTebYZwPYZcM522ZOwOLQ+2OwhcVTIQLZyDHrrQiCbAh8gk5XBHq/Hc7MBlwU3oDqYDoKZVJIY1ONDzQDGsq4wsQlvW80/TIBafb5S58KYLGi7zoAbvlI4699JGV8ux+ewHx6f9X45iWZzUfVh+6b98InEdj9fkZ+KReQw3gNzL15U2QRGINudy1G6L5D7yIh9RWolJHX3N3X2PTGP8XrVQHR/iXFR3k+4cpnhy0bKwGqMkiVJ2NZLnYDwAgsNekgKucFy54Owwm3jlbgcAsQ9lPpe44t5UD0+Vk8nbcmAoLywC0nbRXNB8+L7+ggkA4c9J0Cj5jmoDpYpQxU8TmgXaszTkXl6f4BbbWmV7t7LqWA0m7SebfHtN6eEUw9dA/YhE0o48cEmOoTqER75Zd/ivUCCiKOBXZ0+pK4wb8amdyTUafDIb5SSEZ+58obQCqTFcgYfnTbc81hqO1QggWH41JZYN8IKDEXsWsKum9Hgzn8M5c83hh36uJAc6sj8LcuuTd85YYSEvUW3wCorcWvQFW1eHJT0ZlDqTeNAC52Ki3YYb7/+fdCcks/Xw8JRaAD5GA/k+rmwXWw91zJxtHXAXbg4mNaM7d19urfOerry/QEIOujhr/8jufjxs9Eob5mCxBQzMsBHZmZrE4R41j8EPvE74FHorR0IQgiXy5DRWUNAgWRmQsiT5EevWuEJyEL0HomQOoOBtlno8HSoU4PEV1a52bBFtT31zoKT/kfLI+N8uxr/9RciL4iIEImwTCrh7714VazadSZ3alAgwd2/D5S6IPLBGCHAwNO1sQtWNo8rrTUGGkOzsIybffTOOx4+QLtnJs2Nh544b09Spm3vbVrZJj0X8qegcLFQVvW03eLVwWo7xMsEMJgOiTLj5ZpRRVjkjnkUWCLA7y8JD0nWnkAxtf1tU2AQpfeP11CuhpjVQZ0pBx4wjdmp43yZlF2fbrbRkL/VVMChdR0mGMWfVPpGqjtRHQpJiR3x/v/EnRUtz5ij+k20n7z7Jhcsnni/W6unRIAYNTOrdQxfID0vrJnC0OV9N4dNevBxuSCn4QaMN2SiDGwABiBjstw8xS8p7V+r333wQNAm7bd74w8mbmnIP48BgR1+hDKQJ2FAAHLczEIEbi07OJwDlrX3kIxzmKxpc22Xzsdo9aHchLHIJOCuhnAXsmBD516SwwAlapVVyByX1wAER85ZVUZB64HLIqjgpo5rwQI5DhFfLW8wxxCj9Oyvzv7qpMGWDxldRtQUGCgBLShCEQ63RPADelmxQVw008OItXQakC0WYE0BmRcfHcg7G3bdhda8DVresPoQ0Z3VzpIWsHt8Pgf6fkwDj+g0OEFKkaLMaX42WtwUbQSh8vsamYhCFRno4NwEn68uS3+g7/dBUJGjqg2VuVjR8qB9z9pduPrP7w9hCAOrtaNug5bq7rGuunv3vR2WDEdlOou0l31HoQ4ptmYBnvNI4ER5AVdEtzuLGfdPiyNVXsrNnEKAmddtS4mDI01v/uLVPcLrOp0Afe4UQRBdbRa7grcEMw9mcBo5VRv08V5XeADFdOh3tS65bff89anIwYTQYJOgKGH+j0ch1LArw5B9COjcfVrEEBKir85XTRBgFrQ35YAKg8Gvb/LA9hbDOC0WUsaj734jyEOsQkqolsZZNffmw+/W9qMefZQ2kOiPEswrSUbF7ecY4yfkbrmaD66ErACOjYxcVEny4F1WcLh99zVbdbC/WEOWtWAygHjuUOrMUyQQfBx+PcrKbzXBChC1KtjD3XgY6ncGymYhDls+jqCEHYe2bjZA9es6WuOFK+BZDhiVyUZUYCGghR7NJWI1f14KAt0xCCkMX+vcmN7tw34+QPA3/zdMY0p065Jqee/pNv3D5HGEZEwjrSYhD9aSMFOSxvDQuvh6i/LECbPWh23vsXT99eCyhv4rrY2cKsScEKHjwbTSblkxabATQij2qJQGxE+/7ngz4ca8PQlsRY/XrWtedu3GnI4bAA4NzYU3hSiigHAb66+qzdu45AFp2CivKuHdLjbvJKAqlio8kMEcu1GxCBGJ3Ui8FBBwPf++M6tcXnIIGn+QxBVCVCBfWwJC/QDgvGYRWcunS4RaAzUgGdd/UjUUsC9Cgb66LaoaL+e7/aC9mY7qc+ijowhk8UT4NQrHszuPmHwsGMPRoOtj43PK65TR4P5uy9a/kzKqha0NVNhKDWgAC0bkKnh1Tvg1bFHVnBjKtncsodPu7lx97PvNKXA1tV6WnOef1nOnVmF81ZuCZPXTcM4CA95q6cDjaSjZSgwTUofAydIrznYZr51KjK3aSWFLtEh59wSOgc4kYwIJhLEqPS36jq12pl3A8BeBID/+vXpjfFpsfG21f+GSAQl+PXfRQvJbaH2d+vv3iXIQyxo+LV0xpc574ZZ7EkGUJWAV67a0rEZgL97wb3bC3PyrvS+tBc8kWf8jPJLAMfRz4YfuQ3Huku/HdB3yA+Wxw2qH+/2lHFJ9/XxCYiAgNXn75q0prAeBxj3HzjZN8qQz1rKLHnwpcgY/Sz9QHYmzjiDQ17ZpYMFRNXJ2F6qvIfaQpbZEBDBKIYKIt0A8DlLgMlTr2rMvWVztG1sGqmfaG3hsgqwCC+Gqc2rHPj2x9+IRbIZD0nROgZbXjf6LYYSzOBS6tfJ7UAHwvt8eAzuXN7WePVvhE32nVF2sfgCAr78wZ9iqIgyLjs6LSwMvEVxIE3hweAEug4EAZeGI5FuT0/p53OC/u68B/K6ptfILsQfNPqHGcopiFUhkJt62dpXw1OSkGxucAiWxvPMvmnjAPKXvWVUGbMS5J4BvJEzc1kA8RfcqtFoVw48RiDgdy9c3Hj1o3+PBXCLSOXDQz49IP02ZTuH0vfAECzihO8tDu56veGHn2uXb39Bgx7c9OFO7QLU2/P8G54MEk045KQgmt+/7burAdPnjdCCnrtZQ1iTbup70m3v8AoouPkmPRk2KpuzxjK2syoIeNFdURbI4GR5E8rsADjBhkLgcYB5/SMT1dl+/r1tCMehja/+Jp5TQJExZJORP8btHvMENrwWo8tklboWdRIxByPcgToFSa0vswH4+f+YDFzwAVlqdzTYPqACV0cXzK3VG38eqZZ20VBvdv3eniHEJGiobMNsJkEAmHNyc55deSzIc+2+PmvX1BstxU6fDOx9feLFfwgVpsNggIp2YG2nxvvGIWfexsbhqUyI9zil1251GI02nFIOHbfiCjXdjoOY3l/GIA7g5AABf9MEAbH6pP3WDghIR3Bbysgqu8++CGzgjCzeAVhuJDZ6N/+8khFw7PDPWPBYvOZT6evkvvgl9orsBPNzSsGVBAG/a8wRSDe9w15twQbwRlLQMxUI2Gm/XLumd5+wR7tagBYe+lBqv9q7lRVYWBuodZxYTeduf/ynjSNS2pgj+q2No2Y9FOw1xBa2zliBmF9ufmkpnkF3MMjA8dqMWGQCbnc0YH54RFTBgCtqQO1Y7zWAT/BwO048M2cDc256JlD4VhBw2boMAh4RzjrvDKDQ1jkB6/s+iiwuQMAUUOYV0VENFl6jmoAeM/OOqNlN+ZmxIBvKCCDhK3l/f/x+YQufPmoTGhRTLwlBoBrPSvMh/1XyPDTesSPsw722cieCStcPYAxKgDbUgHWDvJBqR6mdDYTLj4t+/g1PRaun9QDXckC/mWV1HPQy1urAAuwQA5lCS87a+/YfOzr1H1KR9+pvo6c+efaqXWBYUQNC/IFp+Betsxy974LpUcXy20HBtsOv0CGA8ziQIw3X7Cl9e9ZidSKQspA2gfjIjc9WnEowDGO+u7Cp8jM2TgmipFBGei0lwZFlPJnDbv+YIlyDQB0NpuXXjnPUkefdHTTp6+/b3nUFHosA8K2ZC8IRqGdE1lZ+AG8sNFBITQiwkS4elv598/rXmk40rZNiAFNEQTZfHXDpo5rT4a+1b/fgD8QClF/X3rM9nJl3IeL5AaxTog3Ovqorkwwt3HXOKCBgkel673k+tvN+u+1NfXJzC9RVwed1q/8ARyEU8tPmPdC4MK0xq2/qQYGBBJj7EAzBYSchxzEARk6Zc1fc4MF7kMk0Z0eMTnziISHgYJ52B4OMgS343x87s3HBso2pnvvt8Nr+9HkuM1I26RyZKuLQA1t+EcChRXXAudJsLS2aGghsCGYfB7a0dML8MYZHLg1veOh/VxG4K3vCvMTSU0JB+BllcMxVCmQ14JJ479zC1mIwSFuJOzz6lQJqdwKj1inC7Txqr90BBiSOK05ADq6SADZQB8Kq72FHB5U6nS6AC1E1ERVQ1P/+rq+kYCIzQCTDG4kx8m3ax9OWyCjRlruWYGNmC7442kZrY8bcwNrf4bfJuLqoR1c89noQSKrfO863dNHXqxNMzRoQNmLA5fcWNw6bvjIYbuyeILxUbnAAm5xzkOft9EzA3y8YAvK8b9Dv4y57MmYDSpG1/U686oWYrShtRp5Shqm5hzoModkvKsDB/n0ObRCAWmYDbhsBnPTxylVbY51lFQhiyD4yFWAjMRcqcgiBlj09ZEnXW0aS6XRMKLRjl8GeZAD2z/jCe+hmAGNgC37IKZc0Trk8R3eLy5NOO87GcMBRgXED1F1Q4ppi+rxbwKYVEO548qeBDQCgTPxF1XRT0bIfc+ljjZNavN7rA7ptepAbQxBYWaYLd6oUGBKvNBIUj5y5pjlPcUg14FVbAhC0LkaIb23Trrt5EF/8hxDimO6rZremIz1HlRQz4ID21wEi30g3Oj1IrH25AGBFw2E6NRDBJLIceElo+9vVPhx53j1Ni/ruaLCxEAPNXpIi+L9G79fh3a/MARTdATpEItGy+dH9sUHVfBZbPSnik5PKHKSDDrCvjS/oLtFGpHcj0IK1tmQDNr22UKcqAqsUOGYDnntXGY6xfcTDQFKtJADIst9C3BktgArgNPTouZUIVMd6MYAdzXI7Moq0PgbAKgtkK/YMUDfz8/95RDyplfpLzKPdaK+o7UfeJzvi9q9djEeGyXq6AWCPmYBXN7aVN3JpOvQOvwWVyskKHH59aWlmnSxjQIPvU/fbQDIHZA4pJLIJ1Be6G5qANlK7qgjUJdA96MTZgA7Od8r03T2ZDah9VtWADlNgAiMg/Hrz1fpdpsam+8KUslcmqJICdTgYd6O0KwF8OkBEYDKDrT//w5Ct495Sggz+Gs8J9mJxWaTXZ/99ctM7Ynvz//2tSEFhC17ciPq6k4HGCAM4YmrjjPnrmre4jej2d7MDj7SRaL8RTbR8AHrqPQAREJBdGFswDjHmveOTu41iyGVMuGlvMhD78NADpNSuEycDYdFNmnlbOCi52U9q830DitXOitRYEHAYt7+3c4gg84foDgjiamj/Du5/+ppsz7oFmSgUhVsH1P+D/781pe8rjkJDfQ3t2N4CAMILKmhYjUxDBFTKAaUgrgMx1PFXPBOW6Hr/WJGVl5CFQJ90tQBjJgY6akZj/PduCDaWeQDq/6BwFuHHy7/8U5A9ZAWV5FER+97CLtMXzk4wC4M+rG8s/Z/S5ow7t92kSzaEEg51tdMUgQ4gyaz2qpT+G9e2Nxy0OisdUMg2Sqgg6KQggOiTCUKfNsU2bMMdcOsDwwk1YGHyoeQCdEmJHcRQFN78TPAR6mGDE7R78OokYlwQnYFDYpz86gjwCEqt/AW/I08CbUJBTPZ44JmVM5I/6h6QoO/LErFD/QCuDjGQN9oNz4UWu8ztEHbQj77WbO0ACIdKLwUKWQFwyALWfv+eZABooDIATLNOzADgK3jyETjbHapaUHFAmi6OQRnTFzyaAd2UlfFzfOKlX8fhvmndq5Hmq6Hp/J9IWR2nX31+gJz5gVUGvmztyymg3BbkHXJvn+MNAQyuw0K2jUJpdshlixGQ0t9FXEYMZI/pIMgKWtfZvtIhMJxEyanjVDMbwQM+gWcweAhpNwDsrSvwhYvTTfDnaMMR5LjpvfHIJjaVBbBpuAGPVJtbQNnDjIUbYgMKGA51WxjAtT2NQ4oikIClUxWBbktp7lGzH24PA1iwIwRB+xfijfrfYYfqO0D67ei4ntchgtLjBWg1xoSg7+xSA4bc9rpHww7O9B4ZiYMK1ZcR6hh8+ZTrQ2o8f/XWYYeECmYCEXKQ5z3zqrXhKIwUBiRGIPN7ES5lXsKubFIQNO/A7zyxOQchPzgAywSqk3RfVwswtloAC4GiKUWD/LstpIE2CluwviIqCfbZMNRdX7f42oVBO031rBp1+M2cBS5HzXmoMSFt/G9efM8+mfv+ReEAUNkJvgAx479GCp7VHov9mp+ReTk4TDccWCafZ129NlR2bnJpv4xApva1sHdbFKCuwM88xM9idSrzaosNwFeHiDzz2m8jY9C73y9larVjEJbfg/4Ok42ytPyOwI/COjz0CMaT/WOAjlqILpaF9/fH193+ykfcholnLgsjEPZgukh4D/wCEaLoI05M2YQJRr3dNuDYioHqWDDR2kahDRdtK9DDIcjn4QC+Z/u7QwuGfJ4xZHi/T10RZJY6EqwV3YX+U3lNLOYRtOTb3+1cRaCD9MNFj0UrEBZA9bdrRt5AVBy3Qmkm23IYW732uf2GoCutAyq2G99BdMMC+hx+3w/wDSJQeqjXCXoCTEzPY6RX9gX8rJnW91fDkaI1QA2+86mfD7AYByBbSyUIKjH+ALxBym//vJiew3MCGXOreFmwTGUMSkAEJwDgkLMBU2mEHCV4nFjoxGMpCOqqAQf5tNUZgX2ldywzsEHMmEdY4fyyOQwg/7jbzwsQ2kwx7TVtVO6/Ijpk18bG/pL2x+CLtAm0EXs7fDaADApSHoc0HTBzAY+ceXf0yL1n2oOUlCyy8iDQxcWB9/exXg7+AWU2IDae+l+rDdjn+SH/Un5goXHcra482fc/i4nU/9UXUFnha7o+ugueT2AIfkj6HR1ipSJPSJJuHQQBRquOWMnBrnMClBRETLIKt75SQqkSrMC0T7SCs3y8f1jQs5qgeH9kNGN5YXSoIcjIakA3CYIJrzY3DDBHrzhIQ99dFG0lkX1wTeZGkM5/d16uUauSrYnuGgaZNsaplz8QvPGuHLjVWOO3UcfnkWpLmu9bFQM5/IA1ktutb33SnMpTpwub15fr7JVxoHErflAGg1pHLb/hcBYHihkI9x+Kvu+nmrve7PgddzzxsygHzQ/Uvjs6SoeFTRKZUkRJ4caH+leXKTe2YNEqKrLm81dta4J9SppRMaP0deXRxKKKlNV0ZwPuRQD45szrAwQcir1lodelWuuYwhrjGKw74E23Ib4WDrKZKLQ2pXl1U/ko7ZPOHjHt5t0AnbB5SpuBxbgyY0eHGoGOlAm4tVGtHVzp9IGls+IhPWelrdZv3fx1QChrcGCZQ2XdHErr5PC3M0qrZn2zlm1sLE9lmfWBFVhH2QXzUr8bARCwUOYxfeGGoATLCpUbVIwCAiUojoMsRZZwBq+BMzKNuEqamZRyAjrxmm1tTQYKG7lp2WtgLIljHakG/NKxM9MtsSM82lo3RqVrMo38bylqM4moN0QdA+WQywBsMuOsRXWb0g0DVALoYG9hBCJ3AHRE+QzorGiaPZIS93ZHgw3IuphnnH3Vujj8BwwKoBiTVYwjIA8O3r1lJBhQEdcfwxC/IqjCbb7PlThUywQfZRPARMHE7QvF9zovFpAPluAwyh7c9EoDpUMFjSu3JExFYiz4DUEn9vccxhOgjY5RxgZ2BGFIGRA+kt3ZgJ+fCPR/HTm1Me70pcH6e3Dr+03wyELODZupRZHKSUsFiQe2vB8IrNrfLWVy8LmLHo9ywA1z5cqtkbqq7TG46ringYBOtrMmBAoxSAoCDzz/i24QKCi6gIhePb6AgXwTBU4BFAZg86udlWS7/PE/GVYN2Fu8+we37XoK1lPnBw4lABqsV5Dan1rEY0oETND7U2DpDZzgk8gSqxmJluLg27leLHWEnOxEdhP1f5sZgMeh01emEnJZAI3dDOBzBoD//KVjG4d+55LG8bNWB+gDVYYOu8GzWivXnysefT1AwHBwCRDw5gCBTIEFJm37+acRBGzIaO+kuvWIc1cXNdtIo8H6IhsQLJCI9oXX+xdPDvyzmJbrvTcwZcpVW3ZDw7MxxoYAV73nEPUdQ4xoH21EmNRcl0AHwHufp/iOriTE94BRTCr1/xFTbwngMhN/FqXDf3u4EI2UbcQMgu2/apx00d0RTEJcFr4A20clPwGStQqPOe/2xpNj2AnoWDXg06/+LlR+lF0CQRYDLQzvOfRRAp/D4kZaEkYOJ5TIbfGVBm4Fb+APA/Uvgx7nP9cGCaiOBrstAs1YTnr9QgqC0iGUroccuLgqD+uRV3gAMgGoPcZmO0q85hiyta/EOvp5vADmIm7leshH+123xwH+KLj5bvIDY2LPkihNHP7K+W9mGMOUOjCAC294OjoaWoAjqSBPLl0AmaUBqqzGu6PB9pIKfMI5V6UFTXVcSucdZMCMuQBIImq8+1Nqru4TDBB8iDu0qmwgWcC40nu+9bHXI1DEyO+Zd7VFZW0KgS64L7IAfPBOdQYOrX1KpdXDh5xzawTG0dLhrI9fE+Ccw6cccJP3jDLmG3agU0B5iPGJsCPwew43udZf9t9v8QkchvhVx4rZJwJ4kINK6eFw318yjBp4tg0BNOsiUZeOj7LxzsYUZeOCHS38h1I2zn8+yp8Jpy2KzoLn7fIA9nY8+BHnpPr/4ZQKvh+LXq2k9Xshvep5/V5kjer5V4kfgoE+tPpfWXBKur3yaLB792g02KQyGmzuLc927Ggw7y2SjUMJG2mnFnYouCzXNlrGBDaGXdtQY7xgLHT0gEVZnno9G5D+pnHV6m0RCIB3RnopRba+mQ+on4Hs940w7jt4IwVncCiVJViFEP+vpY8yRaKxoSjE/s2N+OS5a9IFkgfL8IjgHCXdp3dAeT7w7OUB/PGhsF+7TMAxVAMy+GTciOVnoR3+s+avDRopiiZH2KFGg0k76yjx7AS7NFK09lxeBwuBtnb0cFABcE+Hg7oVCYhkYYDD3Hp7OtpurTW4tdr02j+lYP9QBIrzinWbQB5dnfT6bmytvBpMLk6/D7AX6Wvagg3BvNs+Ak5Qtf/4/H4ez0OGQT+QJxQtCWD5yZf/YbcyQ/cIy5SmYVfbuMUMlVR42s3RbpSpdv0AxqgEOHH6NWnBtsQBtkhongC5uPm/k+W9Fn600WD6+boAUnmc7fCxa8sMpCcQYLVoJwuBBL55cXAWNY66aG3bKko3pFsWu4+KM9N0FwUgF8Yev8htW/4As27aGDc8MFepAEDD7mP66d87Ck2X8CuCQDqwmHwh4GlODP7psNZh9ogsxs8BCJWQ9ofsQUaQx8rnFiJl3/ZSEsgYzCs8NViDy3Zre/pdlCeUibWj0VUDjuFosJ989O+NNZvejp4xBFcEdiClbbzjetscDQZRxhwTBPi3A2xGHQ0WdmCLY8M+/7N/7tgugACwKGVStX16UlvDQXeEUAbu4v1zkNzigraDDruRVax6+s1w8gXQSssFBrRdrTqfw+HQj9fnFwj8LkRFgoq6fOlDL8doMQfbWrGHJyeu06L9/oLHbY+/EVRkBxZjMI8G29n0GzBdqFrMCQZ4Cj4v4BxYxn4DhLU6lTa17Yn6XNmQsouuH8A+Gg3WV6bS6K1ik0n/9kR77ZYxRcbi5im3d0e/f3ceQH+MgPraBfdHy1D7kTVVXycLgdKmNs4703+XZluwEdWA26NvftiMO5oGnRcue6q0937bOOe6R7PHQ6HpRrtu2i3BBFy+Pns8wBu+fdm9YRG2f2H5uYXvQuj64F+jHJSy11IB4y/LiBfE77nwvh2BHwgYAEzr7rXmllHy9kJkGP27Moyn0+8WbtHA4vRc9AkHl5kRDnseg9a/G2+EXRgMQLCTTXRHg+3T0WDZufXzRFo/V8uBSmTR6wfk4HDHwMc5D0faX+tEXoR9XRJQbGqdEOQr78/kKqW+fvfhoEonARZoxkknMy8XhaZfFqAsg8pfdutzQQsG1qqxtQsPlGafuSzMN3rSeiF4mS/4rUvujczBmjjEz//sD42XPvhTEwSsdbosb2JRDWolyhQPK/iDwy0r4CxkDwhOPiKayQp6i6rw6vR31jLDx0np8GfgeITRYNH2XBp/r7+xOxpsH6kBx4LKqhyYdv2GxiE/uDE2plQyHhhkpy2KhZRiqvu7DMBdWUAF6jKN+ubY9BRyzYN/bU+kxyzBZVlfT4fLQVfHV4WeMg5Hnp1b1eJjbeLt1zr8stuejyDRKuGWOfw4xDl5viCNx+qUpgPypqb6WzlYn08bGOW3TpOm9rv4lk1x+GEZgoOb3QAPuESdUCRAAAE9T/UF8Le0BRjHaLA1sZ8MoemOBvsrDQC1v6umRwdlMDE1pXoOPDRZS9EGpRbs3vy7M/SqCIhM2qE5KGVRJLBq4UOm3RbpuiBKlUl/4SB4H/XgTy1OPJR7F6e6XxovqxMgTr3iwTj82Qtgd9ZlEHfS61sbh182QAgW03zqxOBU59eav04N8v0sxfweGQRcHINDuQX7HmUl/r+fF6CIwGQV5Lz+jkkXtz8YhEmo55eFdAeD/BUHgMG+AnXicOujOxB0eDWgjzc+8mp0ZIB1E8uhPzyl2kgzDtRgD/+w1Xrtdym97g1QzQFWZ5867/5mK+6sdHCk/EPxBFpLEYpPbWEsQWg+cpibflzRHzy+I4OAdS0pA80CrG27O558M0aDNc1EiukI16cqJhIIuqPB/gMHgO5jb4JnVfV9GmCaWxaApwZn3db3zs4hD3Gl39JzANjUywA36bge+qYUINqpnXsLNnDPpneLMcynkXYfMT1P+g2vgXv7I1vROgQct4KAPcOMBlNmsJgX0OposKMveqT90WCX5dFg0RLsZgDdANApGUGrSrOdzCkCRPo+7j24+QJHVQDuaQZXA1L2efggypMKAipDAHzYheMKCLh1BOvu2m1CK5cp5NFgq/ZgNFgeDy4D6o4G6waA7qMNh6HKzR8rzYKHroHuwpFB/loSAQAIuKWNICOYCGqIS2i9ggA+w2ijwVCDZQ7KEq5F3S5ACQBzL728sXDB9Y3rr7uurcfihQsaZ/1wdjcAdB971elxy2+IDOPdMIdxsPcE16E3YWGGdHbA2TfGmLOhzEBPura3yJ9vajoJ7RMewKuvvtr4ojx+8pOfNA4+cVoEgO9NvbAxc/aljR9eeElbj/PS904+bUbjb/5uUuPU2Usbr/36fzT6f/Gn7qP72LNHujhe/OAvjZc+/LfGS7/8S/x7j38+/dzCB19uHDp1RfgbKAeCCXj5043j5z0dmYHR8g4/ivmVq3sbO97/c/rZP4/53yMD+ML8lzKA/vHHnv2Xv91vSuNv9zuxkT+2//jf0s/8L185oTFl6vzfv/T+n/q3vfWH7qP7+P/1seVNHz/tTyVF/5ybnu2f+L2lv2UhV9WNdcKUwHDQ2ct+deltm+P7U/lQfnZsH//pi/bf3447ce5/mXDS//tfxn+jscePCSc1/vcJJ/3b//ylE477T93/uv/9Ffy3/w+W/a8HnH3T+QedteyldPD/7/T4fw48e1lvOvxTD/3ekv9pX7/+/wcCv0YrK2ydSQAAAABJRU5ErkJggg==" + } + }, + "cell_type": "markdown", + "id": "74ca6ea0-5261-4712-b202-043c00b7e4c2", + "metadata": {}, + "source": [ + "# Standard Layers Analysis of a DSPC Floating Bilayer\n", + "\n", + "In this worksheet, we will carry out an analysis of a floating bilayer sample using a 'standard layers' model. \n", + "The sample consists of a DSPC bilayer, on a silane SAM on Silicon:\n", + "\n", + "![image.png](attachment:e72d4765-3d29-4d8b-a0c5-2b9ba546588c.png)\n", + "\n", + "So we are going to need layers for Oxide, SAM tails, SAM heads, and the Heads/Tails of the Bilayer. We also need to consider hydration of the submerged bilayer." + ] + }, + { + "cell_type": "markdown", + "id": "be9b7c0d-dff4-4971-9efa-722215eb5227", + "metadata": {}, + "source": [ + "## Making the Project\n", + "\n", + "Start by initialising a project:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24510c3b-eb41-4981-ac34-9503f742a8dc", + "metadata": {}, + "outputs": [], + "source": [ + "problem = RAT.Project(name=\"original_dspc_bilayer\", calculation=\"normal\", model=\"standard layers\", geometry=\"substrate/liquid\", absorption=False)" + ] + }, + { + "cell_type": "markdown", + "id": "31584d08-aea4-4411-9b3c-84f4eadbef66", + "metadata": {}, + "source": [ + "The add the parameters we are going to need:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f75a8713-0e9c-4972-a803-fae5b5028056", + "metadata": {}, + "outputs": [], + "source": [ + "parameter_list = [\n", + " Parameter(name=\"Oxide Thickness\", min=5.0, value=19.54, max=60.0, fit=True, prior_type=\"uniform\"),\n", + " Parameter(name=\"Oxide SLD\", min=3.39e-06, value=3.39e-06, max=3.41e-06, fit=False, prior_type=\"uniform\"),\n", + " Parameter(name=\"Oxide Hydration\", min=0.0, value=23.61, max=60.0, fit=True, prior_type=\"uniform\"),\n", + " #\n", + " Parameter(name=\"SAM Tails Thickness\", min=15.0, value=22.66, max=35.0, fit=True, prior_type=\"uniform\"),\n", + " Parameter(name=\"SAM Tails SLD\", min=-5e-07, value=-4.01e-07, max=-3e-07, fit=False, prior_type=\"uniform\"),\n", + " Parameter(name=\"SAM Tails Hydration\", min=1.0, value=5.252, max=50.0, fit=True, prior_type=\"uniform\"),\n", + " Parameter(name=\"SAM Roughness\", min=1.0, value=5.64, max=15.0, fit=True, prior_type=\"uniform\"),\n", + " #\n", + " Parameter(name=\"SAM Heads Thickness\", min=5.0, value=8.56, max=17.0, fit=True, prior_type=\"gaussian\", mu=10.0, sigma=2.0),\n", + " Parameter(name=\"SAM Heads SLD\", min=1.0e-07, value=1.75e-06, max=2.0e-06, fit=False, prior_type=\"uniform\"),\n", + " Parameter(name=\"SAM Heads Hydration\", min=10.0, value=45.45, max=50.0, fit=True, prior_type=\"gaussian\", mu=30.0, sigma=3.0),\n", + " #\n", + " Parameter(name=\"CW Thickness\", min=10.0, value=17.12, max=28.0, fit=True, prior_type=\"uniform\"),\n", + " Parameter(name=\"CW SLD\", min=0.0, value=0.0, max=1e-09, fit=False, prior_type=\"uniform\"),\n", + " Parameter(name=\"CW Hydration\", min=99.9, value=100.0, max=100.0, fit=False, prior_type=\"uniform\"),\n", + " #\n", + " Parameter(name=\"Bilayer Heads Thickness\", min=7.0, value=10.7, max=17.0, fit=True, prior_type=\"gaussian\", mu=10.0, sigma=2.0),\n", + " Parameter(name=\"Bilayer Heads SLD\", min=5.0e-07, value=1.47e-06, max=1.5e-06, fit=False, prior_type=\"uniform\"),\n", + " Parameter(name=\"Bilayer Heads Hydration\", min=10.0, value=36.15, max=50.0, fit=True, prior_type=\"gaussian\", mu=30.0, sigma=3.0),\n", + " Parameter(name=\"Bilayer Roughness\", min=2.0, value=6.014, max=15.0, fit=True, prior_type=\"uniform\"),\n", + " Parameter(name=\"Bilayer Tails Thickness\", min=14.0, value=17.82, max=22.0, fit=True, prior_type=\"uniform\"),\n", + " Parameter(name=\"Bilayer Tails SLD\", min=-5.0e-07, value=-4.61e-07, max=0.0, fit=False, prior_type=\"uniform\"),\n", + " Parameter(name=\"Bilayer Tails Hydration\", min=10.0, value=17.64, max=50.0, fit=True, prior_type=\"uniform\") \n", + "]\n", + "\n", + "problem.parameters.extend(parameter_list)\n", + "\n", + "# In addition to these, there is also Substrate Roughness which is always parameter 1. Increase the allowed range of this a bit\n", + "problem.parameters.set_fields(0, max=10)" + ] + }, + { + "cell_type": "markdown", + "id": "52f6752b-ce20-4c36-b357-988eb8ee178b", + "metadata": {}, + "source": [ + "Now we can group these parameters into the layers we need, and add them to the project:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9fb80fe-41a3-4062-b84d-1e4ed524d02b", + "metadata": {}, + "outputs": [], + "source": [ + "layers = [\n", + " Layer(name=\"Oxide\", thickness=\"Oxide Thickness\", SLD=\"Oxide SLD\", roughness=\"Substrate Roughness\",\n", + " hydration=\"Oxide Hydration\", hydrate_with=\"bulk out\"),\n", + " Layer(name=\"SAM Tails\", thickness=\"SAM Tails Thickness\", SLD=\"SAM Tails SLD\", roughness=\"SAM Roughness\",\n", + " hydration=\"SAM Tails Hydration\", hydrate_with=\"bulk out\"),\n", + " Layer(name=\"SAM Heads\", thickness=\"SAM Heads Thickness\", SLD=\"SAM Heads SLD\", roughness=\"SAM Roughness\",\n", + " hydration=\"SAM Heads Hydration\", hydrate_with=\"bulk out\"),\n", + " Layer(name=\"Central Water\", thickness=\"CW Thickness\", SLD=\"CW SLD\", roughness=\"Bilayer Roughness\",\n", + " hydration=\"CW Hydration\", hydrate_with=\"bulk out\"),\n", + " Layer(name=\"Bilayer Heads\", thickness=\"Bilayer Heads Thickness\", SLD=\"Bilayer Heads SLD\", roughness=\"Bilayer Roughness\",\n", + " hydration=\"Bilayer Heads Hydration\", hydrate_with=\"bulk out\"),\n", + " Layer(name=\"Bilayer Tails\", thickness=\"Bilayer Tails Thickness\", SLD=\"Bilayer Tails SLD\", roughness=\"Bilayer Roughness\",\n", + " hydration=\"Bilayer Tails Hydration\", hydrate_with=\"bulk out\")\n", + "]\n", + "\n", + "problem.layers.extend(layers)" + ] + }, + { + "cell_type": "markdown", + "id": "356964f9-83a6-4a92-8092-4d250b68ac16", + "metadata": {}, + "source": [ + "Now deal with the experimental parameters. We will delete the predefined default parameters and add new ones for this specific problem. We need a bulk in of Silicon, and two Bulk outs - D2O and SMW." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b197f3ea-c6ef-4831-9500-9ff0cb5011f3", + "metadata": {}, + "outputs": [], + "source": [ + "del problem.bulk_in[0]\n", + "problem.bulk_in.append(name=\"Silicon\", min=2.0e-06, value=2.073e-06, max=2.1e-06, fit=False)\n", + "\n", + "del problem.bulk_out[0]\n", + "problem.bulk_out.append(name=\"D2O\", min=5.5e-06, value=5.98e-06, max=6.4e-06, fit=True)\n", + "problem.bulk_out.append(name=\"SMW\", min=1.0e-06, value=2.21e-06, max=4.99e-06, fit=True)" + ] + }, + { + "cell_type": "markdown", + "id": "420b57a9-4fc7-49d5-acaa-68570f1876d2", + "metadata": {}, + "source": [ + "Likewise the scalefactors and backgrounds:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92a26ca2-b1ee-41c8-89ce-8b72c0892438", + "metadata": {}, + "outputs": [], + "source": [ + "del problem.scalefactors[0]\n", + "problem.scalefactors.append(name=\"Scalefactor 1\", min=0.05, value=0.10, max=0.2, fit=False)\n", + "problem.scalefactors.append(name=\"Scalefactor 2\", min=0.05, value=0.15, max=0.2, fit=False)\n", + "\n", + "# Now deal with the backgrounds\n", + "del problem.backgrounds[0]\n", + "del problem.background_parameters[0]\n", + "problem.background_parameters.append(name=\"Background parameter D2O\", min=5.0e-10, value=2.23e-06, max=7.0e-06, fit=True)\n", + "problem.background_parameters.append(name=\"Background parameter SMW\", min=1.0e-10, value=3.38e-06, max=4.99e-06, fit=True)\n", + "\n", + "problem.backgrounds.append(name=\"D2O Background\", type=\"constant\", source=\"Background parameter D2O\")\n", + "problem.backgrounds.append(name=\"SMW Background\", type=\"constant\", source=\"Background parameter SMW\")" + ] + }, + { + "cell_type": "markdown", + "id": "a1b04d8b-8cc8-4e35-9e06-a6be3de90c53", + "metadata": {}, + "source": [ + "Now load in and add the data:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73681532-2688-4bfd-8153-1ab763f5687a", + "metadata": {}, + "outputs": [], + "source": [ + "data_path = pathlib.Path(\"../data\")\n", + "\n", + "d2o_dat = np.loadtxt(data_path / \"DSPC_D2O.dat\", delimiter=\",\")\n", + "problem.data.append(name=\"dspc_bil_D2O\", data=d2o_dat)\n", + "\n", + "smw_dat = np.loadtxt(data_path / \"DSPC_SMW.dat\", delimiter=\",\")\n", + "problem.data.append(name=\"dspc_bil_smw\", data=smw_dat)" + ] + }, + { + "cell_type": "markdown", + "id": "0668e70b-3d7a-4d35-bb37-90f73c17cb77", + "metadata": {}, + "source": [ + "Finally, we build everything up into the two contrasts:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e5475631-2aa2-4419-9227-aa41cd94b4ed", + "metadata": {}, + "outputs": [], + "source": [ + "# Set the model\n", + "stack = [\"Oxide\", \"SAM Tails\", \"SAM Heads\", \"Central Water\", \"Bilayer Heads\", \"Bilayer Tails\", \"Bilayer Tails\", \"Bilayer Heads\"]\n", + "\n", + "# Then make the two contrasts\n", + "problem.contrasts.append(\n", + " name=\"D2O\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"D2O\",\n", + " background=\"D2O Background\",\n", + " resolution=\"Resolution 1\",\n", + " scalefactor=\"Scalefactor 1\",\n", + " data=\"dspc_bil_D2O\",\n", + " model=stack,\n", + ")\n", + "\n", + "problem.contrasts.append(\n", + " name=\"SMW\",\n", + " bulk_in=\"Silicon\",\n", + " bulk_out=\"SMW\",\n", + " background=\"SMW Background\",\n", + " resolution=\"Resolution 1\",\n", + " scalefactor=\"Scalefactor 2\",\n", + " data=\"dspc_bil_smw\",\n", + " model=stack,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "85c539d2-84f2-4a0d-a62b-666fbe9b2407", + "metadata": {}, + "source": [ + "Print our project, to check what we have:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0409648-05f4-448b-93d6-5c4382e0dad6", + "metadata": {}, + "outputs": [], + "source": [ + "print(problem)" + ] + }, + { + "cell_type": "markdown", + "id": "136e2c63-f439-4c2d-bb10-453950bbf41b", + "metadata": {}, + "source": [ + "## Running the Project\n", + "\n", + "To run a project in RAT, we first need to define a controls block:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9ec7e39-48a8-4651-b74c-19d5800c67d7", + "metadata": {}, + "outputs": [], + "source": [ + "controls = RAT.Controls(display='iter')\n", + "print(controls)" + ] + }, + { + "cell_type": "markdown", + "id": "05f44162-c5b2-46e4-9233-b63e81089fd8", + "metadata": {}, + "source": [ + "The default action (\"procedure\") is just a single calculation. So call RAT.run() with this, and then plot the results:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e59bf938-804c-458c-891c-c3e56ed32820", + "metadata": {}, + "outputs": [], + "source": [ + "problem, results = RAT.run(problem, controls)\n", + "RAT.plotting.plot_ref_sld(problem, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/RATapi/examples/non_polarised/DSPC_standard_layers.py b/ratapi/examples/normal_reflectivity/DSPC_standard_layers.py similarity index 52% rename from RATapi/examples/non_polarised/DSPC_standard_layers.py rename to ratapi/examples/normal_reflectivity/DSPC_standard_layers.py index 2beb7ce0..6962f036 100644 --- a/RATapi/examples/non_polarised/DSPC_standard_layers.py +++ b/ratapi/examples/normal_reflectivity/DSPC_standard_layers.py @@ -1,102 +1,29 @@ -import os +"""An example of a standard layers model in RAT.""" + import pathlib import numpy as np -import RATapi as RAT +import ratapi as RAT def DSPC_standard_layers(): - """Standard Layers fit of a DSPC floating bilayer""" - problem = RAT.Project( - name="original_dspc_bilayer", - calculation="non polarised", - model="standard layers", - geometry="substrate/liquid", - absorption=False, - ) + """Calculate a standard Layers fit of a DSPC floating bilayer. + + The sample consists of a DSPC bilayer, on a silane SAM on Silicon. + """ + problem = RAT.Project(name="original_dspc_bilayer", model="standard layers", geometry="substrate/liquid") # 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="Oxide Thickness", min=5.0, value=19.54, max=60.0, fit=True) + problem.parameters.append(name="Oxide SLD", min=3.39e-06, value=3.39e-06, max=3.41e-06, fit=False) + problem.parameters.append(name="SAM Tails Thickness", min=15.0, value=22.66, max=35.0, fit=True) + problem.parameters.append(name="SAM Tails SLD", min=-5e-07, value=-4.01e-07, max=-3e-07, fit=False) + problem.parameters.append(name="SAM Tails Hydration", min=1.0, value=5.252, max=50.0, fit=True) + problem.parameters.append(name="SAM Roughness", min=1.0, value=5.64, max=15.0, fit=True) + problem.parameters.append(name="CW Thickness", min=10.0, value=17.12, max=28.0, fit=True) + problem.parameters.append(name="CW SLD", min=0.0, value=0.0, max=1e-09, fit=False) + problem.parameters.append( name="SAM Heads Thickness", min=5.0, @@ -107,23 +34,14 @@ def DSPC_standard_layers(): 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 SLD", min=1.0e-07, value=1.75e-06, max=2.0e-06, fit=False) problem.parameters.append( name="SAM Heads Hydration", min=10.0, value=45.45, max=50.0, fit=True, - prior_type="uniform", + prior_type="gaussian", mu=30.0, sigma=3.0, ) @@ -137,86 +55,14 @@ def DSPC_standard_layers(): 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="Bilayer Heads SLD", min=5.0e-07, value=1.47e-06, max=1.5e-06, fit=False) + problem.parameters.append(name="Bilayer Roughness", min=2.0, value=6.014, max=15.0, fit=True) + problem.parameters.append(name="Bilayer Tails Thickness", min=14.0, value=17.82, max=22.0, fit=True) + problem.parameters.append(name="Bilayer Tails SLD", min=-5.0e-07, value=-4.61e-07, max=0.0, fit=False) + problem.parameters.append(name="Bilayer Tails Hydration", min=10.0, value=17.64, max=50.0, fit=True) + problem.parameters.append(name="Bilayer Heads Hydration", min=10.0, value=36.15, max=50.0, fit=True) + problem.parameters.append(name="CW Hydration", min=99.9, value=100.0, max=100.0, fit=False) + problem.parameters.append(name="Oxide Hydration", min=0.0, value=23.61, max=60.0, fit=True) problem.parameters.set_fields(0, max=10) @@ -306,16 +152,16 @@ def DSPC_standard_layers(): 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") + problem.backgrounds.append(name="D2O Background", type="constant", source="Background parameter D2O") + problem.backgrounds.append(name="SMW Background", type="constant", source="Background parameter SMW") # Now add the data - data_path = os.path.join(pathlib.Path(__file__).parents[1].resolve(), "data") + data_path = pathlib.Path(__file__).parents[1] / "data" - d2o_dat = np.loadtxt(os.path.join(data_path, "DSPC_D2O.dat"), delimiter=",") + d2o_dat = np.loadtxt(data_path / "DSPC_D2O.dat", delimiter=",") problem.data.append(name="dspc_bil_D2O", data=d2o_dat) - smw_dat = np.loadtxt(os.path.join(data_path, "DSPC_SMW.dat"), delimiter=",") + smw_dat = np.loadtxt(data_path / "DSPC_SMW.dat", delimiter=",") problem.data.append(name="dspc_bil_smw", data=smw_dat) # Set the model diff --git a/ratapi/examples/normal_reflectivity/__init__.py b/ratapi/examples/normal_reflectivity/__init__.py new file mode 100644 index 00000000..382a9167 --- /dev/null +++ b/ratapi/examples/normal_reflectivity/__init__.py @@ -0,0 +1 @@ +"""Examples of normal reflectivity calculations in RAT.""" diff --git a/ratapi/examples/normal_reflectivity/background_function.py b/ratapi/examples/normal_reflectivity/background_function.py new file mode 100644 index 00000000..43624a08 --- /dev/null +++ b/ratapi/examples/normal_reflectivity/background_function.py @@ -0,0 +1,16 @@ +"""A background function for an example.""" + +import numpy as np + + +def background_function(xdata, params): + """Return the background function for a given set of points in q.""" + # Split up the params array + Ao = params[0] + k = params[1] + back_const = params[2] + + # Make an exponential decay background + background = Ao * np.exp(-k * np.array(xdata)) + back_const + + return background diff --git a/RATapi/examples/non_polarised/custom_XY_DSPC.py b/ratapi/examples/normal_reflectivity/custom_XY_DSPC.py similarity index 75% rename from RATapi/examples/non_polarised/custom_XY_DSPC.py rename to ratapi/examples/normal_reflectivity/custom_XY_DSPC.py index 0a8c1167..c57adecf 100644 --- a/RATapi/examples/non_polarised/custom_XY_DSPC.py +++ b/ratapi/examples/normal_reflectivity/custom_XY_DSPC.py @@ -1,10 +1,16 @@ -import math +"""A custom XY model for a supported DSPC bilayer.""" + +from math import sqrt import numpy as np +from scipy.special import erf 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.""" + """Calculate the continuous SLD of a supported DSPC bilayer using volume restricted distribution functions.""" + # Note - The first contrast number is 1 (not 0) so be careful if you use + # this variable for array indexing. + # Split up the parameters subRough = params[0] oxideThick = params[1] @@ -49,10 +55,10 @@ def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): z = np.arange(0, 141) # Make our Silicon substrate - vfSilicon, siSurf = layer(z, -25, 50, 1, subRough, subRough) + vfSilicon, siSurf = make_layer(z, -25, 50, 1, subRough, subRough) # Add the Oxide - vfOxide, oxSurface = layer(z, siSurf, oxideThick, 1, subRough, subRough) + vfOxide, oxSurface = make_layer(z, siSurf, oxideThick, 1, subRough, subRough) # We fill in the water at the end, but there may be a hydration layer between the bilayer and the oxide, # so we start the bilayer stack an appropriate distance away @@ -63,15 +69,15 @@ def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): headThick = vHead / lipidAPM # ... and make a box for the volume fraction (1 for now, we correct for coverage later) - vfHeadL, headLSurface = layer(z, watSurface, headThick, 1, bilayerRough, bilayerRough) + vfHeadL, headLSurface = make_layer(z, watSurface, headThick, 1, bilayerRough, bilayerRough) # ... also do the same for the tails # We'll make both together, so the thickness will be twice the volume tailsThick = (2 * vTail) / lipidAPM - vfTails, tailsSurf = layer(z, headLSurface, tailsThick, 1, bilayerRough, bilayerRough) + vfTails, tailsSurf = make_layer(z, headLSurface, tailsThick, 1, bilayerRough, bilayerRough) # Finally the upper head ... - vfHeadR, headSurface = layer(z, tailsSurf, headThick, 1, bilayerRough, bilayerRough) + vfHeadR, headSurface = make_layer(z, tailsSurf, headThick, 1, bilayerRough, bilayerRough) # Making the model # We've created the volume fraction profiles corresponding to each of the groups. @@ -106,19 +112,20 @@ def custom_XY_DSPC(params, bulk_in, bulk_out, contrast): sldHeadL = vfHeadL * sld_Value_Head sldHeadR = vfHeadR * sld_Value_Head sldTails = vfTails * sld_Value_Tails - sldWat = vfWat * bulk_out[contrast] + sldWat = vfWat * bulk_out[contrast - 1] # Put this all together totSLD = sldSilicon + sldOxide + sldHeadL + sldTails + sldHeadR + sldWat # Make the SLD array for output - SLD = [[a, b] for (a, b) in zip(z, totSLD)] + SLD = np.column_stack((z, totSLD)) return SLD, subRough -def layer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): - """This produces a layer, with a defined thickness, height and roughness. +def make_layer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): + """Produce a layer, with a defined thickness, height and roughness. + Each side of the layer has its own roughness value. """ # Find the edges @@ -126,12 +133,9 @@ def layer(z, prevLaySurf, thickness, height, Sigma_L, Sigma_R): right = prevLaySurf + thickness # Make our heaviside - 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]) + erf_left = erf((z - left) / (sqrt(2) * Sigma_L)) + erf_right = erf((z - right) / (sqrt(2) * Sigma_R)) - VF = np.array((height / 2) * (erf_a - erf_b)) + VF = np.array((0.5 * height) * (erf_left - erf_right)) return VF, right diff --git a/RATapi/examples/non_polarised/custom_bilayer_DSPC.py b/ratapi/examples/normal_reflectivity/custom_bilayer_DSPC.py similarity index 80% rename from RATapi/examples/non_polarised/custom_bilayer_DSPC.py rename to ratapi/examples/normal_reflectivity/custom_bilayer_DSPC.py index c97cde4e..8646de71 100644 --- a/RATapi/examples/non_polarised/custom_bilayer_DSPC.py +++ b/ratapi/examples/normal_reflectivity/custom_bilayer_DSPC.py @@ -1,8 +1,10 @@ +"""A custom layer model for a DSPC supported bilayer.""" + import numpy as np def custom_bilayer_DSPC(params, bulk_in, bulk_out, contrast): - """CUSTOMBILAYER RAT Custom Layer Model File. + """Calculate layer parameters for a DSPC supported bilayer. 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,6 +25,8 @@ def custom_bilayer_DSPC(params, bulk_in, bulk_out, contrast): The second output parameter should be the substrate roughness. """ + # Note - The first contrast number is 1 (not 0) so be careful if you use + # this variable for array indexing. sub_rough = params[0] oxide_thick = params[1] oxide_hydration = params[2] @@ -70,13 +74,13 @@ def custom_bilayer_DSPC(params, bulk_in, bulk_out, contrast): tailThick = vTail / lipidAPM # 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) + oxSLD = (oxide_hydration * bulk_out[contrast - 1]) + ((1 - oxide_hydration) * oxide_SLD) + headSLD = (headHydration * bulk_out[contrast - 1]) + ((1 - headHydration) * SLDhead) + tailSLD = (bilayerHydration * bulk_out[contrast - 1]) + ((1 - bilayerHydration) * SLDtail) # Make the layers oxide = [oxide_thick, oxSLD, sub_rough] - water = [waterThick, bulk_out[contrast], bilayerRough] + water = [waterThick, bulk_out[contrast - 1], bilayerRough] head = [headThick, headSLD, bilayerRough] tail = [tailThick, tailSLD, bilayerRough] diff --git a/ratapi/examples/orso_integration/orso_integration.ipynb b/ratapi/examples/orso_integration/orso_integration.ipynb new file mode 100644 index 00000000..03ec671e --- /dev/null +++ b/ratapi/examples/orso_integration/orso_integration.ipynb @@ -0,0 +1,188 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ``orsopy`` Integration" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "``python-RAT`` contains some integration with ``orsopy``, allowing for convenient interaction with the ``.ort`` file format. This integration is available through the `ratapi.utils.orso` submodule." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import ratapi.utils.orso" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Creating models from the ORSO model description language\n", + "\n", + "The [ORSO model description format](https://www.reflectometry.org/advanced_and_expert_level/file_format/simple_model) allows the description of a standard slab model as a one-line string, provided that all the layer materials are defined [in the ORSO SLD database](https://slddb.esss.dk/slddb/).\n", + "\n", + "The function `ratapi.utils.orso.orso_model_to_rat` function can read a model and return an `ORSOSample` dataclass, which gives bulk in and bulk out parameters for the model, a list of all layers defined in the model, and all the parameters needed to define those layers as RAT models. \n", + "\n", + "**Note:** the ORSO format gives the thicknesses of materials in *nanometres*. When we convert them to RAT parameters, the units will be converted to Angstroms.\n", + "\n", + "For example, the string `air | Ni 100 | SiO2 0.5 | Si` describes a 1000 angstrom nickel film backed by a 5 angstrom silicon oxide layer. The bulk-in and bulk-out are air and silicon respectively. The roughnesses and SLDs will be calculated or taken from the ORSO SLD database." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# create the RAT parameters and layers from this model\n", + "sample = ratapi.utils.orso.orso_model_to_rat(\"air | Ni 100 | SiO2 0.5 | Si\")\n", + "print(sample)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also set `absorption=True` and the model will account for absorption. For example if we change the nickel film for a boron carbide film and want to account for its relatively high absorption, we can add it to the output:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sample = ratapi.utils.orso.orso_model_to_rat(\"vacuum | B4C 100 | SiO2 0.5 | Si\", absorption=True)\n", + "print(sample)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, ORSO supports defining repeated layers using parentheses. For example, if we had a polarising multilayer of 5 repetitions of 70 angstrom silicon and 70 angstrom iron, we could represent it as `air | 5 ( Si 7 | Fe 7 ) | Si`.\n", + "\n", + "RAT will only create the number of layers and parameters necessary, but the `ORSOSample` object's `model` attribute will give a list of layer names with the structure of the model preserved, which can be given as the layer model for a Contrast." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sample = ratapi.utils.orso.orso_model_to_rat(\"air | 5 ( Si 7 | Fe 7 ) | Si\")\n", + "print(sample)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Reading in data and models from .ort files" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "RAT can also load both data and model information from an .ort file. This is done through the `ORSOProject` object, which takes a file path and can also optionally account for absorption.\n", + "\n", + "The example data file we use here is example data for an unknown film on deposited on silicon." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pathlib\n", + "data_path = pathlib.Path(\"../data\")\n", + "\n", + "orso_data = ratapi.utils.orso.ORSOProject(data_path / \"c_PLP0011859_q.ort\")\n", + "print(orso_data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `ORSOProject` object contains two lists: `ORSOProject.data` and `ORSOProject.samples`. The former is a list of Data objects with each dataset defined in the file, and the latter is a list of `ORSOSample` objects (like above) with model information. Note that if the .ort file does not define a model for a dataset, that index of `ORSOProject.samples` will be None.\n", + "\n", + "It's then easy to access this data to create a RAT `Project` that represents our data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ratapi.models import Background, Contrast, Parameter, Resolution\n", + "\n", + "dataset = orso_data.data[0]\n", + "sample = orso_data.samples[0]\n", + "\n", + "project = ratapi.Project(\n", + " name = \"Example Project\",\n", + " geometry = \"substrate/liquid\",\n", + " parameters = sample.parameters,\n", + " bulk_in = [sample.bulk_in],\n", + " bulk_out = [sample.bulk_out],\n", + " scalefactors = [Parameter(name=\"Scalefactor\", min=0, value=0.34, max=1.5)],\n", + " background_parameters = [Parameter(name=\"Background Parameter\", min=0, value=2e-6, max=1)],\n", + " backgrounds = [Background(name=\"Background\", type=\"constant\", source=\"Background Parameter\")],\n", + " resolutions = [Resolution(name=\"Data Resolution\", type=\"data\")],\n", + " data = [dataset],\n", + " layers = sample.layers,\n", + " contrasts = [Contrast(\n", + " name = \"prist4\",\n", + " data = dataset.name,\n", + " background = \"Background\",\n", + " bulk_in = sample.bulk_in.name,\n", + " bulk_out = sample.bulk_out.name,\n", + " scalefactor = \"Scalefactor\",\n", + " resolution = \"Data Resolution\",\n", + " model = sample.model,\n", + " )]\n", + ")\n", + "\n", + "controls = ratapi.Controls()\n", + "project, results = ratapi.run(project, controls)\n", + "ratapi.plotting.plot_ref_sld(project, results)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/ratapi/inputs.py b/ratapi/inputs.py new file mode 100644 index 00000000..bdfaddad --- /dev/null +++ b/ratapi/inputs.py @@ -0,0 +1,595 @@ +"""Converts python models to the necessary inputs for the compiled RAT code.""" + +import importlib +import os +import pathlib +from collections.abc import Callable + +import numpy as np + +import ratapi +import ratapi.wrappers +from ratapi.rat_core import Checks, Control, NameStore, ProblemDefinition +from ratapi.utils.enums import Calculations, Languages, LayerModels, TypeOptions + +parameter_field = { + "parameters": "params", + "bulk_in": "bulkIns", + "bulk_out": "bulkOuts", + "scalefactors": "scalefactors", + "domain_ratios": "domainRatios", + "background_parameters": "backgroundParams", + "resolution_parameters": "resolutionParams", +} + + +def get_python_handle(file_name: str, function_name: str, path: str | pathlib.Path = "") -> Callable: + """Get the function handle from a function defined in a python module located anywhere within the filesystem. + + Parameters + ---------- + file_name : str + The name of the file containing the function of interest. + function_name : str + The name of the function we wish to obtain the handle for within the module. + path : str + The path to the file containing the function (default is "", which represent the working directory). + + Returns + ------- + 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) + spec.loader.exec_module(custom_module) + handle = getattr(custom_module, function_name) + return handle + + +class FileHandles: + """Class to defer creation of custom file handles. + + Parameters + ---------- + files : ClassList[CustomFile] + A list of custom file models. + + """ + + def __init__(self, files=None): + self.index = 0 + self.files = [] if files is None else [file.model_dump() for file in files] + + def __iter__(self): + self.index = 0 + return self + + def get_handle(self, index: int): + """Return file handle for a given custom file. + + Parameters + ---------- + index : int + The index of the custom file. + + """ + custom_file = self.files[index] + full_path = os.path.join(custom_file["path"], custom_file["filename"]) + + if not os.path.isfile(full_path): + raise FileNotFoundError(f"The custom file ({custom_file['name']}) does not have a valid path.") + + if not custom_file["function_name"] and custom_file["language"] != Languages.Matlab: + raise ValueError(f"The custom file ({custom_file['name']}) does not have a valid function name.") + + if custom_file["language"] == Languages.Python: + file_handle = get_python_handle(custom_file["filename"], custom_file["function_name"], custom_file["path"]) + elif custom_file["language"] == Languages.Matlab: + file_handle = ratapi.wrappers.MatlabWrapper(full_path).getHandle() + elif custom_file["language"] == Languages.Cpp: + file_handle = ratapi.wrappers.DylibWrapper(full_path, custom_file["function_name"]).getHandle() + + return file_handle + + def copy(self) -> "FileHandles": + """Create a copy of the FileHandles object. + + Returns + ------- + FileHandles + The copy of this FileHandles object. + + """ + handles = FileHandles() + handles.files = [file.copy() for file in self.files] + + return handles + + def __next__(self): + if self.index < len(self.files): + custom_file = self.get_handle(self.index) + self.index += 1 + return custom_file + else: + raise StopIteration + + def __len__(self): + return len(self.files) + + +def make_input(project: ratapi.Project, controls: ratapi.Controls) -> tuple[ProblemDefinition, Control]: + """Construct the inputs required for the compiled RAT code using the data defined in the input project and controls. + + Parameters + ---------- + project : RAT.Project + The project model, which defines the physical system under study. + controls : RAT.Controls + The controls model, which defines algorithmic properties. + + Returns + ------- + problem : RAT.rat_core.ProblemDefinition + The problem input used in the compiled RAT code. + cpp_controls : RAT.rat_core.Control + The controls object used in the compiled RAT code. + + """ + problem = make_problem(project) + cpp_controls = make_controls(controls) + + return problem, cpp_controls + + +def make_problem(project: ratapi.Project) -> ProblemDefinition: + """Construct the problem input required for the compiled RAT code. + + Parameters + ---------- + project : RAT.Project + The project model, which defines the physical system under study. + + Returns + ------- + problem : RAT.rat_core.ProblemDefinition + The problem input used in the compiled RAT code. + + """ + prior_id = {"uniform": 1, "gaussian": 2, "jeffreys": 3} + + # Ensure all contrast fields are properly defined + for contrast in project.contrasts: + contrast_fields = ["data", "background", "bulk_in", "bulk_out", "scalefactor", "resolution"] + + if project.calculation == Calculations.Domains: + contrast_fields.append("domain_ratio") + + for field in contrast_fields: + if getattr(contrast, field) == "": + raise ValueError( + f'In the input project, the "{field}" field of contrast "{contrast.name}" does not have a ' + f"value defined. A value must be supplied before running the project." + ) + + # Ensure backgrounds and resolutions have a source defined + background = project.backgrounds[contrast.background] + resolution = project.resolutions[contrast.resolution] + if background.source == "": + raise ValueError( + f"All backgrounds must have a source defined. For a {background.type} type background, " + f"the source must be defined in " + f'"{ratapi.project.values_defined_in[f"backgrounds.{background.type}.source"]}"' + ) + if resolution.source == "" and resolution.type != TypeOptions.Data: + raise ValueError( + f"Constant resolutions must have a source defined. The source must be defined in " + f'"{ratapi.project.values_defined_in[f"resolutions.{resolution.type}.source"]}"' + ) + + # 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 + ] + else: + contrast_models = [ + [project.layers.index(layer, True) for layer in contrast.model] for contrast in project.contrasts + ] + else: + contrast_models = [[]] * len(project.contrasts) + + # Set contrast parameters according to model type + if project.model == LayerModels.StandardLayers: + 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] + + # Get details of defined layers + layer_details = get_layer_details(project) + + contrast_background_params = [] + contrast_background_types = [] + all_data = [] + data_limits = [] + simulation_limits = [] + contrast_resolution_params = [] + contrast_resolution_types = [] + + # Set data, background and resolution for each contrast + for contrast in project.contrasts: + # Set data + data_index = project.data.index(contrast.data) + data = project.data[data_index].data + data_range = project.data[data_index].data_range + simulation_range = project.data[data_index].simulation_range + + if data_range: + data_limits.append(data_range) + else: + data_limits.append([0.0, 0.0]) + + if simulation_range: + simulation_limits.append(simulation_range) + else: + simulation_limits.append([0.0, 0.0]) + + # Set background parameters + background = project.backgrounds[contrast.background] + contrast_background_types.append(background.type) + contrast_background_param = [] + + if background.type == TypeOptions.Data: + contrast_background_param.append(project.data.index(background.source, True)) + if background.value_1 != "": + contrast_background_param.append(project.background_parameters.index(background.value_1)) + # If we are using a data background, we add the background data to the contrast data + data = append_data_background(data, project.data[background.source].data) + + elif background.type == TypeOptions.Function: + contrast_background_param.append(project.custom_files.index(background.source, True)) + contrast_background_param.extend( + [ + project.background_parameters.index(value, True) + for value in [ + background.value_1, + background.value_2, + background.value_3, + background.value_4, + background.value_5, + ] + if value != "" + ] + ) + + else: + contrast_background_param.append(project.background_parameters.index(background.source, True)) + + contrast_background_params.append(contrast_background_param) + + # Set resolution parameters + resolution = project.resolutions[contrast.resolution] + contrast_resolution_types.append(resolution.type) + contrast_resolution_param = [] + if resolution.type == TypeOptions.Function: + contrast_resolution_param.append(project.custom_files.index(resolution.source, True)) + contrast_resolution_param.extend( + [ + project.resolution_parameters.index(value, True) + for value in [ + resolution.value_1, + resolution.value_2, + resolution.value_3, + resolution.value_4, + resolution.value_5, + ] + if value != "" + ] + ) + + elif resolution.type == TypeOptions.Constant: + contrast_resolution_param.append(project.resolution_parameters.index(resolution.source, True)) + + contrast_resolution_params.append(contrast_resolution_param) + + # Contrast data has exactly six columns to include background data if relevant + all_data.append(np.column_stack((data, np.zeros((data.shape[0], 6 - data.shape[1]))))) + + problem = ProblemDefinition() + + problem.TF = project.calculation + problem.resample = make_resample(project) + problem.data = all_data + problem.dataPresent = make_data_present(project) + problem.dataLimits = data_limits + problem.simulationLimits = simulation_limits + problem.numberOfContrasts = len(project.contrasts) + problem.geometry = project.geometry + problem.useImaginary = project.absorption + problem.repeatLayers = [contrast.repeat_layers for contrast in project.contrasts] + problem.contrastBackgroundParams = contrast_background_params + problem.contrastBackgroundTypes = contrast_background_types + problem.contrastBackgroundActions = [contrast.background_action for contrast in project.contrasts] + problem.contrastScalefactors = [ + project.scalefactors.index(contrast.scalefactor, True) for contrast in project.contrasts + ] + 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.contrastResolutionParams = contrast_resolution_params + problem.contrastResolutionTypes = contrast_resolution_types + + problem.backgroundParams = [param.value for param in project.background_parameters] + problem.scalefactors = [param.value for param in project.scalefactors] + problem.bulkIns = [param.value for param in project.bulk_in] + problem.bulkOuts = [param.value for param in project.bulk_out] + problem.resolutionParams = [param.value for param in project.resolution_parameters] + problem.params = [param.value for param in project.parameters] + problem.numberOfLayers = len(project.layers) + problem.contrastLayers = [contrast_model if contrast_model else [] for contrast_model in contrast_models] + problem.layersDetails = layer_details if project.model == LayerModels.StandardLayers else [] + problem.customFiles = FileHandles(project.custom_files) + problem.modelType = project.model + problem.contrastCustomFiles = contrast_custom_files + + problem.contrastDomainRatios = [ + project.domain_ratios.index(contrast.domain_ratio, True) if hasattr(contrast, "domain_ratio") else 0 + for contrast in project.contrasts + ] + + problem.domainRatios = [param.value for param in project.domain_ratios] + problem.numberOfDomainContrasts = len(project.domain_contrasts) + + domain_contrast_models = [ + [project.layers.index(layer, True) for layer in domain_contrast.model] + for domain_contrast in project.domain_contrasts + ] + + problem.domainContrastLayers = [ + domain_contrast_model if domain_contrast_model else [] for domain_contrast_model in domain_contrast_models + ] + problem.fitParams = [ + param.value + for class_list in ratapi.project.parameter_class_lists + for param in getattr(project, class_list) + if param.fit + ] + problem.fitLimits = [ + [param.min, param.max] + for class_list in ratapi.project.parameter_class_lists + for param in getattr(project, class_list) + if param.fit + ] + problem.priorNames = [ + param.name for class_list in ratapi.project.parameter_class_lists for param in getattr(project, class_list) + ] + problem.priorValues = [ + [prior_id[param.prior_type], param.mu, param.sigma] + for class_list in ratapi.project.parameter_class_lists + for param in getattr(project, class_list) + ] + + # Names + problem.names = NameStore() + for class_list in ratapi.project.parameter_class_lists: + setattr(problem.names, parameter_field[class_list], [param.name for param in getattr(project, class_list)]) + problem.names.contrasts = [contrast.name for contrast in project.contrasts] + + # Checks + problem.checks = Checks() + for class_list in ratapi.project.parameter_class_lists: + setattr( + problem.checks, parameter_field[class_list], [int(element.fit) for element in getattr(project, class_list)] + ) + + check_indices(problem) + + return problem + + +def get_layer_details(project: ratapi.Project) -> list[int]: + """Get parameter indices for all layers defined in the project.""" + hydrate_id = {"bulk in": 0, "bulk out": 1} + layer_details = [] + + # Get the thickness, SLD, roughness fields from the appropriate model + if project.absorption: + layer_fields = list(ratapi.models.AbsorptionLayer.model_fields.keys())[1:-2] + else: + layer_fields = list(ratapi.models.Layer.model_fields.keys())[1:-2] + + for layer in project.layers: + for field in layer_fields: + if getattr(layer, field) == "": + raise ValueError( + f'In the input project, the "{field}" field of layer {layer.name} does not have a value ' + f"defined. A value must be supplied before running the project." + ) + + layer_params = [project.parameters.index(getattr(layer, attribute), True) for attribute in list(layer_fields)] + + 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) + + return layer_details + + +def make_resample(project: ratapi.Project) -> list[int]: + """Construct the "resample" field of the problem input required for the compiled RAT code. + + Parameters + ---------- + project : RAT.Project + The project model, which defines the physical system under study. + + Returns + ------- + list[int] + The "resample" field of the problem input used in the compiled RAT code. + + """ + return [contrast.resample for contrast in project.contrasts] + + +def make_data_present(project: ratapi.Project) -> list[int]: + """Construct the "dataPresent" field of the problem input required for the compiled RAT code. + + Parameters + ---------- + project : RAT.Project + The project model, which defines the physical system under study. + + Returns + ------- + list[int] + The "dataPresent" field of the problem input used in the compiled RAT code. + + """ + return [1 if project.data[contrast.data].data.size != 0 else 0 for contrast in project.contrasts] + + +def check_indices(problem: ProblemDefinition) -> None: + """Check the indices given in a problem's contrasts lie within the range of the corresponding parameter lists. + + Parameters + ---------- + problem : RAT.rat_core.ProblemDefinition + The problem input used in the compiled RAT code. + + """ + index_list = { + "scalefactors": "contrastScalefactors", + "bulkIns": "contrastBulkIns", + "bulkOuts": "contrastBulkOuts", + "domainRatios": "contrastDomainRatios", + } + + # Check the indices -- note we have switched to 1-based indexing at this point + for params in index_list: + param_list = getattr(problem, params) + if len(param_list) > 0: + elements = [ + element + for element in getattr(problem, index_list[params]) + if (element != -1) and not (0 < element <= len(param_list)) + ] + if elements: + raise IndexError( + f'The problem field "{index_list[params]}" contains: {", ".join(str(i) for i in elements)}' + f', which lie{"s" * (len(elements) == 1)} outside of the range of "{params}"', + ) + + # backgroundParams has a different structure, so is handled separately: + # it is of type list[list[int]], where each list[int] is the indices for + # source, value_1, value_2, value_3, value_4, value_5 where they are defined + # e.g. for a data background with offset it is [source value_1], for a function + # with 3 values it is [source value_1 value_2 value_3], etc. + + source_param_lists = { + "constant": "backgroundParams", + "data": "data", + "function": "customFiles", + } + + for i, background_data in enumerate(problem.contrastBackgroundParams): + background_type = problem.contrastBackgroundTypes[i] + + # check source param is in range of the relevant parameter list + param_list = getattr(problem, source_param_lists[background_type]) + source_index = background_data[0] + if not 0 < source_index <= len(param_list): + raise IndexError( + f'Entry {i} of contrastBackgroundParams has type "{background_type}" ' + f"and source index {source_index}, " + f'which is outside the range of "{source_param_lists[background_type]}".' + ) + + # check value params are in range for background params + if len(background_data) > 1: + elements = [element for element in background_data[1:] if not 0 < element <= len(problem.backgroundParams)] + if elements: + raise IndexError( + f"Entry {i} of contrastBackgroundParams contains: {', '.join(str(i) for i in elements)}" + f', which lie{"s" * (len(elements) == 1)} outside of the range of "backgroundParams"', + ) + + +def append_data_background(data: np.array, background: np.array) -> np.array: + """Append background data to contrast data. + + Parameters + ---------- + data : np.array + The contrast data to which we are appending a background. + background : np.array + The background data to append to the contrast. + + Returns + ------- + np.array + The contrast data with background data appended as two additional columns. + + """ + if not np.allclose(data[:, 0], background[:, 0]): + raise ValueError("The q-values of the data and background must be equal.") + + return np.hstack((data, np.zeros((data.shape[0], 4 - data.shape[1])), background[:, 1:])) + + +def make_controls(input_controls: ratapi.Controls) -> Control: + """Convert the controls object to the format required by the compiled RAT code. + + Parameters + ---------- + input_controls : RAT.Controls + The controls model, which defines algorithmic properties. + + Returns + ------- + controls : RAT.rat_core.Control + The controls object used in the compiled RAT code. + + """ + controls = Control() + + controls.procedure = input_controls.procedure + controls.parallel = input_controls.parallel + controls.numSimulationPoints = input_controls.numSimulationPoints + controls.resampleMinAngle = input_controls.resampleMinAngle + controls.resampleNPoints = input_controls.resampleNPoints + controls.display = input_controls.display + # Simplex + controls.xTolerance = input_controls.xTolerance + controls.funcTolerance = input_controls.funcTolerance + controls.maxFuncEvals = input_controls.maxFuncEvals + controls.maxIterations = input_controls.maxIterations + controls.updateFreq = input_controls.updateFreq + controls.updatePlotFreq = input_controls.updatePlotFreq + # DE + controls.populationSize = input_controls.populationSize + controls.fWeight = input_controls.fWeight + controls.crossoverProbability = input_controls.crossoverProbability + controls.strategy = int(input_controls.strategy) # RAT core expects strategy as an integer + controls.targetValue = input_controls.targetValue + controls.numGenerations = input_controls.numGenerations + # NS + controls.nLive = input_controls.nLive + controls.nMCMC = input_controls.nMCMC + controls.propScale = input_controls.propScale + controls.nsTolerance = input_controls.nsTolerance + # Dream + controls.nSamples = input_controls.nSamples + controls.nChains = input_controls.nChains + controls.jumpProbability = input_controls.jumpProbability + controls.pUnitGamma = input_controls.pUnitGamma + controls.boundHandling = input_controls.boundHandling + controls.adaptPCR = input_controls.adaptPCR + + controls.IPCFilePath = input_controls._IPCFilePath + + return controls diff --git a/ratapi/models.py b/ratapi/models.py new file mode 100644 index 00000000..ba0a1e99 --- /dev/null +++ b/ratapi/models.py @@ -0,0 +1,717 @@ +"""The models module. Contains the pydantic models used by RAT to store project parameters.""" + +import pathlib +import warnings +from contextlib import suppress +from typing import Any + +import numpy as np +import prettytable +from pydantic import BaseModel, Field, ValidationInfo, field_validator, model_validator + +from ratapi.utils.enums import BackgroundActions, Hydration, Languages, Priors, TypeOptions + +try: + from enum import StrEnum +except ImportError: + from strenum import StrEnum + + +# Create a counter for each model +background_number = ["Background", 0] +contrast_number = ["Contrast", 0] +custom_file_number = ["Custom File", 0] +data_number = ["Data", 0] +domain_contrast_number = ["Domain Contrast", 0] +layer_number = ["Layer", 0] +parameter_number = ["Parameter", 0] +resolution_number = ["Resolution", 0] + +_model_counter = { + "Background": background_number, + "Contrast": contrast_number, + "ContrastWithRatio": contrast_number, + "CustomFile": custom_file_number, + "Data": data_number, + "DomainContrast": domain_contrast_number, + "Layer": layer_number, + "AbsorptionLayer": layer_number, + "Parameter": parameter_number, + "ProtectedParameter": parameter_number, + "Resolution": resolution_number, +} + + +def _model_name_factory(model_name: str) -> str: + """Generate a unique name for model using a global counter. + + Parameters + ---------- + model_name : str + The name of the model class. + """ + title, number = _model_counter[model_name] + _model_counter[model_name][1] += 1 + return f"New {title} {(number + 1)}" + + +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})" + + @field_validator("name", mode="after", check_fields=False) + @classmethod + def update_counter(cls, name: str) -> str: + """Update the auto name counter if a similar name is manually given. + + Parameters + ---------- + name : str + The name of the model. + """ + title, number = _model_counter[cls.__name__] + prefix = f"New {title} " + if name.startswith(prefix): + with suppress(ValueError): + new_number = int(name[len(prefix) :]) + if new_number > number: + _model_counter[cls.__name__][1] = new_number + return name + + def __str__(self): + table = prettytable.PrettyTable() + table.field_names = [key.replace("_", " ") for key in self.display_fields] + table.add_row(list(self.display_fields.values())) + return table.get_string() + + @property + def display_fields(self) -> dict: + """A dictionary of which fields should be displayed by this model and their values.""" + return self.__dict__ + + +class Signal(RATModel): + """Base model for background & resolution signals.""" + + name: str = Field(default="New Signal", min_length=1) + type: TypeOptions = TypeOptions.Constant + source: str = "" + value_1: str = "" + value_2: str = "" + value_3: str = "" + value_4: str = "" + value_5: str = "" + + def __setattr__(self, name, value): + if name == "type": + warnings.warn(f"Changing the type of {self.name} clears its source and value fields.", stacklevel=2) + for attr in ["source", "value_1", "value_2", "value_3", "value_4", "value_5"]: + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + super().__setattr__(attr, "") + + super().__setattr__(name, value) + + @property + def display_fields(self) -> dict: + """The fields which should be visible in a table and their values. + + Returns + ------- + dict + A dictionary of the fields which should be visible in a table and their values. + + """ + visible_fields = ["name", "type", "source"] + if self.type != TypeOptions.Constant: + visible_fields.append("value_1") + if self.type == TypeOptions.Function: + visible_fields.extend(["value_2", "value_3", "value_4", "value_5"]) + + return {f: getattr(self, f) for f in visible_fields} + + +class Background(Signal): + """A background signal. + + Parameters + ---------- + name : str + The name of the background. + type : TypeOptions + The type of background (constant, function or data) + source : str + The source of the background; + + - if type is 'constant', this should be the name of a background parameter. + - if type is 'data', this should be the name of a dataset defined in `Project.data`. + - if type is 'function', this should be the name of a custom function defined in `Project.custom_files`. + + value_1, value_2, value_3, value_4, value_5 : str + Values required by the background. + + - if type is 'constant', all values will be ignored. + - if type is 'data', value_1 may be the parameter name for an optional offset. Other values are ignored. + - if type is 'function', these values may be the names of up to 5 parameters which are passed to the function. + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("Background"), min_length=1) + + @model_validator(mode="after") + def check_unsupported_parameters(self): + """Raise an error if the parameters given are not supported for the given type.""" + if self.type == TypeOptions.Constant: + expected_empty_fields = ["value_1", "value_2", "value_3", "value_4", "value_5"] + elif self.type == TypeOptions.Data: + expected_empty_fields = ["value_2", "value_3", "value_4", "value_5"] + else: + return self + + non_empty_fields = [v for v in expected_empty_fields if getattr(self, v) != ""] + if non_empty_fields: + raise ValueError( + f'The following values are not supported by the "{self.type}" Background type: ' + f"{', '.join(non_empty_fields)}" + ) + + return self + + +class Contrast(RATModel): + """A group of all of the components of a model. + + Parameters + ---------- + name : str + The name of the contrast. + data : str + The name of the dataset used by the contrast. + background : str + The name of the background for the contrast. + background_action : BackgroundActions + Whether the background should be added ('add') or subtracted ('subtract') from the data. + bulk_in : str + The name of the bulk-in parameter which defines the SLD of the interface between the + first layer and the environment. + bulk_out : str + The name of the bulk-out parameter which defines the SLD of the interface between the last + layer and the environment. + scalefactor : str + The name of the scalefactor which defines how much the data for this contrast should be scaled. + resolution : str + The name of the instrument resolution for this contrast. + resample : bool + Whether adaptive resampling should be used for interface microslicing. + repeat_layers : int + For standard layers, the number of times the set of layers defined in the model should be repeated. + model : list[str] + If this is a standard layers model, this should be a list of layer names + that make up the slab model for this contrast. + For custom models, this should be a list containing just the custom file name for the + custom model function. + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("Contrast"), min_length=1) + data: str = "" + background: str = "" + background_action: BackgroundActions = BackgroundActions.Add + bulk_in: str = "" + bulk_out: str = "" + scalefactor: str = "" + resolution: str = "" + resample: bool = False + repeat_layers: int = Field(default=1, gt=0) + model: list[str] = [] + + @model_validator(mode="before") + @classmethod + def domain_ratio_error(cls, data: Any): + """If the extra input 'domain_ratio' is given, give a more descriptive error.""" + if isinstance(data, dict) and data.get("domain_ratio", False): + raise ValueError( + "The Contrast class does not support domain ratios. Use the ContrastWithRatio class instead." + ) + + return data + + def __str__(self): + table = prettytable.PrettyTable() + table.field_names = [key.replace("_", " ") for key in self.__dict__] + model_entry = "\n".join(element for element in self.model) + table.add_row( + [ + self.name, + self.data, + self.background, + self.background_action, + self.bulk_in, + self.bulk_out, + self.scalefactor, + self.resolution, + self.resample, + self.repeat_layers, + model_entry, + ] + ) + return table.get_string() + + +class ContrastWithRatio(RATModel): + """A group of all of the components of a model, including domain terms. + + Parameters + ---------- + name : str + The name of the contrast. + data : str + The name of the dataset used by the contrast. + background : str + The name of the background for the contrast. + background_action : BackgroundActions + Whether the background should be added ('add') or subtracted ('subtract') from the data. + bulk_in : str + The name of the bulk-in parameter which defines the SLD of the interface between the + first layer and the environment. + bulk_out : str + The name of the bulk-out parameter which defines the SLD of the interface between the last + layer and the environment. + scalefactor : str + resolution : str + The name of the instrument resolution for this contrast. + resample : bool + Whether adaptive resampling should be used for interface microslicing. + repeat_layers : int + For standard layers, the number of times the set of layers defined in the model should be repeated. + domain_ratio : str + The name of the domain ratio parameter describing how the first domain should be weighted + relative to the second. + model : list[str] + If this is a standard layers model, this should be a list of the names of the two domain contrasts + which make up the domain model for this contrast. + For custom models, this should be a list containing just the custom file name for the + custom model function. + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("ContrastWithRatio"), min_length=1) + data: str = "" + background: str = "" + background_action: BackgroundActions = BackgroundActions.Add + bulk_in: str = "" + bulk_out: str = "" + scalefactor: str = "" + resolution: str = "" + resample: bool = False + repeat_layers: int = Field(default=1, gt=0) + domain_ratio: str = "" + model: list[str] = [] + + def __str__(self): + table = prettytable.PrettyTable() + table.field_names = [key.replace("_", " ") for key in self.__dict__] + model_entry = "\n".join(element for element in self.model) + table.add_row( + [ + self.name, + self.data, + self.background, + self.background_action, + self.bulk_in, + self.bulk_out, + self.scalefactor, + self.resolution, + self.resample, + self.repeat_layers, + self.domain_ratio, + model_entry, + ] + ) + return table.get_string() + + +class CustomFile(RATModel): + """A file containing functions to use for a custom model or function background. + + Parameters + ---------- + name : str + The name of this custom file object. + filename : str + The name of the file containing the custom function. + function_name : str + The name of the custom function within the file. + language : Languages + What language the custom function is written in: 'matlab', 'python', or 'cpp' (C++) + path : pathlib.Path + The path to the custom file. + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("CustomFile"), min_length=1) + filename: str = "" + function_name: str = "" + language: Languages = Languages.Python + path: pathlib.Path = pathlib.Path(".") + + def model_post_init(self, __context: Any) -> None: + """Autogenerate the function name from the filename if not set. + + If a filename is supplied but the ``function_name`` field is not set, the ``function_name`` should be set to + the filename 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") + def set_matlab_function_name(self): + """For a matlab custom function, ``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): + """A dataset required for a contrast. + + Parameters + ---------- + name : str + The name of this dataset. + data : np.ndarray[np.float64] + The (x, y, error) data for this dataset, given as a Numpy array of three columns. + data_range : list[float] + simulation_range : list[float] + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("Data"), min_length=1) + data: np.ndarray = 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") + @classmethod + def check_data_dimension(cls, data: np.ndarray) -> np.ndarray: + """Ensure the data is 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') from None + else: + if data.shape[1] < 3: + raise ValueError('"data" must have at least three columns') from None + return data + + @field_validator("data_range", "simulation_range") + @classmethod + def check_min_max(cls, limits: list[float], info: ValidationInfo) -> list[float]: + """Ensure the data range and simulation range maximum is greater than the minimum.""" + if limits[0] > limits[1]: + raise ValueError(f'{info.field_name} "min" value is greater than the "max" value') + return limits + + def model_post_init(self, __context: Any) -> None: + """Automatically generate ``data_range`` and ``simulation_range`` from the data. + + If the ``data_range`` and ``simulation_range`` fields are not set, but ``data`` is supplied, the ranges are + set to the min and max values of the first column (assumed to be q) of the supplied data. + """ + if self.data.shape[0] > 0: + data_min = float(np.min(self.data[:, 0])) + data_max = float(np.max(self.data[:, 0])) + for field in ["data_range", "simulation_range"]: + 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": + """Check that ``data_range`` is within the q-range of the data, and ``simulation_range`` is outside it. + + 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}]", + ) + return self + + 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__ + + 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__ + ) + else: + return NotImplemented # delegate to the other item in the comparison + + def __str__(self): + table = prettytable.PrettyTable() + table.field_names = [key.replace("_", " ") for key in self.__dict__] + array_entry = f"{'Data array: [' + ' x '.join(str(i) for i in self.data.shape) if self.data.size > 0 else '['}]" + table.add_row([self.name, array_entry, self.data_range, self.simulation_range]) + return table.get_string() + + +class DomainContrast(RATModel): + """A group of layers required for a domain. + + Parameters + ---------- + name : str + The name of this domain contrast. + model : list[str] + A list of layer names that make up the slab model for this contrast. + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("DomainContrast"), min_length=1) + model: list[str] = [] + + def __str__(self): + table = prettytable.PrettyTable() + table.field_names = [key.replace("_", " ") for key in self.__dict__] + model_entry = "\n".join(element for element in self.model) + table.add_row([self.name, model_entry]) + return table.get_string() + + +class Layer(RATModel, populate_by_name=True): + """A slab model layer with given physical properties. + + Parameters + ---------- + name : str + The name of this layer. + thickness : str + The name of the parameter describing the thickness of this layer. + SLD : str + The name of the parameter describing the scattering length density + of this layer. + roughness : str + The name of the parameter describing the roughness of this layer. + hydration : str + hydrate_with : str + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("Layer"), min_length=1) + thickness: str + SLD: str = Field(validation_alias="SLD_real") + roughness: str + hydration: str = "" + hydrate_with: Hydration = Hydration.BulkOut + + @model_validator(mode="before") + @classmethod + def sld_imaginary_error(cls, data: Any): + """If the extra input 'sld_imaginary' is given, give a more descriptive error.""" + if isinstance(data, dict) and data.get("SLD_imaginary", False): + raise ValueError("The Layer class does not support imaginary SLD. Use the AbsorptionLayer class instead.") + + return data + + +class AbsorptionLayer(RATModel, populate_by_name=True): + """A slab model layer with a non-negligible absorption term. + + Parameters + ---------- + name : str + The name of this layer. + thickness : str + The name of the parameter describing the thickness of this layer. + SLD_real : str + The name of the parameter describing the real (scattering) term + for the scattering length density of this layer. + SLD_imaginary : str + The name of the parameter describing the imaginary (absorption) term + for the scattering length density of this layer. + roughness : str + The name of the parameter describing the roughness of this layer. + hydration : str + hydrate_with : str + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("AbsorptionLayer"), min_length=1) + thickness: str + SLD_real: str = Field(validation_alias="SLD") + SLD_imaginary: str + roughness: str + hydration: str = "" + hydrate_with: Hydration = Hydration.BulkOut + + +class Parameter(RATModel): + """A parameter needed to specify the model. + + Parameters + ---------- + name : str + The name of this parameter. + min : float + The minimum value that this parameter could take when fitted. + value : float + The value of this parameter. + max : float + The maximum value that this parameter could take when fitted. + fit : bool + Whether this parameter should be fitted in a calculation. + prior_type : Priors + For Bayesian calculations, whether the prior likelihood + is assumed to be 'uniform' or 'gaussian'. + mu, sigma : float + If the prior type is Gaussian, the mu and sigma values describing + the Gaussian function for the prior likelihood. + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("Parameter"), min_length=1) + min: float = 0.0 + value: float = 0.0 + max: float = 0.0 + fit: bool = False + prior_type: Priors = Priors.Uniform + mu: float = 0.0 + sigma: float = np.inf + + show_priors: bool = False + + def model_post_init(self, __context: Any) -> None: + """Apply parameter value to limits if they are not set.""" + if "value" in self.model_fields_set: + if self.value > 0.0: + if "max" not in self.model_fields_set: + self.max = self.value + if "min" not in self.model_fields_set: + self.min = self.value + elif self.value < 0.0: + if "min" not in self.model_fields_set: + self.min = self.value + if "max" not in self.model_fields_set: + self.max = self.value + + @model_validator(mode="after") + def check_min_max(self) -> "Parameter": + """Ensure the maximum value of a parameter is 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}") + return self + + @model_validator(mode="after") + def check_value_in_range(self) -> "Parameter": + """Ensure the value of a parameter lies 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}") + return self + + @property + def display_fields(self) -> dict: + """Only display Prior information if ``show_priors`` is true.""" + visible_fields = ["name", "min", "value", "max", "fit"] + if self.show_priors: + visible_fields.append("prior_type") + if self.prior_type == Priors.Gaussian: + visible_fields.extend(["mu", "sigma"]) + + return {f: getattr(self, f) for f in visible_fields} + + +class ProtectedParameter(Parameter): + """A Parameter with a fixed name.""" + + name: str = Field(frozen=True, min_length=1) + + +class Resolution(Signal): + """An instrument resolution. + + Parameters + ---------- + name : str + The name of the resolution. + type : TypeOptions + The type of resolution: 'constant', 'data', or (NOT YET IMPLEMENTED) 'function'. + source : str + The source data for the resolution; + + - if type is 'constant', this should be the name of a background parameter. + - if type is 'data', this should be empty (resolution data is in the contrast data). + - if type is 'function' (NOT YET IMPLEMENTED), + this should be the name of a custom function defined in `Project.custom_files`. + + value_1, value_2, value_3, value_4, value_5 : str + Values required by the background. + + - if type is 'constant' or 'data', all values will be ignored. + - if type is 'function' (NOT YET IMPLEMENTED), + these values may be the names of up to 5 parameters which are passed to the function. + + """ + + name: str = Field(default_factory=lambda: _model_name_factory("Resolution"), min_length=1) + + @field_validator("type") + @classmethod + def validate_unimplemented_resolutions(cls, type: TypeOptions): + """Raise an error if currently unsupported function resolutions are used.""" + # when function resolutions are added, fix the commented-out parts of + # test_project.py::test_rename_models + # and test_project.py::test_allowed_resolutions + if type == TypeOptions.Function: + raise NotImplementedError("Function resolutions are not yet supported.") + return type + + @model_validator(mode="after") + def check_unsupported_parameters(self): + """Raise an error if the parameters given are not supported for the given type.""" + if self.type == TypeOptions.Constant: + expected_empty_fields = ["value_1", "value_2", "value_3", "value_4", "value_5"] + elif self.type == TypeOptions.Data: + expected_empty_fields = ["source", "value_1", "value_2", "value_3", "value_4", "value_5"] + else: + return self + + non_empty_fields = [v for v in expected_empty_fields if getattr(self, v) != ""] + if non_empty_fields: + raise ValueError( + f'The following values are not supported by the "{self.type}" Resolution type: ' + f"{', '.join(non_empty_fields)}" + ) + + return self diff --git a/ratapi/outputs.py b/ratapi/outputs.py new file mode 100644 index 00000000..c1f5c0ed --- /dev/null +++ b/ratapi/outputs.py @@ -0,0 +1,821 @@ +"""Converts results from the compiled RAT code to python dataclasses.""" + +import json +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Union + +import numpy as np + +import ratapi.rat_core +from ratapi.utils.enums import Procedures + +bayes_results_subclasses = [ + "predictionIntervals", + "confidenceIntervals", + "dreamParams", + "dreamOutput", + "nestedSamplerOutput", +] + +bayes_results_fields = { + "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"], + "nestedSamplerOutput": ["logZ", "logZErr"], + }, + "list_fields": { + "predictionIntervals": ["reflectivity"], + "confidenceIntervals": [], + "dreamParams": [], + "dreamOutput": [], + "nestedSamplerOutput": [], + }, + "double_list_fields": { + "predictionIntervals": ["sld"], + "confidenceIntervals": [], + "dreamParams": [], + "dreamOutput": [], + "nestedSamplerOutput": [], + }, + "array_fields": { + "predictionIntervals": ["sampleChi"], + "confidenceIntervals": ["percentile65", "percentile95", "mean"], + "dreamParams": ["R"], + "dreamOutput": ["allChains", "outlierChains", "AR", "R_stat", "CR"], + "nestedSamplerOutput": ["nestSamples", "postSamples"], + }, +} + +results_fields = { + "list_fields": ["reflectivity", "simulation", "shiftedData", "backgrounds", "resolutions"], + "double_list_fields": ["sldProfiles", "layers", "resampledLayers"], +} + + +def get_field_string(field: str, value: Any, array_limit: int): + """Return a string representation of class fields where large arrays are represented by their shape. + + An array will be displayed as just its shape if it is multidimensional or 1D and longer than ``array_limit``. + + Parameters + ---------- + field : str + The name of the field in the RAT output class. + value : Any + The value of the given field in the RAT output class. + array_limit : int + The maximum length of 1D arrays which will be fully displayed. + + Returns + ------- + field_string : str + The string representation of the field in the RAT output class. + + Examples + -------- + >>> get_field_string("data", 130, 5) + "data = 130" + + >>> get_field_string("data", array([1, 2, 3, 4, 5]), 10) + "data = [1 2 3 4 5]" + + >>> get_field_string("data", array([1, 2, 3, 4, 5]), 3) + "data = Data array: [5]," + + >>> get_field_string("data", array([[1, 2, 3], [4, 5, 6]]), 10) + "data = Data array: [2 x 3]," + + """ + array_text = "Data array: " + if isinstance(value, list) and len(value) > 0: + if isinstance(value[0], np.ndarray): + array_strings = [f"{array_text}[{' x '.join(str(i) for i in array.shape)}]" for array in value] + field_string = f"{field} = [{', '.join(str(string) for string in array_strings)}],\n" + elif isinstance(value[0], list) and len(value[0]) > 0 and isinstance(value[0][0], np.ndarray): + array_strings = [ + [f"{array_text}[{' x '.join(str(i) for i in array.shape)}]" for array in sub_list] for sub_list in value + ] + list_strings = [f"[{', '.join(string for string in list_string)}]" for list_string in array_strings] + field_string = f"{field} = [{', '.join(list_strings)}],\n" + else: + field_string = f"{field} = {str(value)},\n" + elif isinstance(value, np.ndarray): + if value.ndim == 1 and value.size < array_limit: + field_string = f"{field} = {str(value) if value.size > 0 else '[]'},\n" + else: + field_string = f"{field} = {array_text}[{' x '.join(str(i) for i in value.shape)}],\n" + else: + field_string = f"{field} = {str(value)},\n" + + return field_string + + +class RATResult: + """A mixin class which truncates arrays when the class is displayed.""" + + def __str__(self): + output = f"{self.__class__.__name__}(\n" + for key, value in self.__dict__.items(): + output += "\t" + get_field_string(key, value, 100) + output += ")" + return output + + +@dataclass +class CalculationResults(RATResult): + """The goodness of fit from the Abeles calculation. + + Parameters + ---------- + chiValues : np.ndarray + The chi-squared value for each contrast. + sumChi : float + The sum of the chiValues array. + + """ + + chiValues: np.ndarray + sumChi: float + + +@dataclass +class ContrastParams(RATResult): + """The experimental parameters for each contrast. + + Parameters + ---------- + scalefactors : np.ndarray + The scalefactor values for each contrast. + bulkIn : np.ndarray + The bulk in values for each contrast. + bulkOut : np.ndarray + The bulk out values for each contrast. + subRoughs : np.ndarray + The substrate roughness values for each contrast. + resample : np.ndarray + An array containing whether each contrast was resampled. + + """ + + scalefactors: np.ndarray + bulkIn: np.ndarray + bulkOut: np.ndarray + subRoughs: np.ndarray + resample: np.ndarray + + +@dataclass +class Results: + """The results of a RAT calculation. + + Parameters + ---------- + reflectivity : list + The reflectivity curves for each contrast, + with the same range as the data + (``data_range`` in the contrast's ``Data`` object) + simulation : list + The reflectivity curves for each contrast, + which can be a wider range to allow extrapolation + (``simulation_range`` in the contrast's ``Data`` object). + shiftedData : list + The data with scalefactors and background corrections applied. + backgrounds : list + The background for each contrast defined over the simulation range. + resolutions : list + The resolution for each contrast defined over the simulation range. + sldProfiles : list + The SLD profiles for each contrast. + layers : list + The array of layer parameter values for each contrast. + resampledLayers : list + If resampling is used, the array of layer parameter values for each contrast after resampling has been + performed. + calculationResults : CalculationResults + The chi-squared fit results from the final calculation and fit. + contrastParams : ContrastParams + The experimental parameters for the contrasts. + fitParams : np.ndarray + The best fit value of the parameter with name ``fitNames[i]``. + fitNames : list[str] + The names of the fit parameters, where ``fitNames[i]`` is the name + of the parameter with value given in ``fitParams[i]``. + + """ + + reflectivity: list + simulation: list + shiftedData: list + backgrounds: list + resolutions: list + sldProfiles: list + layers: list + resampledLayers: list + calculationResults: CalculationResults + contrastParams: ContrastParams + fitParams: np.ndarray + fitNames: list[str] + + def __str__(self): + output = "" + for key, value in self.__dict__.items(): + output += get_field_string(key, value, 100) + return output + + def save(self, filepath: str | Path = "./results.json"): + """Save the Results object to a JSON file. + + Parameters + ---------- + filepath : str or Path + The path to where the results file will be written. + """ + filepath = Path(filepath).with_suffix(".json") + json_dict = write_core_results_fields(self) + + filepath.write_text(json.dumps(json_dict)) + + @classmethod + def load(cls, path: str | Path) -> Union["Results", "BayesResults"]: + """Load a Results object from file. + + Parameters + ---------- + path : str or Path + The path to the results json file. + """ + path = Path(path) + input_data = path.read_text() + results_dict = json.loads(input_data) + + results_dict = read_core_results_fields(results_dict) + + if all(key in results_dict for key in bayes_results_subclasses): + results_dict = read_bayes_results_fields(results_dict) + + return BayesResults( + reflectivity=results_dict["reflectivity"], + simulation=results_dict["simulation"], + shiftedData=results_dict["shiftedData"], + backgrounds=results_dict["backgrounds"], + resolutions=results_dict["resolutions"], + sldProfiles=results_dict["sldProfiles"], + layers=results_dict["layers"], + resampledLayers=results_dict["resampledLayers"], + calculationResults=CalculationResults(**results_dict["calculationResults"]), + contrastParams=ContrastParams(**results_dict["contrastParams"]), + fitParams=np.array(results_dict["fitParams"]), + fitNames=results_dict["fitNames"], + predictionIntervals=PredictionIntervals(**results_dict["predictionIntervals"]), + confidenceIntervals=ConfidenceIntervals(**results_dict["confidenceIntervals"]), + dreamParams=DreamParams(**results_dict["dreamParams"]), + dreamOutput=DreamOutput(**results_dict["dreamOutput"]), + nestedSamplerOutput=NestedSamplerOutput(**results_dict["nestedSamplerOutput"]), + chain=np.array(results_dict["chain"]), + ) + + else: + return Results( + reflectivity=results_dict["reflectivity"], + simulation=results_dict["simulation"], + shiftedData=results_dict["shiftedData"], + backgrounds=results_dict["backgrounds"], + resolutions=results_dict["resolutions"], + sldProfiles=results_dict["sldProfiles"], + layers=results_dict["layers"], + resampledLayers=results_dict["resampledLayers"], + calculationResults=CalculationResults(**results_dict["calculationResults"]), + contrastParams=ContrastParams(**results_dict["contrastParams"]), + fitParams=np.array(results_dict["fitParams"]), + fitNames=results_dict["fitNames"], + ) + + +@dataclass +class PredictionIntervals(RATResult): + """The Bayesian prediction intervals for 95% and 65% confidence. + + For ``reflectivity`` and ``sld``, each list item is an array + with five rows. The rows represent: + + - 0: the 5th percentile; + - 1: the 35th percentile; + - 2: the mean value of the interval; + - 3: the 65th percentile; + - 4: the 95th percentile. + + Parameters + ---------- + reflectivity : list + The prediction interval data for reflectivity of each contrast. + SLD : list + The prediction interval data for SLD of each contrast. + sampleChi : np.ndarray + The value of sumChi at each point of the Markov chain. + + """ + + reflectivity: list + sld: list + sampleChi: np.ndarray + + +@dataclass +class ConfidenceIntervals(RATResult): + """The 65% and 95% confidence intervals for the best fit results. + + Parameters + ---------- + percentile95 : np.ndarray + The 95% confidence intervals for each fit parameter. + percentile65 : np.ndarray + The 65% confidence intervals for each fit parameter. + mean : np.ndarray + The mean values for each fit parameter. + + """ + + percentile95: np.ndarray + percentile65: np.ndarray + mean: np.ndarray + + +@dataclass +class DreamParams(RATResult): + """The parameters used by the inner DREAM algorithm. + + Parameters + ---------- + nParams : float + The number of parameters used by the algorithm. + nChains : float + The number of MCMC chains used by the algorithm. + nGenerations : float + The number of DE generations calculated per iteration. + parallel : bool + Whether the algorithm should run chains in parallel. + CPU : float + The number of processor cores used for parallel chains. + jumpProbability : float + A probability range for the size of jumps when performing subspace sampling. + pUnitGamma : float + The probability that the scaling-down factor of jumps will be ignored + and a larger jump will be taken for one iteration. + nCR : float + The number of crossovers performed each iteration. + delta : float + The number of chain mutation pairs proposed each iteration. + steps : float + The number of MCMC steps to perform between conversion checks. + zeta : float + The ergodicity of the algorithm. + outlier : str + What test should be used to detect outliers. + adaptPCR : bool + Whether the crossover probability for differential evolution should be + adapted by the algorithm as it runs. + thinning : float + The thinning rate of each Markov chain (to reduce memory intensity) + epsilon : float + The cutoff threshold for Approximate Bayesian Computation (if used) + ABC : bool + Whether Approximate Bayesian Computation is used. + IO : bool + Whether the algorithm should perform IO writes of the model in parallel. + storeOutput : bool + Whether output model simulations are performed. + R : np.ndarray + An array where row ``i`` is the list of chains + with which chain ``i`` can mutate. + + """ + + nParams: float + nChains: float + nGenerations: float + parallel: bool + CPU: float + jumpProbability: float + pUnitGamma: float + nCR: float + delta: float + steps: float + zeta: float + outlier: str + adaptPCR: bool + thinning: float + epsilon: float + ABC: bool + IO: bool + storeOutput: bool + R: np.ndarray + + +@dataclass +class DreamOutput(RATResult): + """The diagnostic output information from DREAM. + + Parameters + ---------- + allChains : np.ndarray + An ``nGenerations`` x ``nParams + 2`` x ``nChains`` size array, + where ``chain_k = DreamOutput.allChains[:, :, k]`` + is the data of chain ``k`` in the final iteration; + for generation i of the final iteration, ``chain_k[i, j]`` represents: + + - the sampled value of parameter ``j`` for ``j in 0:nParams``; + - the associated log-prior for those sampled values for ``j = nParams + 1``; + - the associated log-likelihood for those sampled values for ``j = nParams + 2``. + + outlierChains : np.ndarray + A two-column array where ``DreamOutput.AR[i, 1]`` is the index of a chain + and ``DreamOutput.AR[i, 0]`` is the length of that chain when it was removed + for being an outlier. + runtime : float + The runtime of the DREAM algorithm in seconds. + iteration : float + The number of iterations performed. + AR : np.ndarray + A two-column array where ``DreamOutput.AR[i, 0]`` is an iteration number + and ``DreamOutput.AR[i, 1]`` is the average acceptance rate of chain step + proposals for that iteration. + R_stat : np.ndarray + An array where ``DreamOutput.R_stat[i, 0]`` is an iteration number and + ``DreamOutput.R_stat[i, j]`` is the convergence statistic for parameter ``j`` + at that iteration (where chains are indexed 1 to ``nParams`` inclusive). + CR : np.ndarray + A four-column array where ``DreamOutput.CR[i, 0]`` is an iteration number, + ``and DreamOutput.CR[i, j]`` is the selection probability of the ``j``'th crossover + value for that iteration. + + """ + + allChains: np.ndarray + outlierChains: np.ndarray + runtime: float + iteration: float + AR: np.ndarray + R_stat: np.ndarray + CR: np.ndarray + + +@dataclass +class NestedSamplerOutput(RATResult): + """The output information from the Nested Sampler (ns). + + Parameters + ---------- + logZ : float + The natural logarithm of the evidence Z for the parameter values. + logZErr : float + The estimated uncertainty in the final value of logZ. + nestSamples : np.ndarray + ``NestedSamplerOutput.nestSamples[i, j]`` represents the values + sampled at iteration ``i``, where this value is: + + - the value sampled for parameter ``j``, for ``j`` in ``0:nParams``, + - the minimum log-likelihood for ``j = nParams + 1``. + + postSamples : np.ndarray + The posterior values at the points sampled in ``NestedSamplerOutput.nestSamples``. + + """ + + logZ: float + logZErr: float + nestSamples: np.ndarray + postSamples: np.ndarray + + +@dataclass +class BayesResults(Results): + """The results of a Bayesian RAT calculation. + + Parameters + ---------- + predictionIntervals : PredictionIntervals + The prediction intervals. + confidenceIntervals : ConfidenceIntervals + The 65% and 95% confidence intervals for the best fit results. + dreamParams : DreamParams + The parameters used by DREAM, if relevant. + dreamOutput : DreamOutput + The output from DREAM if DREAM was used. + nestedSamplerOutput : NestedSamplerOutput + The output from nested sampling if ns was used. + chain : np.ndarray + The MCMC chains for each parameter. + The ``i``'th column of the array contains the chain for parameter ``fitNames[i]``. + + """ + + predictionIntervals: PredictionIntervals + confidenceIntervals: ConfidenceIntervals + dreamParams: DreamParams + dreamOutput: DreamOutput + nestedSamplerOutput: NestedSamplerOutput + chain: np.ndarray + + def from_procedure(self) -> Procedures: + """Return the procedure that created the result. + + Returns + ------- + procedure: Procedures + The procedure that created the result. + """ + samples = self.nestedSamplerOutput.nestSamples + if samples.shape == (1, 2) and not np.any(samples): + return Procedures.DREAM + return Procedures.NS + + def save(self, filepath: str | Path = "./results.json"): + """Save the BayesResults object to a JSON file. + + Parameters + ---------- + filepath : str or Path + The path to where the results file will be written. + """ + filepath = Path(filepath).with_suffix(".json") + json_dict = write_core_results_fields(self) + + # Take each of the subclasses in a BayesResults instance and switch the numpy arrays to lists + for subclass_name in bayes_results_subclasses: + subclass = getattr(self, subclass_name) + subclass_dict = {} + + for field in bayes_results_fields["param_fields"][subclass_name]: + subclass_dict[field] = getattr(subclass, field) + + for field in bayes_results_fields["list_fields"][subclass_name]: + subclass_dict[field] = [result_array.tolist() for result_array in getattr(subclass, field)] + + for field in bayes_results_fields["double_list_fields"][subclass_name]: + subclass_dict[field] = [ + [result_array.tolist() for result_array in inner_list] for inner_list in getattr(subclass, field) + ] + + for field in bayes_results_fields["array_fields"][subclass_name]: + subclass_dict[field] = getattr(subclass, field).tolist() + + json_dict[subclass_name] = subclass_dict + + json_dict["chain"] = self.chain.tolist() + filepath.write_text(json.dumps(json_dict)) + + +def write_core_results_fields(results: Results | BayesResults, json_dict: dict | None = None) -> dict: + """Modify the values of the fields that appear in both Results and BayesResults when saving to a json file. + + Parameters + ---------- + results: Union[Results, BayesResults] + The results or BayesResults object we are writing to json. + json_dict: Optional[dict] + The dictionary containing the json output. + + Returns + ------- + json_dict: dict + The output json dict updated with the fields that appear in both Results and BayesResults. + """ + if json_dict is None: + json_dict = {} + + for field in results_fields["list_fields"]: + json_dict[field] = [result_array.tolist() for result_array in getattr(results, field)] + + for field in results_fields["double_list_fields"]: + json_dict[field] = [ + [result_array.tolist() for result_array in inner_list] for inner_list in getattr(results, field) + ] + + json_dict["calculationResults"] = {} + json_dict["calculationResults"]["chiValues"] = results.calculationResults.chiValues.tolist() + json_dict["calculationResults"]["sumChi"] = results.calculationResults.sumChi + + json_dict["contrastParams"] = {} + for field in results.contrastParams.__dict__: + json_dict["contrastParams"][field] = getattr(results.contrastParams, field).tolist() + + json_dict["fitParams"] = results.fitParams.tolist() + json_dict["fitNames"] = results.fitNames + + return json_dict + + +def read_core_results_fields(results_dict: dict) -> dict: + """Modify the values of the fields that appear in both Results and BayesResults when loading a json file. + + Parameters + ---------- + results_dict: Optional[dict] + The dictionary containing the json input. + + Returns + ------- + results_dict: dict + The input json dict with the fields that appear in both Results and BayesResults converted to numpy arrays + where necessary. + """ + for field in results_fields["list_fields"]: + results_dict[field] = [np.array(result_array) for result_array in results_dict[field]] + + for field in results_fields["double_list_fields"]: + results_dict[field] = [ + [np.array(result_array) for result_array in inner_list] for inner_list in results_dict[field] + ] + + results_dict["calculationResults"]["chiValues"] = np.array(results_dict["calculationResults"]["chiValues"]) + + for field in results_dict["contrastParams"]: + results_dict["contrastParams"][field] = np.array(results_dict["contrastParams"][field]) + + return results_dict + + +def read_bayes_results_fields(results_dict: dict) -> dict: + """Modify the values of the fields that appear only in BayesResults when loading a json file. + + Parameters + ---------- + results_dict: Optional[dict] + The dictionary containing the json input. + + Returns + ------- + results_dict: dict + The input json dict with the fields that appear in both Results and BayesResults converted to numpy arrays + where necessary. + """ + for subclass_name in bayes_results_subclasses: + subclass_dict = {} + + for field in bayes_results_fields["param_fields"][subclass_name]: + subclass_dict[field] = results_dict[subclass_name][field] + + for field in bayes_results_fields["list_fields"][subclass_name]: + subclass_dict[field] = [np.array(result_array) for result_array in results_dict[subclass_name][field]] + + for field in bayes_results_fields["double_list_fields"][subclass_name]: + subclass_dict[field] = [ + [np.array(result_array) for result_array in inner_list] + for inner_list in results_dict[subclass_name][field] + ] + + for field in bayes_results_fields["array_fields"][subclass_name]: + subclass_dict[field] = np.array(results_dict[subclass_name][field]) + + results_dict[subclass_name] = subclass_dict + + return results_dict + + +def make_results( + procedure: Procedures, + output_results: ratapi.rat_core.OutputResult, + bayes_results: ratapi.rat_core.OutputBayesResult | None = None, +) -> Results | BayesResults: + """Initialise a python Results or BayesResults object using the outputs from a RAT calculation. + + Parameters + ---------- + procedure : Procedures + The procedure used by the calculation. + output_results : ratapi.rat_core.OutputResult + The C++ output results from the calculation. + bayes_results : Optional[ratapi.rat_core.OutputBayesResult] + The optional extra C++ Bayesian output results from a Bayesian calculation. + + Returns + ------- + Results or BayesResults + A result object containing the results of the calculation, of type + Results for non-Bayesian procedures and BayesResults for Bayesian procedures. + + """ + calculation_results = CalculationResults( + chiValues=output_results.calculationResults.chiValues, + sumChi=output_results.calculationResults.sumChi, + ) + contrast_params = ContrastParams( + scalefactors=output_results.contrastParams.scalefactors, + bulkIn=output_results.contrastParams.bulkIn, + bulkOut=output_results.contrastParams.bulkOut, + subRoughs=output_results.contrastParams.subRoughs, + 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, + sampleChi=bayes_results.predictionIntervals.sampleChi, + ) + + confidence_intervals = ConfidenceIntervals( + percentile95=bayes_results.confidenceIntervals.percentile95, + percentile65=bayes_results.confidenceIntervals.percentile65, + mean=bayes_results.confidenceIntervals.mean, + ) + + dream_params = DreamParams( + nParams=bayes_results.dreamParams.nParams, + nChains=bayes_results.dreamParams.nChains, + nGenerations=bayes_results.dreamParams.nGenerations, + parallel=bool(bayes_results.dreamParams.parallel), + CPU=bayes_results.dreamParams.CPU, + jumpProbability=bayes_results.dreamParams.jumpProbability, + pUnitGamma=bayes_results.dreamParams.pUnitGamma, + nCR=bayes_results.dreamParams.nCR, + delta=bayes_results.dreamParams.delta, + steps=bayes_results.dreamParams.steps, + zeta=bayes_results.dreamParams.zeta, + outlier=bayes_results.dreamParams.outlier, + adaptPCR=bool(bayes_results.dreamParams.adaptPCR), + thinning=bayes_results.dreamParams.thinning, + epsilon=bayes_results.dreamParams.epsilon, + ABC=bool(bayes_results.dreamParams.ABC), + IO=bool(bayes_results.dreamParams.IO), + storeOutput=bool(bayes_results.dreamParams.storeOutput), + R=bayes_results.dreamParams.R, + ) + + dream_output = DreamOutput( + allChains=bayes_results.dreamOutput.allChains, + outlierChains=bayes_results.dreamOutput.outlierChains, + runtime=bayes_results.dreamOutput.runtime, + iteration=bayes_results.dreamOutput.iteration, + AR=bayes_results.dreamOutput.AR, + R_stat=bayes_results.dreamOutput.R_stat, + CR=bayes_results.dreamOutput.CR, + ) + + nested_sampler_output = NestedSamplerOutput( + logZ=bayes_results.nestedSamplerOutput.logZ, + logZErr=bayes_results.nestedSamplerOutput.logZErr, + nestSamples=bayes_results.nestedSamplerOutput.nestSamples, + postSamples=bayes_results.nestedSamplerOutput.postSamples, + ) + + results = BayesResults( + reflectivity=output_results.reflectivity, + simulation=output_results.simulation, + shiftedData=output_results.shiftedData, + backgrounds=output_results.backgrounds, + resolutions=output_results.resolutions, + sldProfiles=output_results.sldProfiles, + layers=output_results.layers, + resampledLayers=output_results.resampledLayers, + calculationResults=calculation_results, + contrastParams=contrast_params, + fitParams=output_results.fitParams, + fitNames=output_results.fitNames, + predictionIntervals=prediction_intervals, + confidenceIntervals=confidence_intervals, + dreamParams=dream_params, + dreamOutput=dream_output, + nestedSamplerOutput=nested_sampler_output, + chain=bayes_results.chain, + ) + + else: + results = Results( + reflectivity=output_results.reflectivity, + simulation=output_results.simulation, + shiftedData=output_results.shiftedData, + backgrounds=output_results.backgrounds, + resolutions=output_results.resolutions, + sldProfiles=output_results.sldProfiles, + layers=output_results.layers, + resampledLayers=output_results.resampledLayers, + calculationResults=calculation_results, + contrastParams=contrast_params, + fitParams=output_results.fitParams, + fitNames=output_results.fitNames, + ) + + return results diff --git a/ratapi/project.py b/ratapi/project.py new file mode 100644 index 00000000..b8ca49f2 --- /dev/null +++ b/ratapi/project.py @@ -0,0 +1,1080 @@ +"""The project module. Defines and stores all the input data required for reflectivity calculations in RAT.""" + +import collections +import copy +import functools +import json +import warnings +from collections.abc import Callable +from enum import Enum +from pathlib import Path +from textwrap import indent +from typing import Annotated, Any, get_args, get_origin + +import numpy as np +from pydantic import ( + BaseModel, + Discriminator, + Field, + Tag, + ValidationError, + ValidationInfo, + field_validator, + model_validator, +) + +import ratapi.models +from ratapi.classlist import ClassList +from ratapi.utils.custom_errors import custom_pydantic_validation_error +from ratapi.utils.enums import Calculations, Geometries, LayerModels, Priors, TypeOptions + + +# note for these discriminators that the before-validator discriminate_ambiguous_dicts +# guarantees we don't run into the ambiguous case of a sequence of dicts +def discriminate_layers(layer_input): + """Union discriminator for layers.""" + if isinstance(layer_input, collections.abc.Sequence): + # if classlist is empty, just label it as no absorption and it'll get fixed in post_init + if len(layer_input) > 0 and isinstance(layer_input[0], ratapi.models.AbsorptionLayer): + return "abs" + return "no_abs" + + +def discriminate_contrasts(contrast_input): + """Union discriminator for contrasts.""" + if isinstance(contrast_input, collections.abc.Sequence): + # if classlist is empty, just label it as no ratio and it'll get fixed in post_init + if len(contrast_input) > 0 and isinstance(contrast_input[0], ratapi.models.ContrastWithRatio): + return "ratio" + return "no_ratio" + + +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", + "backgrounds.constant.source": "background_parameters", + "backgrounds.data.source": "data", + "backgrounds.function.source": "custom_files", + "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", + "resolutions.constant.source": "resolution_parameters", + "resolutions.function.source": "custom_files", + "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", ["source", "value_1", "value_2", "value_3", "value_4", "value_5"]) + ], + "resolution_parameters": [ + AllFields("resolutions", ["source", "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"]), + AllFields("backgrounds", ["source"]), + ], + "custom_files": [AllFields("backgrounds", ["source"]), AllFields("resolutions", ["source"])], + "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", use_attribute_docstrings=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 = "" + """The name of the project.""" + + calculation: Calculations = Calculations.Normal + """What calculation type should be used. Can be 'normal' or 'domains'.""" + + model: LayerModels = LayerModels.StandardLayers + """What layer model should be used. Can be 'standard layers', 'custom layers', or 'custom xy'.""" + + geometry: Geometries = Geometries.AirSubstrate + """What geometry should be used. Can be 'air/substrate' or 'substrate/liquid'""" + + absorption: bool = False + """Whether imaginary SLD (absorption) should be accounted for.""" + + parameters: ClassList[ratapi.models.Parameter] = ClassList() + """The list of parameters used in the layers of a model.""" + + bulk_in: ClassList[ratapi.models.Parameter] = ClassList( + ratapi.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, + ), + ) + """The list of parameters for SLD of the entry interfaces of a model.""" + + bulk_out: ClassList[ratapi.models.Parameter] = ClassList( + ratapi.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, + ), + ) + """The list of parameters for SLD of the exit interfaces of a model.""" + + scalefactors: ClassList[ratapi.models.Parameter] = ClassList( + ratapi.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, + ), + ) + """The list of parameters for scale factors to handle systematic error in model data.""" + + domain_ratios: ClassList[ratapi.models.Parameter] = ClassList( + ratapi.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, + ), + ) + """The list of parameters for weighting between domains of a domains model.""" + + background_parameters: ClassList[ratapi.models.Parameter] = ClassList( + ratapi.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, + ), + ) + """The list of parameters for models of backgrounds.""" + + backgrounds: ClassList[ratapi.models.Background] = ClassList( + ratapi.models.Background(name="Background 1", type=TypeOptions.Constant, source="Background Param 1"), + ) + """The list of models for background noise in the project.""" + + resolution_parameters: ClassList[ratapi.models.Parameter] = ClassList( + ratapi.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, + ), + ) + """The list of parameters for models of resolutions.""" + + resolutions: ClassList[ratapi.models.Resolution] = ClassList( + ratapi.models.Resolution(name="Resolution 1", type=TypeOptions.Constant, source="Resolution Param 1"), + ) + """The list of models for instrument resolution in the project.""" + + custom_files: ClassList[ratapi.models.CustomFile] = ClassList() + """Handles for custom files used by the project.""" + + data: ClassList[ratapi.models.Data] = ClassList() + """Experimental data for a model.""" + + layers: ( + Annotated[ClassList[ratapi.models.Layer], Tag("no_abs")] + | Annotated[ClassList[ratapi.models.AbsorptionLayer], Tag("abs")] + ) = Field( + default=ClassList(), + discriminator=Discriminator( + discriminate_layers, + custom_error_type="invalid_union_member", + custom_error_message="Input should be an instance of ClassList", + custom_error_context={"discriminator": "absorption_or_no"}, + ), + ) + """The layers of a standard layer model.""" + + domain_contrasts: ClassList[ratapi.models.DomainContrast] = ClassList() + """The groups of layers required by each domain in a domains model.""" + + contrasts: ( + Annotated[ClassList[ratapi.models.Contrast], Tag("no_ratio")] + | Annotated[ClassList[ratapi.models.ContrastWithRatio], Tag("ratio")] + ) = Field( + default=ClassList(), + discriminator=Discriminator( + discriminate_contrasts, + custom_error_type="invalid_union_member", + custom_error_message="Input should be an instance of ClassList.", + custom_error_context={"discriminator": "ratio_or_no_ratio"}, + ), + ) + """All groups of components used to define each model in the project.""" + + _all_names: dict + _contrast_model_field: str + _protected_parameters: dict + + @model_validator(mode="before") + @classmethod + def discriminate_ambiguous_dicts(cls, data: Any) -> Any: + """If layers or contrasts contain a dict, convert it to the relevant model.""" + # pydantic docs says data can be anything, but i can't see anywhere where it isn't a dict. + # if it's not a dict, just return and let the library handle it + if isinstance(data, dict): + layer_model = ratapi.models.AbsorptionLayer if data.get("absorption", False) else ratapi.models.Layer + if data.get("calculation", Calculations.Normal) == Calculations.Domains: + contrast_model = ratapi.models.ContrastWithRatio + else: + contrast_model = ratapi.models.Contrast + + # note we aren't modifying the layers and contrasts in-place: + # if a ClassList of dicts is passed, in-place conversion would make the ClassList heterogenous + # & it'd throw an error + if layers := data.get("layers", False): + new_layers = ClassList() + for layer in layers: + if isinstance(layer, dict): + layer = layer_model.model_validate(layer) + new_layers.append(layer) + data["layers"] = new_layers + + if contrasts := data.get("contrasts", False): + new_contrasts = ClassList() + for contrast in contrasts: + if isinstance(contrast, dict): + contrast = contrast_model.model_validate(contrast) + new_contrasts.append(contrast) + data["contrasts"] = new_contrasts + + return data + + @field_validator("layers") + @classmethod + def check_layers(cls, value: ClassList, info: ValidationInfo): + """Check that layers are AbsorptionLayers if doing absorption, and Layers otherwise.""" + if info.data["absorption"]: + model_name = "AbsorptionLayer" + other_model = "Layer" + else: + model_name = "Layer" + other_model = "AbsorptionLayer" + model = getattr(ratapi.models, model_name) + if not all(isinstance(element, model) for element in value): + raise ValueError( + f'"The layers attribute contains {other_model}s, ' + f"but the absorption parameter is {info.data['absorption']}. " + f'The attribute should be a ClassList of {model_name} instead."' + ) + + return value + + @field_validator("contrasts") + @classmethod + def check_contrasts(cls, value: ClassList, info: ValidationInfo): + """Check that contrasts are with ratio if calculating domains, and without otherwise.""" + if info.data["calculation"] == Calculations.Domains: + model_name = "ContrastWithRatio" + error_word = "without" + else: + model_name = "Contrast" + error_word = "with" + model = getattr(ratapi.models, model_name) + if not all(isinstance(element, model) for element in value): + raise ValueError( + f'"The contrasts attribute contains contrasts {error_word} ratio, ' + f'but the calculation is {str(info.data["calculation"])}", ' + f"The attribute should be a ClassList of {model_name} instead." + ) + + return value + + def model_post_init(self, __context: Any) -> None: + """Set up the Class to protect against disallowed modification. + + We initialise the class handle in the ClassLists for empty data fields, set protected parameters, get names of + all defined parameters, determine the contents of the "model" field in contrasts, and wrap ClassList routines + to control revalidation. + """ + # Ensure all ClassLists have the correct _class_handle defined + for field in (fields := Project.model_fields): + annotation = fields[field].annotation + if get_origin(annotation) == ClassList: + classlist = getattr(self, field) + if not hasattr(field, "_class_handle"): + classlist._class_handle = get_args(annotation)[0] + + layers_field = self.layers + if not hasattr(layers_field, "_class_handle"): + if self.absorption: + layers_field._class_handle = ratapi.models.AbsorptionLayer + else: + layers_field._class_handle = ratapi.models.Layer + + contrast_field = self.contrasts + if not hasattr(contrast_field, "_class_handle"): + if self.calculation == Calculations.Domains: + contrast_field._class_handle = ratapi.models.ContrastWithRatio + else: + contrast_field._class_handle = ratapi.models.Contrast + + if "Substrate Roughness" not in [name.title() for name in self.parameters.get_names()]: + self.parameters.insert( + 0, + ratapi.models.ProtectedParameter( + name="Substrate Roughness", + min=1.0, + value=3.0, + max=5.0, + fit=True, + prior_type=ratapi.models.Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ) + elif "Substrate Roughness" not in [name.title() for name in self.get_all_protected_parameters()["parameters"]]: + # If substrate roughness is included as a standard parameter replace it with a protected parameter + substrate_roughness_values = self.parameters["Substrate Roughness"].model_dump() + self.parameters.remove("Substrate Roughness") + self.parameters.insert(0, ratapi.models.ProtectedParameter(**substrate_roughness_values)) + + if "Simulation" not in [name.title() for name in self.data.get_names()]: + self.data.insert(0, ratapi.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() + self._protected_parameters = self.get_all_protected_parameters() + + # 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", + ] + + 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": + """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": + """Ensure ``domain_contrasts`` is empty if we are not running a standard layer domains calculation.""" + if not (self.calculation == Calculations.Domains and self.model == LayerModels.StandardLayers): + self.domain_contrasts.data = [] + return self + + @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_repeat_layers(self) -> "Project": + """If we are not using a standard layers model, warn that the repeat layers setting is not valid.""" + if self.model != LayerModels.StandardLayers: + for contrast in self.contrasts: + if "repeat_layers" in contrast.model_fields_set and contrast.repeat_layers != 1: + warnings.warn( + 'For a custom layers or custom XY calculation, the "repeat_layers" setting for each ' + "contrast is not valid - resetting to 1.", + stacklevel=2, + ) + contrast.repeat_layers = 1 + return self + + @model_validator(mode="after") + def set_resample(self) -> "Project": + """If we are using a custom XY model, warn that the resample setting for each contrast must always be True.""" + if self.model == LayerModels.CustomXY: + for contrast in self.contrasts: + if "resample" in contrast.model_fields_set and contrast.resample is False: + warnings.warn( + 'For a custom XY calculation, "resample" must be True for each contrast - resetting to True.', + stacklevel=2, + ) + contrast.resample = True + return self + + @model_validator(mode="after") + def set_calculation(self) -> "Project": + """Apply the calc setting to the project.""" + contrast_list = [] + handle = self.contrasts._class_handle.__name__ + if self.calculation == Calculations.Domains and handle == "Contrast": + for contrast in self.contrasts: + contrast_list.append(ratapi.models.ContrastWithRatio(**contrast.model_dump())) + self.contrasts.data = contrast_list + self.domain_ratios.data = [ + ratapi.models.Parameter( + name="Domain Ratio 1", + min=0.4, + value=0.5, + max=0.6, + fit=False, + prior_type=ratapi.models.Priors.Uniform, + mu=0.0, + sigma=np.inf, + ), + ] + self.contrasts._class_handle = ratapi.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"] + contrast_list.append(ratapi.models.Contrast(**contrast_params)) + self.contrasts.data = contrast_list + self.contrasts._class_handle = ratapi.models.Contrast + return self + + @model_validator(mode="after") + def set_contrast_model_field(self) -> "Project": + """Clear the contrast models if ``calculation`` or ``model_type`` has changed. + + The contents of the "model" field of "contrasts" depend on the values of the "calculation" and "model_type" + defined in the project. + """ + model_field = self.get_contrast_model_field() + if model_field != self._contrast_model_field: + for contrast in self.contrasts: + contrast.model = [] + self._contrast_model_field = model_field + return self + + @model_validator(mode="after") + def check_contrast_model_length(self) -> "Project": + """Ensure the contrast model isn't too long for a domains, custom layers, or custom XY calculation. + + If a custom model is used, the ``model`` field of the contrast should just be one item long. For + a standard layers domain calculation, it should be exactly two items long. + """ + 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.", + ) + 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.", + ) + return self + + @model_validator(mode="after") + def set_absorption(self) -> "Project": + """Apply the absorption setting to the project.""" + layer_list = [] + handle = self.layers._class_handle.__name__ + if self.absorption and handle == "Layer": + for layer in self.layers: + layer_params = layer.model_dump() + layer_params["SLD_imaginary"] = "" + layer_list.append(ratapi.models.AbsorptionLayer(**layer_params)) + self.layers.data = layer_list + self.layers._class_handle = ratapi.models.AbsorptionLayer + elif not self.absorption and handle == "AbsorptionLayer": + for layer in self.layers: + layer_params = layer.model_dump() + del layer_params["SLD_imaginary"] + layer_list.append(ratapi.models.Layer(**layer_params)) + self.layers.data = layer_list + self.layers._class_handle = ratapi.models.Layer + return self + + @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, fields_to_update in model_names_used_in.items(): + 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, strict=False) if old != new] + for old_name, new_name in name_diff: + for field in fields_to_update: + project_field = getattr(self, field.attribute) + all_matches = project_field.get_all_matches(old_name) + params = field.fields + for index, param in all_matches: + if param in params: + setattr(project_field[index], param, new_name) + return self + + @model_validator(mode="after") + def cross_check_model_values(self) -> "Project": + """Certain model fields should contain values defined elsewhere in the project.""" + values = ["value_1", "value_2", "value_3", "value_4", "value_5"] + for field in ["backgrounds", "resolutions"]: + self.check_allowed_source(field) + self.check_allowed_values( + field, + values, + getattr(self, f"{field[:-1]}_parameters").get_names(), + self._all_names[f"{field[:-1]}_parameters"], + ) + + self.check_allowed_values( + "layers", + ["thickness", "SLD", "SLD_real", "SLD_imaginary", "roughness"], + self.parameters.get_names(), + self._all_names["parameters"], + ) + + self.check_allowed_values("contrasts", ["data"], self.data.get_names(), self._all_names["data"]) + self.check_allowed_values( + "contrasts", ["background"], self.backgrounds.get_names(), self._all_names["backgrounds"] + ) + self.check_allowed_values("contrasts", ["bulk_in"], self.bulk_in.get_names(), self._all_names["bulk_in"]) + self.check_allowed_values("contrasts", ["bulk_out"], self.bulk_out.get_names(), self._all_names["bulk_out"]) + self.check_allowed_values( + "contrasts", ["scalefactor"], self.scalefactors.get_names(), self._all_names["scalefactors"] + ) + self.check_allowed_values( + "contrasts", ["resolution"], self.resolutions.get_names(), self._all_names["resolutions"] + ) + self.check_allowed_values( + "contrasts", ["domain_ratio"], self.domain_ratios.get_names(), self._all_names["domain_ratios"] + ) + + self.check_contrast_model_allowed_values( + "contrasts", + getattr(self, self._contrast_model_field).get_names(), + self._all_names[self._contrast_model_field], + self._contrast_model_field, + ) + self.check_contrast_model_allowed_values( + "domain_contrasts", self.layers.get_names(), self._all_names["layers"], "layers" + ) + return self + + @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, ratapi.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 + ] + 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 + + @model_validator(mode="after") + def update_names(self) -> "Project": + """Following validation, update the list of all parameter names.""" + self._all_names = self.get_all_names() + return self + + def __str__(self): + output = "" + for key, value in self.__dict__.items(): + if value: + output += f"{key.replace('_', ' ').title() + ': ':-<100}\n\n" + try: + output += value.value + "\n\n" # For enums + except AttributeError: + output += str(value) + "\n\n" + return output + + def get_all_names(self): + """Record the names of all models defined in the project.""" + return {class_list: getattr(self, class_list).get_names() for class_list in class_lists} + + 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, ratapi.models.ProtectedParameter) + ] + for class_list in parameter_class_lists + } + + def check_allowed_values( + self, attribute: str, field_list: list[str], allowed_values: list[str], previous_values: list[str] + ) -> None: + """Check the values of the given fields in the given model are in the supplied list of allowed values. + + Parameters + ---------- + attribute : str + The attribute of Project being validated. + field_list : list [str] + The fields of the attribute to be checked for valid values. + allowed_values : list [str] + The list of allowed values for the fields given in field_list. + previous_values : list [str] + The list of allowed values for the fields given in field_list after the previous validation. + + Raises + ------ + ValueError + Raised if any field in field_list has a value not specified in allowed_values. + + """ + class_list = getattr(self, attribute) + for index, model in enumerate(class_list): + for field in field_list: + value = getattr(model, field, "") + if value and value not in allowed_values: + if value in previous_values: + raise ValueError( + f'The value "{value}" used in the "{field}" field of {attribute}[{index}] must be defined ' + f'in "{values_defined_in[f"{attribute}.{field}"]}". Please remove "{value}" from ' + f'"{attribute}[{index}].{field}" before attempting to delete it.', + ) + else: + raise ValueError( + f'The value "{value}" used in the "{field}" field of {attribute}[{index}] must be defined ' + f'in "{values_defined_in[f"{attribute}.{field}"]}". Please add "{value}" to ' + f'"{values_defined_in[f"{attribute}.{field}"]}" before including it in "{attribute}".', + ) + + def check_allowed_source(self, attribute: str) -> None: + """Check that the source of a background or resolution is defined in the relevant field for its type. + + - A constant background or resolution source should be defined in + `background_parameters` or `resolution_parameters` respectively; + - A data background source should be defined in `data` + - A function background source should be defined in `custom_files` + + Parameters + ---------- + attribute : str + The attribute of Project being validated. + + Raises + ------ + ValueError + Raised if any field in field_list has a value not specified in allowed_constants or allowed_data as + appropriate. + + """ + class_list = getattr(self, attribute) + for index, model in enumerate(class_list): + if model.type == TypeOptions.Constant: + allowed_values = getattr(self, f"{attribute[:-1]}_parameters").get_names() + previous_values = self._all_names[f"{attribute[:-1]}_parameters"] + elif model.type == TypeOptions.Data: + allowed_values = self.data.get_names() + previous_values = self._all_names["data"] + else: + allowed_values = self.custom_files.get_names() + previous_values = self._all_names["custom_files"] + + if (value := model.source) != "" and value not in allowed_values: + if value in previous_values: + raise ValueError( + f'The value "{value}" used in the "source" field of {attribute}[{index}] must be defined in ' + f'"{values_defined_in[f"{attribute}.{model.type}.source"]}". Please remove "{value}" from ' + f'"{attribute}[{index}].source" before attempting to delete it.', + ) + else: + raise ValueError( + f'The value "{value}" used in the "source" field of {attribute}[{index}] must be defined in ' + f'"{values_defined_in[f"{attribute}.{model.type}.source"]}". Please add "{value}" to ' + f'"{values_defined_in[f"{attribute}.{model.type}.source"]}" before including it in ' + f'"{attribute}".', + ) + + def check_contrast_model_allowed_values( + self, + contrast_attribute: str, + allowed_values: list[str], + previous_values: list[str], + allowed_field: str, + ) -> None: + """Ensure the contents of the ``model`` for a contrast or domain contrast exist in the required project fields. + + Parameters + ---------- + contrast_attribute : str + The specific contrast attribute of Project being validated (either "contrasts" or "domain_contrasts"). + allowed_values : list [str] + The list of allowed values for the model of the contrast_attribute. + previous_values : list [str] + The list of allowed values for the model of the contrast_attribute after the previous validation. + allowed_field : str + The name of the field in the project in which the allowed_values are defined. + + Raises + ------ + ValueError + Raised if any model in contrast_attribute has a value not specified in allowed_values. + + """ + class_list = getattr(self, contrast_attribute) + for index, contrast in enumerate(class_list): + if (model_values := contrast.model) and (missing_values := list(set(model_values) - set(allowed_values))): + if all(value in previous_values for value in model_values): + raise ValueError( + f"The value{'s' if len(missing_values) > 1 else ''}: " + f'"{", ".join(str(i) for i in missing_values)}" used in the "model" field of ' + f'{contrast_attribute}[{index}] must be defined in "{allowed_field}". Please remove all ' + f'unnecessary values from "model" before attempting to delete them.', + ) + else: + raise ValueError( + f"The value{'s' if len(missing_values) > 1 else ''}: " + f'"{", ".join(str(i) for i in missing_values)}" used in the "model" field of ' + f'{contrast_attribute}[{index}] must be defined in "{allowed_field}". Please add all ' + f'required values to "{allowed_field}" before including them in "{contrast_attribute}".', + ) + + def get_contrast_model_field(self): + """Get the field used to define the contents of the "model" field in contrasts. + + Returns + ------- + 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" + else: + model_field = "layers" + else: + model_field = "custom_files" + return model_field + + def set_prior_visibility(self, priors_visible: bool): + """Set whether priors are visible or invisible for all parameters. + + Parameters + ---------- + priors_visible : bool + Whether priors should be shown. + + """ + for classlist_name in parameter_class_lists: + classlist = getattr(self, classlist_name) + for i in range(0, len(classlist)): + classlist[i].show_priors = priors_visible + + def show_priors(self): + """Show priors for all parameters in the model.""" + # convenience function from set_prior_visibility + self.set_prior_visibility(True) + + def hide_priors(self): + """Hide priors for all parameters in the model.""" + # convenience function from set_prior_visibility + self.set_prior_visibility(False) + + 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 + ---------- + obj_name : str, optional + 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 + script_path = Path(script) + if script_path.suffix == "": + script_path = script_path.with_suffix(".py") + elif script_path.suffix != ".py": + raise ValueError('The script name provided to "write_script" must use the ".py" format') + + def write_item(item): + """Write a model item as a string of a dictionary.""" + if isinstance(item, ratapi.models.Data): + item_str = "{" + f"'name': '{item.name}'," + if not np.any(item.data): # if array is empty, e.g. in simulation data + item_str += "'data': empty([0, 3]), " + else: + item_str += f"'data': {repr(item.data)}, " + if len(item.data_range) != 0: + item_str += f"'data_range': {item.data_range}, " + if len(item.simulation_range) != 0: + item_str += f"'simulation_range': {item.simulation_range}" + item_str += "}" + return item_str + + if isinstance(item, ratapi.models.CustomFile): + # convert file paths to strings because pathlib gets too specific + item_str = ( + "{" + + f"'name': '{item.name}', " + + f"'filename': '{item.filename}', " + + f"'function_name': '{item.function_name}', " + + f"'language': '{str(item.language)}', " + # Raw string to ensure backslash is not interpreted as escape + + f"'path': r'{str(try_relative_to(item.path, script_path.parent))}'" + + "}" + ) + return item_str + # converting a dict to a string doesn't automatically convert StrEnums to str :( + return str({key: str(value) if isinstance(value, Enum) else value for key, value in dict(item).items()}) + + def classlist_script(name, classlist): + """Write a classlist as a script.""" + return f"{name}=[\n " + "\n ".join([write_item(item) + "," for item in classlist.data]) + "]," + + script_path.write_text( + f"""# THIS FILE IS GENERATED FROM RAT VIA THE "WRITE_SCRIPT" ROUTINE. IT IS NOT PART OF THE RAT CODE. + +import ratapi +from numpy import array, empty, inf + +{obj_name} = ratapi.Project( + name="{self.name}", + calculation="{self.calculation}", + model="{self.model}", + geometry="{self.geometry}", + absorption="{self.absorption}", +""" + + indent( + "\n".join([classlist_script(class_list, getattr(self, class_list)) for class_list in class_lists]), + " " * 4, + ) + + "\n)" + ) + + def save(self, filepath: str | Path = "./project.json"): + """Save a project to a JSON file. + + Parameters + ---------- + filepath : str or Path + The path to where the project file will be written. + """ + filepath = Path(filepath).with_suffix(".json") + + json_dict = {} + for field in self.model_fields: + attr = getattr(self, field) + + if field == "data": + + def make_data_dict(item): + return { + "name": item.name, + "data": item.data.tolist(), + "data_range": item.data_range, + "simulation_range": item.simulation_range, + } + + json_dict["data"] = [make_data_dict(data) for data in attr] + + elif field == "custom_files": + + def make_custom_file_dict(item): + file_dict = { + "name": item.name, + "filename": item.filename, + "language": item.language, + "path": try_relative_to(item.path, filepath.parent), + } + if item.name != item.function_name: + file_dict["function_name"] = item.function_name + + return file_dict + + json_dict["custom_files"] = [make_custom_file_dict(file) for file in attr] + + elif isinstance(attr, ClassList): + json_dict[field] = [item.model_dump() for item in attr] + else: + json_dict[field] = attr + + filepath.write_text(json.dumps(json_dict)) + + @classmethod + def load(cls, path: str | Path) -> "Project": + """Load a project from file. + + Parameters + ---------- + path : str or Path + The path to the project file. + + """ + path = Path(path) + input_data = path.read_text() + model_dict = json.loads(input_data) + for dataset in model_dict["data"]: + if dataset["name"] == "Simulation": + dataset["data"] = np.empty([0, 3]) + del dataset["data_range"] + else: + data = dataset["data"] + dataset["data"] = np.array(data) + + # file paths are saved as relative to the project directory + for file in model_dict["custom_files"]: + if not Path(file["path"]).is_absolute(): + file["path"] = Path(path.parent, file["path"]).resolve() + + return cls.model_validate(model_dict) + + def _classlist_wrapper(self, class_list: ClassList, func: Callable): + """Define the function used to wrap around ClassList routines to force revalidation. + + Parameters + ---------- + class_list : ClassList + The ClassList defined in the "Project" model that is being modified. + func : Callable + The routine being wrapped. + + Returns + ------- + 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(class_list.data) + return_value = None + try: + return_value = func(*args, **kwargs) + Project.model_validate(self) + except ValidationError as exc: + class_list.data = previous_state + custom_error_list = custom_pydantic_validation_error(exc.errors(include_url=False)) + raise ValidationError.from_exception_data(exc.title, custom_error_list, hide_input=True) from None + except (TypeError, ValueError): + class_list.data = previous_state + raise + finally: + del previous_state + return return_value + + return wrapped_func + + +def try_relative_to(path: Path, relative_to: Path) -> str: + """Attempt to create a relative path and warn the user if it isn't possible. + + Parameters + ---------- + path : Path + The path to try to find a relative path for. + relative_to: Path + The path to which we find a relative path for ``path``. + + Returns + ------- + str + The relative path if successful, else the absolute path. + + """ + path = Path(path) + relative_to = Path(relative_to) + if not path.is_absolute(): + return str(path) + elif path.is_relative_to(relative_to): + return str(path.relative_to(relative_to)) + else: + warnings.warn( + "Could not write custom file path as relative to the project directory, " + "which means that it may not work on other devices. If you would like to share your project, " + "make sure your custom files are in a subfolder of the project save location.", + stacklevel=2, + ) + return str(path.resolve()) diff --git a/ratapi/run.py b/ratapi/run.py new file mode 100644 index 00000000..d973d068 --- /dev/null +++ b/ratapi/run.py @@ -0,0 +1,140 @@ +"""The function used to run a RAT algorithm for a given project and controls.""" + +import time + +from tqdm.auto import tqdm + +import ratapi.rat_core +from ratapi.inputs import make_input +from ratapi.outputs import make_results +from ratapi.utils.enums import Display + + +class ProgressBar: + """Create a progress bar that gets updates from the progress event during a calculation. + + Parameters + ---------- + display : bool, default True + Indicates if displaying is allowed + + """ + + def __init__(self, display=True): + self.pbar = None + self.display = display + self.tqdm_kwargs = {"total": 100, "desc": "", "bar_format": "{l_bar}{bar}", "disable": not self.display} + # Determine if the auto tqdm is standard or notebook + from tqdm.asyncio import tqdm as asyncio_tqdm + + if tqdm == asyncio_tqdm: + self.tqdm_kwargs.update({"ncols": 90}) + + def __enter__(self): + if self.display: + ratapi.events.register(ratapi.events.EventTypes.Progress, self.updateProgress) + + return self + + def updateProgress(self, event): + """Update the progress bar with progress event data. + + Parameters + ---------- + event: ProgressEventData + The progress event data. + + """ + if self.pbar is None: + self.pbar = tqdm(**self.tqdm_kwargs) + value = event.percent * 100 + self.pbar.desc = event.message + self.pbar.update(value - self.pbar.n) + + def __exit__(self, _exc_type, _exc_val, _traceback): + if self.pbar is not None: + self.pbar.close() + print("") # Print new line after bar + + if self.display: + ratapi.events.clear(ratapi.events.EventTypes.Progress, self.updateProgress) + + +class TextOutput: + """Context manager to pipe message events to stdout. + + Parameters + ---------- + display : bool, default: True + Indicates if displaying is allowed + + """ + + def __init__(self, display=True): + self.display = display + + def __enter__(self): + if self.display: + ratapi.events.register(ratapi.events.EventTypes.Message, self.printMessage) + + return self + + def printMessage(self, msg): + """Print an event message. + + Parameters + ---------- + msg: str + The event message. + + """ + print(msg, end="") + + def __exit__(self, _exc_type, _exc_val, _traceback): + if self.display: + ratapi.events.clear(ratapi.events.EventTypes.Message, self.printMessage) + + +def run(project, controls): + """Run RAT for the given project and controls inputs.""" + parameter_field = { + "parameters": "params", + "bulk_in": "bulkIns", + "bulk_out": "bulkOuts", + "scalefactors": "scalefactors", + "domain_ratios": "domainRatios", + "background_parameters": "backgroundParams", + "resolution_parameters": "resolutionParams", + } + + horizontal_line = "\u2500" * 107 + "\n" + display_on = controls.display != Display.Off + problem_definition, cpp_controls = make_input(project, controls) + + if display_on: + print("Starting RAT " + horizontal_line) + + start = time.time() + with ProgressBar(display=display_on), TextOutput(display=display_on): + problem_definition, output_results, bayes_results = ratapi.rat_core.RATMain( + problem_definition, + cpp_controls, + ) + end = time.time() + + if display_on: + print(f"Elapsed time is {end - start:.3f} seconds\n") + + results = make_results(controls.procedure, output_results, bayes_results) + + # Update parameter values in project + for class_list in ratapi.project.parameter_class_lists: + for index, value in enumerate(getattr(problem_definition, parameter_field[class_list])): + getattr(project, class_list)[index].value = value + + controls.delete_IPC() + + if display_on: + print("Finished RAT " + horizontal_line) + + return project, results diff --git a/ratapi/utils/__init__.py b/ratapi/utils/__init__.py new file mode 100644 index 00000000..56b312d4 --- /dev/null +++ b/ratapi/utils/__init__.py @@ -0,0 +1 @@ +"""Additional utilities for ratapi.""" diff --git a/RATapi/utils/convert.py b/ratapi/utils/convert.py similarity index 75% rename from RATapi/utils/convert.py rename to ratapi/utils/convert.py index 432dd7a1..7b3a44f7 100644 --- a/RATapi/utils/convert.py +++ b/ratapi/utils/convert.py @@ -1,23 +1,25 @@ """Utilities for converting input files to Python `Project`s.""" +import warnings +from collections.abc import Iterable +from os import PathLike from pathlib import Path -from typing import Iterable, Union -from numpy import array +from numpy import array, empty, ndarray from scipy.io.matlab import MatlabOpaque, loadmat -from RATapi import Project, wrappers -from RATapi.classlist import ClassList -from RATapi.models import Background, Contrast, CustomFile, Data, Layer, Parameter, Resolution -from RATapi.utils.enums import Geometries, Languages, LayerModels +from ratapi import Project, wrappers +from ratapi.classlist import ClassList +from ratapi.models import Background, Contrast, CustomFile, Data, Layer, Parameter, Resolution +from ratapi.utils.enums import Geometries, Languages, LayerModels -def r1_to_project_class(filename: str) -> Project: +def r1_to_project(filename: str | PathLike) -> Project: """Read a RasCAL1 project struct as a Python `Project`. Parameters ---------- - filename : str + filename : str, PathLike The path to a .mat file containing project data. Returns @@ -26,7 +28,7 @@ def r1_to_project_class(filename: str) -> Project: A RAT `Project` equivalent to the RasCAL1 project struct. """ - mat_project = loadmat(filename, simplify_cells=True)["problem"] + mat_project = loadmat(str(filename), simplify_cells=True)["problem"] mat_module = mat_project["module"] if mat_module["experiment_type"] == "Air / Liquid (or solid)": @@ -36,14 +38,15 @@ def r1_to_project_class(filename: str) -> Project: # R1 uses a different name for custom xy layer model layer_model = mat_module["type"] - if layer_model == "custom XY profile": + if layer_model.lower() == "custom xy profile": layer_model = LayerModels.CustomXY layer_model = LayerModels(layer_model) - def zip_if_several(*params) -> Union[tuple, list[tuple]]: + def zip_if_several(*params) -> tuple | list[tuple]: """Zips parameters if necessary, but can handle single-item parameters. - Examples: + Examples + -------- zip_if_several([1, 2], [3, 4]) = [(1, 3), (2, 4)] zip_if_several(1, 2, 3) = [(1, 2, 3)] @@ -60,11 +63,11 @@ def zip_if_several(*params) -> Union[tuple, list[tuple]]: """ if all(isinstance(param, Iterable) and not isinstance(param, str) for param in params): - return zip(*params) + return zip(*params, strict=False) return [params] def read_param(names, constrs, values, fits): - """Read in a parameter list from the relevant keys. + """Read in a parameter list from the relevant keys, and fix constraints for non-fit parameters. Parameters ---------- @@ -74,10 +77,56 @@ def read_param(names, constrs, values, fits): Returns ------- - list + ClassList A list of all relevant parameters. + """ + def fix_invalid_constraints(name: str, constrs: tuple[float, float], value: float) -> tuple[float, float]: + """Check that constraints are valid and fix them if they aren't. + + RasCAL-1 allowed the constraints of non-fit parameters to be invalid, which means + we need to fix them here so that the project is valid. + + Parameters + ---------- + name: str + The name of the parameter. + constrs : tuple[float, float] + The constraints of the parameter (min and max, respectively) + value : float + The value of the parameter. + + Returns + ------- + tuple[float, float] + The adjusted constraints (identical to constrs if constraints were valid) + + """ + new_constrs = (min(constrs[0], value), max(constrs[1], value)) + if new_constrs[0] != constrs[0] or new_constrs[1] != constrs[1]: + warnings.warn( + f"The parameter {name} has invalid constraints," + " these have been adjusted to satisfy the current value of the parameter.", + stacklevel=2, + ) + return new_constrs + + # adjust invalid constraints + # if just one item in the classlist, these objects won't be in lists + if not isinstance(fit := mat_project[fits], Iterable): + if not fit: + mat_project[constrs] = fix_invalid_constraints( + mat_project[names], mat_project[constrs], mat_project[values] + ) + # else they will be iterable + else: + for i, fit in enumerate(mat_project[fits]): + if not fit: + mat_project[constrs][i] = fix_invalid_constraints( + mat_project[names][i], mat_project[constrs][i], mat_project[values][i] + ) + return ClassList( [ Parameter( @@ -104,7 +153,9 @@ def read_param(names, constrs, values, fits): f"Background parameter {i}" for i in range(1, mat_project["numberOfBacks"] + 1) ] - if mat_project["numberOfResolutions"] == 1: + # sometimes numberOfResolutions isn't defined: in all these cases there's only one resolution + # maybe from before multiple resolutions were possible? + if getattr(mat_project, "numberOfResolutions", 1) == 1: mat_project["res_param_names"] = "Resolution parameter 1" else: mat_project["res_param_names"] = [ @@ -132,13 +183,13 @@ def read_param(names, constrs, values, fits): # create backgrounds and resolutions from parameters backs = ClassList( [ - Background(name=back_name, value_1=mat_project["back_param_names"][i]) + Background(name=back_name, type="constant", source=mat_project["back_param_names"][i]) for i, back_name in enumerate(mat_project["backsNames"]) ] ) res = ClassList( [ - Resolution(name=res_name, value_1=mat_project["res_param_names"][i]) + Resolution(name=res_name, type="constant", source=mat_project["res_param_names"][i]) for i, res_name in enumerate(mat_project["resolNames"]) ] ) @@ -176,6 +227,12 @@ def read_param(names, constrs, values, fits): if isinstance(mat_project["resolNames"], str): mat_project["resolNames"] = [mat_project["resolNames"]] + if isinstance(mat_project["contrastNames"], (ndarray, list)) and len( + dict.fromkeys(mat_project["contrastNames"]) + ) != len(mat_project["contrastNames"]): + # contrast names are not unique so create unique ones + mat_project["contrastNames"] = [f"Contrast {i + 1}" for i in range(len(mat_project["contrastNames"]))] + contrasts = ClassList( [ Contrast( @@ -207,10 +264,11 @@ def read_param(names, constrs, values, fits): [ Layer( name=name, - thickness=params[thickness - 1].name, - SLD=params[sld - 1].name, - roughness=params[roughness - 1].name, - hydration=params[hydration - 1].name, + thickness=params[int(thickness) - 1].name, + SLD=params[int(sld) - 1].name, + roughness=params[int(roughness) - 1].name, + # if hydration is not set, it is an empty numpy array, else it is a string representing a number + hydration=params[int(hydration) - 1].name if getattr(hydration, "size", 1) > 0 else "", hydrate_with=hydrate_with, ) # R1 layers are 6-item arrays, unpack into a Layer object @@ -223,7 +281,8 @@ def read_param(names, constrs, values, fits): if ( isinstance(mat_project["contrastsNumberOfLayers"], int) and mat_project["contrastsNumberOfLayers"] == 0 - or mat_project["contrastsNumberOfLayers"][i] == 0 + or isinstance(mat_project["contrastsNumberOfLayers"], list) + and mat_project["contrastsNumberOfLayers"][i] == 0 ): continue # contrastLayers is not an array, but rather a string with commas between entries @@ -238,7 +297,14 @@ def read_param(names, constrs, values, fits): if Path(custom_filepath).suffix != ".m": custom_filepath += ".m" model_name = Path(custom_filepath).stem - custom_file = ClassList([CustomFile(name=model_name, filename=custom_filepath, language=Languages.Matlab)]) + # Assume the custom file is in the same directory as the mat file + custom_file = ClassList( + [ + CustomFile( + name=model_name, filename=custom_filepath, language=Languages.Matlab, path=Path(filename).parent + ) + ] + ) layers = ClassList() for contrast in contrasts: contrast.model = [model_name] @@ -264,16 +330,16 @@ def read_param(names, constrs, values, fits): return project -def project_class_to_r1( - project: Project, filename: str = "RAT_project", return_struct: bool = False -) -> Union[dict, None]: +def project_to_r1( + project: Project, filename: str | PathLike = "RAT_project", return_struct: bool = False +) -> dict | None: """Convert a RAT Project to a RasCAL1 project struct. Parameters ---------- project : Project The RAT Project to convert. - filename : str, default "RAT_project" + filename : str or PathLike, default "RAT_project" If given, saves as a .mat file with the given filename. return_struct : bool, default False If True, do not save and instead return the R1 struct. @@ -282,16 +348,19 @@ def project_class_to_r1( ------- dict or None If `return_struct` is True, return the r1 struct. Else, return nothing. + """ - def convert_parameters(params: ClassList, name: str, value: str, constr: str, fit: str, number: str = ""): + def convert_parameters( + params: ClassList[Parameter], name: str, value: str, constr: str, fit: str, number: str = "" + ): """Convert a list of parameters to r1 data fields. Parameters ---------- params: ClassList A list of parameter type from the Project. - names, constrs, values, fits : str + name, constr, value, fit : str The keys for names, constraints, values and whether to fit for a type of parameter. number : str, optional, default "" @@ -301,6 +370,7 @@ def convert_parameters(params: ClassList, name: str, value: str, constr: str, fi ------- dict A dict of the relevant struct fields. + """ output = { name: [p.name for p in params], @@ -379,24 +449,24 @@ def convert_parameters(params: ClassList, name: str, value: str, constr: str, fi resolutions = { "resolNames": [r.name for r in project.resolutions], - "resolution": [project.resolution_parameters[r.value_1].value for r in project.resolutions], + "resolution": [project.resolution_parameters[r.source].value for r in project.resolutions], "resolution_constr": [ - [project.resolution_parameters[r.value_1].min, project.resolution_parameters[r.value_1].max] + [project.resolution_parameters[r.source].min, project.resolution_parameters[r.source].max] for r in project.resolutions ], - "resolution_fityesno": [int(project.resolution_parameters[r.value_1].fit) for r in project.resolutions], + "resolution_fityesno": [int(project.resolution_parameters[r.source].fit) for r in project.resolutions], "numberOfResolutions": len(project.resolutions), } r1.update(resolutions) backgrounds = { "backsNames": [b.name for b in project.backgrounds], - "backs": [project.background_parameters[b.value_1].value for b in project.backgrounds], + "backs": [project.background_parameters[b.source].value for b in project.backgrounds], "backs_constr": [ - [project.background_parameters[b.value_1].min, project.background_parameters[b.value_1].max] + [project.background_parameters[b.source].min, project.background_parameters[b.source].max] for b in project.backgrounds ], - "backgrounds_fityesno": [int(project.background_parameters[b.value_1].fit) for b in project.backgrounds], + "backgrounds_fityesno": [int(project.background_parameters[b.source].fit) for b in project.backgrounds], "numberOfBacks": len(project.backgrounds), } r1.update(backgrounds) @@ -409,7 +479,7 @@ def convert_parameters(params: ClassList, name: str, value: str, constr: str, fi project.parameters.index(layer.thickness, True), project.parameters.index(layer.SLD, True), project.parameters.index(layer.roughness, True), - project.parameters.index(layer.hydration, True), + project.parameters.index(layer.hydration, True) if layer.hydration else empty(shape=(0, 0)), layer.name, str(layer.hydrate_with), ] @@ -447,10 +517,10 @@ def convert_parameters(params: ClassList, name: str, value: str, constr: str, fi for contrast in project.contrasts: # R1 stores contrast resolutions and background by the index of the relevant parameter resolution = project.resolutions[contrast.resolution] - contrasts["contrastResolutions"].append(project.resolution_parameters.index(resolution.value_1, True)) + contrasts["contrastResolutions"].append(project.resolution_parameters.index(resolution.source, True)) background = project.backgrounds[contrast.background] - contrasts["contrastBacks"].append(project.background_parameters.index(background.value_1, True)) + contrasts["contrastBacks"].append(project.background_parameters.index(background.source, True)) data = project.data[contrast.data] if "simulation" in data.name: @@ -491,10 +561,10 @@ def convert_parameters(params: ClassList, name: str, value: str, constr: str, fi # scipy.io.savemat doesn't do cells properly: # https://github.com/scipy/scipy/issues/3756 # rather than fiddling we just use matlab - eng = wrappers.start_matlab().result() - if eng is None: + loader = wrappers.MatlabWrapper.loader + if loader is None: raise ImportError("matlabengine is not installed.") + eng = loader.result() eng.workspace["problem"] = r1 - eng.save(filename, "problem", nargout=0) - eng.exit() + eng.save(str(filename), "problem", nargout=0) return None diff --git a/RATapi/utils/custom_errors.py b/ratapi/utils/custom_errors.py similarity index 73% rename from RATapi/utils/custom_errors.py rename to ratapi/utils/custom_errors.py index 1778841a..83bf084f 100644 --- a/RATapi/utils/custom_errors.py +++ b/ratapi/utils/custom_errors.py @@ -1,19 +1,17 @@ """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: Optional[dict[str, str]] = None, + custom_error_msgs: dict[str, str] | None = 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. + """Give Pydantic errors a better custom message with extraneous information removed. - For errors that do not have a custom error message defined, we redefine them using a PydanticCustomError to remove - the url from the error message. + We substitute the standard error for a PydanticCustomError for a given set of error types. + For errors that do not have a custom error message defined, + we redefine them using a PydanticCustomError to remove the url from the error message. Parameters ---------- diff --git a/ratapi/utils/enums.py b/ratapi/utils/enums.py new file mode 100644 index 00000000..313f04c7 --- /dev/null +++ b/ratapi/utils/enums.py @@ -0,0 +1,204 @@ +"""The Enum values used in the parameters of various ratapi classes and functions.""" + +try: + from enum import StrEnum +except ImportError: + from strenum import StrEnum + + +class RATEnum(StrEnum): + """A subclass of StrEnum with some adjustments for variable spellings.""" + + @classmethod + def _missing_(cls, value: str): + value = value.lower() + + # Replace common alternative spellings + value = value.replace("-", " ").replace("_", " ").replace("++", "pp").replace("polarized", "polarised") + + for member in cls: + if member.value.lower() == value: + return member + return None + + +# Controls +class Procedures(RATEnum): + """The available options for procedures.""" + + Calculate = "calculate" + """Run an Abelès reflectivity calculation and calculate chi-squared to the data.""" + + Simplex = "simplex" + """Run a Nelder-Mead simplex optimisation over the fit parameters.""" + + DE = "de" + """Run a Differential Evolution optimisation over the fit parameters.""" + + NS = "ns" + """Run Bayesian Nested Sampling over the fit parameters.""" + + DREAM = "dream" + """Run the Bayesian DREAM algorithm over the fit parameters.""" + + +class Parallel(RATEnum): + """The available options for parallelisation.""" + + Single = "single" + """Do not parallelise.""" + + Points = "points" + """Split all contrasts into groups of points, and assign a process to each group.""" + + Contrasts = "contrasts" + """Assign one process to each contrast.""" + + +class Display(RATEnum): + """The available options for terminal output.""" + + Off = "off" + Iter = "iter" + Notify = "notify" + Final = "final" + + +class Strategies(RATEnum): + """The available strategies for generating base vectors in differential evolution.""" + + Random = "random" + """The base vector is random.""" + + LocalToBest = "local to best" + """The base vector is a combination of one randomly-selected local solution + and the best solution of the previous iteration.""" + + BestWithJitter = "best jitter" + """The base vector is the best solution of the previous iteration, with a small random perturbation applied.""" + + RandomWithPerVectorDither = "vector dither" + """The base vector is random, with a random scaling factor applied to each mutant. + This scaling factor is different for each mutant.""" + + RandomWithPerGenerationDither = "generation dither" + """The base vector is random, with a random scaling factor applied to each mutant. + This scaling factor is the same for every mutant, and randomised every generation.""" + + RandomEitherOrAlgorithm = "either or" + """The base vector is randomly chosen from either a pure random mutation, + or a pure recombination of parent parameter values.""" + + @classmethod + def _missing_(cls, value: int | str): + # legacy compatibility with strategies being 1-indexed ints under the hood + if isinstance(value, int): + if value < 1 or value > 6: + raise IndexError("Strategy indices must be between 1 and 6.") + return list(cls)[value - 1] + return super()._missing_(value) + + def __int__(self): + """Convert the DE strategy to its hardcoded index in the internal code. + + RAT core expects strategy to be an integer, as this is how it is given to + the internal DE algorithm. + """ + return list(Strategies).index(self) + 1 + + +class BoundHandling(RATEnum): + """The available options for bound handling in DREAM.""" + + Off = "off" + """Allow points to be sampled out of the parameter bounds.""" + + Reflect = "reflect" + """If a step passes a boundary, reflect it back across the boundary.""" + + Bound = "bound" + """If a step passes a boundary, set it equal to the nearest point on the boundary.""" + + Fold = "fold" + """Treat the boundary as periodic and ‘wrap the step around’ to the other side of the space.""" + + +# Models +class TypeOptions(RATEnum): + """The types of signal (``Background`` and ``Resolution``).""" + + Constant = "constant" + """A uniform constant signal given by a parameter.""" + + Data = "data" + """A signal for each q-value given by a dataset.""" + + Function = "function" + """A signal defined by a custom function.""" + + +class BackgroundActions(RATEnum): + """Ways that the background can be applied to the model.""" + + Add = "add" + Subtract = "subtract" + + +class Languages(RATEnum): + """Language options for custom files.""" + + Cpp = "cpp" + Python = "python" + Matlab = "matlab" + + +class Hydration(RATEnum): + """Options for the 'hydrate with' parameter of a Layer.""" + + BulkIn = "bulk in" + BulkOut = "bulk out" + + +class Priors(RATEnum): + """Prior distributions for parameters.""" + + Uniform = "uniform" + """A uniform distribution over the parameter range.""" + + Gaussian = "gaussian" + """A Gaussian distribution centred on the parameter value, + with shape defined by ``mu`` and ``sigma`` for the parameter.""" + + Jeffreys = "jeffreys" + """A Jeffreys' prior distribution over the parameter range.""" + + +# Project +class Calculations(RATEnum): + """Types of calculations that can be performed by RAT.""" + + Normal = "normal" + Domains = "domains" + + +class LayerModels(RATEnum): + """Types of layer model supported by RAT.""" + + CustomLayers = "custom layers" + """The layer model is given by a custom function.""" + + CustomXY = "custom xy" + """The continuous SLD of the layer model is given by a custom function.""" + + StandardLayers = "standard layers" + """The layer model is given by a list of ``Layer``s or ``DomainContrast``s.""" + + +class Geometries(RATEnum): + """Where the substrate roughness is placed.""" + + AirSubstrate = "air/substrate" + """The substrate roughness is placed at the end of the stack.""" + + SubstrateLiquid = "substrate/liquid" + """The substrate roughness is placed at the beginning of the stack.""" diff --git a/ratapi/utils/orso.py b/ratapi/utils/orso.py new file mode 100644 index 00000000..2d0345fc --- /dev/null +++ b/ratapi/utils/orso.py @@ -0,0 +1,247 @@ +"""Readers from file formats.""" + +from dataclasses import dataclass +from itertools import count +from pathlib import Path +from textwrap import shorten + +import orsopy +import prettytable +from orsopy.fileio import load_orso + +from ratapi import ClassList +from ratapi.models import AbsorptionLayer, Data, Layer, Parameter + + +class ORSOProject: + """A class to encapsulate model information and data from an .ort file. + + Parameters + ---------- + filepath : str or Path + The path to the .ort file. + absorption : bool, default None + Whether to account for absorption in the model data. + + """ + + def __init__(self, filepath: str | Path, absorption: bool = False): + ort_data = load_orso(filepath) + datasets = [Data(name=dataset.info.data_source.sample.name, data=dataset.data) for dataset in ort_data] + # orso datasets in the same file can have repeated names! + # but classlists do not allow this + # use this dict to keep track of counts for repeated names + name_counts = {d.name: count(1) for d in datasets} + names = [d.name for d in datasets] + if len(names) > len(list(set(names))): + for i, data in enumerate(datasets): + if data.name in names[:i]: + data.name += f"-{next(name_counts[data.name])}" + self.data = ClassList(datasets) + self.samples = [ + orso_model_to_rat(dataset.info.data_source.sample.model, absorption=absorption) for dataset in ort_data + ] + + def __str__(self): + data_str = f"Data:\n{str(self.data)}\n\n" + if len(self.samples) == 1: + samples_str = f"Sample:\n{str(self.samples[0])}" + else: + table = prettytable.PrettyTable() + table.field_names = ["index", "bulk in", "bulk out", "parameters", "layers", "model"] + for index, sample in enumerate(self.samples): + if sample is None: + row = [index, "", "", "", "", ""] + else: + row = [ + index, + sample.bulk_in.name, + sample.bulk_out.name, + shorten(", ".join([p.name for p in sample.parameters]), width=20, placeholder="..."), + shorten(", ".join([layer.name for layer in sample.layers]), width=20, placeholder="..."), + shorten(str(sample.model), width=20, placeholder="..."), + ] + table.add_row(row) + samples_str = table.get_string() + + return data_str + samples_str + + +@dataclass +class ORSOSample: + """The stack data from an ORSO SampleModel, in RAT models.""" + + bulk_in: Parameter + bulk_out: Parameter + parameters: ClassList[Parameter] + layers: ClassList[Layer] | ClassList[AbsorptionLayer] + model: list[str] + + def __str__(self): + return ( + "Bulk in:\n" + f"{str(self.bulk_in)}\n\n" + "Bulk out:\n" + f"{str(self.bulk_out)}\n\n" + "Parameters:\n" + f"{str(self.parameters)}\n\n" + "Layers:\n" + f"{str(self.layers)}\n\n" + "Model:\n" + f"{self.model}" + ) + + +def orso_model_to_rat( + model: orsopy.fileio.model_language.SampleModel | str, absorption: bool = False +) -> ORSOSample | None: + """Get information from an ORSO SampleModel object. + + Parameters + ---------- + model : orsopy.fileio.model_language.SampleModel or str + The sample model to turn into a RAT data. If given as a string, + the string is interpreted as a layer stack in ORSO model language. + absorption : bool, default False + Whether to account for absorption in the model. + + Returns + ------- + ORSOSample + A dataclass containing the sample data, or None if the model is None. + + """ + if model is None: + return None + + if isinstance(model, str): + model = orsopy.fileio.model_language.SampleModel(stack=model) + + stack = model.resolve_to_layers() + # if bulk in or out is air, it has SLD predefined + # else we need to grab it from SLDDB + if bulk_in_sld := stack[0].material.sld is None: + bulk_in_sld = stack[0].material.get_sld() + + # resolve_to_layers loses the name of bulk in and out + bulk_in_name = model.stack.split("|")[0].strip() + bulk_in = Parameter( + name=f"{bulk_in_name} SLD", + min=bulk_in_sld.real, + value=bulk_in_sld.real, + max=bulk_in_sld.real, + fit=False, + ) + + if bulk_out_sld := stack[-1].material.sld is None: + bulk_out_sld = stack[-1].material.get_sld() + + bulk_out_name = model.stack.split("|")[-1].strip() + bulk_out = Parameter( + name=f"{bulk_out_name} SLD", + min=bulk_out_sld.real, + value=bulk_out_sld.real, + max=bulk_out_sld.real, + fit=False, + ) + + parameters = ClassList() + layers = ClassList() + contrast_model = [] + + for orso_layer in stack[1:-1]: + name = get_material_name(orso_layer.material, model) + contrast_model.append(name) + layer_params, layer = orso_layer_to_rat_layer(orso_layer, name, absorption) + parameters.union(layer_params) + layers.union(layer) + + return ORSOSample( + bulk_in=bulk_in, + bulk_out=bulk_out, + parameters=parameters, + layers=layers, + model=contrast_model, + ) + + +def orso_layer_to_rat_layer( + layer: orsopy.fileio.model_language.Layer, name: str, absorption: bool = False +) -> tuple[ClassList[Parameter], Layer]: + """Convert an ``orsopy`` layer to a RAT layer. + + Parameters + ---------- + layer : orsopy.fileio.model_language.Layer + An ``orsopy`` Layer. + name : str + The name of the material in the layer. + absorption : bool, default True + Whether absorption should be accounted for in the layer. + + Returns + ------- + ClassList[Parameter], Layer + The parameters required for the RAT layer and the layer itself. + + """ + thickness = layer.thickness.as_unit("angstrom") + roughness = layer.roughness.as_unit("angstrom") + sld = layer.material.get_sld() + + params = ClassList( + [ + Parameter(name=f"{name} Thickness", min=thickness, value=thickness, max=thickness, fit=False), + Parameter(name=f"{name} Roughness", min=roughness, value=roughness, max=roughness, fit=False), + Parameter(name=f"{name} SLD", min=sld.real, value=sld.real, max=sld.real, fit=False), + ] + ) + if absorption: + params.append(Parameter(name=f"{name} SLD imaginary", min=sld.imag, value=sld.imag, max=sld.imag, fit=False)) + layer = AbsorptionLayer( + name=name, + thickness=f"{name} Thickness", + roughness=f"{name} Roughness", + SLD_real=f"{name} SLD", + SLD_imaginary=f"{name} SLD imaginary", + ) + else: + layer = Layer( + name=name, + thickness=f"{name} Thickness", + roughness=f"{name} Roughness", + SLD=f"{name} SLD", + ) + + return params, layer + + +def get_material_name( + material: orsopy.fileio.model_language.Material, model: orsopy.fileio.model_language.SampleModel +) -> str: + """Get the name of a material in the model. + + Layers with custom property definitions may not have a formula, so this adjusts the name for that. + + Parameters + ---------- + material : Material + The material to get the name of. + model : SampleModel + The sample model from which the material came. + + Returns + ------- + str + The name of the material. + + """ + if material.formula is not None: + return material.formula + else: + matching_materials = [k for k, v in model.materials.items() if v == material] + if matching_materials: + return matching_materials[0] + else: + # orsopy should catch that this is the case before we get here, but just in case... + raise ValueError("ORSO model contains layers with undefined materials!") diff --git a/ratapi/utils/plotting.py b/ratapi/utils/plotting.py new file mode 100644 index 00000000..509c7a4f --- /dev/null +++ b/ratapi/utils/plotting.py @@ -0,0 +1,1262 @@ +"""Plot results using the matplotlib library.""" + +import copy +import types +from collections.abc import Callable +from functools import partial, wraps +from math import ceil, floor, sqrt +from statistics import stdev +from typing import Literal + +import matplotlib +import matplotlib.figure +import matplotlib.pyplot as plt +import matplotlib.transforms as mtransforms +import numpy as np +from matplotlib.axes._axes import Axes +from scipy.ndimage import gaussian_filter1d +from scipy.stats import gaussian_kde, lognorm, norm + +import ratapi +import ratapi.inputs +import ratapi.outputs +from ratapi.rat_core import PlotEventData, makeSLDProfile + + +def _extract_plot_data(event_data: PlotEventData, q4: bool, show_error_bar: bool, shift_value: float): + """Extract the plot data for the sld, ref, error plot lines. + + Parameters + ---------- + event_data : PlotEventData + The plot event data that contains all the information + to generate the ref and sld plots + q4 : bool, default: False + Controls whether Q^4 is plotted on the reflectivity plot + show_error_bar : bool, default: True + Controls whether the error bars are shown + shift_value : float + A value between 0 and 100 that controls the spacing between the reflectivity plots for each of the contrasts + + Returns + ------- + plot_values : dict + A dict containing the data for the sld, ref, error plot lines. + + """ + results = {"ref": [], "error": [], "sld": [], "sld_resample": []} + + if shift_value < 0 or shift_value > 100: + raise ValueError("Parameter `shift_value` must be between 0 and 100") + + for i, (r, data, sld) in enumerate( + zip(event_data.reflectivity, event_data.shiftedData, event_data.sldProfiles, strict=False) + ): + # Calculate the divisor + div = 10 ** (i / 100 * shift_value) + q4_data = 1 if not q4 or not event_data.dataPresent[i] else data[:, 0] ** 4 + mult = q4_data / div + + # Plot the reflectivity on plot (1,1) + results["ref"].append([r[:, 0], r[:, 1] * mult]) + + if event_data.dataPresent[i]: + sd_x = data[:, 0] + sd_y, sd_e = map(lambda x: x * mult, (data[:, 1], data[:, 2])) + errors = np.zeros(len(sd_e)) + + if show_error_bar: + valid = sd_y - sd_e >= 0 + errors[valid] = sd_e[valid] + valid |= sd_y < 0 + else: + valid = np.ones(len(sd_e)).astype(bool) + sd_e = errors + + results["error"].append([sd_x[valid], sd_y[valid], sd_e[valid]]) + + results["sld"].append([]) + for j in range(len(sld)): + results["sld"][-1].append([sld[j][:, 0], sld[j][:, 1]]) + + results["sld_resample"].append([]) + if event_data.resample[i] == 1 or event_data.modelType == "custom xy": + layers = event_data.resampledLayers[i][0] + for j in range(len(event_data.resampledLayers[i])): + layer = event_data.resampledLayers[i][j] + if layers.shape[1] == 4: + layer = np.delete(layer, 2, 1) + new_profile = makeSLDProfile( + layers[0, 1], # Bulk In + layers[-1, 1], # Bulk Out + layer, + event_data.subRoughs[i], # roughness + 1, + ) + + results["sld_resample"][-1].append([new_profile[:, 0] - 49, new_profile[:, 1]]) + + return results + + +def plot_ref_sld_helper( + data: PlotEventData, + fig: matplotlib.figure.Figure, + delay: bool = True, + confidence_intervals: dict | None = None, + linear_x: bool = False, + q4: bool = False, + show_error_bar: bool = True, + show_grid: bool = False, + show_legend: bool = True, + shift_value: float = 100, + animated=False, +): + """Clear 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 : matplotlib.figure.Figure + The figure object that has two subplots + delay : bool, default: True + Controls whether to delay 0.005s after plot is created + confidence_intervals : dict or None, default None + The Bayesian confidence intervals for reflectivity and SLD. + Only relevant if the procedure used is Bayesian (NS or DREAM) + linear_x : bool, default: False + Controls whether the x-axis on reflectivity plot uses the linear scale + q4 : bool, default: False + Controls whether Q^4 is plotted on the reflectivity plot + show_error_bar : bool, default: True + Controls whether the error bars are shown + show_grid : bool, default: False + Controls whether the grid is shown + show_legend : bool, default: True + Controls whether the legend is shown + shift_value : float, default: 100 + A value between 0 and 100 that controls the spacing between the reflectivity plots for each of the contrasts + animated : bool, default: False + Controls whether the animated property of foreground plot elements should be set. + + """ + preserve_zoom = False + + if len(fig.axes) != 2: + fig.clf() + fig.subplots(1, 2) + + fig.subplots_adjust(wspace=0.3, hspace=0) + + ref_plot: plt.Axes = fig.axes[0] + sld_plot: plt.Axes = fig.axes[1] + if ref_plot.lines and fig.canvas.toolbar is not None: + preserve_zoom = True + fig.canvas.toolbar.push_current() + + # Clears the previous plots + ref_plot.cla() + sld_plot.cla() + + plot_data = _extract_plot_data(data, q4, show_error_bar, shift_value) + for i, name in enumerate(data.contrastNames): + ref_plot.plot(plot_data["ref"][i][0], plot_data["ref"][i][1], label=name, linewidth=1, animated=animated) + color = ref_plot.get_lines()[-1].get_color() + + # Plot confidence intervals if required + if confidence_intervals is not None: + # Calculate the divisor + div = 10 ** (i / 100 * shift_value) + ref_min, ref_max = confidence_intervals["reflectivity"][i] + mult = (1 if not q4 else plot_data["ref"][i][0] ** 4) / div + ref_plot.fill_between(plot_data["ref"][i][0], ref_min * mult, ref_max * mult, alpha=0.6, color="grey") + + if data.dataPresent[i]: + # Plot the errorbars + ref_plot.errorbar( + x=plot_data["error"][i][0], + y=plot_data["error"][i][1], + yerr=plot_data["error"][i][2], + elinewidth=1, + ecolor=color, + marker=".", + markersize=3, + linestyle="none", + color=color, + capsize=0, + animated=animated, + ) + + # Plot the slds on plot (1,2) + for j in range(len(plot_data["sld"][i])): + label = name if len(plot_data["sld"][i]) == 1 else f"{name} Domain {j + 1}" + sld_plot.plot( + plot_data["sld"][i][j][0], plot_data["sld"][i][j][1], label=label, linewidth=1, animated=animated + ) + + # Plot confidence intervals if required + if confidence_intervals is not None: + sld_min, sld_max = confidence_intervals["sld"][i][j] + sld_plot.fill_between(plot_data["sld"][i][j][0], sld_min, sld_max, alpha=0.6, color="grey") + + for j in range(len(plot_data["sld_resample"][i])): + sld_plot.plot( + plot_data["sld_resample"][i][j][0], + plot_data["sld_resample"][i][j][1], + color=color, + linewidth=1, + animated=animated, + ) + + # Format the axis + ref_plot.set_yscale("log") + if not linear_x: + ref_plot.set_xscale("log") + ref_plot.set_xlabel("$Q_{z} (\u00c5^{-1})$") + ref_plot.set_ylabel("Reflectivity") + + sld_plot.set_xlabel("$Z (\u00c5)$") + sld_plot.set_ylabel("$SLD (\u00c5^{-2})$", labelpad=1) + + if show_legend: + ref_plot.legend() + sld_plot.legend() + + if show_grid: + ref_plot.grid() + sld_plot.grid() + + if preserve_zoom: + fig.canvas.toolbar.back() + if delay: + plt.pause(0.005) + + +def plot_ref_sld( + project: ratapi.Project, + results: ratapi.outputs.Results | ratapi.outputs.BayesResults, + block: bool = False, + fig: matplotlib.figure.Figure | None = None, + return_fig: bool = False, + bayes: Literal[65, 95, None] = None, + linear_x: bool = False, + q4: bool = False, + show_error_bar: bool = True, + show_grid: bool = False, + show_legend: bool = True, + shift_value: float = 100, +) -> plt.Figure | None: + """Plot the reflectivity and SLD profiles. + + Parameters + ---------- + project : Project + An instance of the Project class + results : Union[Results, BayesResults] + The result from the calculation + block : bool, default: False + Indicates the plot should block until it is closed + fig : matplotlib.figure.Figure, optional + The figure object that has two subplots + return_fig : bool, default False + If True, return the figure instead of displaying it. + bayes : 65, 95 or None, default None + Whether to shade Bayesian confidence intervals. Can be `None` + (if no intervals), `65` to show 65% confidence intervals, + and `95` to show 95% confidence intervals. + linear_x : bool, default: False + Controls whether the x-axis on reflectivity plot uses the linear scale + q4 : bool, default: False + Controls whether Q^4 is plotted on the reflectivity plot + show_error_bar : bool, default: True + Controls whether the error bars are shown + show_grid : bool, default: False + Controls whether the grid is shown + show_legend : bool, default: True + Controls whether the legend is shown + shift_value : float, default: 100 + A value between 0 and 100 that controls the spacing between the reflectivity plots for each of the contrasts + + Returns + ------- + Figure or None + Returns Figure if `return_fig` is True, else returns nothing. + + """ + data = PlotEventData() + + # We need to take a copy of reflectivity and SLD in case we are plotting a + # shaded plot and will therefore change the plotted data to that from the + # centre of the Bayesian distribution + data.modelType = project.model + data.reflectivity = copy.deepcopy(results.reflectivity) + data.shiftedData = results.shiftedData + data.sldProfiles = copy.deepcopy(results.sldProfiles) + data.resampledLayers = results.resampledLayers + data.dataPresent = ratapi.inputs.make_data_present(project) + data.subRoughs = results.contrastParams.subRoughs + data.resample = ratapi.inputs.make_resample(project) + data.contrastNames = [contrast.name for contrast in project.contrasts] + + if bayes: + if isinstance(results, ratapi.outputs.BayesResults): + # the predictionIntervals data consists of 5 rows: + # row 0: min with 95% confidence + # row 1: min with 65% confidence + # row 2: mean + # row 3: max with 65% confidence + # row 4: max with 95% confidence + if bayes == 95: + interval = [0, 4] + elif bayes == 65: + interval = [1, 3] + else: + raise ValueError("Parameter `bayes` must be 95, 65 or None") + confidence_intervals = { + "reflectivity": [ + (ref_inter[interval[0]], ref_inter[interval[1]]) + for ref_inter in results.predictionIntervals.reflectivity + ], + "sld": [ + [(sld_inter[interval[0]], sld_inter[interval[1]]) for sld_inter in sld] + for sld in results.predictionIntervals.sld + ], + } + # For a shaded plot, use the mean values from predictionIntervals + for reflectivity, mean_reflectivity in zip( + data.reflectivity, results.predictionIntervals.reflectivity, strict=False + ): + reflectivity[:, 1] = mean_reflectivity[2] + for sldProfile, mean_sld_profile in zip(data.sldProfiles, results.predictionIntervals.sld, strict=False): + for sld, mean_sld in zip(sldProfile, mean_sld_profile, strict=False): + sld[:, 1] = mean_sld[2] + else: + raise ValueError( + "Shaded confidence intervals are only available for the results of Bayesian analysis (NS or DREAM)" + ) + else: + confidence_intervals = None + + if fig is None: + fig = plt.subplots(1, 2)[0] + elif len(fig.axes) != 2: + fig.clf() + fig.subplots(1, 2) + + plot_ref_sld_helper( + data, + fig, + confidence_intervals=confidence_intervals, + linear_x=linear_x, + q4=q4, + show_error_bar=show_error_bar, + show_grid=show_grid, + show_legend=show_legend, + shift_value=shift_value, + ) + + if return_fig: + return fig + + plt.show(block=block) + + +class BlittingSupport: + """Create a SLD plot that uses blitting to get faster draws. + + The blit plot stores the background from an + initial draw then updates the foreground (lines and error bars) if the background is not changed. + + Parameters + ---------- + data : PlotEventData + The plot event data that contains all the information + to generate the ref and sld plots + fig : matplotlib.figure.Figure, optional + The figure class that has two subplots + linear_x : bool, default: False + Controls whether the x-axis on reflectivity plot uses the linear scale + q4 : bool, default: False + Controls whether Q^4 is plotted on the reflectivity plot + show_error_bar : bool, default: True + Controls whether the error bars are shown + show_grid : bool, default: False + Controls whether the grid is shown + show_legend : bool, default: True + Controls whether the legend is shown + shift_value : float, default: 100 + A value between 0 and 100 that controls the spacing between the reflectivity plots for each of the contrasts + """ + + def __init__( + self, + data, + fig=None, + linear_x: bool = False, + q4: bool = False, + show_error_bar: bool = True, + show_grid: bool = False, + show_legend: bool = True, + shift_value: float = 100, + ): + self.figure = fig + self.linear_x = linear_x + self.q4 = q4 + self.show_error_bar = show_error_bar + self.show_grid = show_grid + self.show_legend = show_legend + self.shift_value = shift_value + self.update_plot(data) + self.event_id = self.figure.canvas.mpl_connect("resize_event", self.resizeEvent) + + def __del__(self): + self.figure.canvas.mpl_disconnect(self.event_id) + + def resizeEvent(self, _event): + """Ensure the background is updated after a resize event.""" + self.__background_changed = True + + def update(self, data): + """Update the foreground, if background has not changed otherwise it updates full plot. + + Parameters + ---------- + data : PlotEventData + The plot event data that contains all the information + to generate the ref and sld plots + """ + if self.__background_changed: + self.update_plot(data) + else: + self.update_foreground(data) + + def __setattr__(self, name, value): + old_value = getattr(self, name, None) + if value == old_value: + return + + super().__setattr__(name, value) + if name in ["figure", "linear_x", "q4", "show_error_bar", "show_grid", "show_legend", "shift_value"]: + self.__background_changed = True + + def set_animated(self, is_animated: bool): + """Set the animated property of foreground plot elements. + + Parameters + ---------- + is_animated : bool + Indicates if the animated property should be set. + """ + for line in self.figure.axes[0].lines: + line.set_animated(is_animated) + for line in self.figure.axes[1].lines: + line.set_animated(is_animated) + for container in self.figure.axes[0].containers: + container[2][0].set_animated(is_animated) + + def adjust_error_bar(self, error_bar_container, x, y, y_error): + """Adjust the error bar data. + + Parameters + ---------- + error_bar_container : Tuple + Tuple containing the artist of the errorbar i.e. (data line, cap lines, bar lines) + x : np.ndarray + The shifted data x axis data + y : np.ndarray + The shifted data y axis data + y_error : np.ndarray + The shifted data y axis error data + """ + line, _, (bars_y,) = error_bar_container + + line.set_data(x, y) + x_base = x + y_base = y + + y_error_top = y_base + y_error + y_error_bottom = y_base - y_error + + new_segments_y = [ + np.array([[x, yt], [x, yb]]) for x, yt, yb in zip(x_base, y_error_top, y_error_bottom, strict=False) + ] + bars_y.set_segments(new_segments_y) + + def update_plot(self, data): + """Update the full plot. + + Parameters + ---------- + data : PlotEventData + The plot event data that contains all the information + to generate the ref and sld plots + """ + if self.figure is not None: + self.figure.clf() + + self.figure.tight_layout() + plot_ref_sld_helper( + data, + self.figure, + linear_x=self.linear_x, + q4=self.q4, + show_error_bar=self.show_error_bar, + show_grid=self.show_grid, + show_legend=self.show_legend, + shift_value=self.shift_value, + animated=True, + ) + self.figure.canvas.draw() + self.bg = self.figure.canvas.copy_from_bbox(self.figure.bbox) + for line in self.figure.axes[0].lines: + self.figure.axes[0].draw_artist(line) + for line in self.figure.axes[1].lines: + self.figure.axes[1].draw_artist(line) + for container in self.figure.axes[0].containers: + self.figure.axes[0].draw_artist(container[2][0]) + self.figure.canvas.blit(self.figure.bbox) + self.set_animated(False) + self.__background_changed = False + + def update_foreground(self, data): + """Update the plot foreground only. + + Parameters + ---------- + data : PlotEventData + The plot event data that contains all the information + to generate the ref and sld plots + """ + self.set_animated(True) + self.figure.canvas.restore_region(self.bg) + plot_data = _extract_plot_data(data, self.q4, self.show_error_bar, self.shift_value) + + offset = 2 + for i in range( + 0, + len(self.figure.axes[0].lines), + ): + self.figure.axes[0].lines[i].set_data(plot_data["ref"][i // offset][0], plot_data["ref"][i // offset][1]) + self.figure.axes[0].draw_artist(self.figure.axes[0].lines[i]) + + i = 0 + for j in range(len(plot_data["sld"])): + for sld in plot_data["sld"][j]: + self.figure.axes[1].lines[i].set_data(sld[0], sld[1]) + self.figure.axes[1].draw_artist(self.figure.axes[1].lines[i]) + i += 1 + + for resampled in plot_data["sld_resample"][j]: + self.figure.axes[1].lines[i].set_data(resampled[0], resampled[1]) + self.figure.axes[1].draw_artist(self.figure.axes[1].lines[i]) + i += 1 + + for i, container in enumerate(self.figure.axes[0].containers): + self.adjust_error_bar( + container, plot_data["error"][i][0], plot_data["error"][i][1], plot_data["error"][i][2] + ) + self.figure.axes[0].draw_artist(container[2][0]) + self.figure.axes[0].draw_artist(container[0]) + + self.figure.canvas.blit(self.figure.bbox) + self.figure.canvas.flush_events() + self.set_animated(False) + + +class LivePlot: + """Create a plot that gets updates from the plot event during a calculation. + + Parameters + ---------- + block : bool, default: False + Indicates the plot should block until it is closed + + """ + + def __init__(self, block=False): + self.block = block + self.closed = False + self.blit_plot = None + + def __enter__(self): + self.figure = plt.subplots(1, 2)[0] + self.figure.canvas.mpl_connect("close_event", self._setCloseState) + self.figure.show() + ratapi.events.register(ratapi.events.EventTypes.Plot, self.plotEvent) + + return self.figure + + def _setCloseState(self, _): + """Close event handler.""" + self.closed = True + + def plotEvent(self, event): + """Plot the figure from plot event data. + + This is a callback for the plot event. + + Parameters + ---------- + event: PlotEventData + The plot event data. + + """ + if not self.closed and self.figure.number in plt.get_fignums(): + if self.blit_plot is None: + self.blit_plot = BlittingSupport(event, self.figure) + else: + self.blit_plot.update(event) + + def __exit__(self, _exc_type, _exc_val, _traceback): + ratapi.events.clear(ratapi.events.EventTypes.Plot, self.plotEvent) + if not self.closed and self.figure.number in plt.get_fignums(): + plt.show(block=self.block) + + +def assert_bayesian(name: str): + """Ensure the results passed to a function are Bayesian. + + This is a decorator. + + Parameters + ---------- + name : str + The name of the plot for the error message. + + """ + + def decorator(func: Callable): + @wraps(func) + def inner(results, *args, **kwargs): + if isinstance(results, ratapi.outputs.BayesResults): + return func(results, *args, **kwargs) + raise ValueError(f"{name} plots are only available for the results of Bayesian analysis (NS or DREAM)") + + return inner + + return decorator + + +def name_to_index(param: str | int, names: list[str]): + """Convert parameter names to indices.""" + if isinstance(param, str): + if param not in names: + raise ValueError(f"Parameter {param} is not in this analysis.") + param = names.index(param) + elif isinstance(param, int): + if param > len(names) or param < 0: + raise IndexError(f"Index {param} has been given, but indices must be between zero and {len(names)}.") + else: + raise ValueError(f"Parameters must be given as indices or names, not {type(param)}.") + return param + + +@assert_bayesian("Corner") +def plot_corner( + results: ratapi.outputs.BayesResults, + params: list[int | str] | None = None, + smooth: bool = True, + block: bool = False, + fig: matplotlib.figure.Figure | None = None, + return_fig: bool = False, + hist_kwargs: dict | None = None, + hist2d_kwargs: dict | None = None, + progress_callback: Callable[[int, int], None] | None = None, +): + """Create a corner plot from a Bayesian analysis. + + Parameters + ---------- + results : BayesResults + The results from a Bayesian calculation. + params : list[int or str], default None + The indices or names of a subset of parameters if required. + If None, uses all indices. + smooth : bool, default True + Whether to apply Gaussian smoothing to the corner plot. + block : bool, default False + Whether Python should block until the plot is closed. + fig : matplotlib.figure.Figure, optional + The figure object to use for plot. + return_fig: bool, default False + If True, return the figure as an object instead of showing it. + hist_kwargs : dict + Extra keyword arguments to pass to the 1d histograms. + Default is {'density': True, 'bins': 25} + hist2d_kwargs : dict + Extra keyword arguments to pass to the 2d histograms. + Default is {'density': True, 'bins': 25} + progress_callback: Union[Callable[[int, int], None], None] + Callback function for providing progress during plot creation + First argument is current completed sub plot and second is total number of sub plots + + Returns + ------- + Figure or None + If `return_fig` is True, return the figure - otherwise, return nothing. + + """ + fitname_to_index = partial(name_to_index, names=results.fitNames) + + if params is None: + params = range(0, len(results.fitNames)) + else: + params = list(map(fitname_to_index, params)) + + # defaults are applied inside each function - just pass blank dicts for now + if hist_kwargs is None: + hist_kwargs = {} + if hist2d_kwargs is None: + hist2d_kwargs = {} + + num_params = len(params) + total_count = num_params + (num_params**2 - num_params) // 2 + + if fig is None: + fig, axes = plt.subplots(num_params, num_params, figsize=(11, 10), subplot_kw={"visible": False}) + else: + fig.clf() + axes = fig.subplots(num_params, num_params, subplot_kw={"visible": False}) + + # i is row, j is column + current_count = 0 + for i in range(num_params): + for j in range(i + 1): + row_param = params[i] + col_param = params[j] + current_axes: Axes = axes if isinstance(axes, matplotlib.axes.Axes) else axes[i][j] + current_axes.tick_params(which="both", labelsize="medium") + current_axes.xaxis.offsetText.set_fontsize("small") + current_axes.yaxis.offsetText.set_fontsize("small") + current_axes.set_visible(True) + if i == j: # diagonal: histograms + plot_one_hist(results, param=row_param, smooth=smooth, axes=current_axes, **hist_kwargs) + elif i > j: # lower triangle: 2d histograms + plot_contour( + results, x_param=col_param, y_param=row_param, smooth=smooth, axes=current_axes, **hist2d_kwargs + ) + + # remove label if on inside of corner plot + if j != 0: + current_axes.get_yaxis().set_visible(False) + if i != len(params) - 1: + current_axes.get_xaxis().set_visible(False) + # make labels invisible as titles cover that + current_axes.yaxis._update_offset_text_position = types.MethodType( + _y_update_offset_text_position, current_axes.yaxis + ) + current_axes.yaxis.offset_text_position = "center" + current_axes.set_ylabel("") + current_axes.set_xlabel("") + if progress_callback is not None: + current_count += 1 + progress_callback(current_count, total_count) + if return_fig: + return fig + plt.show(block=block) + + +@assert_bayesian("Histogram") +def plot_one_hist( + results: ratapi.outputs.BayesResults, + param: int | str, + smooth: bool = True, + window_size: int = 8, + estimated_density: Literal["normal", "lognor", "kernel", None] = None, + axes: Axes | None = None, + block: bool = False, + return_fig: bool = False, + **hist_settings, +): + """Plot the marginalised posterior for a parameter of a Bayesian analysis. + + Parameters + ---------- + results : BayesResults + The results from a Bayesian calculation. + param : Union[int, str] + Either the index or name of a parameter. + block : bool, default False + Whether Python should block until the plot is closed. + smooth : bool, default True + Whether to apply Gaussian smoothing to the histogram. + Defaults to True. + window_size : int, default 8 + The width of the smoothing window centered around the element being averaged. + The window moves down the length of the data, computing an average over the elements within each window. + estimated_density : 'normal', 'lognor', 'kernel' or None, default None + If None (default), ignore. Else, add an estimated density + of the given form on top of the histogram by the following estimations: + 'normal': normal Gaussian. + 'lognor': Log-normal probability density. + 'kernel': kernel density estimation. + axes: Axes or None, default None + If provided, plot on the given Axes object. + block : bool, default False + Whether Python should block until the plot is closed. + return_fig: bool, default False + If True, return the figure as an object instead of showing it. + **hist_settings : + Settings passed to `np.histogram`. By default, the settings + passed are `bins = 25` and `density = True`. + + Returns + ------- + Figure or None + If `return_fig` is True, return the figure - otherwise, return nothing. + + """ + chain = results.chain + param = name_to_index(param, results.fitNames) + + if axes is None: + fig, axes = plt.subplots(1, 1) + else: + fig = None + + # apply default settings if not set by user + default_settings = {"bins": 25, "density": True} + hist_settings = {**default_settings, **hist_settings} + + parameter_chain = chain[:, param] + counts, bins = np.histogram(parameter_chain, **hist_settings) + mean_y = np.mean(parameter_chain) + sd_y = np.std(parameter_chain) + + if smooth: + counts = moving_average(counts, window_size=window_size) + axes.hist( + bins[:-1], + bins, + weights=counts, + edgecolor="black", + linewidth=1.2, + color="white", + ) + + axes.set_title(results.fitNames[param], loc="left", fontsize="medium") + + if estimated_density: + dx = bins[1] - bins[0] + if estimated_density == "normal": + t = np.linspace(mean_y - 3.5 * sd_y, mean_y + 3.5 * sd_y) + axes.plot(t, norm.pdf(t, loc=mean_y, scale=sd_y**2)) + elif estimated_density == "lognor": + t = np.linspace(bins[0] - 0.5 * dx, bins[-1] + 2 * dx) + axes.plot(t, lognorm.pdf(t, np.mean(np.log(parameter_chain)), np.std(np.log(parameter_chain)))) + elif estimated_density == "kernel": + t = np.linspace(bins[0] - 2 * dx, bins[-1] + 2 * dx, 200) + kde = gaussian_kde(parameter_chain) + axes.plot(t, kde.evaluate(t)) + else: + raise ValueError( + f"{estimated_density} is not a supported estimated density function." + " Supported functions are 'normal' 'lognor' or 'kernel'." + ) + + # adding the estimated density extends the figure range - reset it to histogram range + x_range = hist_settings.get("range", (parameter_chain.min(), parameter_chain.max())) + axes.set_xlim(x_range) + + if fig is not None: + if return_fig: + return fig + plt.show(block=block) + + +def _y_update_offset_text_position(axis, _bboxes, bboxes2): + """Update the position of the Y axis offset text using the provided bounding boxes. + + Adapted from https://github.com/matplotlib/matplotlib/issues/4476#issuecomment-105627334. + + Parameters + ---------- + axis : matplotlib.axis.YAxis + Y axis to update. + _bboxes : List + list of bounding boxes + bboxes2 : List + list of bounding boxes + """ + x, y = axis.offsetText.get_position() + + if axis.offset_text_position == "left": + # y in axes coords, x in display coords + axis.offsetText.set_transform( + mtransforms.blended_transform_factory(axis.axes.transAxes, mtransforms.IdentityTransform()) + ) + + top = axis.axes.bbox.ymax + y = top + axis.OFFSETTEXTPAD * axis.figure.dpi / 72.0 + + else: + # x & y in display coords + axis.offsetText.set_transform(mtransforms.IdentityTransform()) + + # Northwest of upper-right corner of right-hand extent of tick labels + if bboxes2: + bbox = mtransforms.Bbox.union(bboxes2) + else: + bbox = axis.axes.bbox + center = bbox.ymin + (bbox.ymax - bbox.ymin) / 2 + x = bbox.xmin - axis.OFFSETTEXTPAD * axis.figure.dpi / 72.0 + y = center + x_offset = 110 + axis.offsetText.set_position((x - x_offset, y)) + + +@assert_bayesian("Contour") +def plot_contour( + results: ratapi.outputs.BayesResults, + x_param: int | str, + y_param: int | str, + smooth: bool = True, + sigma: tuple[float] | None = None, + axes: Axes | None = None, + block: bool = False, + return_fig: bool = False, + **hist2d_settings, +): + """Plot a 2D histogram of two indexed chain parameters, with contours. + + Parameters + ---------- + results : ratapi.outputs.BayesResults + The results of a Bayesian analysis. + x_param : int + The index or name of the parameter on the x-axis. + y_param : int + The index or name ofthe parameter on the y-axis. + smooth : bool, default True + If True, apply Gaussian smoothing to the histogram. + sigma : tuple[float] or None, default None + If given, is used as parameters for Gaussian smoothing in x and y direction respectively. + If None, defaults to the standard deviation of the parameter chain in either direction. + axes: Axes or None, default None + If provided, plot on the given Axes object. + block : bool, default False + Whether Python should block until the plot is closed. + return_fig: bool, default False + If True, return the figure as an object instead of showing it. + **hist2d_settings: + Settings passed to `np.histogram2d`. + Default settings are `bins = 25` and `density = True`. + + Returns + ------- + Figure or None + If `return_fig` is True, return the figure - otherwise, return nothing. + + """ + if axes is None: + fig, axes = plt.subplots(1, 1) + else: + fig = None + x_param = name_to_index(x_param, results.fitNames) + y_param = name_to_index(y_param, results.fitNames) + + default_settings = {"bins": 25, "density": True} + hist2d_settings = {**default_settings, **hist2d_settings} + + counts, x_bins, y_bins = np.histogram2d(results.chain[:, x_param], results.chain[:, y_param], **hist2d_settings) + if smooth: + if sigma is None: + sigma_x = stdev(results.chain[:, x_param]) / 2 + sigma_y = stdev(results.chain[:, y_param]) / 2 + else: + sigma_x, sigma_y = sigma + # perform a 1d smooth along both axes + counts = gaussian_filter1d(counts, axis=0, sigma=sigma_x) + counts = gaussian_filter1d(counts, axis=1, sigma=sigma_y) + + axes.pcolormesh(x_bins, y_bins, counts.max() - counts, cmap=matplotlib.colormaps["Greys"].reversed()) + axes.contour(x_bins[:-1], y_bins[:-1], counts.max() - counts, colors="black") + axes.set_xlabel(results.fitNames[x_param]) + axes.set_ylabel(results.fitNames[y_param]) + + if fig is not None: + if return_fig: + return fig + plt.show(block=block) + + +def panel_plot_helper( + plot_func: Callable, + indices: list[int], + fig: matplotlib.figure.Figure | None = None, + progress_callback: Callable[[int, int], None] | None = None, +) -> matplotlib.figure.Figure: + """Generate a panel-based plot from a single plot function. + + Parameters + ---------- + plot_func : Callable + A function which plots one parameter on an Axes object, given its index. + indices : list[int] + The list of indices to pass into ``plot_func``. + fig : matplotlib.figure.Figure, optional + The figure object to use for plot. + progress_callback: Union[Callable[[int, int], None], None] + Callback function for providing progress during plot creation + First argument is current completed sub plot and second is total number of sub plots + + Returns + ------- + matplotlib.figure.Figure + A figure containing a grid of plots over the indices in `indices`. + + """ + nplots = len(indices) + nrows, ncols = ceil(sqrt(nplots)), round(sqrt(nplots)) + + if fig is None: + fig = plt.subplots(nrows, ncols, figsize=(11, 10), subplot_kw={"visible": False})[0] + else: + fig.clf() + fig.subplots(nrows, ncols, subplot_kw={"visible": False}) + axs = fig.get_axes() + for index, plot_num in enumerate(indices): + axs[index].tick_params(which="both", labelsize="medium") + axs[index].xaxis.offsetText.set_fontsize("small") + axs[index].yaxis.offsetText.set_fontsize("small") + axs[index].set_visible(True) + plot_func(axs[index], plot_num) + if progress_callback is not None: + progress_callback(index, nplots) + + fig.tight_layout() + return fig + + +@assert_bayesian("Histogram") +def plot_hists( + results: ratapi.outputs.BayesResults, + params: list[int | str] | None = None, + smooth: bool = True, + sigma: float | None = None, + estimated_density: dict[Literal["normal", "lognor", "kernel", None]] + | Literal["normal", "lognor", "kernel", None] = None, + block: bool = False, + fig: matplotlib.figure.Figure | None = None, + return_fig: bool = False, + progress_callback: Callable[[int, int], None] | None = None, + **hist_settings, +): + """Plot marginalised posteriors for several parameters from a Bayesian analysis. + + Parameters + ---------- + results : BayesResults + The results from a Bayesian calculation. + params : list[int], default None + The indices or names of a subset of parameters if required. + If None, uses all indices. + smooth : bool, default True + Whether to apply a Gaussian smoothing to the histogram. + Defaults to True. + sigma: float or None, default None + If given, is used as the sigma-parameter for the Gaussian smoothing. + If None, the default (1/3rd of parameter chain standard deviation) is used. + estimated_density : dict, default None + If None (default), ignore. + Can also be a string 'normal', 'lognor' or 'kernel' to apply the same estimated density to all parameters. + Else, a dictionary where the keys are + indices or names of parameters, and values denote an estimated density + of the given form on top of the histogram: + None : do not plot estimated density for this parameter. + 'normal': normal Gaussian. + 'lognor': Log-normal probability density. + 'kernel': kernel density estimation. + To provide a default estimated density function to all parameters that haven't been specifically set, + pass the 'default' key, + e.g. to apply 'normal' to all unset parameters, set `estimated_density = {'default': 'normal'}`. + block : bool, default False + Whether Python should block until the plot is closed. + fig : matplotlib.figure.Figure, optional + The figure object to use for plot. + return_fig: bool, default False + If True, return the figure as an object instead of showing it. + progress_callback: Union[Callable[[int, int], None], None] + Callback function for providing progress during plot creation + First argument is current completed sub plot and second is total number of sub plots + hist_settings : + Settings passed to `np.histogram`. By default, the settings + passed are `bins = 25` and `density = True`. + + Returns + ------- + Figure or None + If `return_fig` is True, return the figure - otherwise, return nothing. + + """ + # first convert names to indices if given + fitname_to_index = partial(name_to_index, names=results.fitNames) + + if params is None: + params = range(0, len(results.fitNames)) + else: + params = list(map(fitname_to_index, params)) + + if estimated_density is not None: + + def validate_dens_type(dens_type: str | None, param: str): + """Check estimated density is a supported type.""" + if dens_type not in [None, "normal", "lognor", "kernel"]: + raise ValueError( + f"Parameter {param} has estimated density function {dens_type}," + " which is not supported. Supported estimated density functions" + " are 'normal', 'lognor', and 'kernel'." + ) + return dens_type + + if isinstance(estimated_density, str): + validate_dens_type(estimated_density, "default") + estimated_density = {fitname_to_index(param): estimated_density for param in params} + else: + default = estimated_density.pop("default", None) + validate_dens_type(default, "default") + default_density = {fitname_to_index(param): default for param in params} + # convert names to indices and ensure density types given are correct + estimated_density = { + name_to_index(k, results.fitNames): validate_dens_type(v, k) for k, v in estimated_density.items() + } + # merge other estimated densities into default dict + estimated_density = {**default_density, **estimated_density} + else: + estimated_density = {} + + fig = panel_plot_helper( + lambda ax, i: plot_one_hist( + results, + i, + smooth=smooth, + estimated_density=estimated_density.get(i), + axes=ax, + **hist_settings, + ), + params, + fig, + progress_callback, + ) + if return_fig: + return fig + plt.show(block=block) + + +@assert_bayesian("Chain") +def plot_chain( + results: ratapi.outputs.BayesResults, + params: list[int | str] | None = None, + maxpoints: int = 15000, + block: bool = False, + fig: matplotlib.figure.Figure | None = None, + return_fig: bool = False, + progress_callback: Callable[[int, int], None] | None = None, +): + """Plot the MCMC chain for each parameter of a Bayesian analysis. + + Parameters + ---------- + results : ratapi.outputs.BayesResults + The results of a Bayesian analysis. + params : list[int], default None + The indices or names of a subset of parameters if required. + If None, uses all indices. + maxpoints : int + The maximum number of points to plot for each parameter. + block : bool, default False + Whether Python should block until the plot is closed. + fig : matplotlib.figure.Figure, optional + The figure object to use for plot. + return_fig: bool, default False + If True, return the figure as an object instead of showing it. + progress_callback: Union[Callable[[int, int], None], None] + Callback function for providing progress during plot creation + First argument is current completed sub plot and second is total number of sub plots + + Returns + ------- + Figure or None + If `return_fig` is True, return the figure - otherwise, return nothing. + + """ + chain = results.chain + nsimulations, _ = chain.shape + # skip is to evenly distribute points plotted + # all points will be plotted if maxpoints < nsimulations + skip = max(floor(nsimulations / maxpoints), 1) + + # convert names to indices if given + fitname_to_index = partial(name_to_index, names=results.fitNames) + + if params is None: + params = range(0, len(results.fitNames)) + else: + params = list(map(fitname_to_index, params)) + + def plot_one_chain(axes: Axes, i: int): + axes.plot(range(0, nsimulations, skip), chain[:, i][0:nsimulations:skip]) + axes.set_title(results.fitNames[i], fontsize="small") + + fig = panel_plot_helper(plot_one_chain, params, fig, progress_callback) + if return_fig: + return fig + plt.show(block=block) + + +def plot_bayes(project: ratapi.Project, results: ratapi.outputs.BayesResults): + """Plot the results of a Bayesian analysis with confidence information. + + This produces an unshaded reflectivity/SLD plot, a reflectivity/SLD plot with shaded 95% confidence + intervals, a grid of histograms giving probability density for each parameter, and a corner plot for + all parameters. + + Parameters + ---------- + project : Project + An instance of the Project class + results : Union[Results, BayesResults] + The result from the calculation + block : bool, default: False + Indicates the plot should block until it is closed + + """ + if isinstance(results, ratapi.outputs.BayesResults): + plot_ref_sld(project, results) + plot_ref_sld(project, results, bayes=95) + plot_hists(results) + plot_corner(results) + else: + raise ValueError("Bayes plots are only available for the results of Bayesian analysis (NS or DREAM)") + + +def moving_average(data: np.ndarray, window_size: int = 8) -> list[float]: + """Calculate the moving average of an array with a given window size. + + This is a python equivalent to MATLABs smoothdata(A, 'movmean') + + Parameters + ---------- + data : np.ndarray + The input array to smooth + window_size : int + The window slides down the length of the vector, + computing an average over the elements within each window. + + """ + if not 0 <= window_size <= len(data): + raise ValueError( + "The moving average window size is out of range. Please change to a positive integer which " + "does not exceed the number of histogram bins." + ) + moving_averages = [] + + for i in range(len(data)): + start_window_ind = floor(float(i - window_size / 2)) if i - window_size / 2 > 0 else 0 + end_window_ind = floor(float(i + window_size / 2)) if i + window_size / 2 < len(data) else len(data) + window_average = np.sum(data[start_window_ind:end_window_ind]) / (end_window_ind + 0 - start_window_ind) + moving_averages.append(window_average) + + return moving_averages diff --git a/ratapi/wrappers.py b/ratapi/wrappers.py new file mode 100644 index 00000000..38f276ac --- /dev/null +++ b/ratapi/wrappers.py @@ -0,0 +1,147 @@ +"""Wrappers for the interface between ratapi and MATLAB custom files.""" + +import os +import pathlib +from collections.abc import Callable +from contextlib import suppress + +import numpy as np +from numpy.typing import ArrayLike + +import ratapi.rat_core + + +def start_matlab(): + """Start MATLAB asynchronously and returns a future to retrieve the engine later. + + Returns + ------- + future : matlab.engine.futureresult.FutureResult + A future used to get the actual matlab engine. + + """ + future = None + if os.environ.get("DELAY_MATLAB_START", "0") == "0": + with suppress(ImportError): + import atexit + + import matlab.engine + + future = matlab.engine.start_matlab(background=True) + atexit.register(lambda: future.result()) + + return future + + +class MatlabWrapper: + """Creates a python callback for a MATLAB function. + + Parameters + ---------- + filename : string + The path of the file containing MATLAB function + + """ + + loader = start_matlab() + loader_error_message = "matlabengine is required to use MatlabWrapper" + + def __init__(self, filename: str) -> None: + if self.loader is None: + raise ImportError(self.loader_error_message) from None + + self.engine = self.loader.result() + path = pathlib.Path(filename) + self.engine.cd(str(path.parent), nargout=0) + self.function_name = path.stem + + def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], tuple[ArrayLike, float]]: + """Return a wrapper for the custom MATLAB function. + + Returns + ------- + wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], tuple[ArrayLike, float]] + The wrapper function for the MATLAB callback + + """ + + def handle(*args): + if len(args) == 2: + output = getattr(self.engine, self.function_name)( + np.array(args[0], "float"), # xdata + np.array(args[1], "float"), # params + nargout=1, + ) + return np.array(output, "float").tolist() + else: + matlab_args = [ + np.array(args[0], "float"), # params + np.array(args[1], "float"), # bulk in + np.array(args[2], "float"), # bulk out + float(args[3]), # contrast + ] + if len(args) > 4: + matlab_args.append(float(args[4])) # domain number + + output, sub_rough = getattr(self.engine, self.function_name)( + *matlab_args, + nargout=2, + ) + return np.array(output, "float").tolist(), float(sub_rough) + + return handle + + +def use_shared_matlab(name, custom_error_message): + """Connect asynchronously to shared MATLAB engine instance with the given name. + + Parameters + ---------- + name : str + The name of shared MATLAB engine instance + custom_error_message : str + The custom error message in case of failed connection + + Returns + ------- + future : matlab.engine.futureresult.FutureResult + A future used to get the actual matlab engine. + + """ + with suppress(ImportError): + import matlab.engine + + MatlabWrapper.loader = matlab.engine.connect_matlab(name, background=True) + MatlabWrapper.loader_error_message = custom_error_message + return MatlabWrapper.loader + + +class DylibWrapper: + """Creates a python callback for a function in dynamic library. + + Parameters + ---------- + filename : str + 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 = ratapi.rat_core.DylibEngine(filename, function_name) + + def getHandle(self) -> Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], tuple[ArrayLike, float]]: + """Return a wrapper for the custom dynamic library function. + + Returns + ------- + wrapper : Callable[[ArrayLike, ArrayLike, ArrayLike, int, int], tuple[ArrayLike, float]] + The wrapper function for the dynamic library callback + + """ + + def handle(*args): + return self.engine.invoke(*args) + + return handle diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 47a268b5..00000000 --- a/requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -numpy >= 1.20 -scipy >= 1.13.1 -prettytable >= 3.9.0 -pybind11 >= 2.4 -pydantic >= 2.7.2 -pytest >= 7.4.0 -pytest-cov >= 4.1.0 -matplotlib >= 3.8.3 -StrEnum >= 0.4.15; python_version < '3.11' -ruff >= 0.4.10 -scipy >= 1.13.1 -tqdm >= 4.66.5 diff --git a/setup.py b/setup.py index 00e94b34..9f70ff77 100644 --- a/setup.py +++ b/setup.py @@ -8,8 +8,7 @@ from setuptools.command.build_clib import build_clib from setuptools.command.build_ext import build_ext -__version__ = "0.0.0.dev1" -PACKAGE_NAME = "RATapi" +PACKAGE_NAME = "ratapi" with open("README.md") as f: LONG_DESCRIPTION = f.read() @@ -19,13 +18,14 @@ ext_modules = [ Extension( - "RATapi.rat_core", + "ratapi.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/includes/", ], language="c++", ), @@ -60,8 +60,8 @@ class BuildExt(build_ext): """A custom build extension for adding compiler-specific options.""" c_opts = { - "msvc": ["/EHsc"], - "unix": ["-fopenmp", "-std=c++11"], + "msvc": ["/O2", "/EHsc", "/openmp"], + "unix": ["-O2", "-fopenmp", "-std=c++11"], } l_opts = { "msvc": [], @@ -69,8 +69,8 @@ class BuildExt(build_ext): } if sys.platform == "darwin": - darwin_opts = ["-stdlib=libc++", "-mmacosx-version-min=10.9"] - c_opts["unix"] = [*darwin_opts, "-fopenmp"] + darwin_opts = ["-stdlib=libc++"] + c_opts["unix"] = [*darwin_opts, "-fopenmp", "-O2"] l_opts["unix"] = [*darwin_opts, "-lomp"] def build_extensions(self): @@ -120,7 +120,7 @@ def build_libraries(self, libraries): compiler_type = self.compiler.compiler_type if compiler_type == "msvc": - compile_args = ["/EHsc", "/LD"] + compile_args = ["/EHsc", "/LD", "-D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR"] else: compile_args = ["-std=c++11", "-fPIC"] @@ -151,38 +151,11 @@ def build_libraries(self, libraries): setup( name=PACKAGE_NAME, - version=__version__, - author="", - author_email="", - url="https://github.com/RascalSoftware/python-RAT", - description="Python extension for the Reflectivity Analysis Toolbox (RAT)", - long_description=LONG_DESCRIPTION, - long_description_content_type="text/markdown", - packages=find_packages(), + packages=find_packages(exclude=("tests",)), include_package_data=True, - package_data={"": [get_shared_object_name(libevent[0])], "RATapi.examples": ["data/*.dat"]}, + package_data={"": [get_shared_object_name(libevent[0])], "ratapi.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", - "scipy >= 1.13.1", - "tqdm>=4.66.5", - ], - 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 d73a108c..0f3b3569 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,10 +1,24 @@ +import shutil +import tempfile +from pathlib import Path + +import matplotlib + +matplotlib.use("Agg") import numpy as np import pytest -import RATapi -import RATapi.classlist -import RATapi.outputs -import RATapi.rat_core +import ratapi +import ratapi.classlist +import ratapi.outputs +import ratapi.rat_core + + +@pytest.fixture +def temp_dir(): + path = tempfile.mkdtemp() + yield path + shutil.rmtree(path) @pytest.fixture @@ -12,9 +26,9 @@ def input_project(): """A cut-down version of the input Project object for a reflectivity calculation set out in "DSPC_standard_layers.py". """ - project = RATapi.Project( + project = ratapi.Project( name="original_dspc_bilayer", - calculation="non polarised", + calculation="normal", model="standard layers", geometry="substrate/liquid", absorption=False, @@ -258,7 +272,7 @@ def input_project(): @pytest.fixture def reflectivity_calculation_output_results(): """The C++ results object for a reflectivity calculation of the project set out in "DSPC_standard_layers.py".""" - results = RATapi.rat_core.OutputResult() + results = ratapi.rat_core.OutputResult() results.reflectivity = [ np.array( [ @@ -415,35 +429,353 @@ def reflectivity_calculation_output_results(): ], ), ] - 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.backgrounds = [ + np.array( + [ + [1.1403e-02, 2.2300e-06, 0.0000e00], + [1.1973e-02, 2.2300e-06, 0.0000e00], + [1.2572e-02, 2.2300e-06, 0.0000e00], + [1.3201e-02, 2.2300e-06, 0.0000e00], + [1.3861e-02, 2.2300e-06, 0.0000e00], + [1.4554e-02, 2.2300e-06, 0.0000e00], + [1.5281e-02, 2.2300e-06, 0.0000e00], + [1.6045e-02, 2.2300e-06, 0.0000e00], + [1.6848e-02, 2.2300e-06, 0.0000e00], + [1.7690e-02, 2.2300e-06, 0.0000e00], + [1.8575e-02, 2.2300e-06, 0.0000e00], + [1.9503e-02, 2.2300e-06, 0.0000e00], + [2.0479e-02, 2.2300e-06, 0.0000e00], + [2.1502e-02, 2.2300e-06, 0.0000e00], + [2.2578e-02, 2.2300e-06, 0.0000e00], + [2.3706e-02, 2.2300e-06, 0.0000e00], + [2.4892e-02, 2.2300e-06, 0.0000e00], + [2.6136e-02, 2.2300e-06, 0.0000e00], + [2.7443e-02, 2.2300e-06, 0.0000e00], + [2.8815e-02, 2.2300e-06, 0.0000e00], + [3.0256e-02, 2.2300e-06, 0.0000e00], + [3.1769e-02, 2.2300e-06, 0.0000e00], + [3.3357e-02, 2.2300e-06, 0.0000e00], + [3.5025e-02, 2.2300e-06, 0.0000e00], + [3.6777e-02, 2.2300e-06, 0.0000e00], + [3.8615e-02, 2.2300e-06, 0.0000e00], + [4.0546e-02, 2.2300e-06, 0.0000e00], + [4.2573e-02, 2.2300e-06, 0.0000e00], + [4.4702e-02, 2.2300e-06, 0.0000e00], + [4.6937e-02, 2.2300e-06, 0.0000e00], + [4.9284e-02, 2.2300e-06, 0.0000e00], + [5.1748e-02, 2.2300e-06, 0.0000e00], + [5.4336e-02, 2.2300e-06, 0.0000e00], + [5.7052e-02, 2.2300e-06, 0.0000e00], + [5.9905e-02, 2.2300e-06, 0.0000e00], + [6.2900e-02, 2.2300e-06, 0.0000e00], + [6.6045e-02, 2.2300e-06, 0.0000e00], + [6.9348e-02, 2.2300e-06, 0.0000e00], + [7.2815e-02, 2.2300e-06, 0.0000e00], + [7.6456e-02, 2.2300e-06, 0.0000e00], + [8.0279e-02, 2.2300e-06, 0.0000e00], + [8.4292e-02, 2.2300e-06, 0.0000e00], + [8.8507e-02, 2.2300e-06, 0.0000e00], + [9.2932e-02, 2.2300e-06, 0.0000e00], + [9.7579e-02, 2.2300e-06, 0.0000e00], + [1.0246e-01, 2.2300e-06, 0.0000e00], + [1.0758e-01, 2.2300e-06, 0.0000e00], + [1.1296e-01, 2.2300e-06, 0.0000e00], + [1.1861e-01, 2.2300e-06, 0.0000e00], + [1.2454e-01, 2.2300e-06, 0.0000e00], + [1.3077e-01, 2.2300e-06, 0.0000e00], + [1.3730e-01, 2.2300e-06, 0.0000e00], + [1.4417e-01, 2.2300e-06, 0.0000e00], + [1.5138e-01, 2.2300e-06, 0.0000e00], + [1.5895e-01, 2.2300e-06, 0.0000e00], + [1.6689e-01, 2.2300e-06, 0.0000e00], + [1.7524e-01, 2.2300e-06, 0.0000e00], + [1.8400e-01, 2.2300e-06, 0.0000e00], + [1.9320e-01, 2.2300e-06, 0.0000e00], + [2.0286e-01, 2.2300e-06, 0.0000e00], + [2.1300e-01, 2.2300e-06, 0.0000e00], + [2.2365e-01, 2.2300e-06, 0.0000e00], + [2.3484e-01, 2.2300e-06, 0.0000e00], + [2.4658e-01, 2.2300e-06, 0.0000e00], + [2.5891e-01, 2.2300e-06, 0.0000e00], + [2.7185e-01, 2.2300e-06, 0.0000e00], + [2.8544e-01, 2.2300e-06, 0.0000e00], + [2.9972e-01, 2.2300e-06, 0.0000e00], + [3.1470e-01, 2.2300e-06, 0.0000e00], + [3.3044e-01, 2.2300e-06, 0.0000e00], + [3.4696e-01, 2.2300e-06, 0.0000e00], + [3.6431e-01, 2.2300e-06, 0.0000e00], + [3.8252e-01, 2.2300e-06, 0.0000e00], + [4.0165e-01, 2.2300e-06, 0.0000e00], + [4.2173e-01, 2.2300e-06, 0.0000e00], + [4.4282e-01, 2.2300e-06, 0.0000e00], + [4.6496e-01, 2.2300e-06, 0.0000e00], + [4.8821e-01, 2.2300e-06, 0.0000e00], + [5.1262e-01, 2.2300e-06, 0.0000e00], + [5.3825e-01, 2.2300e-06, 0.0000e00], + [5.6516e-01, 2.2300e-06, 0.0000e00], + [5.9342e-01, 2.2300e-06, 0.0000e00], + ] + ), + np.array( + [ + [1.1403e-02, 3.3800e-06, 0.0000e00], + [1.1973e-02, 3.3800e-06, 0.0000e00], + [1.2572e-02, 3.3800e-06, 0.0000e00], + [1.3201e-02, 3.3800e-06, 0.0000e00], + [1.3861e-02, 3.3800e-06, 0.0000e00], + [1.4554e-02, 3.3800e-06, 0.0000e00], + [1.5281e-02, 3.3800e-06, 0.0000e00], + [1.6045e-02, 3.3800e-06, 0.0000e00], + [1.6848e-02, 3.3800e-06, 0.0000e00], + [1.7690e-02, 3.3800e-06, 0.0000e00], + [1.8575e-02, 3.3800e-06, 0.0000e00], + [1.9503e-02, 3.3800e-06, 0.0000e00], + [2.0479e-02, 3.3800e-06, 0.0000e00], + [2.1502e-02, 3.3800e-06, 0.0000e00], + [2.2578e-02, 3.3800e-06, 0.0000e00], + [2.3706e-02, 3.3800e-06, 0.0000e00], + [2.4892e-02, 3.3800e-06, 0.0000e00], + [2.6136e-02, 3.3800e-06, 0.0000e00], + [2.7443e-02, 3.3800e-06, 0.0000e00], + [2.8815e-02, 3.3800e-06, 0.0000e00], + [3.0256e-02, 3.3800e-06, 0.0000e00], + [3.1769e-02, 3.3800e-06, 0.0000e00], + [3.3357e-02, 3.3800e-06, 0.0000e00], + [3.5025e-02, 3.3800e-06, 0.0000e00], + [3.6777e-02, 3.3800e-06, 0.0000e00], + [3.8615e-02, 3.3800e-06, 0.0000e00], + [4.0546e-02, 3.3800e-06, 0.0000e00], + [4.2573e-02, 3.3800e-06, 0.0000e00], + [4.4702e-02, 3.3800e-06, 0.0000e00], + [4.6937e-02, 3.3800e-06, 0.0000e00], + [4.9284e-02, 3.3800e-06, 0.0000e00], + [5.1748e-02, 3.3800e-06, 0.0000e00], + [5.4336e-02, 3.3800e-06, 0.0000e00], + [5.7052e-02, 3.3800e-06, 0.0000e00], + [5.9905e-02, 3.3800e-06, 0.0000e00], + [6.2900e-02, 3.3800e-06, 0.0000e00], + [6.6045e-02, 3.3800e-06, 0.0000e00], + [6.9348e-02, 3.3800e-06, 0.0000e00], + [7.2815e-02, 3.3800e-06, 0.0000e00], + [7.6456e-02, 3.3800e-06, 0.0000e00], + [8.0279e-02, 3.3800e-06, 0.0000e00], + [8.4292e-02, 3.3800e-06, 0.0000e00], + [8.8507e-02, 3.3800e-06, 0.0000e00], + [9.2932e-02, 3.3800e-06, 0.0000e00], + [9.7579e-02, 3.3800e-06, 0.0000e00], + [1.0246e-01, 3.3800e-06, 0.0000e00], + [1.0758e-01, 3.3800e-06, 0.0000e00], + [1.1296e-01, 3.3800e-06, 0.0000e00], + [1.1861e-01, 3.3800e-06, 0.0000e00], + [1.2454e-01, 3.3800e-06, 0.0000e00], + [1.3077e-01, 3.3800e-06, 0.0000e00], + [1.3730e-01, 3.3800e-06, 0.0000e00], + [1.4417e-01, 3.3800e-06, 0.0000e00], + [1.5138e-01, 3.3800e-06, 0.0000e00], + [1.5895e-01, 3.3800e-06, 0.0000e00], + [1.6689e-01, 3.3800e-06, 0.0000e00], + [1.7524e-01, 3.3800e-06, 0.0000e00], + [1.8400e-01, 3.3800e-06, 0.0000e00], + [1.9320e-01, 3.3800e-06, 0.0000e00], + [2.0286e-01, 3.3800e-06, 0.0000e00], + [2.1300e-01, 3.3800e-06, 0.0000e00], + [2.2365e-01, 3.3800e-06, 0.0000e00], + [2.3484e-01, 3.3800e-06, 0.0000e00], + [2.4658e-01, 3.3800e-06, 0.0000e00], + [2.5891e-01, 3.3800e-06, 0.0000e00], + [2.7185e-01, 3.3800e-06, 0.0000e00], + [2.8544e-01, 3.3800e-06, 0.0000e00], + [2.9972e-01, 3.3800e-06, 0.0000e00], + [3.1470e-01, 3.3800e-06, 0.0000e00], + [3.3044e-01, 3.3800e-06, 0.0000e00], + [3.4696e-01, 3.3800e-06, 0.0000e00], + [3.6431e-01, 3.3800e-06, 0.0000e00], + [3.8252e-01, 3.3800e-06, 0.0000e00], + [4.0165e-01, 3.3800e-06, 0.0000e00], + [4.2173e-01, 3.3800e-06, 0.0000e00], + [4.4282e-01, 3.3800e-06, 0.0000e00], + [4.6496e-01, 3.3800e-06, 0.0000e00], + [4.8821e-01, 3.3800e-06, 0.0000e00], + [5.1262e-01, 3.3800e-06, 0.0000e00], + [5.3825e-01, 3.3800e-06, 0.0000e00], + [5.6516e-01, 3.3800e-06, 0.0000e00], + [5.9342e-01, 3.3800e-06, 0.0000e00], + ] + ), + ] + results.resolutions = [ + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), ] results.sldProfiles = [ [ @@ -507,16 +839,44 @@ def reflectivity_calculation_output_results(): ), ], ] + results.layers = [ + [ + 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.resampledLayers = [[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]] - results.calculationResults = RATapi.rat_core.Calculation() + results.calculationResults = ratapi.rat_core.Calculation() results.calculationResults.chiValues = np.array([202.83057377, 1641.4024969]) results.calculationResults.sumChi = 1844.2330706690975 - results.contrastParams = RATapi.rat_core.ContrastParams() - results.contrastParams.backgroundParams = np.array([2.23e-06, 3.38e-06]) + results.contrastParams = ratapi.rat_core.ContrastParams() results.contrastParams.scalefactors = np.array([0.1, 0.15]) results.contrastParams.bulkIn = np.array([2.073e-06, 2.073e-06]) results.contrastParams.bulkOut = np.array([5.98e-06, 2.21e-06]) - 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( @@ -568,7 +928,7 @@ def reflectivity_calculation_output_results(): @pytest.fixture def reflectivity_calculation_results(): """The python results object for a reflectivity calculation of the project set out in "DSPC_standard_layers.py".""" - return RATapi.outputs.Results( + return ratapi.outputs.Results( reflectivity=[ np.array( [ @@ -725,35 +1085,353 @@ def reflectivity_calculation_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], - ], - ), - ], + backgrounds=[ + np.array( + [ + [1.1403e-02, 2.2300e-06, 0.0000e00], + [1.1973e-02, 2.2300e-06, 0.0000e00], + [1.2572e-02, 2.2300e-06, 0.0000e00], + [1.3201e-02, 2.2300e-06, 0.0000e00], + [1.3861e-02, 2.2300e-06, 0.0000e00], + [1.4554e-02, 2.2300e-06, 0.0000e00], + [1.5281e-02, 2.2300e-06, 0.0000e00], + [1.6045e-02, 2.2300e-06, 0.0000e00], + [1.6848e-02, 2.2300e-06, 0.0000e00], + [1.7690e-02, 2.2300e-06, 0.0000e00], + [1.8575e-02, 2.2300e-06, 0.0000e00], + [1.9503e-02, 2.2300e-06, 0.0000e00], + [2.0479e-02, 2.2300e-06, 0.0000e00], + [2.1502e-02, 2.2300e-06, 0.0000e00], + [2.2578e-02, 2.2300e-06, 0.0000e00], + [2.3706e-02, 2.2300e-06, 0.0000e00], + [2.4892e-02, 2.2300e-06, 0.0000e00], + [2.6136e-02, 2.2300e-06, 0.0000e00], + [2.7443e-02, 2.2300e-06, 0.0000e00], + [2.8815e-02, 2.2300e-06, 0.0000e00], + [3.0256e-02, 2.2300e-06, 0.0000e00], + [3.1769e-02, 2.2300e-06, 0.0000e00], + [3.3357e-02, 2.2300e-06, 0.0000e00], + [3.5025e-02, 2.2300e-06, 0.0000e00], + [3.6777e-02, 2.2300e-06, 0.0000e00], + [3.8615e-02, 2.2300e-06, 0.0000e00], + [4.0546e-02, 2.2300e-06, 0.0000e00], + [4.2573e-02, 2.2300e-06, 0.0000e00], + [4.4702e-02, 2.2300e-06, 0.0000e00], + [4.6937e-02, 2.2300e-06, 0.0000e00], + [4.9284e-02, 2.2300e-06, 0.0000e00], + [5.1748e-02, 2.2300e-06, 0.0000e00], + [5.4336e-02, 2.2300e-06, 0.0000e00], + [5.7052e-02, 2.2300e-06, 0.0000e00], + [5.9905e-02, 2.2300e-06, 0.0000e00], + [6.2900e-02, 2.2300e-06, 0.0000e00], + [6.6045e-02, 2.2300e-06, 0.0000e00], + [6.9348e-02, 2.2300e-06, 0.0000e00], + [7.2815e-02, 2.2300e-06, 0.0000e00], + [7.6456e-02, 2.2300e-06, 0.0000e00], + [8.0279e-02, 2.2300e-06, 0.0000e00], + [8.4292e-02, 2.2300e-06, 0.0000e00], + [8.8507e-02, 2.2300e-06, 0.0000e00], + [9.2932e-02, 2.2300e-06, 0.0000e00], + [9.7579e-02, 2.2300e-06, 0.0000e00], + [1.0246e-01, 2.2300e-06, 0.0000e00], + [1.0758e-01, 2.2300e-06, 0.0000e00], + [1.1296e-01, 2.2300e-06, 0.0000e00], + [1.1861e-01, 2.2300e-06, 0.0000e00], + [1.2454e-01, 2.2300e-06, 0.0000e00], + [1.3077e-01, 2.2300e-06, 0.0000e00], + [1.3730e-01, 2.2300e-06, 0.0000e00], + [1.4417e-01, 2.2300e-06, 0.0000e00], + [1.5138e-01, 2.2300e-06, 0.0000e00], + [1.5895e-01, 2.2300e-06, 0.0000e00], + [1.6689e-01, 2.2300e-06, 0.0000e00], + [1.7524e-01, 2.2300e-06, 0.0000e00], + [1.8400e-01, 2.2300e-06, 0.0000e00], + [1.9320e-01, 2.2300e-06, 0.0000e00], + [2.0286e-01, 2.2300e-06, 0.0000e00], + [2.1300e-01, 2.2300e-06, 0.0000e00], + [2.2365e-01, 2.2300e-06, 0.0000e00], + [2.3484e-01, 2.2300e-06, 0.0000e00], + [2.4658e-01, 2.2300e-06, 0.0000e00], + [2.5891e-01, 2.2300e-06, 0.0000e00], + [2.7185e-01, 2.2300e-06, 0.0000e00], + [2.8544e-01, 2.2300e-06, 0.0000e00], + [2.9972e-01, 2.2300e-06, 0.0000e00], + [3.1470e-01, 2.2300e-06, 0.0000e00], + [3.3044e-01, 2.2300e-06, 0.0000e00], + [3.4696e-01, 2.2300e-06, 0.0000e00], + [3.6431e-01, 2.2300e-06, 0.0000e00], + [3.8252e-01, 2.2300e-06, 0.0000e00], + [4.0165e-01, 2.2300e-06, 0.0000e00], + [4.2173e-01, 2.2300e-06, 0.0000e00], + [4.4282e-01, 2.2300e-06, 0.0000e00], + [4.6496e-01, 2.2300e-06, 0.0000e00], + [4.8821e-01, 2.2300e-06, 0.0000e00], + [5.1262e-01, 2.2300e-06, 0.0000e00], + [5.3825e-01, 2.2300e-06, 0.0000e00], + [5.6516e-01, 2.2300e-06, 0.0000e00], + [5.9342e-01, 2.2300e-06, 0.0000e00], + ] + ), + np.array( + [ + [1.1403e-02, 3.3800e-06, 0.0000e00], + [1.1973e-02, 3.3800e-06, 0.0000e00], + [1.2572e-02, 3.3800e-06, 0.0000e00], + [1.3201e-02, 3.3800e-06, 0.0000e00], + [1.3861e-02, 3.3800e-06, 0.0000e00], + [1.4554e-02, 3.3800e-06, 0.0000e00], + [1.5281e-02, 3.3800e-06, 0.0000e00], + [1.6045e-02, 3.3800e-06, 0.0000e00], + [1.6848e-02, 3.3800e-06, 0.0000e00], + [1.7690e-02, 3.3800e-06, 0.0000e00], + [1.8575e-02, 3.3800e-06, 0.0000e00], + [1.9503e-02, 3.3800e-06, 0.0000e00], + [2.0479e-02, 3.3800e-06, 0.0000e00], + [2.1502e-02, 3.3800e-06, 0.0000e00], + [2.2578e-02, 3.3800e-06, 0.0000e00], + [2.3706e-02, 3.3800e-06, 0.0000e00], + [2.4892e-02, 3.3800e-06, 0.0000e00], + [2.6136e-02, 3.3800e-06, 0.0000e00], + [2.7443e-02, 3.3800e-06, 0.0000e00], + [2.8815e-02, 3.3800e-06, 0.0000e00], + [3.0256e-02, 3.3800e-06, 0.0000e00], + [3.1769e-02, 3.3800e-06, 0.0000e00], + [3.3357e-02, 3.3800e-06, 0.0000e00], + [3.5025e-02, 3.3800e-06, 0.0000e00], + [3.6777e-02, 3.3800e-06, 0.0000e00], + [3.8615e-02, 3.3800e-06, 0.0000e00], + [4.0546e-02, 3.3800e-06, 0.0000e00], + [4.2573e-02, 3.3800e-06, 0.0000e00], + [4.4702e-02, 3.3800e-06, 0.0000e00], + [4.6937e-02, 3.3800e-06, 0.0000e00], + [4.9284e-02, 3.3800e-06, 0.0000e00], + [5.1748e-02, 3.3800e-06, 0.0000e00], + [5.4336e-02, 3.3800e-06, 0.0000e00], + [5.7052e-02, 3.3800e-06, 0.0000e00], + [5.9905e-02, 3.3800e-06, 0.0000e00], + [6.2900e-02, 3.3800e-06, 0.0000e00], + [6.6045e-02, 3.3800e-06, 0.0000e00], + [6.9348e-02, 3.3800e-06, 0.0000e00], + [7.2815e-02, 3.3800e-06, 0.0000e00], + [7.6456e-02, 3.3800e-06, 0.0000e00], + [8.0279e-02, 3.3800e-06, 0.0000e00], + [8.4292e-02, 3.3800e-06, 0.0000e00], + [8.8507e-02, 3.3800e-06, 0.0000e00], + [9.2932e-02, 3.3800e-06, 0.0000e00], + [9.7579e-02, 3.3800e-06, 0.0000e00], + [1.0246e-01, 3.3800e-06, 0.0000e00], + [1.0758e-01, 3.3800e-06, 0.0000e00], + [1.1296e-01, 3.3800e-06, 0.0000e00], + [1.1861e-01, 3.3800e-06, 0.0000e00], + [1.2454e-01, 3.3800e-06, 0.0000e00], + [1.3077e-01, 3.3800e-06, 0.0000e00], + [1.3730e-01, 3.3800e-06, 0.0000e00], + [1.4417e-01, 3.3800e-06, 0.0000e00], + [1.5138e-01, 3.3800e-06, 0.0000e00], + [1.5895e-01, 3.3800e-06, 0.0000e00], + [1.6689e-01, 3.3800e-06, 0.0000e00], + [1.7524e-01, 3.3800e-06, 0.0000e00], + [1.8400e-01, 3.3800e-06, 0.0000e00], + [1.9320e-01, 3.3800e-06, 0.0000e00], + [2.0286e-01, 3.3800e-06, 0.0000e00], + [2.1300e-01, 3.3800e-06, 0.0000e00], + [2.2365e-01, 3.3800e-06, 0.0000e00], + [2.3484e-01, 3.3800e-06, 0.0000e00], + [2.4658e-01, 3.3800e-06, 0.0000e00], + [2.5891e-01, 3.3800e-06, 0.0000e00], + [2.7185e-01, 3.3800e-06, 0.0000e00], + [2.8544e-01, 3.3800e-06, 0.0000e00], + [2.9972e-01, 3.3800e-06, 0.0000e00], + [3.1470e-01, 3.3800e-06, 0.0000e00], + [3.3044e-01, 3.3800e-06, 0.0000e00], + [3.4696e-01, 3.3800e-06, 0.0000e00], + [3.6431e-01, 3.3800e-06, 0.0000e00], + [3.8252e-01, 3.3800e-06, 0.0000e00], + [4.0165e-01, 3.3800e-06, 0.0000e00], + [4.2173e-01, 3.3800e-06, 0.0000e00], + [4.4282e-01, 3.3800e-06, 0.0000e00], + [4.6496e-01, 3.3800e-06, 0.0000e00], + [4.8821e-01, 3.3800e-06, 0.0000e00], + [5.1262e-01, 3.3800e-06, 0.0000e00], + [5.3825e-01, 3.3800e-06, 0.0000e00], + [5.6516e-01, 3.3800e-06, 0.0000e00], + [5.9342e-01, 3.3800e-06, 0.0000e00], + ] + ), + ], + resolutions=[ + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), ], sldProfiles=[ [ @@ -817,17 +1495,45 @@ def reflectivity_calculation_results(): ), ], ], + layers=[ + [ + 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], + ], + ), + ], + ], resampledLayers=[[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]], - calculationResults=RATapi.outputs.CalculationResults( + calculationResults=ratapi.outputs.CalculationResults( chiValues=np.array([202.83057377, 1641.4024969]), sumChi=1844.2330706690975, ), - contrastParams=RATapi.outputs.ContrastParams( - backgroundParams=np.array([2.23e-06, 3.38e-06]), + contrastParams=ratapi.outputs.ContrastParams( 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]), ), @@ -883,7 +1589,7 @@ def dream_output_results(): This optimisation used the parameters: nSamples=1, nChains=1. However, the calculationResults, contrastParams, and fitParams are taken from an optimisation with the parameters: nSamples=50000, nChains=10. """ - results = RATapi.rat_core.OutputResult() + results = ratapi.rat_core.OutputResult() results.reflectivity = [ np.array( [ @@ -1040,35 +1746,353 @@ def dream_output_results(): ], ), ] - 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.backgrounds = [ + np.array( + [ + [1.14030000e-02, 2.37401704e-06, 0.00000000e00], + [1.19730000e-02, 2.37401704e-06, 0.00000000e00], + [1.25720000e-02, 2.37401704e-06, 0.00000000e00], + [1.32010000e-02, 2.37401704e-06, 0.00000000e00], + [1.38610000e-02, 2.37401704e-06, 0.00000000e00], + [1.45540000e-02, 2.37401704e-06, 0.00000000e00], + [1.52810000e-02, 2.37401704e-06, 0.00000000e00], + [1.60450000e-02, 2.37401704e-06, 0.00000000e00], + [1.68480000e-02, 2.37401704e-06, 0.00000000e00], + [1.76900000e-02, 2.37401704e-06, 0.00000000e00], + [1.85750000e-02, 2.37401704e-06, 0.00000000e00], + [1.95030000e-02, 2.37401704e-06, 0.00000000e00], + [2.04790000e-02, 2.37401704e-06, 0.00000000e00], + [2.15020000e-02, 2.37401704e-06, 0.00000000e00], + [2.25780000e-02, 2.37401704e-06, 0.00000000e00], + [2.37060000e-02, 2.37401704e-06, 0.00000000e00], + [2.48920000e-02, 2.37401704e-06, 0.00000000e00], + [2.61360000e-02, 2.37401704e-06, 0.00000000e00], + [2.74430000e-02, 2.37401704e-06, 0.00000000e00], + [2.88150000e-02, 2.37401704e-06, 0.00000000e00], + [3.02560000e-02, 2.37401704e-06, 0.00000000e00], + [3.17690000e-02, 2.37401704e-06, 0.00000000e00], + [3.33570000e-02, 2.37401704e-06, 0.00000000e00], + [3.50250000e-02, 2.37401704e-06, 0.00000000e00], + [3.67770000e-02, 2.37401704e-06, 0.00000000e00], + [3.86150000e-02, 2.37401704e-06, 0.00000000e00], + [4.05460000e-02, 2.37401704e-06, 0.00000000e00], + [4.25730000e-02, 2.37401704e-06, 0.00000000e00], + [4.47020000e-02, 2.37401704e-06, 0.00000000e00], + [4.69370000e-02, 2.37401704e-06, 0.00000000e00], + [4.92840000e-02, 2.37401704e-06, 0.00000000e00], + [5.17480000e-02, 2.37401704e-06, 0.00000000e00], + [5.43360000e-02, 2.37401704e-06, 0.00000000e00], + [5.70520000e-02, 2.37401704e-06, 0.00000000e00], + [5.99050000e-02, 2.37401704e-06, 0.00000000e00], + [6.29000000e-02, 2.37401704e-06, 0.00000000e00], + [6.60450000e-02, 2.37401704e-06, 0.00000000e00], + [6.93480000e-02, 2.37401704e-06, 0.00000000e00], + [7.28150000e-02, 2.37401704e-06, 0.00000000e00], + [7.64560000e-02, 2.37401704e-06, 0.00000000e00], + [8.02790000e-02, 2.37401704e-06, 0.00000000e00], + [8.42920000e-02, 2.37401704e-06, 0.00000000e00], + [8.85070000e-02, 2.37401704e-06, 0.00000000e00], + [9.29320000e-02, 2.37401704e-06, 0.00000000e00], + [9.75790000e-02, 2.37401704e-06, 0.00000000e00], + [1.02460000e-01, 2.37401704e-06, 0.00000000e00], + [1.07580000e-01, 2.37401704e-06, 0.00000000e00], + [1.12960000e-01, 2.37401704e-06, 0.00000000e00], + [1.18610000e-01, 2.37401704e-06, 0.00000000e00], + [1.24540000e-01, 2.37401704e-06, 0.00000000e00], + [1.30770000e-01, 2.37401704e-06, 0.00000000e00], + [1.37300000e-01, 2.37401704e-06, 0.00000000e00], + [1.44170000e-01, 2.37401704e-06, 0.00000000e00], + [1.51380000e-01, 2.37401704e-06, 0.00000000e00], + [1.58950000e-01, 2.37401704e-06, 0.00000000e00], + [1.66890000e-01, 2.37401704e-06, 0.00000000e00], + [1.75240000e-01, 2.37401704e-06, 0.00000000e00], + [1.84000000e-01, 2.37401704e-06, 0.00000000e00], + [1.93200000e-01, 2.37401704e-06, 0.00000000e00], + [2.02860000e-01, 2.37401704e-06, 0.00000000e00], + [2.13000000e-01, 2.37401704e-06, 0.00000000e00], + [2.23650000e-01, 2.37401704e-06, 0.00000000e00], + [2.34840000e-01, 2.37401704e-06, 0.00000000e00], + [2.46580000e-01, 2.37401704e-06, 0.00000000e00], + [2.58910000e-01, 2.37401704e-06, 0.00000000e00], + [2.71850000e-01, 2.37401704e-06, 0.00000000e00], + [2.85440000e-01, 2.37401704e-06, 0.00000000e00], + [2.99720000e-01, 2.37401704e-06, 0.00000000e00], + [3.14700000e-01, 2.37401704e-06, 0.00000000e00], + [3.30440000e-01, 2.37401704e-06, 0.00000000e00], + [3.46960000e-01, 2.37401704e-06, 0.00000000e00], + [3.64310000e-01, 2.37401704e-06, 0.00000000e00], + [3.82520000e-01, 2.37401704e-06, 0.00000000e00], + [4.01650000e-01, 2.37401704e-06, 0.00000000e00], + [4.21730000e-01, 2.37401704e-06, 0.00000000e00], + [4.42820000e-01, 2.37401704e-06, 0.00000000e00], + [4.64960000e-01, 2.37401704e-06, 0.00000000e00], + [4.88210000e-01, 2.37401704e-06, 0.00000000e00], + [5.12620000e-01, 2.37401704e-06, 0.00000000e00], + [5.38250000e-01, 2.37401704e-06, 0.00000000e00], + [5.65160000e-01, 2.37401704e-06, 0.00000000e00], + [5.93420000e-01, 2.37401704e-06, 0.00000000e00], + ] + ), + np.array( + [ + [1.14030000e-02, 2.19553929e-06, 0.00000000e00], + [1.19730000e-02, 2.19553929e-06, 0.00000000e00], + [1.25720000e-02, 2.19553929e-06, 0.00000000e00], + [1.32010000e-02, 2.19553929e-06, 0.00000000e00], + [1.38610000e-02, 2.19553929e-06, 0.00000000e00], + [1.45540000e-02, 2.19553929e-06, 0.00000000e00], + [1.52810000e-02, 2.19553929e-06, 0.00000000e00], + [1.60450000e-02, 2.19553929e-06, 0.00000000e00], + [1.68480000e-02, 2.19553929e-06, 0.00000000e00], + [1.76900000e-02, 2.19553929e-06, 0.00000000e00], + [1.85750000e-02, 2.19553929e-06, 0.00000000e00], + [1.95030000e-02, 2.19553929e-06, 0.00000000e00], + [2.04790000e-02, 2.19553929e-06, 0.00000000e00], + [2.15020000e-02, 2.19553929e-06, 0.00000000e00], + [2.25780000e-02, 2.19553929e-06, 0.00000000e00], + [2.37060000e-02, 2.19553929e-06, 0.00000000e00], + [2.48920000e-02, 2.19553929e-06, 0.00000000e00], + [2.61360000e-02, 2.19553929e-06, 0.00000000e00], + [2.74430000e-02, 2.19553929e-06, 0.00000000e00], + [2.88150000e-02, 2.19553929e-06, 0.00000000e00], + [3.02560000e-02, 2.19553929e-06, 0.00000000e00], + [3.17690000e-02, 2.19553929e-06, 0.00000000e00], + [3.33570000e-02, 2.19553929e-06, 0.00000000e00], + [3.50250000e-02, 2.19553929e-06, 0.00000000e00], + [3.67770000e-02, 2.19553929e-06, 0.00000000e00], + [3.86150000e-02, 2.19553929e-06, 0.00000000e00], + [4.05460000e-02, 2.19553929e-06, 0.00000000e00], + [4.25730000e-02, 2.19553929e-06, 0.00000000e00], + [4.47020000e-02, 2.19553929e-06, 0.00000000e00], + [4.69370000e-02, 2.19553929e-06, 0.00000000e00], + [4.92840000e-02, 2.19553929e-06, 0.00000000e00], + [5.17480000e-02, 2.19553929e-06, 0.00000000e00], + [5.43360000e-02, 2.19553929e-06, 0.00000000e00], + [5.70520000e-02, 2.19553929e-06, 0.00000000e00], + [5.99050000e-02, 2.19553929e-06, 0.00000000e00], + [6.29000000e-02, 2.19553929e-06, 0.00000000e00], + [6.60450000e-02, 2.19553929e-06, 0.00000000e00], + [6.93480000e-02, 2.19553929e-06, 0.00000000e00], + [7.28150000e-02, 2.19553929e-06, 0.00000000e00], + [7.64560000e-02, 2.19553929e-06, 0.00000000e00], + [8.02790000e-02, 2.19553929e-06, 0.00000000e00], + [8.42920000e-02, 2.19553929e-06, 0.00000000e00], + [8.85070000e-02, 2.19553929e-06, 0.00000000e00], + [9.29320000e-02, 2.19553929e-06, 0.00000000e00], + [9.75790000e-02, 2.19553929e-06, 0.00000000e00], + [1.02460000e-01, 2.19553929e-06, 0.00000000e00], + [1.07580000e-01, 2.19553929e-06, 0.00000000e00], + [1.12960000e-01, 2.19553929e-06, 0.00000000e00], + [1.18610000e-01, 2.19553929e-06, 0.00000000e00], + [1.24540000e-01, 2.19553929e-06, 0.00000000e00], + [1.30770000e-01, 2.19553929e-06, 0.00000000e00], + [1.37300000e-01, 2.19553929e-06, 0.00000000e00], + [1.44170000e-01, 2.19553929e-06, 0.00000000e00], + [1.51380000e-01, 2.19553929e-06, 0.00000000e00], + [1.58950000e-01, 2.19553929e-06, 0.00000000e00], + [1.66890000e-01, 2.19553929e-06, 0.00000000e00], + [1.75240000e-01, 2.19553929e-06, 0.00000000e00], + [1.84000000e-01, 2.19553929e-06, 0.00000000e00], + [1.93200000e-01, 2.19553929e-06, 0.00000000e00], + [2.02860000e-01, 2.19553929e-06, 0.00000000e00], + [2.13000000e-01, 2.19553929e-06, 0.00000000e00], + [2.23650000e-01, 2.19553929e-06, 0.00000000e00], + [2.34840000e-01, 2.19553929e-06, 0.00000000e00], + [2.46580000e-01, 2.19553929e-06, 0.00000000e00], + [2.58910000e-01, 2.19553929e-06, 0.00000000e00], + [2.71850000e-01, 2.19553929e-06, 0.00000000e00], + [2.85440000e-01, 2.19553929e-06, 0.00000000e00], + [2.99720000e-01, 2.19553929e-06, 0.00000000e00], + [3.14700000e-01, 2.19553929e-06, 0.00000000e00], + [3.30440000e-01, 2.19553929e-06, 0.00000000e00], + [3.46960000e-01, 2.19553929e-06, 0.00000000e00], + [3.64310000e-01, 2.19553929e-06, 0.00000000e00], + [3.82520000e-01, 2.19553929e-06, 0.00000000e00], + [4.01650000e-01, 2.19553929e-06, 0.00000000e00], + [4.21730000e-01, 2.19553929e-06, 0.00000000e00], + [4.42820000e-01, 2.19553929e-06, 0.00000000e00], + [4.64960000e-01, 2.19553929e-06, 0.00000000e00], + [4.88210000e-01, 2.19553929e-06, 0.00000000e00], + [5.12620000e-01, 2.19553929e-06, 0.00000000e00], + [5.38250000e-01, 2.19553929e-06, 0.00000000e00], + [5.65160000e-01, 2.19553929e-06, 0.00000000e00], + [5.93420000e-01, 2.19553929e-06, 0.00000000e00], + ] + ), + ] + results.resolutions = [ + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), ] results.sldProfiles = [ [ @@ -1140,16 +2164,44 @@ def dream_output_results(): ), ], ] + results.layers = [ + [ + 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.resampledLayers = [[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]] - results.calculationResults = RATapi.rat_core.Calculation() + results.calculationResults = ratapi.rat_core.Calculation() results.calculationResults.chiValues = (np.array([4.6077885, 7.00028098]),) results.calculationResults.sumChi = 11.608069475997699 - results.contrastParams = RATapi.rat_core.ContrastParams() - results.contrastParams.backgroundParams = np.array([2.37113128e-06, 1.99006694e-06]) + results.contrastParams = ratapi.rat_core.ContrastParams() results.contrastParams.scalefactors = np.array([0.1, 0.15]) results.contrastParams.bulkIn = np.array([2.073e-06, 2.073e-06]) results.contrastParams.bulkOut = np.array([6.01489149e-06, 1.59371685e-06]) - 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( @@ -1204,8 +2256,8 @@ def dream_bayes(): This optimisation used the parameters: nSamples=1, nChains=1. """ - bayes = RATapi.rat_core.BayesResults() - bayes.predictionIntervals = RATapi.rat_core.PredictionIntervals() + bayes = ratapi.rat_core.OutputBayesResult() + bayes.predictionIntervals = ratapi.rat_core.PredictionIntervals() bayes.predictionIntervals.reflectivity = [ np.array( [ @@ -1480,7 +2532,6 @@ def dream_bayes(): 9.14706158e-07, 9.14597081e-07, 9.14576711e-07, - 9.14569865e-07, ], [ -2.26996619e-06, @@ -1512,7 +2563,6 @@ def dream_bayes(): 9.14706158e-07, 9.14597081e-07, 9.14576711e-07, - 9.14569865e-07, ], [ -1.50598689e-07, @@ -1544,7 +2594,6 @@ def dream_bayes(): 3.33756709e-06, 3.33751126e-06, 3.33750083e-06, - 3.33749733e-06, ], [ 2.07300000e-06, @@ -1576,7 +2625,6 @@ def dream_bayes(): 5.87958511e-06, 5.87958515e-06, 5.87958515e-06, - 5.87958515e-06, ], [ 2.07300000e-06, @@ -1608,7 +2656,6 @@ def dream_bayes(): 5.87958511e-06, 5.87958515e-06, 5.87958515e-06, - 5.87958515e-06, ], ], ), @@ -1644,7 +2691,6 @@ def dream_bayes(): 4.65378471e-06, 4.65378475e-06, 4.65378475e-06, - 4.65378475e-06, ], [ -1.35107208e-06, @@ -1676,7 +2722,6 @@ def dream_bayes(): 4.65378471e-06, 4.65378475e-06, 4.65378475e-06, - 4.65378475e-06, ], [ 3.19875093e-07, @@ -1708,7 +2753,6 @@ def dream_bayes(): 4.92196879e-06, 4.92248720e-06, 4.92261931e-06, - 4.92266441e-06, ], [ 2.07300000e-06, @@ -1740,7 +2784,6 @@ def dream_bayes(): 5.17758173e-06, 5.17859423e-06, 5.17885226e-06, - 5.17894035e-06, ], [ 2.07300000e-06, @@ -1772,145 +2815,12 @@ def dream_bayes(): 5.17758173e-06, 5.17859423e-06, 5.17885226e-06, - 5.17894035e-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( + bayes.predictionIntervals.sampleChi = np.array( [ 1.46133559e16, 1.46133559e16, @@ -2914,7 +3824,7 @@ def dream_bayes(): 1.46133559e16, ], ) - bayes.confidenceIntervals = RATapi.rat_core.ConfidenceIntervals() + bayes.confidenceIntervals = ratapi.rat_core.ConfidenceIntervals() bayes.confidenceIntervals.percentile65 = np.array( [ [ @@ -3027,7 +3937,7 @@ def dream_bayes(): ], ], ) - bayes.dreamParams = RATapi.rat_core.DreamParams() + bayes.dreamParams = ratapi.rat_core.DreamParams() bayes.dreamParams.nParams = 18.0 bayes.dreamParams.nChains = 1.0 bayes.dreamParams.nGenerations = 1.0 @@ -3047,7 +3957,7 @@ def dream_bayes(): bayes.dreamParams.IO = 0 bayes.dreamParams.storeOutput = 0 bayes.dreamParams.R = np.array([[0.0]]) - bayes.dreamOutput = RATapi.rat_core.DreamOutput() + bayes.dreamOutput = ratapi.rat_core.DreamOutput() bayes.dreamOutput.allChains = np.array( [ [ @@ -3077,7 +3987,6 @@ def dream_bayes(): 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( [ @@ -3105,7 +4014,7 @@ def dream_bayes(): ], ) bayes.dreamOutput.CR = np.array([[1.00000000, 0.33333333, 0.33333333, 0.33333333]]) - bayes.nestedSamplerOutput = RATapi.rat_core.NestedSamplerOutput() + bayes.nestedSamplerOutput = ratapi.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]]) @@ -3164,7 +4073,7 @@ def dream_results(): This optimisation used the parameters: nSamples=1, nChains=1. However, the calculationResults, contrastParams, and fitParams are taken from an optimisation with the parameters: nSamples=50000, nChains=10. """ - return RATapi.outputs.BayesResults( + return ratapi.outputs.BayesResults( reflectivity=[ np.array( [ @@ -3321,35 +4230,353 @@ def dream_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], - ], - ), - ], + backgrounds=[ + np.array( + [ + [1.14030000e-02, 2.37401704e-06, 0.00000000e00], + [1.19730000e-02, 2.37401704e-06, 0.00000000e00], + [1.25720000e-02, 2.37401704e-06, 0.00000000e00], + [1.32010000e-02, 2.37401704e-06, 0.00000000e00], + [1.38610000e-02, 2.37401704e-06, 0.00000000e00], + [1.45540000e-02, 2.37401704e-06, 0.00000000e00], + [1.52810000e-02, 2.37401704e-06, 0.00000000e00], + [1.60450000e-02, 2.37401704e-06, 0.00000000e00], + [1.68480000e-02, 2.37401704e-06, 0.00000000e00], + [1.76900000e-02, 2.37401704e-06, 0.00000000e00], + [1.85750000e-02, 2.37401704e-06, 0.00000000e00], + [1.95030000e-02, 2.37401704e-06, 0.00000000e00], + [2.04790000e-02, 2.37401704e-06, 0.00000000e00], + [2.15020000e-02, 2.37401704e-06, 0.00000000e00], + [2.25780000e-02, 2.37401704e-06, 0.00000000e00], + [2.37060000e-02, 2.37401704e-06, 0.00000000e00], + [2.48920000e-02, 2.37401704e-06, 0.00000000e00], + [2.61360000e-02, 2.37401704e-06, 0.00000000e00], + [2.74430000e-02, 2.37401704e-06, 0.00000000e00], + [2.88150000e-02, 2.37401704e-06, 0.00000000e00], + [3.02560000e-02, 2.37401704e-06, 0.00000000e00], + [3.17690000e-02, 2.37401704e-06, 0.00000000e00], + [3.33570000e-02, 2.37401704e-06, 0.00000000e00], + [3.50250000e-02, 2.37401704e-06, 0.00000000e00], + [3.67770000e-02, 2.37401704e-06, 0.00000000e00], + [3.86150000e-02, 2.37401704e-06, 0.00000000e00], + [4.05460000e-02, 2.37401704e-06, 0.00000000e00], + [4.25730000e-02, 2.37401704e-06, 0.00000000e00], + [4.47020000e-02, 2.37401704e-06, 0.00000000e00], + [4.69370000e-02, 2.37401704e-06, 0.00000000e00], + [4.92840000e-02, 2.37401704e-06, 0.00000000e00], + [5.17480000e-02, 2.37401704e-06, 0.00000000e00], + [5.43360000e-02, 2.37401704e-06, 0.00000000e00], + [5.70520000e-02, 2.37401704e-06, 0.00000000e00], + [5.99050000e-02, 2.37401704e-06, 0.00000000e00], + [6.29000000e-02, 2.37401704e-06, 0.00000000e00], + [6.60450000e-02, 2.37401704e-06, 0.00000000e00], + [6.93480000e-02, 2.37401704e-06, 0.00000000e00], + [7.28150000e-02, 2.37401704e-06, 0.00000000e00], + [7.64560000e-02, 2.37401704e-06, 0.00000000e00], + [8.02790000e-02, 2.37401704e-06, 0.00000000e00], + [8.42920000e-02, 2.37401704e-06, 0.00000000e00], + [8.85070000e-02, 2.37401704e-06, 0.00000000e00], + [9.29320000e-02, 2.37401704e-06, 0.00000000e00], + [9.75790000e-02, 2.37401704e-06, 0.00000000e00], + [1.02460000e-01, 2.37401704e-06, 0.00000000e00], + [1.07580000e-01, 2.37401704e-06, 0.00000000e00], + [1.12960000e-01, 2.37401704e-06, 0.00000000e00], + [1.18610000e-01, 2.37401704e-06, 0.00000000e00], + [1.24540000e-01, 2.37401704e-06, 0.00000000e00], + [1.30770000e-01, 2.37401704e-06, 0.00000000e00], + [1.37300000e-01, 2.37401704e-06, 0.00000000e00], + [1.44170000e-01, 2.37401704e-06, 0.00000000e00], + [1.51380000e-01, 2.37401704e-06, 0.00000000e00], + [1.58950000e-01, 2.37401704e-06, 0.00000000e00], + [1.66890000e-01, 2.37401704e-06, 0.00000000e00], + [1.75240000e-01, 2.37401704e-06, 0.00000000e00], + [1.84000000e-01, 2.37401704e-06, 0.00000000e00], + [1.93200000e-01, 2.37401704e-06, 0.00000000e00], + [2.02860000e-01, 2.37401704e-06, 0.00000000e00], + [2.13000000e-01, 2.37401704e-06, 0.00000000e00], + [2.23650000e-01, 2.37401704e-06, 0.00000000e00], + [2.34840000e-01, 2.37401704e-06, 0.00000000e00], + [2.46580000e-01, 2.37401704e-06, 0.00000000e00], + [2.58910000e-01, 2.37401704e-06, 0.00000000e00], + [2.71850000e-01, 2.37401704e-06, 0.00000000e00], + [2.85440000e-01, 2.37401704e-06, 0.00000000e00], + [2.99720000e-01, 2.37401704e-06, 0.00000000e00], + [3.14700000e-01, 2.37401704e-06, 0.00000000e00], + [3.30440000e-01, 2.37401704e-06, 0.00000000e00], + [3.46960000e-01, 2.37401704e-06, 0.00000000e00], + [3.64310000e-01, 2.37401704e-06, 0.00000000e00], + [3.82520000e-01, 2.37401704e-06, 0.00000000e00], + [4.01650000e-01, 2.37401704e-06, 0.00000000e00], + [4.21730000e-01, 2.37401704e-06, 0.00000000e00], + [4.42820000e-01, 2.37401704e-06, 0.00000000e00], + [4.64960000e-01, 2.37401704e-06, 0.00000000e00], + [4.88210000e-01, 2.37401704e-06, 0.00000000e00], + [5.12620000e-01, 2.37401704e-06, 0.00000000e00], + [5.38250000e-01, 2.37401704e-06, 0.00000000e00], + [5.65160000e-01, 2.37401704e-06, 0.00000000e00], + [5.93420000e-01, 2.37401704e-06, 0.00000000e00], + ] + ), + np.array( + [ + [1.14030000e-02, 2.19553929e-06, 0.00000000e00], + [1.19730000e-02, 2.19553929e-06, 0.00000000e00], + [1.25720000e-02, 2.19553929e-06, 0.00000000e00], + [1.32010000e-02, 2.19553929e-06, 0.00000000e00], + [1.38610000e-02, 2.19553929e-06, 0.00000000e00], + [1.45540000e-02, 2.19553929e-06, 0.00000000e00], + [1.52810000e-02, 2.19553929e-06, 0.00000000e00], + [1.60450000e-02, 2.19553929e-06, 0.00000000e00], + [1.68480000e-02, 2.19553929e-06, 0.00000000e00], + [1.76900000e-02, 2.19553929e-06, 0.00000000e00], + [1.85750000e-02, 2.19553929e-06, 0.00000000e00], + [1.95030000e-02, 2.19553929e-06, 0.00000000e00], + [2.04790000e-02, 2.19553929e-06, 0.00000000e00], + [2.15020000e-02, 2.19553929e-06, 0.00000000e00], + [2.25780000e-02, 2.19553929e-06, 0.00000000e00], + [2.37060000e-02, 2.19553929e-06, 0.00000000e00], + [2.48920000e-02, 2.19553929e-06, 0.00000000e00], + [2.61360000e-02, 2.19553929e-06, 0.00000000e00], + [2.74430000e-02, 2.19553929e-06, 0.00000000e00], + [2.88150000e-02, 2.19553929e-06, 0.00000000e00], + [3.02560000e-02, 2.19553929e-06, 0.00000000e00], + [3.17690000e-02, 2.19553929e-06, 0.00000000e00], + [3.33570000e-02, 2.19553929e-06, 0.00000000e00], + [3.50250000e-02, 2.19553929e-06, 0.00000000e00], + [3.67770000e-02, 2.19553929e-06, 0.00000000e00], + [3.86150000e-02, 2.19553929e-06, 0.00000000e00], + [4.05460000e-02, 2.19553929e-06, 0.00000000e00], + [4.25730000e-02, 2.19553929e-06, 0.00000000e00], + [4.47020000e-02, 2.19553929e-06, 0.00000000e00], + [4.69370000e-02, 2.19553929e-06, 0.00000000e00], + [4.92840000e-02, 2.19553929e-06, 0.00000000e00], + [5.17480000e-02, 2.19553929e-06, 0.00000000e00], + [5.43360000e-02, 2.19553929e-06, 0.00000000e00], + [5.70520000e-02, 2.19553929e-06, 0.00000000e00], + [5.99050000e-02, 2.19553929e-06, 0.00000000e00], + [6.29000000e-02, 2.19553929e-06, 0.00000000e00], + [6.60450000e-02, 2.19553929e-06, 0.00000000e00], + [6.93480000e-02, 2.19553929e-06, 0.00000000e00], + [7.28150000e-02, 2.19553929e-06, 0.00000000e00], + [7.64560000e-02, 2.19553929e-06, 0.00000000e00], + [8.02790000e-02, 2.19553929e-06, 0.00000000e00], + [8.42920000e-02, 2.19553929e-06, 0.00000000e00], + [8.85070000e-02, 2.19553929e-06, 0.00000000e00], + [9.29320000e-02, 2.19553929e-06, 0.00000000e00], + [9.75790000e-02, 2.19553929e-06, 0.00000000e00], + [1.02460000e-01, 2.19553929e-06, 0.00000000e00], + [1.07580000e-01, 2.19553929e-06, 0.00000000e00], + [1.12960000e-01, 2.19553929e-06, 0.00000000e00], + [1.18610000e-01, 2.19553929e-06, 0.00000000e00], + [1.24540000e-01, 2.19553929e-06, 0.00000000e00], + [1.30770000e-01, 2.19553929e-06, 0.00000000e00], + [1.37300000e-01, 2.19553929e-06, 0.00000000e00], + [1.44170000e-01, 2.19553929e-06, 0.00000000e00], + [1.51380000e-01, 2.19553929e-06, 0.00000000e00], + [1.58950000e-01, 2.19553929e-06, 0.00000000e00], + [1.66890000e-01, 2.19553929e-06, 0.00000000e00], + [1.75240000e-01, 2.19553929e-06, 0.00000000e00], + [1.84000000e-01, 2.19553929e-06, 0.00000000e00], + [1.93200000e-01, 2.19553929e-06, 0.00000000e00], + [2.02860000e-01, 2.19553929e-06, 0.00000000e00], + [2.13000000e-01, 2.19553929e-06, 0.00000000e00], + [2.23650000e-01, 2.19553929e-06, 0.00000000e00], + [2.34840000e-01, 2.19553929e-06, 0.00000000e00], + [2.46580000e-01, 2.19553929e-06, 0.00000000e00], + [2.58910000e-01, 2.19553929e-06, 0.00000000e00], + [2.71850000e-01, 2.19553929e-06, 0.00000000e00], + [2.85440000e-01, 2.19553929e-06, 0.00000000e00], + [2.99720000e-01, 2.19553929e-06, 0.00000000e00], + [3.14700000e-01, 2.19553929e-06, 0.00000000e00], + [3.30440000e-01, 2.19553929e-06, 0.00000000e00], + [3.46960000e-01, 2.19553929e-06, 0.00000000e00], + [3.64310000e-01, 2.19553929e-06, 0.00000000e00], + [3.82520000e-01, 2.19553929e-06, 0.00000000e00], + [4.01650000e-01, 2.19553929e-06, 0.00000000e00], + [4.21730000e-01, 2.19553929e-06, 0.00000000e00], + [4.42820000e-01, 2.19553929e-06, 0.00000000e00], + [4.64960000e-01, 2.19553929e-06, 0.00000000e00], + [4.88210000e-01, 2.19553929e-06, 0.00000000e00], + [5.12620000e-01, 2.19553929e-06, 0.00000000e00], + [5.38250000e-01, 2.19553929e-06, 0.00000000e00], + [5.65160000e-01, 2.19553929e-06, 0.00000000e00], + [5.93420000e-01, 2.19553929e-06, 0.00000000e00], + ] + ), + ], + resolutions=[ + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), + np.array( + [ + [0.011403, 0.03], + [0.011973, 0.03], + [0.012572, 0.03], + [0.013201, 0.03], + [0.013861, 0.03], + [0.014554, 0.03], + [0.015281, 0.03], + [0.016045, 0.03], + [0.016848, 0.03], + [0.01769, 0.03], + [0.018575, 0.03], + [0.019503, 0.03], + [0.020479, 0.03], + [0.021502, 0.03], + [0.022578, 0.03], + [0.023706, 0.03], + [0.024892, 0.03], + [0.026136, 0.03], + [0.027443, 0.03], + [0.028815, 0.03], + [0.030256, 0.03], + [0.031769, 0.03], + [0.033357, 0.03], + [0.035025, 0.03], + [0.036777, 0.03], + [0.038615, 0.03], + [0.040546, 0.03], + [0.042573, 0.03], + [0.044702, 0.03], + [0.046937, 0.03], + [0.049284, 0.03], + [0.051748, 0.03], + [0.054336, 0.03], + [0.057052, 0.03], + [0.059905, 0.03], + [0.0629, 0.03], + [0.066045, 0.03], + [0.069348, 0.03], + [0.072815, 0.03], + [0.076456, 0.03], + [0.080279, 0.03], + [0.084292, 0.03], + [0.088507, 0.03], + [0.092932, 0.03], + [0.097579, 0.03], + [0.10246, 0.03], + [0.10758, 0.03], + [0.11296, 0.03], + [0.11861, 0.03], + [0.12454, 0.03], + [0.13077, 0.03], + [0.1373, 0.03], + [0.14417, 0.03], + [0.15138, 0.03], + [0.15895, 0.03], + [0.16689, 0.03], + [0.17524, 0.03], + [0.184, 0.03], + [0.1932, 0.03], + [0.20286, 0.03], + [0.213, 0.03], + [0.22365, 0.03], + [0.23484, 0.03], + [0.24658, 0.03], + [0.25891, 0.03], + [0.27185, 0.03], + [0.28544, 0.03], + [0.29972, 0.03], + [0.3147, 0.03], + [0.33044, 0.03], + [0.34696, 0.03], + [0.36431, 0.03], + [0.38252, 0.03], + [0.40165, 0.03], + [0.42173, 0.03], + [0.44282, 0.03], + [0.46496, 0.03], + [0.48821, 0.03], + [0.51262, 0.03], + [0.53825, 0.03], + [0.56516, 0.03], + [0.59342, 0.03], + ] + ), ], sldProfiles=[ [ @@ -3421,17 +4648,45 @@ def dream_results(): ), ], ], + layers=[ + [ + 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], + ], + ), + ], + ], resampledLayers=[[np.array([[0.0, 0.0, 0.0]])], [np.array([[0.0, 0.0, 0.0]])]], - calculationResults=RATapi.outputs.CalculationResults( + calculationResults=ratapi.outputs.CalculationResults( chiValues=np.array([4.6077885, 7.00028098]), sumChi=11.608069475997699, ), - contrastParams=RATapi.outputs.ContrastParams( - backgroundParams=np.array([2.37113128e-06, 1.99006694e-06]), + contrastParams=ratapi.outputs.ContrastParams( scalefactors=np.array([0.1, 0.15]), bulkIn=np.array([2.073e-06, 2.073e-06]), 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]), ), @@ -3477,7 +4732,7 @@ def dream_results(): "D2O", "SMW", ], - predictionIntervals=RATapi.outputs.PredictionIntervals( + predictionIntervals=ratapi.outputs.PredictionIntervals( reflectivity=[ np.array( [ @@ -3752,7 +5007,6 @@ def dream_results(): 9.14706158e-07, 9.14597081e-07, 9.14576711e-07, - 9.14569865e-07, ], [ -2.26996619e-06, @@ -3784,7 +5038,6 @@ def dream_results(): 9.14706158e-07, 9.14597081e-07, 9.14576711e-07, - 9.14569865e-07, ], [ -1.50598689e-07, @@ -3816,7 +5069,6 @@ def dream_results(): 3.33756709e-06, 3.33751126e-06, 3.33750083e-06, - 3.33749733e-06, ], [ 2.07300000e-06, @@ -3848,7 +5100,6 @@ def dream_results(): 5.87958511e-06, 5.87958515e-06, 5.87958515e-06, - 5.87958515e-06, ], [ 2.07300000e-06, @@ -3880,7 +5131,6 @@ def dream_results(): 5.87958511e-06, 5.87958515e-06, 5.87958515e-06, - 5.87958515e-06, ], ] ), @@ -3916,7 +5166,6 @@ def dream_results(): 4.65378471e-06, 4.65378475e-06, 4.65378475e-06, - 4.65378475e-06, ], [ -1.35107208e-06, @@ -3948,7 +5197,6 @@ def dream_results(): 4.65378471e-06, 4.65378475e-06, 4.65378475e-06, - 4.65378475e-06, ], [ 3.19875093e-07, @@ -3980,7 +5228,6 @@ def dream_results(): 4.92196879e-06, 4.92248720e-06, 4.92261931e-06, - 4.92266441e-06, ], [ 2.07300000e-06, @@ -4012,7 +5259,6 @@ def dream_results(): 5.17758173e-06, 5.17859423e-06, 5.17885226e-06, - 5.17894035e-06, ], [ 2.07300000e-06, @@ -4044,144 +5290,11 @@ def dream_results(): 5.17758173e-06, 5.17859423e-06, 5.17885226e-06, - 5.17894035e-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, @@ -5187,7 +6300,7 @@ def dream_results(): ], ), ), - confidenceIntervals=RATapi.outputs.ConfidenceIntervals( + confidenceIntervals=ratapi.outputs.ConfidenceIntervals( percentile65=np.array( [ [ @@ -5301,7 +6414,7 @@ def dream_results(): ], ), ), - dreamParams=RATapi.outputs.DreamParams( + dreamParams=ratapi.outputs.DreamParams( nParams=18.0, nChains=1.0, nGenerations=1.0, @@ -5322,7 +6435,7 @@ def dream_results(): storeOutput=False, R=np.array([[0.0]]), ), - dreamOutput=RATapi.outputs.DreamOutput( + dreamOutput=ratapi.outputs.DreamOutput( allChains=np.array( [ [ @@ -5352,7 +6465,6 @@ def dream_results(): 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( [ @@ -5381,8 +6493,9 @@ def dream_results(): ), CR=np.array([[1.0, 0.33333333, 0.33333333, 0.33333333]]), ), - nestedSamplerOutput=RATapi.outputs.NestedSamplerOutput( + nestedSamplerOutput=ratapi.outputs.NestedSamplerOutput( logZ=0.0, + logZErr=0.0, nestSamples=np.array([[0.0, 0.0]]), postSamples=np.array([[0.0, 0.0]]), ), @@ -5433,18 +6546,29 @@ def dream_results(): ) +@pytest.fixture +def nested_sampler_results(dream_results): + results = dream_results + results.nestedSamplerOutput = ratapi.outputs.NestedSamplerOutput( + logZ=-28.99992503667041, + logZErr=0.3391187711291207, + nestSamples=np.ones((100, 9)), + postSamples=np.ones((100, 10)), + ) + return results + + @pytest.fixture def r1_default_project(): """The Project corresponding to the data in R1defaultProject.mat.""" - - project = RATapi.Project( + project = ratapi.Project( name="defaultProject", - calculation="non polarised", + calculation="normal", model="standard layers", geometry="air/substrate", absorption=False, - parameters=RATapi.ClassList( - RATapi.models.Parameter( + parameters=ratapi.ClassList( + ratapi.models.Parameter( name="Substrate Roughness", min=3.0, value=4.844363132849221, @@ -5455,8 +6579,8 @@ def r1_default_project(): sigma=np.inf, ) ), - bulk_in=RATapi.ClassList( - RATapi.models.Parameter( + bulk_in=ratapi.ClassList( + ratapi.models.Parameter( name="Air", min=0.0, value=0.0, @@ -5467,8 +6591,8 @@ def r1_default_project(): sigma=np.inf, ) ), - bulk_out=RATapi.ClassList( - RATapi.models.Parameter( + bulk_out=ratapi.ClassList( + ratapi.models.Parameter( name="D2O", min=6.3e-06, value=6.35e-06, @@ -5479,8 +6603,8 @@ def r1_default_project(): sigma=np.inf, ) ), - scalefactors=RATapi.ClassList( - RATapi.models.Parameter( + scalefactors=ratapi.ClassList( + ratapi.models.Parameter( name="Scalefactor 1", min=0.009999999776482582, value=0.10141560336360426, @@ -5491,11 +6615,11 @@ def r1_default_project(): sigma=np.inf, ) ), - backgrounds=RATapi.ClassList( - RATapi.models.Background(name="Background 1", type="constant", value_1="Background parameter 1") + backgrounds=ratapi.ClassList( + ratapi.models.Background(name="Background 1", type="constant", source="Background parameter 1") ), - background_parameters=RATapi.ClassList( - RATapi.models.Parameter( + background_parameters=ratapi.ClassList( + ratapi.models.Parameter( name="Background parameter 1", min=5e-08, value=3.069003361230152e-06, @@ -5506,11 +6630,11 @@ def r1_default_project(): sigma=np.inf, ) ), - resolutions=RATapi.ClassList( - RATapi.models.Resolution(name="Resolution 1", type="constant", value_1="Resolution parameter 1") + resolutions=ratapi.ClassList( + ratapi.models.Resolution(name="Resolution 1", type="constant", source="Resolution parameter 1") ), - resolution_parameters=RATapi.ClassList( - RATapi.models.Parameter( + resolution_parameters=ratapi.ClassList( + ratapi.models.Parameter( name="Resolution parameter 1", min=0.01, value=0.03, @@ -5602,15 +6726,15 @@ def r1_default_project(): @pytest.fixture def r1_monolayer(): """The Project file corresponding to the data in R1monolayerVolumeModel.mat.""" - project = RATapi.Project( + project = ratapi.Project( name="monolayerVolumeModel", - calculation="non polarised", + calculation="normal", model="custom layers", geometry="air/substrate", absorption=False, - parameters=RATapi.ClassList( + parameters=ratapi.ClassList( [ - RATapi.models.Parameter( + ratapi.models.Parameter( name="Substrate Roughness", min=1.0, value=2.9979642781948908, @@ -5620,7 +6744,7 @@ def r1_monolayer(): mu=0.0, sigma=np.inf, ), - RATapi.models.Parameter( + ratapi.models.Parameter( name="Area per molecule", min=47.0, value=53.052680457664785, @@ -5630,7 +6754,7 @@ def r1_monolayer(): mu=0.0, sigma=np.inf, ), - RATapi.models.Parameter( + ratapi.models.Parameter( name="Head Thickness", min=7.0, value=12.276333836779942, @@ -5640,7 +6764,7 @@ def r1_monolayer(): mu=0.0, sigma=np.inf, ), - RATapi.models.Parameter( + ratapi.models.Parameter( name="Theta", min=0.0, value=28.870541049836262, @@ -5652,8 +6776,8 @@ def r1_monolayer(): ), ] ), - bulk_in=RATapi.ClassList( - RATapi.models.Parameter( + bulk_in=ratapi.ClassList( + ratapi.models.Parameter( name="Air", min=0.0, value=0.0, @@ -5665,9 +6789,9 @@ def r1_monolayer(): ) ), bulk_out=( - RATapi.ClassList( + ratapi.ClassList( [ - RATapi.models.Parameter( + ratapi.models.Parameter( name="D2O", min=6.3e-06, value=6.35e-06, @@ -5677,7 +6801,7 @@ def r1_monolayer(): mu=0.0, sigma=np.inf, ), - RATapi.models.Parameter( + ratapi.models.Parameter( name="ACMW", min=-5e-07, value=0.0, @@ -5690,8 +6814,8 @@ def r1_monolayer(): ] ) ), - scalefactors=RATapi.ClassList( - RATapi.models.Parameter( + scalefactors=ratapi.ClassList( + ratapi.models.Parameter( name="Scalefactor 1", min=0.1, value=0.2272676786810902, @@ -5702,15 +6826,15 @@ def r1_monolayer(): sigma=np.inf, ) ), - backgrounds=RATapi.ClassList( + backgrounds=ratapi.ClassList( [ - RATapi.models.Background(name="Background D2O", type="constant", value_1="Background parameter 1"), - RATapi.models.Background(name="Background ACMW", type="constant", value_1="Background parameter 2"), + ratapi.models.Background(name="Background D2O", type="constant", source="Background parameter 1"), + ratapi.models.Background(name="Background ACMW", type="constant", source="Background parameter 2"), ] ), - background_parameters=RATapi.ClassList( + background_parameters=ratapi.ClassList( [ - RATapi.models.Parameter( + ratapi.models.Parameter( name="Background parameter 1", min=1e-07, value=2.2653463958223856e-06, @@ -5720,7 +6844,7 @@ def r1_monolayer(): mu=0.0, sigma=np.inf, ), - RATapi.models.Parameter( + ratapi.models.Parameter( name="Background parameter 2", min=1e-07, value=5.7431759430575025e-06, @@ -5732,11 +6856,11 @@ def r1_monolayer(): ), ] ), - resolutions=RATapi.ClassList( - RATapi.models.Resolution(name="Resolution 1", type="constant", value_1="Resolution parameter 1") + resolutions=ratapi.ClassList( + ratapi.models.Resolution(name="Resolution 1", type="constant", source="Resolution parameter 1") ), - resolution_parameters=RATapi.ClassList( - RATapi.models.Parameter( + resolution_parameters=ratapi.ClassList( + ratapi.models.Parameter( name="Resolution parameter 1", min=0.01, value=0.03, @@ -5747,9 +6871,13 @@ def r1_monolayer(): sigma=np.inf, ) ), - custom_files=RATapi.ClassList( - RATapi.models.CustomFile( - name="Model_IIb", filename="Model_IIb.m", function_name="Model_IIb", language="matlab", path="" + custom_files=ratapi.ClassList( + ratapi.models.CustomFile( + name="Model_IIb", + filename="Model_IIb.m", + function_name="Model_IIb", + language="matlab", + path=Path(__file__).parent / "test_data", ) ), ) @@ -6262,3 +7390,1158 @@ def r1_monolayer(): ) return project + + +@pytest.fixture +def r1_monolayer_8_contrasts(): + """The Project equivalent of the R1 Monolayer_8_contrasts RasCAL-1 project.""" + return ratapi.Project( + name="20nM_data", + calculation="normal", + model="standard layers", + geometry="air/substrate", + absorption=False, + parameters=[ + ratapi.models.ProtectedParameter( + name="Substrate Roughness", + min=3.0, + value=6.990825828311747, + max=7.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Tails thick", + min=12.0, + value=18.769067940891517, + max=20.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Deuterated tails SLD", + min=5e-06, + value=6.935587727961928e-06, + max=9e-06, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Tails roughness", + min=3.0, + value=3.0000000000074776, + max=7.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Hydrogenated tails SLD", + min=-6e-07, + value=-2.1907853109709215e-07, + max=-2e-07, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Head thickness", + min=7.0, + value=7.000000000117902, + max=12.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Deuterated head SLD", + min=3e-06, + value=5.855129143529369e-06, + max=6e-06, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Head roughness", + min=3.0, + value=3.0000000000000258, + max=7.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Hydrogenated head SLD", + min=1e-06, + value=1.8079398141440577e-06, + max=2e-06, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Head hydration", + min=0.0, + value=9.33740417574095, + max=20.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ], + bulk_in=[ + ratapi.models.Parameter( + name="Air", + min=0.0, + value=0.0, + max=0.0, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + bulk_out=[ + ratapi.models.Parameter( + name="D2O", + min=6.3e-06, + value=6.349999999999999e-06, + max=6.4e-06, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="ACMW", + min=-5e-07, + value=3.492898018624419e-08, + max=5e-07, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ], + scalefactors=[ + ratapi.models.Parameter( + name="Scalefactor 1", + min=0.1, + value=0.23251357931599084, + max=0.4, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + domain_ratios=[], + background_parameters=[ + ratapi.models.Parameter( + name="Background parameter 1", + min=1e-07, + value=2.889465920816701e-06, + max=7e-06, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Background parameter 2", + min=1e-07, + value=5.172884539063037e-06, + max=7e-06, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ], + backgrounds=[ + ratapi.models.Background( + name="Background D2O", + type="constant", + source="Background parameter 1", + ), + ratapi.models.Background( + name="Background ACMW", + type="constant", + source="Background parameter 2", + ), + ], + resolution_parameters=[ + ratapi.models.Parameter( + name="Resolution parameter 1", + min=0.01, + value=0.029999999999999964, + max=0.05, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + resolutions=[ + ratapi.models.Resolution( + name="Resolution 1", + type="constant", + source="Resolution parameter 1", + ) + ], + custom_files=[], + data=[ + ratapi.models.Data( + name="d70acmw20", + data=np.array( + [ + [5.1793e-02, 2.3792e-04, 3.6498e-06], + [5.4383e-02, 2.2030e-04, 3.1361e-06], + [5.7102e-02, 1.9302e-04, 2.6450e-06], + [5.9957e-02, 1.7223e-04, 2.2673e-06], + [6.2955e-02, 1.5210e-04, 1.9699e-06], + [6.6103e-02, 1.3650e-04, 1.7055e-06], + [6.9408e-02, 1.1806e-04, 1.5072e-06], + [7.2878e-02, 1.0904e-04, 1.3658e-06], + [7.6522e-02, 9.5873e-05, 1.2024e-06], + [8.0348e-02, 8.2201e-05, 1.0754e-06], + [8.4365e-02, 7.0764e-05, 9.4576e-07], + [8.8584e-02, 6.2973e-05, 8.3975e-07], + [9.3013e-02, 5.3710e-05, 7.3854e-07], + [9.7664e-02, 4.6651e-05, 6.5893e-07], + [1.0255e-01, 4.0448e-05, 5.8945e-07], + [1.0767e-01, 3.4559e-05, 5.2655e-07], + [1.1306e-01, 2.9817e-05, 4.7806e-07], + [1.1871e-01, 2.5965e-05, 4.4165e-07], + [1.2465e-01, 2.1963e-05, 3.9117e-07], + [1.3088e-01, 1.8535e-05, 3.5668e-07], + [1.3742e-01, 1.6299e-05, 3.4665e-07], + [1.4429e-01, 1.3704e-05, 3.2491e-07], + [1.5151e-01, 1.0571e-05, 2.9830e-07], + [1.5908e-01, 8.9320e-06, 2.9188e-07], + [1.6704e-01, 6.8328e-06, 2.7922e-07], + [1.7539e-01, 5.7856e-06, 2.7261e-07], + [1.8416e-01, 4.5358e-06, 2.5335e-07], + [1.9337e-01, 3.9935e-06, 2.5336e-07], + [2.0304e-01, 3.1800e-06, 5.2440e-07], + [2.1319e-01, 2.7006e-06, 4.6690e-07], + [2.2385e-01, 2.2210e-06, 4.5090e-07], + [2.3504e-01, 1.6163e-06, 4.9340e-07], + [2.4679e-01, 1.7554e-06, 3.2120e-07], + [2.5913e-01, 1.3194e-06, 1.7170e-07], + [2.7209e-01, 1.5033e-06, 3.4760e-07], + [2.8569e-01, 1.3801e-06, 7.2017e-07], + [2.9998e-01, 1.2640e-06, 4.5486e-07], + [3.1497e-01, 1.0585e-06, 3.6820e-07], + [3.3072e-01, 1.3063e-06, 4.5401e-07], + [3.4726e-01, 1.1229e-06, 2.3240e-07], + [3.6462e-01, 1.5197e-06, 4.8780e-07], + [3.8285e-01, 1.1419e-06, 4.1880e-07], + [4.0200e-01, 1.3285e-06, 4.0215e-07], + [4.2210e-01, 1.2467e-06, 5.8010e-07], + [4.4320e-01, 1.1322e-06, 3.2730e-07], + [4.6536e-01, 1.1336e-06, 4.3291e-07], + [4.8863e-01, 1.4843e-06, 5.0110e-07], + [5.1306e-01, 1.2055e-06, 3.0660e-07], + [5.3871e-01, 1.2170e-06, 4.0500e-07], + [5.6565e-01, 8.9674e-07, 3.5866e-07], + [5.8877e-01, 9.4625e-07, 7.6511e-07], + ] + ), + data_range=[0.051793, 0.58877], + simulation_range=[0.051793, 0.58877], + ), + ratapi.models.Data( + name="d70d2o20", + data=np.array( + [ + [5.1793e-02, 1.4943e-04, 3.2517e-06], + [5.4383e-02, 1.1882e-04, 2.5846e-06], + [5.7102e-02, 9.2164e-05, 2.0507e-06], + [5.9957e-02, 7.7813e-05, 1.7070e-06], + [6.2955e-02, 6.1143e-05, 1.3983e-06], + [6.6103e-02, 4.8033e-05, 1.1343e-06], + [6.9408e-02, 4.1379e-05, 1.0006e-06], + [7.2878e-02, 3.5090e-05, 8.6919e-07], + [7.6522e-02, 3.0350e-05, 7.5890e-07], + [8.0348e-02, 2.4115e-05, 6.5226e-07], + [8.4365e-02, 2.0755e-05, 5.7445e-07], + [8.8584e-02, 1.7500e-05, 4.9617e-07], + [9.3013e-02, 1.5011e-05, 4.3754e-07], + [9.7664e-02, 1.3632e-05, 3.9907e-07], + [1.0255e-01, 1.2997e-05, 3.7469e-07], + [1.0767e-01, 1.1656e-05, 3.4282e-07], + [1.1306e-01, 1.0820e-05, 3.2299e-07], + [1.1871e-01, 9.5831e-06, 3.0088e-07], + [1.2465e-01, 8.9996e-06, 2.8102e-07], + [1.3088e-01, 8.6498e-06, 2.7363e-07], + [1.3742e-01, 7.9412e-06, 2.7158e-07], + [1.4429e-01, 7.4042e-06, 2.6829e-07], + [1.5151e-01, 6.8321e-06, 2.6877e-07], + [1.5908e-01, 5.6809e-06, 2.6232e-07], + [1.6704e-01, 5.6646e-06, 2.8607e-07], + [1.7539e-01, 4.7762e-06, 2.7767e-07], + [1.8416e-01, 4.1971e-06, 2.7353e-07], + [1.9337e-01, 4.1815e-06, 2.9140e-07], + [2.0304e-01, 3.2725e-06, 2.3160e-07], + [2.1319e-01, 2.3244e-06, 4.2270e-07], + [2.2385e-01, 2.2892e-06, 1.4970e-07], + [2.3504e-01, 1.9198e-06, 8.1460e-07], + [2.4679e-01, 1.4828e-06, 1.0840e-07], + [2.5913e-01, 1.1450e-06, 4.7440e-07], + [2.7209e-01, 1.3047e-06, 1.8840e-07], + [2.8569e-01, 9.6081e-07, 3.9385e-07], + [2.9998e-01, 8.2280e-07, 2.3955e-07], + [3.1497e-01, 6.3219e-07, 3.5324e-07], + [3.3072e-01, 6.1254e-07, 5.0846e-07], + [3.4726e-01, 7.4092e-07, 2.2312e-07], + [3.6462e-01, 6.3584e-07, 4.2866e-07], + [3.8285e-01, 7.7287e-07, 2.9493e-07], + [4.0200e-01, 9.4637e-07, 2.3347e-07], + [4.2210e-01, 7.0576e-07, 3.3494e-07], + [4.4320e-01, 7.8969e-07, 2.3371e-07], + [4.6536e-01, 5.8374e-07, 3.2624e-07], + [4.8863e-01, 5.6711e-07, 6.0419e-07], + [5.1306e-01, 4.7782e-07, 3.4822e-07], + [5.3871e-01, 6.3813e-07, 4.3279e-07], + [5.6565e-01, 4.6186e-07, 1.8863e-07], + [5.8877e-01, 5.6129e-07, 4.3960e-07], + ] + ), + data_range=[0.051793, 0.58877], + simulation_range=[0.051793, 0.58877], + ), + ratapi.models.Data( + name="d13acmw20", + data=np.array( + [ + [5.1793e-02, 1.8087e-05, 7.9683e-07], + [5.4383e-02, 1.4582e-05, 6.3691e-07], + [5.7102e-02, 1.3621e-05, 5.5407e-07], + [5.9957e-02, 1.2409e-05, 4.8014e-07], + [6.2955e-02, 1.0992e-05, 4.1824e-07], + [6.6103e-02, 1.0619e-05, 3.7541e-07], + [6.9408e-02, 1.0162e-05, 3.4945e-07], + [7.2878e-02, 1.0716e-05, 3.3763e-07], + [7.6522e-02, 8.3468e-06, 2.8040e-07], + [8.0348e-02, 7.5250e-06, 2.5702e-07], + [8.4365e-02, 6.4395e-06, 2.2528e-07], + [8.8584e-02, 6.0544e-06, 2.0545e-07], + [9.3013e-02, 5.9517e-06, 1.9417e-07], + [9.7664e-02, 5.6433e-06, 1.8108e-07], + [1.0255e-01, 4.8172e-06, 1.6076e-07], + [1.0767e-01, 4.8066e-06, 1.5520e-07], + [1.1306e-01, 4.1559e-06, 1.4115e-07], + [1.1871e-01, 4.1418e-06, 1.3926e-07], + [1.2465e-01, 3.4580e-06, 1.2273e-07], + [1.3088e-01, 3.2376e-06, 1.1791e-07], + [1.3742e-01, 3.0976e-06, 1.1948e-07], + [1.4429e-01, 2.7478e-06, 1.1518e-07], + [1.5151e-01, 2.5492e-06, 1.1573e-07], + [1.5908e-01, 2.7500e-06, 1.2812e-07], + [1.6704e-01, 2.1813e-06, 2.0450e-07], + [1.7539e-01, 1.8609e-06, 5.4900e-07], + [1.8416e-01, 1.9405e-06, 1.5660e-07], + [1.9337e-01, 1.7421e-06, 2.3280e-07], + [2.0304e-01, 1.8050e-06, 3.9820e-07], + [2.1319e-01, 1.5801e-06, 1.4110e-07], + [2.2385e-01, 1.6724e-06, 7.7900e-08], + [2.3504e-01, 1.4150e-06, 4.0820e-07], + [2.4679e-01, 1.4340e-06, 5.3180e-07], + [2.5913e-01, 1.3102e-06, 2.6000e-07], + [2.7209e-01, 1.3702e-06, 2.8540e-07], + [2.8569e-01, 1.2468e-06, 2.3230e-07], + [2.9998e-01, 1.2956e-06, 5.3240e-07], + [3.1497e-01, 1.2947e-06, 3.9940e-07], + [3.3072e-01, 1.2488e-06, 2.1390e-07], + [3.4726e-01, 1.4620e-06, 3.3640e-07], + [3.6462e-01, 1.3056e-06, 2.1600e-07], + [3.8285e-01, 1.4553e-06, 2.3170e-07], + [4.0200e-01, 1.1579e-06, 2.6740e-07], + [4.2210e-01, 1.1753e-06, 3.0940e-07], + [4.4320e-01, 1.0066e-06, 5.2040e-07], + [4.6536e-01, 1.1043e-06, 3.1870e-07], + [4.8863e-01, 1.2969e-06, 4.1670e-07], + [5.1306e-01, 1.2495e-06, 2.0890e-07], + [5.3871e-01, 1.3898e-06, 4.7560e-07], + [5.6565e-01, 1.1225e-06, 3.0470e-07], + [5.8877e-01, 8.3346e-07, 3.8944e-07], + ] + ), + data_range=[0.051793, 0.58877], + simulation_range=[0.051793, 0.58877], + ), + ratapi.models.Data( + name="d13d2o20", + data=np.array( + [ + [5.1793e-02, 2.2464e-04, 3.4007e-06], + [5.4383e-02, 1.8531e-04, 2.7523e-06], + [5.7102e-02, 1.5463e-04, 2.2639e-06], + [5.9957e-02, 1.2459e-04, 1.8443e-06], + [6.2955e-02, 1.0332e-04, 1.5526e-06], + [6.6103e-02, 8.3207e-05, 1.2736e-06], + [6.9408e-02, 6.6859e-05, 1.0850e-06], + [7.2878e-02, 5.5540e-05, 9.3212e-07], + [7.6522e-02, 4.6869e-05, 8.0410e-07], + [8.0348e-02, 3.6672e-05, 6.8717e-07], + [8.4365e-02, 3.0955e-05, 5.9837e-07], + [8.8584e-02, 2.4781e-05, 5.0395e-07], + [9.3013e-02, 2.0163e-05, 4.3266e-07], + [9.7664e-02, 1.7194e-05, 3.8276e-07], + [1.0255e-01, 1.3801e-05, 3.2953e-07], + [1.0767e-01, 1.0868e-05, 2.8268e-07], + [1.1306e-01, 8.9118e-06, 2.5019e-07], + [1.1871e-01, 8.2266e-06, 2.3789e-07], + [1.2465e-01, 6.7891e-06, 2.0822e-07], + [1.3088e-01, 5.5048e-06, 1.8610e-07], + [1.3742e-01, 4.3011e-06, 1.7064e-07], + [1.4429e-01, 3.7549e-06, 1.6291e-07], + [1.5151e-01, 3.0281e-06, 1.5298e-07], + [1.5908e-01, 2.7102e-06, 1.5371e-07], + [1.6704e-01, 1.9817e-06, 5.2560e-07], + [1.7539e-01, 1.8156e-06, 6.2930e-07], + [1.8416e-01, 1.6126e-06, 1.0180e-07], + [1.9337e-01, 1.5010e-06, 2.6400e-07], + [2.0304e-01, 1.3504e-06, 3.6310e-07], + [2.1319e-01, 1.0658e-06, 6.1751e-07], + [2.2385e-01, 1.0028e-06, 2.4871e-07], + [2.3504e-01, 9.1701e-07, 2.3499e-07], + [2.4679e-01, 7.5092e-07, 2.4518e-07], + [2.5913e-01, 1.0126e-06, 1.6429e-07], + [2.7209e-01, 7.5725e-07, 4.1481e-07], + [2.8569e-01, 6.2167e-07, 3.5735e-07], + [2.9998e-01, 7.0777e-07, 2.0772e-07], + [3.1497e-01, 8.5576e-07, 1.6916e-07], + [3.3072e-01, 8.4284e-07, 2.2151e-07], + [3.4726e-01, 4.4441e-07, 3.2246e-07], + [3.6462e-01, 6.6378e-07, 2.3675e-07], + [3.8285e-01, 7.1382e-07, 3.7039e-07], + [4.0200e-01, 5.6163e-07, 4.4157e-07], + [4.2210e-01, 5.9761e-07, 3.4927e-07], + [4.4320e-01, 4.9182e-07, 3.5155e-07], + [4.6536e-01, 5.6609e-07, 2.3558e-07], + [4.8863e-01, 5.3547e-07, 1.7267e-07], + [5.1306e-01, 4.7647e-07, 5.4127e-07], + [5.3871e-01, 3.8841e-07, 2.9179e-07], + [5.6565e-01, 4.7749e-07, 8.6240e-08], + [5.8877e-01, 4.6278e-07, 2.3214e-07], + ] + ), + data_range=[0.051793, 0.58877], + simulation_range=[0.051793, 0.58877], + ), + ratapi.models.Data( + name="d83acmw20", + data=np.array( + [ + [5.1793e-02, 3.1675e-04, 4.7735e-06], + [5.4383e-02, 2.7591e-04, 3.9806e-06], + [5.7102e-02, 2.4370e-04, 3.3680e-06], + [5.9957e-02, 2.1836e-04, 2.8915e-06], + [6.2955e-02, 1.9492e-04, 2.5226e-06], + [6.6103e-02, 1.7128e-04, 2.1638e-06], + [6.9408e-02, 1.5381e-04, 1.9499e-06], + [7.2878e-02, 1.3398e-04, 1.7140e-06], + [7.6522e-02, 1.1643e-04, 1.5011e-06], + [8.0348e-02, 9.7386e-05, 1.3256e-06], + [8.4365e-02, 8.5091e-05, 1.1744e-06], + [8.8584e-02, 7.2996e-05, 1.0224e-06], + [9.3013e-02, 6.0693e-05, 8.8816e-07], + [9.7664e-02, 5.1967e-05, 7.8767e-07], + [1.0255e-01, 4.3371e-05, 6.9118e-07], + [1.0767e-01, 3.6363e-05, 6.1123e-07], + [1.1306e-01, 2.9948e-05, 5.4231e-07], + [1.1871e-01, 2.5863e-05, 4.9879e-07], + [1.2465e-01, 2.1196e-05, 4.3527e-07], + [1.3088e-01, 1.7278e-05, 3.8999e-07], + [1.3742e-01, 1.3647e-05, 3.5922e-07], + [1.4429e-01, 1.0898e-05, 3.2810e-07], + [1.5151e-01, 8.3399e-06, 2.9972e-07], + [1.5908e-01, 6.7776e-06, 2.8761e-07], + [1.6704e-01, 5.8668e-06, 2.9311e-07], + [1.7539e-01, 4.1380e-06, 2.6133e-07], + [1.8416e-01, 2.7663e-06, 2.2329e-07], + [1.9337e-01, 2.3200e-06, 2.1903e-07], + [2.0304e-01, 1.9127e-06, 5.6910e-07], + [2.1319e-01, 1.7434e-06, 1.2640e-07], + [2.2385e-01, 1.7550e-06, 1.9990e-07], + [2.3504e-01, 1.4527e-06, 3.8840e-07], + [2.4679e-01, 1.1333e-06, 5.9440e-07], + [2.5913e-01, 1.1667e-06, 5.7100e-07], + [2.7209e-01, 1.3539e-06, 2.1560e-07], + [2.8569e-01, 1.5357e-06, 3.5990e-07], + [2.9998e-01, 9.0768e-07, 8.9822e-07], + [3.1497e-01, 1.2821e-06, 3.1450e-07], + [3.3072e-01, 1.2360e-06, 4.1700e-07], + [3.4726e-01, 9.6932e-07, 4.5458e-07], + [3.6462e-01, 1.4644e-06, 4.7300e-07], + [3.8285e-01, 1.2330e-06, 3.4780e-07], + [4.0200e-01, 1.3783e-06, 4.5143e-07], + [4.2210e-01, 1.2637e-06, 2.4980e-07], + [4.4320e-01, 1.1299e-06, 1.9310e-07], + [4.6536e-01, 1.1748e-06, 4.3340e-07], + [4.8863e-01, 1.2029e-06, 1.4040e-07], + [5.1306e-01, 9.9648e-07, 6.1262e-07], + [5.3871e-01, 9.4235e-07, 6.9825e-07], + [5.6565e-01, 1.2561e-06, 4.5650e-07], + [5.8877e-01, 1.0005e-06, 1.1520e-07], + ] + ), + data_range=[0.051793, 0.58877], + simulation_range=[0.051793, 0.58877], + ), + ratapi.models.Data( + name="d83d2o20", + data=np.array( + [ + [5.1793e-02, 2.3497e-04, 4.1366e-06], + [5.4383e-02, 1.9138e-04, 3.3298e-06], + [5.7102e-02, 1.6092e-04, 2.7523e-06], + [5.9957e-02, 1.3177e-04, 2.2579e-06], + [6.2955e-02, 1.0694e-04, 1.8785e-06], + [6.6103e-02, 9.0449e-05, 1.5805e-06], + [6.9408e-02, 7.2115e-05, 1.3407e-06], + [7.2878e-02, 5.9602e-05, 1.1494e-06], + [7.6522e-02, 4.9097e-05, 9.7903e-07], + [8.0348e-02, 4.1264e-05, 8.6633e-07], + [8.4365e-02, 3.2611e-05, 7.3101e-07], + [8.8584e-02, 2.7676e-05, 6.3311e-07], + [9.3013e-02, 2.2224e-05, 5.4031e-07], + [9.7664e-02, 1.9035e-05, 4.7882e-07], + [1.0255e-01, 1.5324e-05, 4.1267e-07], + [1.0767e-01, 1.3008e-05, 3.6731e-07], + [1.1306e-01, 1.0121e-05, 3.1672e-07], + [1.1871e-01, 9.3837e-06, 3.0201e-07], + [1.2465e-01, 7.4003e-06, 2.5840e-07], + [1.3088e-01, 6.6417e-06, 2.4288e-07], + [1.3742e-01, 5.5185e-06, 2.2950e-07], + [1.4429e-01, 4.6301e-06, 2.1511e-07], + [1.5151e-01, 3.8179e-06, 2.0421e-07], + [1.5908e-01, 3.6504e-06, 2.1327e-07], + [1.6704e-01, 3.3693e-06, 5.8910e-07], + [1.7539e-01, 2.9089e-06, 6.0910e-07], + [1.8416e-01, 2.0826e-06, 8.8760e-07], + [1.9337e-01, 1.8413e-06, 2.0110e-07], + [2.0304e-01, 1.7280e-06, 4.2860e-07], + [2.1319e-01, 2.0794e-06, 4.5100e-07], + [2.2385e-01, 1.2345e-06, 4.2410e-07], + [2.3504e-01, 1.3707e-06, 2.7770e-07], + [2.4679e-01, 1.2666e-06, 9.8800e-08], + [2.5913e-01, 1.1391e-06, 6.9332e-07], + [2.7209e-01, 1.1299e-06, 2.1680e-07], + [2.8569e-01, 8.4537e-07, 5.3956e-07], + [2.9998e-01, 6.8579e-07, 4.6611e-07], + [3.1497e-01, 8.3948e-07, 3.2138e-07], + [3.3072e-01, 8.8276e-07, 4.6705e-07], + [3.4726e-01, 7.8563e-07, 6.4686e-07], + [3.6462e-01, 6.8788e-07, 3.9930e-07], + [3.8285e-01, 6.1412e-07, 1.8886e-07], + [4.0200e-01, 6.8538e-07, 4.0952e-07], + [4.2210e-01, 5.8111e-07, 5.0615e-07], + [4.4320e-01, 5.4626e-07, 2.3667e-07], + [4.6536e-01, 6.5234e-07, 4.2512e-07], + [4.8863e-01, 3.6587e-07, 4.3870e-07], + [5.1306e-01, 4.1699e-07, 1.9893e-07], + [5.3871e-01, 4.9769e-07, 2.1907e-07], + [5.6565e-01, 3.7836e-07, 3.9193e-07], + [5.8877e-01, 4.2082e-07, 3.5255e-07], + ] + ), + data_range=[0.051793, 0.58877], + simulation_range=[0.051793, 0.58877], + ), + ratapi.models.Data( + name="hd2o20", + data=np.array( + [ + [5.1793e-02, 2.1311e-04, 3.8170e-06], + [5.4383e-02, 1.7454e-04, 3.0814e-06], + [5.7102e-02, 1.4351e-04, 2.5155e-06], + [5.9957e-02, 1.1515e-04, 2.0424e-06], + [6.2955e-02, 9.0901e-05, 1.6762e-06], + [6.6103e-02, 7.4677e-05, 1.3909e-06], + [6.9408e-02, 6.1965e-05, 1.2044e-06], + [7.2878e-02, 4.9933e-05, 1.0186e-06], + [7.6522e-02, 4.1322e-05, 8.7025e-07], + [8.0348e-02, 3.2145e-05, 7.4114e-07], + [8.4365e-02, 2.6927e-05, 6.4343e-07], + [8.8584e-02, 2.0970e-05, 5.3415e-07], + [9.3013e-02, 1.6109e-05, 4.4582e-07], + [9.7664e-02, 1.2974e-05, 3.8305e-07], + [1.0255e-01, 1.0411e-05, 3.2993e-07], + [1.0767e-01, 7.7586e-06, 2.7512e-07], + [1.1306e-01, 6.8947e-06, 2.5357e-07], + [1.1871e-01, 5.5102e-06, 2.2445e-07], + [1.2465e-01, 4.3486e-06, 1.9200e-07], + [1.3088e-01, 3.3433e-06, 1.6724e-07], + [1.3742e-01, 2.7268e-06, 1.5634e-07], + [1.4429e-01, 2.2001e-06, 1.4377e-07], + [1.5151e-01, 1.8064e-06, 1.3591e-07], + [1.5908e-01, 1.4947e-06, 1.3214e-07], + [1.6704e-01, 1.5335e-06, 3.9200e-07], + [1.7539e-01, 1.0430e-06, 8.5200e-08], + [1.8416e-01, 1.0070e-06, 3.9617e-07], + [1.9337e-01, 7.5452e-07, 1.7785e-07], + [2.0304e-01, 6.9356e-07, 2.8065e-07], + [2.1319e-01, 5.9018e-07, 4.0612e-07], + [2.2385e-01, 7.0286e-07, 3.4384e-07], + [2.3504e-01, 6.0890e-07, 2.8376e-07], + [2.4679e-01, 8.0600e-07, 2.2092e-07], + [2.5913e-01, 7.9177e-07, 3.4918e-07], + [2.7209e-01, 8.5193e-07, 3.3083e-07], + [2.8569e-01, 8.1507e-07, 2.7682e-07], + [2.9998e-01, 7.1477e-07, 1.6790e-07], + [3.1497e-01, 6.1835e-07, 2.0612e-07], + [3.3072e-01, 5.7863e-07, 3.3869e-07], + [3.4726e-01, 4.0735e-07, 6.1275e-07], + [3.6462e-01, 8.2937e-07, 3.2510e-07], + [3.8285e-01, 7.5561e-07, 2.0851e-07], + [4.0200e-01, 6.6174e-07, 2.9566e-07], + [4.2210e-01, 5.6503e-07, 2.0503e-07], + [4.4320e-01, 6.5599e-07, 3.0025e-07], + [4.6536e-01, 4.8085e-07, 2.6812e-07], + [4.8863e-01, 4.1179e-07, 2.7538e-07], + [5.1306e-01, 6.0006e-07, 2.6417e-07], + [5.3871e-01, 6.3395e-07, 3.9303e-07], + [5.6565e-01, 6.3474e-07, 2.3217e-07], + [5.8877e-01, 3.3414e-07, 3.9170e-07], + ] + ), + data_range=[0.051793, 0.58877], + simulation_range=[0.051793, 0.58877], + ), + ], + layers=[ + ratapi.models.Layer( + name="Deuterated tails", + thickness="Tails thick", + SLD="Deuterated tails SLD", + roughness="Tails roughness", + hydration="", + hydrate_with="bulk out", + ), + ratapi.models.Layer( + name="Hydrogenated tails", + thickness="Tails thick", + SLD="Hydrogenated tails SLD", + roughness="Tails roughness", + hydration="", + hydrate_with="bulk out", + ), + ratapi.models.Layer( + name="Deuterated heads", + thickness="Head thickness", + SLD="Deuterated head SLD", + roughness="Head roughness", + hydration="Head hydration", + hydrate_with="bulk out", + ), + ratapi.models.Layer( + name="Hydrogenated heads", + thickness="Head thickness", + SLD="Hydrogenated head SLD", + roughness="Head roughness", + hydration="Head hydration", + hydrate_with="bulk out", + ), + ], + domain_contrasts=[], + contrasts=[ + ratapi.models.Contrast( + name="d70, acmw", + data="d70acmw20", + background="Background ACMW", + background_action="add", + bulk_in="Air", + bulk_out="ACMW", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["Deuterated tails", "Hydrogenated heads"], + ), + ratapi.models.Contrast( + name="d70 d2o", + data="d70d2o20", + background="Background D2O", + background_action="add", + bulk_in="Air", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["Deuterated tails", "Hydrogenated heads"], + ), + ratapi.models.Contrast( + name="d13 acmw", + data="d13acmw20", + background="Background ACMW", + background_action="add", + bulk_in="Air", + bulk_out="ACMW", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["Hydrogenated tails", "Deuterated heads"], + ), + ratapi.models.Contrast( + name="d13 d2o", + data="d13d2o20", + background="Background D2O", + background_action="add", + bulk_in="Air", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["Hydrogenated tails", "Deuterated heads"], + ), + ratapi.models.Contrast( + name="d83 acmw", + data="d83acmw20", + background="Background ACMW", + background_action="add", + bulk_in="Air", + bulk_out="ACMW", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["Deuterated tails", "Deuterated heads"], + ), + ratapi.models.Contrast( + name="d83 d2o", + data="d83d2o20", + background="Background D2O", + background_action="add", + bulk_in="Air", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["Deuterated tails", "Deuterated heads"], + ), + ratapi.models.Contrast( + name="fully h, D2O", + data="hd2o20", + background="Background D2O", + background_action="add", + bulk_in="Air", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["Hydrogenated tails", "Hydrogenated heads"], + ), + ], + ) + + +@pytest.fixture +def r1_orso_polymer(): + """The project equivalent of the RasCAL-1 ORSO Polymer example.""" + # the test data is BIG (400 lines) so it's easier to just load it in + orso_poly_data = np.loadtxt(Path(__file__).parent / "test_data/orso_poly.dat") + + return ratapi.Project( + name="orsoPolymerExample", + calculation="normal", + model="standard layers", + geometry="air/substrate", + absorption=False, + parameters=[ + ratapi.models.ProtectedParameter( + name="Substrate Roughness", + min=3.0, + value=4.844363132849221, + max=8.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + bulk_in=[ + ratapi.models.Parameter( + name="Air", + min=0.0, + value=0.0, + max=0.0, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + bulk_out=[ + ratapi.models.Parameter( + name="D2O", + min=6.3e-06, + value=6.35e-06, + max=6.4e-06, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + scalefactors=[ + ratapi.models.Parameter( + name="Scalefactor 1", + min=0.05, + value=0.10141560336360426, + max=0.3, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + domain_ratios=[], + background_parameters=[ + ratapi.models.Parameter( + name="Background parameter 1", + min=5e-08, + value=3.069003361230152e-06, + max=7e-06, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + backgrounds=[ + ratapi.models.Background( + name="Background 1", + type="constant", + source="Background parameter 1", + ) + ], + resolution_parameters=[ + ratapi.models.Parameter( + name="Resolution parameter 1", + min=0.01, + value=0.03, + max=0.05, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + resolutions=[ + ratapi.models.Resolution( + name="Resolution 1", + type="constant", + source="Resolution parameter 1", + ) + ], + custom_files=[], + data=[ + ratapi.models.Data( + name="polymerData", + data=orso_poly_data, + data_range=[0.0080602, 0.46555], + simulation_range=[0.0080602, 0.46555], + ) + ], + layers=[], + domain_contrasts=[], + contrasts=[ + ratapi.models.Contrast( + name="Chain-d, acmw", + data="polymerData", + background="Background 1", + background_action="add", + bulk_in="Air", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=[], + ) + ], + ) + + +@pytest.fixture +def r1_motofit_bench_mark(): + """The project from the R1motofitBenchMark RasCAL-1 project file.""" + moto_data = np.loadtxt(Path(__file__).parent / "test_data/moto.dat") + + return ratapi.Project( + name="motofitBenchMark", + calculation="normal", + model="standard layers", + geometry="air/substrate", + absorption=False, + parameters=[ + ratapi.models.ProtectedParameter( + name="Substrate Roughness", + min=1.0, + value=3.0, + max=5.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="sub rough", + min=3.0, + value=3.9949146424129665, + max=8.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Thick", + min=0.0, + value=33.2791896400743, + max=100.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="SLD 1", + min=0.0, + value=1.074484187182878e-06, + max=5e-06, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="SLD 2", + min=9e-06, + value=1.0658506835478824e-05, + max=1.2e-05, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Thick2", + min=100.0, + value=498.6676783112137, + max=1000.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Rough 1", + min=2.0, + value=4.563688983733924, + max=7.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ratapi.models.Parameter( + name="Rough 2", + min=2.0, + value=4.410704485333302, + max=7.0, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ), + ], + bulk_in=[ + ratapi.models.Parameter( + name="Air", + min=0.0, + value=0.0, + max=0.0, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + bulk_out=[ + ratapi.models.Parameter( + name="D2O", + min=2e-05, + value=2.01e-05, + max=2.2e-05, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + scalefactors=[ + ratapi.models.Parameter( + name="Scalefactor 1", + min=0.99, + value=0.9999894027309877, + max=1.01, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + domain_ratios=[], + background_parameters=[ + ratapi.models.Parameter( + name="Background parameter 1", + min=5e-08, + value=1.306895319301746e-07, + max=1e-06, + fit=True, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + backgrounds=[ + ratapi.models.Background( + name="Background 1", + type="constant", + source="Background parameter 1", + ) + ], + resolution_parameters=[ + ratapi.models.Parameter( + name="Resolution parameter 1", + min=0.0, + value=0.0, + max=0.05, + fit=False, + prior_type="uniform", + mu=0.0, + sigma=np.inf, + ) + ], + resolutions=[ + ratapi.models.Resolution( + name="Resolution 1", + type="constant", + source="Resolution parameter 1", + ) + ], + custom_files=[], + data=[ + ratapi.models.Data( + name="mFitBench", + data=moto_data, + data_range=[0.02, 0.59188], + simulation_range=[0.02, 0.59188], + ) + ], + layers=[ + ratapi.models.Layer( + name="New Layer 0", + thickness="Thick", + SLD="SLD 1", + roughness="Rough 1", + hydration="", + hydrate_with="bulk out", + ), + ratapi.models.Layer( + name="New Layer 1", + thickness="Thick2", + SLD="SLD 2", + roughness="Rough 2", + hydration="", + hydrate_with="bulk out", + ), + ], + domain_contrasts=[], + contrasts=[ + ratapi.models.Contrast( + name="Chain-d, acmw", + data="mFitBench", + background="Background 1", + background_action="add", + bulk_in="Air", + bulk_out="D2O", + scalefactor="Scalefactor 1", + resolution="Resolution 1", + resample=False, + model=["New Layer 0"], + ) + ], + ) + + +@pytest.fixture +def dspc_standard_layers(): + """The project from the DSPC Standard Layers example.""" + project, _ = ratapi.examples.DSPC_standard_layers() + return project + + +@pytest.fixture +def dspc_custom_layers(): + """The project from the DSPC Custom Layers example.""" + project, _ = ratapi.examples.DSPC_custom_layers() + return project + + +@pytest.fixture +def dspc_custom_xy(): + """The project from the DSPC Custom XY example.""" + project, _ = ratapi.examples.DSPC_custom_XY() + return project + + +@pytest.fixture +def domains_standard_layers(): + """The project from the domains Standard Layers example.""" + project, _ = ratapi.examples.domains_standard_layers() + return project + + +@pytest.fixture +def domains_custom_layers(): + """The project from the domains Custom Layers example.""" + project, _ = ratapi.examples.domains_custom_layers() + return project + + +@pytest.fixture +def domains_custom_xy(): + """The project from the domains Custom XY example.""" + project, _ = ratapi.examples.domains_custom_XY() + return project + + +@pytest.fixture +def absorption(): + """The project from the absorption example.""" + project, _ = ratapi.examples.absorption() + return project + + +@pytest.fixture +def absorption_different_function(): + """The project from the absorption example with a function name different from filename.""" + project, _ = ratapi.examples.absorption() + project.custom_files[0].function_name = "test_func" + return project diff --git a/tests/test_classlist.py b/tests/test_classlist.py index b97bb529..98d9440c 100644 --- a/tests/test_classlist.py +++ b/tests/test_classlist.py @@ -1,13 +1,16 @@ """Test the ClassList.""" +import importlib import re import warnings +from collections import deque from collections.abc import Iterable, Sequence -from typing import Any, Union +from typing import Any +import prettytable import pytest -from RATapi.classlist import ClassList +from ratapi.classlist import ClassList from tests.utils import InputAttributes, SubInputAttributes @@ -42,6 +45,23 @@ def three_name_class_list(): return ClassList([InputAttributes(name="Alice"), InputAttributes(name="Bob"), InputAttributes(name="Eve")]) +class DisplayFieldsClass: + """A classlist with four attributes and a display_fields property.""" + + def __init__(self, display_range): + self.a = 1 + self.b = 2 + self.c = 3 + self.d = 4 + + self.display_range = display_range + + @property + def display_fields(self): + fields = ["a", "b", "c", "d"][self.display_range[0] : self.display_range[1]] + return {f: getattr(self, f) for f in fields} + + class TestInitialisation: @pytest.mark.parametrize( "input_object", @@ -117,7 +137,8 @@ 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__}'", + match=f"This ClassList only supports elements of type {type(input_list[0]).__name__}. In the input list:\n" + f" index 1 is of type {type(input_list[1]).__name__}\n", ): ClassList(input_list) @@ -134,7 +155,9 @@ def test_identical_name_fields(self, input_list: Sequence[object], name_field: s """ with pytest.raises( ValueError, - match=f"Input list contains objects with the same value of the {name_field} attribute", + match=f"The value of the '{name_field}' attribute must be unique for each item in the " + f"ClassList:\n '{getattr(input_list[0], name_field).lower()}'" + f" is shared between items 0 and 1 of the input list", ): ClassList(input_list, name_field=name_field) @@ -169,6 +192,26 @@ def test_str_empty_classlist() -> None: assert str(ClassList()) == str([]) +@pytest.mark.parametrize( + "display_ranges, expected_header", + ( + ([(1, 3), (1, 3), (1, 3)], ["b", "c"]), + ([(1, 2), (0, 4), (2, 3)], ["a", "b", "c", "d"]), + ([(0, 2), (0, 1), (2, 3)], ["a", "b", "c"]), + ), +) +def test_str_display_fields(display_ranges, expected_header): + """If a class has the `display_fields` property, the ClassList should print with the minimal required attributes.""" + class_list = ClassList([DisplayFieldsClass(dr) for dr in display_ranges]) + expected_table = prettytable.PrettyTable() + expected_table.field_names = ["index"] + expected_header + expected_vals = {"a": 1, "b": 2, "c": 3, "d": 4} + row = [expected_vals[v] for v in expected_header] + expected_table.add_rows([[0] + row, [1] + row, [2] + row]) + + assert str(class_list) == expected_table.get_string() + + @pytest.mark.parametrize( ["new_item", "expected_classlist"], [ @@ -194,7 +237,12 @@ def test_setitem(two_name_class_list: ClassList, new_item: InputAttributes, expe ) 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"): + with pytest.raises( + ValueError, + match=f"The value of the '{two_name_class_list.name_field}' attribute must be unique for each item in the " + f"ClassList:\n '{new_item.name.lower()}' is shared between item 1 of the existing ClassList," + f" and item 0 of the input list", + ): two_name_class_list[0] = new_item @@ -206,7 +254,11 @@ def test_setitem_same_name_field(two_name_class_list: ClassList, new_item: Input ) 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="Input list contains elements of type other than 'InputAttributes'"): + with pytest.raises( + ValueError, + match=f"This ClassList only supports elements of type {two_name_class_list._class_handle.__name__}. " + f"In the input list:\n index 0 is of type {type(new_values).__name__}\n", + ): two_name_class_list[0] = new_values @@ -403,7 +455,9 @@ def test_append_object_same_name_field(two_name_class_list: ClassList, new_objec """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", + match=f"The value of the '{two_name_class_list.name_field}' attribute must be unique for each item in the " + f"ClassList:\n '{new_object.name.lower()}' is shared between item 0 of the existing ClassList, and " + f"item 0 of the input list", ): two_name_class_list.append(new_object) @@ -420,7 +474,7 @@ def test_append_kwargs_same_name_field(two_name_class_list: ClassList, new_value 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", + f"which is already specified at index 0 of the ClassList", ): two_name_class_list.append(**new_values) @@ -526,7 +580,9 @@ def test_insert_object_same_name(two_name_class_list: ClassList, new_object: obj """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", + match=f"The value of the '{two_name_class_list.name_field}' attribute must be unique for each item in the " + f"ClassList:\n '{new_object.name.lower()}' is shared between item 0 of the existing " + f"ClassList, and item 0 of the input list", ): two_name_class_list.insert(1, new_object) @@ -543,7 +599,7 @@ def test_insert_kwargs_same_name(two_name_class_list: ClassList, new_values: dic 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", + f"which is already specified at index 0 of the ClassList", ): two_name_class_list.insert(1, **new_values) @@ -555,7 +611,7 @@ def test_insert_kwargs_same_name(two_name_class_list: ClassList, new_values: dic (InputAttributes(name="Bob")), ], ) -def test_remove(two_name_class_list: ClassList, remove_value: Union[object, str]) -> None: +def test_remove(two_name_class_list: ClassList, remove_value: 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. """ @@ -570,7 +626,7 @@ def test_remove(two_name_class_list: ClassList, remove_value: Union[object, str] (InputAttributes(name="Eve")), ], ) -def test_remove_not_present(two_name_class_list: ClassList, remove_value: Union[object, str]) -> None: +def test_remove_not_present(two_name_class_list: ClassList, remove_value: 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) @@ -585,7 +641,7 @@ def test_remove_not_present(two_name_class_list: ClassList, remove_value: Union[ (InputAttributes(name="Eve"), 0), ], ) -def test_count(two_name_class_list: ClassList, count_value: Union[object, str], expected_count: int) -> None: +def test_count(two_name_class_list: ClassList, count_value: 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. """ @@ -599,7 +655,7 @@ def test_count(two_name_class_list: ClassList, count_value: Union[object, str], (InputAttributes(name="Bob"), 1), ], ) -def test_index(two_name_class_list: ClassList, index_value: Union[object, str], expected_index: int) -> None: +def test_index(two_name_class_list: ClassList, index_value: 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. """ @@ -615,7 +671,7 @@ def test_index(two_name_class_list: ClassList, index_value: Union[object, str], ) def test_index_offset( two_name_class_list: ClassList, - index_value: Union[object, str], + index_value: object | str, offset: int, expected_index: int, ) -> None: @@ -632,7 +688,7 @@ def test_index_offset( (InputAttributes(name="Eve")), ], ) -def test_index_not_present(two_name_class_list: ClassList, index_value: Union[object, str]) -> None: +def test_index_not_present(two_name_class_list: ClassList, index_value: 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: with pytest.raises(ValueError): @@ -673,6 +729,7 @@ 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("index", [0, "Alice", InputAttributes(name="Alice")]) @pytest.mark.parametrize( ["new_values", "expected_classlist"], [ @@ -683,10 +740,12 @@ def test_extend_empty_classlist(extended_list: Sequence, one_name_class_list: Cl ), ], ) -def test_set_fields(two_name_class_list: ClassList, new_values: dict[str, Any], expected_classlist: ClassList) -> None: +def test_set_fields( + two_name_class_list: ClassList, index: int | str, 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) + class_list.set_fields(index, **new_values) assert class_list == expected_classlist @@ -702,7 +761,7 @@ def test_set_fields_same_name_field(two_name_class_list: ClassList, new_values: 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", + f"which is already specified at index 1 of the ClassList", ): two_name_class_list.set_fields(0, **new_values) @@ -767,18 +826,19 @@ def test__validate_name_field(two_name_class_list: ClassList, input_dict: dict[s "input_dict", [ ({"name": "Alice"}), - ({"name": "ALICE"}), + ({"name": "BOB"}), ({"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, - accounting for case sensitivity.""" + accounting for case sensitivity. + """ 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", + f"'{input_dict[two_name_class_list.name_field]}', which is already specified at index " + f"{two_name_class_list.index(input_dict['name'].lower())} of the ClassList", ): two_name_class_list._validate_name_field(input_dict) @@ -786,9 +846,9 @@ def test__validate_name_field_not_unique(two_name_class_list: ClassList, input_d @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(name="Eve"), InputAttributes(name="Gareth")]), + ([InputAttributes(surname="Polastri"), InputAttributes(surname="Mallory")]), + ([InputAttributes(name="Eve", surname="Polastri"), InputAttributes(surname="Mallory")]), ([InputAttributes()]), ([]), ], @@ -801,20 +861,59 @@ def test__check_unique_name_fields(two_name_class_list: ClassList, input_list: I @pytest.mark.parametrize( - "input_list", + ["input_list", "error_message"], [ - ([InputAttributes(name="Alice"), InputAttributes(name="Alice")]), - ([InputAttributes(name="Alice"), InputAttributes(name="ALICE")]), - ([InputAttributes(name="Alice"), InputAttributes(name="alice")]), + ( + [InputAttributes(name="Alice"), InputAttributes(name="Bob")], + ( + " 'alice' is shared between item 0 of the existing ClassList, and item 0 of the input list\n" + " 'bob' is shared between item 1 of the existing ClassList, and item 1 of the input list" + ), + ), + ( + [InputAttributes(name="Alice"), InputAttributes(name="Alice")], + " 'alice' is shared between item 0 of the existing ClassList, and items 0 and 1 of the input list", + ), + ( + [InputAttributes(name="Alice"), InputAttributes(name="ALICE")], + " 'alice' is shared between item 0 of the existing ClassList, and items 0 and 1 of the input list", + ), + ( + [InputAttributes(name="Alice"), InputAttributes(name="alice")], + " 'alice' is shared between item 0 of the existing ClassList, and items 0 and 1 of the input list", + ), + ( + [InputAttributes(name="Eve"), InputAttributes(name="Eve")], + " 'eve' is shared between items 0 and 1 of the input list", + ), + ( + [ + InputAttributes(name="Bob"), + InputAttributes(name="Alice"), + InputAttributes(name="Eve"), + InputAttributes(name="Alice"), + InputAttributes(name="Eve"), + InputAttributes(name="Alice"), + ], + ( + " 'bob' is shared between item 1 of the existing ClassList, and item 0 of the input list\n" + " 'alice' is shared between item 0 of the existing ClassList," + " and items 1, 3 and 5 of the input list\n" + " 'eve' is shared between items 2 and 4 of the input list" + ), + ), ], ) -def test__check_unique_name_fields_not_unique(two_name_class_list: ClassList, input_list: Iterable) -> None: +def test__check_unique_name_fields_not_unique( + two_name_class_list: ClassList, input_list: Sequence, error_message: str +) -> None: """We should raise a ValueError if an input list contains multiple objects with (case-insensitive) 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", + match=f"The value of the '{two_name_class_list.name_field}' attribute must be unique for each item in the " + f"ClassList:\n{error_message}", ): two_name_class_list._check_unique_name_fields(input_list) @@ -837,12 +936,15 @@ def test__check_classes(input_list: Iterable) -> None: ([InputAttributes(name="Alice"), dict(name="Bob")]), ], ) -def test__check_classes_different_classes(input_list: Iterable) -> None: +def test__check_classes_different_classes(input_list: Sequence) -> 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__}'"), + match=( + f"This ClassList only supports elements of type {class_list._class_handle.__name__}. " + f"In the input list:\n index 1 is of type {type(input_list[1]).__name__}" + ), ): class_list._check_classes(input_list) @@ -861,7 +963,7 @@ def test__check_classes_different_classes(input_list: Iterable) -> None: def test__get_item_from_name_field( two_name_class_list: ClassList, value: str, - expected_output: Union[object, str], + expected_output: 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. @@ -899,3 +1001,71 @@ def test_get_item(two_name_class_list): alice = InputAttributes(name="Alice") assert two_name_class_list[alice] == two_name_class_list["Alice"] assert two_name_class_list[alice] == two_name_class_list[0] + + +@pytest.mark.skipif(importlib.util.find_spec("pydantic") is None, reason="Pydantic not installed") +class TestPydantic: + """Tests for the Pydantic integration for ClassLists.""" + + import pydantic + + class Model(pydantic.BaseModel): + classlist: ClassList[str] + + model_class = Model + + @pytest.mark.parametrize( + "sequence", [["a", "b", "c"], ("a", "b", "c", "d"), deque(["a", "b", "c"]), ClassList(["a", "b"])] + ) + def test_sequence_coercion(self, sequence): + """Test that sequences are coerced to ClassLists.""" + model = self.model_class(classlist=sequence) + assert model.classlist.data == list(sequence) + assert model.classlist._class_handle is type(sequence[0]) + + @pytest.mark.parametrize("input", [[1, 2, "string"], deque(["a", "b", 5.3]), [3.0, 4]]) + def test_coerce_bad_inputs(self, input): + """Test that Pydantic successfully checks the type for input sequences.""" + with pytest.raises(self.pydantic.ValidationError, match="This ClassList only supports elements of type str."): + self.model_class(classlist=input) + + def test_coerce_models(self): + """Test that a ClassList of pydantic Models is coerced from a list of dicts.""" + import pydantic + + class SubModel(pydantic.BaseModel): + i: int + s: str + f: float + + class NestedModel(pydantic.BaseModel): + submodels: ClassList[SubModel] + + submodels_list = [{"i": 3, "s": "hello", "f": 3.0}, {"i": 4, "s": "hi", "f": 3.14}] + + model = NestedModel(submodels=submodels_list) + for submodel, exp_dict in zip(model.submodels, submodels_list, strict=False): + for key, value in exp_dict.items(): + assert getattr(submodel, key) == value + + def test_set_pydantic_fields(self): + """Test that intermediate validation errors for pydantic models are suppressed when using "set_fields".""" + from pydantic import BaseModel, model_validator + + class MinMaxModel(BaseModel): + min: float + value: float + max: float + + @model_validator(mode="after") + def check_value_in_range(self) -> "MinMaxModel": + 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}" + ) + return self + + model_list = ClassList([MinMaxModel(min=1, value=2, max=5)]) + model_list.set_fields(0, min=3, value=4) + + assert model_list == ClassList([MinMaxModel(min=3.0, value=4.0, max=5.0)]) diff --git a/tests/test_controls.py b/tests/test_controls.py index b0c33a24..5a83bccc 100644 --- a/tests/test_controls.py +++ b/tests/test_controls.py @@ -1,12 +1,27 @@ """Test the controls module.""" -from typing import Any, Union +import contextlib +import os +import tempfile +from pathlib import Path +from typing import Any import pydantic import pytest -from RATapi.controls import Controls, fields -from RATapi.utils.enums import BoundHandling, Display, Parallel, Procedures, Strategies +from ratapi.controls import Controls, fields +from ratapi.utils.enums import BoundHandling, Display, Parallel, Procedures, Strategies + + +@pytest.fixture +def IPC_controls(): + """A controls object with a temporary file set as the IPC file.""" + IPC_controls = Controls() + IPC_obj, IPC_controls._IPCFilePath = tempfile.mkstemp() + os.close(IPC_obj) + yield IPC_controls + with contextlib.suppress(FileNotFoundError): + os.remove(IPC_controls._IPCFilePath) def test_initialise_procedure_error() -> None: @@ -31,6 +46,30 @@ def test_extra_property_error() -> None: controls.test = 1 +@pytest.mark.parametrize( + "inputs", + [ + {"parallel": Parallel.Contrasts, "resampleMinAngle": 0.66}, + {"procedure": "simplex"}, + {"procedure": "dream", "nSamples": 504, "nChains": 1200}, + {"procedure": "de", "crossoverProbability": 0.45, "strategy": Strategies.RandomEitherOrAlgorithm}, + {"procedure": "ns", "nMCMC": 4, "propScale": 0.6}, + ], +) +def test_save_load(inputs): + """Test that saving and loading controls returns the same controls.""" + + original_controls = Controls(**inputs) + with tempfile.TemporaryDirectory() as tmp: + # ignore relative path warnings + path = Path(tmp, "controls.json") + original_controls.save(path) + converted_controls = Controls.load(path) + + for field in Controls.model_fields: + assert getattr(converted_controls, field) == getattr(original_controls, field) + + class TestCalculate: """Tests the Calculate class.""" @@ -41,15 +80,16 @@ def setup_class(self): @pytest.fixture def table_str(self): table_str = ( - "+------------------+-----------+\n" - "| Property | Value |\n" - "+------------------+-----------+\n" - "| procedure | calculate |\n" - "| parallel | single |\n" - "| calcSldDuringFit | False |\n" - "| resampleParams | [0.9, 50] |\n" - "| display | iter |\n" - "+------------------+-----------+" + "+---------------------+-----------+\n" + "| Property | Value |\n" + "+---------------------+-----------+\n" + "| procedure | calculate |\n" + "| parallel | single |\n" + "| numSimulationPoints | 500 |\n" + "| resampleMinAngle | 0.9 |\n" + "| resampleNPoints | 50 |\n" + "| display | iter |\n" + "+---------------------+-----------+" ) return table_str @@ -58,8 +98,9 @@ def table_str(self): "control_property, value", [ ("parallel", Parallel.Single), - ("calcSldDuringFit", False), - ("resampleParams", [0.9, 50]), + ("numSimulationPoints", 500), + ("resampleMinAngle", 0.9), + ("resampleNPoints", 50), ("display", Display.Iter), ("procedure", Procedures.Calculate), ], @@ -72,8 +113,9 @@ def test_calculate_property_values(self, control_property: str, value: Any) -> N "control_property, value", [ ("parallel", Parallel.Points), - ("calcSldDuringFit", True), - ("resampleParams", [0.2, 1]), + ("numSimulationPoints", 10), + ("resampleMinAngle", 0.2), + ("resampleNPoints", 1), ("display", Display.Notify), ], ) @@ -115,9 +157,9 @@ def test_initialise_non_calculate_properties(self, wrong_property: str, value: A UserWarning, match=f'\nThe current controls procedure is "calculate", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "calculate" controls procedure are:\n' - f' {", ".join(fields["calculate"])}\n', + f" {', '.join(fields['calculate'])}\n", ): Controls(procedure=Procedures.Calculate, **{wrong_property: value}) @@ -154,9 +196,9 @@ def test_set_non_calculate_properties(self, wrong_property: str, value: Any) -> UserWarning, match=f'\nThe current controls procedure is "calculate", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "calculate" controls procedure are:\n' - f' {", ".join(fields["calculate"])}\n', + f" {', '.join(fields['calculate'])}\n", ): setattr(self.calculate, wrong_property, value) @@ -166,45 +208,12 @@ def test_calculate_parallel_validation(self, value: Any) -> None: with pytest.raises(pydantic.ValidationError, match="Input should be 'single', 'points' or 'contrasts'"): self.calculate.parallel = value - @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, match="Input should be a valid boolean, unable to interpret input" - ): - self.calculate.calcSldDuringFit = value - @pytest.mark.parametrize("value", ["test", "iterate", 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, match="Input should be 'off', 'iter', 'notify' or 'final'"): self.calculate.display = value - @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, match=msg): - self.calculate.resampleParams = value - - @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: - self.calculate.resampleParams = value - assert exp.value.errors()[0]["msg"] == msg - def test_str(self, table_str) -> None: """Tests the Calculate model __str__.""" assert self.calculate.__str__() == table_str @@ -220,21 +229,22 @@ def setup_class(self): @pytest.fixture def table_str(self): 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 | 20 |\n" - "+------------------+-----------+" + "+---------------------+---------+\n" + "| Property | Value |\n" + "+---------------------+---------+\n" + "| procedure | simplex |\n" + "| parallel | single |\n" + "| numSimulationPoints | 500 |\n" + "| resampleMinAngle | 0.9 |\n" + "| resampleNPoints | 50 |\n" + "| display | iter |\n" + "| xTolerance | 1e-06 |\n" + "| funcTolerance | 1e-06 |\n" + "| maxFuncEvals | 10000 |\n" + "| maxIterations | 1000 |\n" + "| updateFreq | 1 |\n" + "| updatePlotFreq | 20 |\n" + "+---------------------+---------+" ) return table_str @@ -243,8 +253,9 @@ def table_str(self): "control_property, value", [ ("parallel", Parallel.Single), - ("calcSldDuringFit", False), - ("resampleParams", [0.9, 50]), + ("numSimulationPoints", 500), + ("resampleMinAngle", 0.9), + ("resampleNPoints", 50), ("display", Display.Iter), ("procedure", Procedures.Simplex), ("xTolerance", 1e-6), @@ -263,8 +274,9 @@ def test_simplex_property_values(self, control_property: str, value: Any) -> Non "control_property, value", [ ("parallel", Parallel.Points), - ("calcSldDuringFit", True), - ("resampleParams", [0.2, 1]), + ("numSimulationPoints", 10), + ("resampleMinAngle", 0.2), + ("resampleNPoints", 1), ("display", Display.Notify), ("xTolerance", 4e-6), ("funcTolerance", 3e-4), @@ -306,9 +318,9 @@ def test_initialise_non_simplex_properties(self, wrong_property: str, value: Any UserWarning, match=f'\nThe current controls procedure is "simplex", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "simplex" controls procedure are:\n' - f' {", ".join(fields["simplex"])}\n', + f" {', '.join(fields['simplex'])}\n", ): Controls(procedure=Procedures.Simplex, **{wrong_property: value}) @@ -339,9 +351,9 @@ def test_set_non_simplex_properties(self, wrong_property: str, value: Any) -> No UserWarning, match=f'\nThe current controls procedure is "simplex", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "simplex" controls procedure are:\n' - f' {", ".join(fields["simplex"])}\n', + f" {', '.join(fields['simplex'])}\n", ): setattr(self.simplex, wrong_property, value) @@ -354,7 +366,7 @@ def test_set_non_simplex_properties(self, wrong_property: str, value: Any) -> No ("maxIterations", -50), ], ) - def test_simplex_property_errors(self, control_property: str, value: Union[float, int]) -> None: + def test_simplex_property_errors(self, control_property: str, value: float | int) -> None: """Tests the property errors of Simplex class.""" with pytest.raises(pydantic.ValidationError, match="Input should be greater than 0"): setattr(self.simplex, control_property, value) @@ -374,23 +386,24 @@ def setup_class(self): @pytest.fixture def table_str(self): 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" - "| updateFreq | 1 |\n" - "| updatePlotFreq | 20 |\n" - "+----------------------+--------------------------------------+" + "+----------------------+---------------+\n" + "| Property | Value |\n" + "+----------------------+---------------+\n" + "| procedure | de |\n" + "| parallel | single |\n" + "| numSimulationPoints | 500 |\n" + "| resampleMinAngle | 0.9 |\n" + "| resampleNPoints | 50 |\n" + "| display | iter |\n" + "| populationSize | 20 |\n" + "| fWeight | 0.5 |\n" + "| crossoverProbability | 0.8 |\n" + "| strategy | vector dither |\n" + "| targetValue | 1.0 |\n" + "| numGenerations | 500 |\n" + "| updateFreq | 1 |\n" + "| updatePlotFreq | 20 |\n" + "+----------------------+---------------+" ) return table_str @@ -399,8 +412,9 @@ def table_str(self): "control_property, value", [ ("parallel", Parallel.Single), - ("calcSldDuringFit", False), - ("resampleParams", [0.9, 50]), + ("numSimulationPoints", 500), + ("resampleMinAngle", 0.9), + ("resampleNPoints", 50), ("display", Display.Iter), ("procedure", Procedures.DE), ("populationSize", 20), @@ -419,8 +433,9 @@ def test_de_property_values(self, control_property: str, value: Any) -> None: "control_property, value", [ ("parallel", Parallel.Points), - ("calcSldDuringFit", True), - ("resampleParams", [0.2, 1]), + ("numSimulationPoints", 10), + ("resampleMinAngle", 0.2), + ("resampleNPoints", 1), ("display", Display.Notify), ("populationSize", 20), ("fWeight", 0.3), @@ -460,9 +475,9 @@ def test_initialise_non_de_properties(self, wrong_property: str, value: Any) -> UserWarning, match=f'\nThe current controls procedure is "de", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "de" controls procedure are:\n' - f' {", ".join(fields["de"])}\n', + f" {', '.join(fields['de'])}\n", ): Controls(procedure=Procedures.DE, **{wrong_property: value}) @@ -491,9 +506,9 @@ def test_set_non_de_properties(self, wrong_property: str, value: Any) -> None: UserWarning, match=f'\nThe current controls procedure is "de", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "de" controls procedure are:\n' - f' {", ".join(fields["de"])}\n', + f" {', '.join(fields['de'])}\n", ): setattr(self.de, wrong_property, value) @@ -523,7 +538,7 @@ def test_de_crossoverProbability_error(self, value: int, msg: str) -> None: def test_de_targetValue_numGenerations_populationSize_error( self, control_property: str, - value: Union[int, float], + value: int | float, ) -> None: """Tests the targetValue, numGenerations, populationSize setter error in DE class.""" with pytest.raises(pydantic.ValidationError, match="Input should be greater than or equal to 1"): @@ -544,19 +559,20 @@ def setup_class(self): @pytest.fixture def table_str(self): 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" - "+------------------+-----------+" + "+---------------------+--------+\n" + "| Property | Value |\n" + "+---------------------+--------+\n" + "| procedure | ns |\n" + "| parallel | single |\n" + "| numSimulationPoints | 500 |\n" + "| resampleMinAngle | 0.9 |\n" + "| resampleNPoints | 50 |\n" + "| display | iter |\n" + "| nLive | 150 |\n" + "| nMCMC | 0 |\n" + "| propScale | 0.1 |\n" + "| nsTolerance | 0.1 |\n" + "+---------------------+--------+" ) return table_str @@ -565,8 +581,9 @@ def table_str(self): "control_property, value", [ ("parallel", Parallel.Single), - ("calcSldDuringFit", False), - ("resampleParams", [0.9, 50]), + ("numSimulationPoints", 500), + ("resampleMinAngle", 0.9), + ("resampleNPoints", 50), ("display", Display.Iter), ("procedure", Procedures.NS), ("nLive", 150), @@ -583,8 +600,9 @@ def test_ns_property_values(self, control_property: str, value: Any) -> None: "control_property, value", [ ("parallel", Parallel.Points), - ("calcSldDuringFit", True), - ("resampleParams", [0.2, 1]), + ("numSimulationPoints", 10), + ("resampleMinAngle", 0.2), + ("resampleNPoints", 1), ("display", Display.Notify), ("nLive", 1500), ("nMCMC", 1), @@ -626,9 +644,9 @@ def test_initialise_non_ns_properties(self, wrong_property: str, value: Any) -> UserWarning, match=f'\nThe current controls procedure is "ns", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "ns" controls procedure are:\n' - f' {", ".join(fields["ns"])}\n', + f" {', '.join(fields['ns'])}\n", ): Controls(procedure=Procedures.NS, **{wrong_property: value}) @@ -661,21 +679,21 @@ def test_set_non_ns_properties(self, wrong_property: str, value: Any) -> None: UserWarning, match=f'\nThe current controls procedure is "ns", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "ns" controls procedure are:\n' - f' {", ".join(fields["ns"])}\n', + f" {', '.join(fields['ns'])}\n", ): setattr(self.ns, wrong_property, value) @pytest.mark.parametrize( "control_property, value, bound", [ - ("nMCMC", -0.6, 0), + ("nMCMC", -1, 0), ("nsTolerance", -500, 0), ("nLive", -500, 1), ], ) - def test_ns_setter_error(self, control_property: str, value: Union[int, float], bound: int) -> None: + def test_ns_setter_error(self, control_property: str, value: int | float, bound: int) -> None: """Tests the nMCMC, nsTolerance, nLive setter error in NS class.""" with pytest.raises(pydantic.ValidationError, match=f"Input should be greater than or equal to {bound}"): setattr(self.ns, control_property, value) @@ -707,21 +725,22 @@ def setup_class(self): @pytest.fixture def table_str(self): 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 | 20000 |\n" - "| nChains | 10 |\n" - "| jumpProbability | 0.5 |\n" - "| pUnitGamma | 0.2 |\n" - "| boundHandling | reflect |\n" - "| adaptPCR | True |\n" - "+------------------+-----------+" + "+---------------------+---------+\n" + "| Property | Value |\n" + "+---------------------+---------+\n" + "| procedure | dream |\n" + "| parallel | single |\n" + "| numSimulationPoints | 500 |\n" + "| resampleMinAngle | 0.9 |\n" + "| resampleNPoints | 50 |\n" + "| display | iter |\n" + "| nSamples | 20000 |\n" + "| nChains | 10 |\n" + "| jumpProbability | 0.5 |\n" + "| pUnitGamma | 0.2 |\n" + "| boundHandling | reflect |\n" + "| adaptPCR | True |\n" + "+---------------------+---------+" ) return table_str @@ -730,8 +749,9 @@ def table_str(self): "control_property, value", [ ("parallel", Parallel.Single), - ("calcSldDuringFit", False), - ("resampleParams", [0.9, 50]), + ("numSimulationPoints", 500), + ("resampleMinAngle", 0.9), + ("resampleNPoints", 50), ("display", Display.Iter), ("procedure", Procedures.DREAM), ("nSamples", 20000), @@ -750,8 +770,9 @@ def test_dream_property_values(self, control_property: str, value: Any) -> None: "control_property, value", [ ("parallel", Parallel.Points), - ("calcSldDuringFit", True), - ("resampleParams", [0.2, 1]), + ("numSimulationPoints", 10), + ("resampleMinAngle", 0.2), + ("resampleNPoints", 1), ("display", Display.Notify), ("nSamples", 500), ("nChains", 1000), @@ -793,9 +814,9 @@ def test_initialise_non_dream_properties(self, wrong_property: str, value: Any) UserWarning, match=f'\nThe current controls procedure is "dream", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "dream" controls procedure are:\n' - f' {", ".join(fields["dream"])}\n', + f" {', '.join(fields['dream'])}\n", ): Controls(procedure=Procedures.DREAM, **{wrong_property: value}) @@ -826,9 +847,9 @@ def test_set_non_dream_properties(self, wrong_property: str, value: Any) -> None UserWarning, match=f'\nThe current controls procedure is "dream", but the property' f' "{wrong_property}" applies instead to the' - f' {", ".join(incorrect_procedures)} procedure.\n\n' + f" {', '.join(incorrect_procedures)} procedure.\n\n" f' The fields for the "dream" controls procedure are:\n' - f' {", ".join(fields["dream"])}\n', + f" {', '.join(fields['dream'])}\n", ): setattr(self.dream, wrong_property, value) @@ -855,9 +876,41 @@ def test_dream_nSamples_error(self, value: int) -> None: @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, match="Input should be greater than 0"): + with pytest.raises(pydantic.ValidationError, match="Input should be greater than 1"): self.dream.nChains = value def test_control_class_dream_str(self, table_str) -> None: """Tests the Dream model __str__.""" assert self.dream.__str__() == table_str + + +def test_initialise_IPC() -> None: + """Tests that an Inter-Process Communication File can be set up.""" + test_controls = Controls() + test_controls.initialise_IPC() + assert test_controls._IPCFilePath != "" + with open(test_controls._IPCFilePath, "rb") as f: + file_content = f.read() + assert file_content == b"\x00" + os.remove(test_controls._IPCFilePath) + + +def test_sendStopEvent(IPC_controls) -> None: + """Tests that an Inter-Process Communication File can be modified.""" + IPC_controls.sendStopEvent() + with open(IPC_controls._IPCFilePath, "rb") as f: + file_content = f.read() + assert file_content == b"\x01" + + +def test_sendStopEvent_empty_file() -> None: + """Tests that we do not write to a non-existent Inter-Process Communication File.""" + test_controls = Controls() + with pytest.warns(UserWarning, match="An IPC file was not initialised."): + test_controls.sendStopEvent() + + +def test_delete_IPC(IPC_controls) -> None: + """Tests that an Inter-Process Communication File can be safely removed.""" + IPC_controls.delete_IPC() + assert not os.path.isfile(IPC_controls._IPCFilePath) diff --git a/tests/test_convert.py b/tests/test_convert.py index 17a5bd0e..0cbd621b 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -2,12 +2,13 @@ import importlib import os +import pathlib import tempfile import pytest -import RATapi -from RATapi.utils.convert import project_class_to_r1, r1_to_project_class +import ratapi +from ratapi.utils.convert import project_to_r1, r1_to_project TEST_DIR_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data") @@ -18,10 +19,10 @@ def dspc_bilayer(): with some changes to make it compatible with R1. """ - project, _ = RATapi.examples.DSPC_standard_layers() + project, _ = ratapi.examples.DSPC_standard_layers() # change parameters to standardise arguments not in R1 - for class_list in RATapi.project.parameter_class_lists: + for class_list in ratapi.project.parameter_class_lists: params = getattr(project, class_list) for param in params: param.prior_type = "uniform" @@ -31,44 +32,65 @@ def dspc_bilayer(): for i in range(0, len(project.background_parameters)): param = project.background_parameters[i] for background in project.backgrounds: - if background.value_1 == param.name: - background.value_1 = f"Background parameter {i+1}" - param.name = f"Background parameter {i+1}" + if background.source == param.name: + background.source = f"Background parameter {i + 1}" + param.name = f"Background parameter {i + 1}" for i in range(0, len(project.resolution_parameters)): param = project.resolution_parameters[i] for resolution in project.resolutions: - if resolution.value_1 == param.name: - resolution.value_1 = f"Resolution parameter {i+1}" - param.name = f"Resolution parameter {i+1}" + if resolution.source == param.name: + resolution.source = f"Resolution parameter {i + 1}" + param.name = f"Resolution parameter {i + 1}" return project @pytest.mark.parametrize( - ["file", "expected"], + ["file", "project"], [ ["R1defaultProject.mat", "r1_default_project"], ["R1monolayerVolumeModel.mat", "r1_monolayer"], ["R1DSPCBilayer.mat", "dspc_bilayer"], + ["R1Monolayer_8_contrasts.mat", "r1_monolayer_8_contrasts"], + ["R1orsoPolymerExample.mat", "r1_orso_polymer"], + ["R1motofitBenchMark.mat", "r1_motofit_bench_mark"], ], ) -def test_r1_to_project_class(file, expected, request): +@pytest.mark.parametrize("path_type", [os.path.join, pathlib.Path]) +def test_r1_to_project(file, project, path_type, request): """Test that R1 to Project class conversion returns the expected Project.""" - output_project = r1_to_project_class(os.path.join(TEST_DIR_PATH, file)) - expected_project = request.getfixturevalue(expected) + output_project = r1_to_project(path_type(TEST_DIR_PATH, file)) + expected_project = request.getfixturevalue(project) # assert statements have to be more careful due to R1 missing features # e.g. R1 doesn't support background parameter names, mu, sigma... - for class_list in RATapi.project.class_lists: + for class_list in ratapi.project.class_lists: assert getattr(output_project, class_list) == getattr(expected_project, class_list) -@pytest.mark.parametrize("project", ["r1_default_project", "r1_monolayer", "dspc_bilayer"]) +def test_r1_with_non_unique_contrast_names(): + """Test that R1 to Project class conversion returns the expected Project.""" + output_project = r1_to_project(pathlib.Path(TEST_DIR_PATH, "nonUniqueContrast.mat")) + assert output_project.contrasts[0].name == "Contrast 1" + assert output_project.contrasts[1].name == "Contrast 2" + + +@pytest.mark.parametrize( + "project", + [ + "r1_default_project", + "r1_monolayer", + "r1_monolayer_8_contrasts", + "r1_orso_polymer", + "r1_motofit_bench_mark", + "dspc_bilayer", + ], +) def test_r1_involution(project, request, monkeypatch): """Test that converting a Project to an R1 struct and back returns the same project.""" original_project = request.getfixturevalue(project) - r1_struct = project_class_to_r1(original_project, return_struct=True) + r1_struct = project_to_r1(original_project, return_struct=True) # rather than writing the struct to a file and reading the file, just directly # hand the struct over @@ -76,21 +98,33 @@ def mock_load(ignored_filename, **ignored_settings): """Load the generated R1 struct instead of reading a file.""" return {"problem": r1_struct} - monkeypatch.setattr("RATapi.utils.convert.loadmat", mock_load, raising=True) + monkeypatch.setattr("ratapi.utils.convert.loadmat", mock_load, raising=True) - converted_project = r1_to_project_class(project) + converted_project = r1_to_project(pathlib.Path(__file__).parent / "test_data" / project) - for class_list in RATapi.project.class_lists: + for class_list in ratapi.project.class_lists: assert getattr(converted_project, class_list) == getattr(original_project, class_list) +def test_invalid_constraints(): + """Test that invalid constraints are fixed where necessary.""" + with pytest.warns( + match=r"The parameter (.+) has invalid constraints," + " these have been adjusted to satisfy the current value of the parameter." + ): + output_project = r1_to_project(pathlib.Path(TEST_DIR_PATH, "R1DoubleBilayerVolumeModel.mat")) + + assert output_project.background_parameters[0].min == output_project.background_parameters[0].value + + @pytest.mark.skipif(importlib.util.find_spec("matlab") is None, reason="Matlab not installed") -def test_matlab_save(request): +@pytest.mark.parametrize("path_type", [os.path.join, pathlib.Path]) +def test_matlab_save(path_type, request): """Test that MATLAB correctly saves the .mat file.""" project = request.getfixturevalue("r1_default_project") with tempfile.TemporaryDirectory() as temp: - matfile = os.path.join(temp, "testfile.mat") - project_class_to_r1(project, filename=matfile) - converted_project = r1_to_project_class(matfile) + matfile = path_type(temp, "testfile.mat") + project_to_r1(project, filename=matfile) + converted_project = r1_to_project(matfile) assert project == converted_project diff --git a/tests/test_custom_errors.py b/tests/test_custom_errors.py index 7793ff85..92dbcab8 100644 --- a/tests/test_custom_errors.py +++ b/tests/test_custom_errors.py @@ -5,7 +5,7 @@ import pytest from pydantic import ValidationError, create_model -import RATapi.utils.custom_errors +import ratapi.utils.custom_errors @pytest.fixture @@ -43,7 +43,7 @@ def test_custom_pydantic_validation_error( try: TestModel(int_field="string", str_field=5) except ValidationError as exc: - custom_error_list = RATapi.utils.custom_errors.custom_pydantic_validation_error(exc.errors(), custom_errors) + custom_error_list = ratapi.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) diff --git a/tests/test_data/ORSO/test0.layers b/tests/test_data/ORSO/test0.layers new file mode 100644 index 00000000..f52fa9ae --- /dev/null +++ b/tests/test_data/ORSO/test0.layers @@ -0,0 +1,4 @@ +0.000000000000000000e+00 2.069999999999999840e+00 0.000000000000000000e+00 0.000000000000000000e+00 +1.000000000000000000e+02 3.450000000000000178e+00 1.000000000000000056e-01 3.000000000000000000e+00 +2.000000000000000000e+02 5.000000000000000000e+00 1.000000000000000021e-02 1.000000000000000000e+00 +0.000000000000000000e+00 6.000000000000000000e+00 0.000000000000000000e+00 5.000000000000000000e+00 diff --git a/tests/test_data/ORSO/test1.layers b/tests/test_data/ORSO/test1.layers new file mode 100644 index 00000000..087d4d5a --- /dev/null +++ b/tests/test_data/ORSO/test1.layers @@ -0,0 +1,22 @@ +0.0000 0.0000 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +30.0000 -1.9493 0.0000 0.0000 +70.0000 9.4245 0.0000 0.0000 +0.0000 2.0704 0.0000 0.0000 diff --git a/tests/test_data/ORSO/test2.layers b/tests/test_data/ORSO/test2.layers new file mode 100644 index 00000000..b8c75ded --- /dev/null +++ b/tests/test_data/ORSO/test2.layers @@ -0,0 +1,2 @@ +0.0000 0.0000 0.0000 0.0000 +0.0000 6.3600 0.0000 3.0000 diff --git a/tests/test_data/ORSO/test3.layers b/tests/test_data/ORSO/test3.layers new file mode 100644 index 00000000..ad808bb5 --- /dev/null +++ b/tests/test_data/ORSO/test3.layers @@ -0,0 +1,2001 @@ +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997976e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.061018436615995952e-16 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.059152765492399442e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.059152765492399442e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.059152765492399442e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.059152765492399442e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.412203687323199190e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.412203687323199190e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.412203687323199190e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.412203687323199190e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.765254609153998939e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.765254609153998939e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.765254609153998939e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.118305530984798884e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.118305530984798884e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.471356452815598633e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.471356452815598633e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.471356452815598633e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.824407374646398381e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.177458296477198129e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.177458296477198129e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997877e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.530509218307997877e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.883560140138798020e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.236611061969597768e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.589661983800397517e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.942712905631197265e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.295763827461997013e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.648814749292796762e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.001865671123596510e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354916592954396258e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.707967514785196007e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.414069358446795503e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.767120280277596040e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.120171202108395000e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.826273045769994496e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.532374889431593993e-15 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.023847673309319349e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.094457857675479299e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.165068042041639406e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.235678226407799356e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.306288410773959305e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.412203687323199151e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.518118963872439154e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.624034240421679000e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.729949516970919161e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.835864793520159007e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.977085162252478906e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.118305530984798805e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.259525899717118705e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.400746268449438604e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.577271729364838557e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.753797190280238510e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.930322651195638148e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.106848112111038416e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.318678665209518107e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.565814310491077852e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.812949955772637597e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.060085601054197973e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.342526338518837772e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.624967075983477570e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.942712905631197423e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.260458735278917275e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.613509657109716550e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.001865671123596510e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.390221685137476470e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.813882791334435852e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.272848989714475919e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.767120280277595409e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.261391570840714899e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.826273045769994496e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.426459612882354778e-14 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.002664617999471380e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.069744293147323419e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.140354477513483400e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.218025680316259392e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.299227392337343200e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.383959613576735329e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.475752853252743090e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.574607111365366988e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.676991878696298954e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.786437664463847058e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.902944468668010793e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.030042800527098734e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.164202150822802812e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.305422519555122522e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.453703906724058369e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.616107330766226490e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.785571773245010243e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.969158252597026270e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.163336259603966250e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.368105794265830183e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.586997365800925884e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.820010974209253860e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.067146619490813605e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.331934810863913440e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.610845039110245044e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.907407813448116738e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.225153643095837348e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.564082528053404854e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.920663959102512954e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.301958954679776272e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.707967514785195817e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.138689639418771589e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.597655837798811909e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.084866109925315766e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.600320455798283162e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.151079893854331748e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.733613914875150173e-13 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.035498353729735811e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.101518876112095354e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.171776009556424477e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.246269754062723384e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.325353160552822503e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.409379279948552867e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.498701163171745106e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.593671861144230255e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.694291373866008313e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.801265803180740541e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.914595149088427142e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.035338564354560812e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.163496048979141148e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.299420653883998982e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.443818480912796383e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.597042580987363374e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.759446005029531192e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.932087905804792333e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.115321334234977225e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.309852392163747936e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.516034130512935298e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.734925702048031000e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.967233208612697514e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.213662752050595696e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.475273485127218042e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.752418458764396192e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.046509876649452667e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.358606891547879156e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.689415605303338937e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.040701272524984556e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.412816944134647654e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.807174823819650749e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.225893217110979644e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.669325174930463553e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.139589002809089894e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.638096904434177955e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.166614134414885937e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.726552896438533935e-12 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.032038454695794020e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.094952128966042482e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.161608143007697442e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.232253632466040562e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.307100427894170018e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.386395664937367798e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.470421784333098081e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.559425921726642692e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.653690517855466298e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.753533318549216566e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.859272069637540842e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.971295127134453767e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.089884931777419361e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.215465144672634947e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.348424121834114195e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.489220829460237109e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.638243623565017683e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.796022080531201924e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.963015166557170155e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.139787763117851708e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.326904751688175591e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.524895708650888134e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.734396125665284671e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.956112104575027192e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.190714442131593387e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.438909240178645891e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.701473210744211403e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.979253676040685212e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.273062653188276375e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.583853379675929835e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.912543787900403655e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.260157725535009428e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.627754345345238521e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.016463410280949595e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.427449988384183671e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.861985062973531420e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.321374922459768455e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.806996465438033811e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.320367810872199822e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.862936467541772821e-11 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.043643238496372316e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.104247959737847411e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.168294927467172804e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.235974789182137225e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.307481722889747382e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.383034620161538535e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.462852372569045687e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.547171524229895536e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.636239210789369746e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.730316689929622922e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.829679341369683388e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.934616666865451893e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.045432290209703421e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.162447487741303617e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.286004718854428575e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.416453503961691116e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.554175138058667409e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.699561507668591172e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.853032743388439423e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.015019567342847247e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.185988006748630534e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.366421741368697130e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.556836225548920807e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.757761035672047249e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.969768114231442517e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.193450586775782085e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.429436883945925336e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.678383680456477536e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.940986486623444803e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.217976117855017161e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.510118694651566991e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.818222703624087568e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.143135466984973019e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.485753734075672252e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.847013089839038127e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.227905607365415273e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.629469256364985127e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.052794964186206017e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.499033676834244985e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.969389297952545969e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.465132810859700674e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.987595217531008488e-10 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.053818519114457877e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.111837142353522234e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.172970380824978214e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.237380637952867445e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.305239496485199954e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.376726306290265728e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.452029596560322530e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.531348134964361084e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.614889868495339475e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.702873335673871373e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.795528372650068183e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.893096819305384497e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.995831460099850640e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.103998495428527316e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.217877188570582985e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.337760924842058429e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.463957564646790620e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.596790502629176039e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.736599020725094550e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.883738641212829949e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.038583598069522139e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.201526130869325603e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.372977190885251341e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.553369265496542084e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.743154965984985513e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.942809498891364361e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.152832078219148570e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.373745219332647560e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.606097563364386261e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.850464583316949538e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.107449996266666900e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.377686116414537607e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.661836679493604226e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.960597195819872770e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.274697421648767766e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.604901712226052401e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.952011846195205379e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.316867731699262041e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.700350230788188744e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.103382571622575841e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.526931054575471353e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.972009994945296889e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.439681016853996603e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.931056936807181112e-09 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.044730352894873730e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.098964129031543319e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.155935003049890543e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.215776922469658027e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.278630225032273515e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.344641850531402944e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.413965693863872414e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.486762887470405455e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.563202189691637257e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.643460161293575150e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.727721800959258837e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.816180686509128120e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.909039363257036958e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.006509979501913862e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.108814427748129291e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.216185050807339909e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.328864818323950230e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.447108103487139078e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.571180965471598026e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.701361749624098530e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.837941687650058736e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.981225356579742234e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.131531384870100991e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.289192946676067685e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.454558573867672120e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.627992650301337531e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.809876223836994684e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.000607677134837506e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.200603539672443139e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.410299264456796421e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.630150004736322307e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.860631567238371663e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.102241224186343966e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.355498631232080830e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.620946921913728134e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.899153590283035305e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.190711585363217433e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.496240476216996634e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.816387405184088499e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.151828535389982212e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.503270109898708421e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.871449722696155398e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.257137836809036987e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.661138949372927336e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.084293215666506299e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.527477896620340212e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.991608876935843226e-08 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.047764243033988513e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.098657680831394251e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.151945404065379819e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.207736173602924591e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.266143509437434076e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.327285884866746759e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.391286924201651306e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.458275632248984213e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.528386606142184711e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.601760278946429319e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.678543152672240651e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.758888048941642672e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.842954373776351015e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.930908389446983736e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.022923496913797819e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.119180525328445866e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.219868028596750042e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.325182620777077708e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.435329290295662623e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.550521745936507130e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.670982766361796022e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.796944574345872006e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.928649211009215407e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.066348941827001943e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.210306659107154124e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.360796316242975479e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.518103376087822495e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.682525248738244696e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.854371799927314284e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.033965831173880380e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.221643588175894426e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.417755308039339659e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.622665777098689253e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.836754888737360232e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.060418254165810735e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.294067813199631986e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.538132483873248572e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.793058829706155389e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.059311734030181640e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.337375137865919455e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.627752763677108983e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.930968902674195515e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.247569195056869612e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.578121470275256992e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.923216604943661508e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.283469398406851661e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.659519508324997955e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.052032400380661170e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.461700333290857156e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.889243389715751167e-07 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.033541053188091803e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.080098071015722765e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.128676398576278259e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.179360273466656369e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.232237284796156095e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.287398500990910611e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.344938599716627538e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.404956005215396524e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.467553027054702133e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.532836005937454793e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.600915465513885868e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.671906266664802174e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.745927768845856439e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.823103997080633043e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.903563816014752884e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.987441105735232803e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.074874949240523796e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.166009821675807398e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.260995789806763632e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.359988714670802017e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.463150464466767954e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.570649132740410486e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.682659264690023736e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.799362091592261169e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.920945771229810599e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.047605639263650936e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.179544466254125080e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.316972726685741063e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.460108872581635624e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.609179620533975791e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.764420245795374920e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.926074885902686230e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.094396857363680435e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.269648979051688136e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.452103907603976837e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.642044485529961508e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.839764098851784607e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.045567046395582724e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.259768922145636034e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.482697008896142421e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.714690686378088391e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.956101850683737030e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.207295348166219538e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.468649422755046141e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.740556179158919327e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.023422058425322066e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.317668330446558671e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.623731601646977449e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.942064338204436240e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.273135406924315746e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.617430631647771529e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.975453369430842055e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.347725100845583125e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.734786044288679989e-06 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.013719578335292704e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.055553391820618433e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.099040073532897539e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.144241789702293843e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.191222915527978604e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.240050108294976747e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.290792383103589499e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.343521190787733282e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.398310498128108044e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.455236870501419636e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.514379557248091248e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.575820579299502824e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.639644819488417403e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.705940115860338292e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.774797357315005772e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.846310582531263366e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.920577081363283853e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.997697499661388443e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.077775946987880915e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.160920107333819199e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.247241353330986757e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.336854863782544811e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.429879744265228653e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.526439151756321288e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.626660422332172172e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.730675202891497352e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.838619586621016523e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.950634251956296992e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.066864606167563230e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.187460932334796259e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.312578540877187246e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.442377925283901952e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.577024922222671620e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.716690875990913737e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.861552807591817370e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.011793588859058590e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.167602120747516004e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.329173517166884502e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.496709293475565348e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.670417560270312651e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.850513222506958153e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.037218183952196727e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.230761557248886904e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.431379879559550559e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.639317333999916077e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.854825977250843831e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.078165972924987412e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.309605831217757633e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.549422655125036849e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.797902392874588745e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.055340097136043084e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.322040191044765169e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.598316741074918423e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.884493737079446211e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.180905379532311104e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.487896374114179126e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.805822234135840803e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.135049590375699403e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.475956508931516293e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.828932817157022084e-05 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.019438043789522362e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.057271373204371522e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.096435984969912450e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.136975908998660850e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.178936527017460220e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.222364610350989999e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.267308358665575297e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.313817439637987637e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.361943029637502421e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.411737855343542236e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.463256236415411246e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.516554129168223950e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.571689171311519036e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.628720727750554540e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.687709937464410101e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.748719761545625096e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.811815032295460725e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.877062503558368865e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.944530902157981598e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.014290980586430863e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.086415570879918363e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.160979639751148479e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.238060344996273352e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.317737093165761562e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.400091598573328682e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.485207943618217221e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.573172640484378080e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.664074694209484276e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.758005667162622245e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.855059744965960191e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.955333803853333165e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.058927479518702979e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.165943237472146495e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.276486444910431525e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.390665444169261005e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.508591627736001774e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.630379514861736779e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.756146829843243413e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.886014581907826530e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.020107146831630816e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.158552350234945576e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.301481552642760883e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.449029736271748175e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.601335593638978053e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.758541617967671205e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.920794195453526447e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.088243699370442741e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.261044586110963676e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.439355493115538738e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.623339338771815707e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.813163424283951169e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.008999537554316275e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.211024059084647216e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.419418069942550969e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.634367461814538606e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.856063049163241318e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.084700683534706682e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.320481370036958316e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.563611385982760759e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.814302401784845812e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.072771604082418272e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.339241821141319278e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.613941650566659530e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.897105589303234020e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.188974166047270695e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.489794075981251419e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.799818317944787756e-04 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.011930633402036194e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.044852415157278107e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.078774452777762124e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.113724709665282449e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.149731851859341503e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.186825263249406941e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.225035061042780826e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.264392111491603526e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.304928045884650150e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.346675276801088212e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.389667014631141813e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.433937284367548101e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.479520942666035085e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.526453695177652087e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.574772114160007943e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.624513656361419381e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.675716681186085891e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.728420469138176700e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.782665240550829373e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.838492174595822773e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.895943428582047650e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.955062157538887350e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.015892534089807134e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.078479768614740694e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.142870129704799263e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.209110964910017145e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.277250721777302183e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.347338969189538549e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.419426418993488904e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.493564947929549722e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.569807619855249067e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.648208708269188510e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.728823719131903344e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.811709413986105723e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.896923833375613343e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.984526320566134334e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.074577545560850615e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.167139529420328562e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.262275668878998006e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.360050761259952053e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.460531029690905314e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.563784148616360500e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.669879269605274327e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.778887047459176651e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.890879666612257013e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.005930867825547095e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.124115975176954191e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.245511923337979415e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.370197285144872268e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.498252299453294085e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.629758899282472584e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.764800740240043332e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.903463229228968538e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.045833553435493182e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.192000709589648759e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.342055533500789620e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.496090729863563167e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.654200902329729016e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.816482583842293511e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.983034267232665605e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.153956436068839381e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.329351595759176788e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.509324304900856659e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.693981206871935270e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.883431061660647693e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.077784777929494418e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.277155445304220142e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.481658366886976934e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.691411091985205471e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.906533449051287785e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.127147578827669319e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.353377967686875447e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.585351481167458054e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.823197397690014238e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.067047442453599754e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.317035821499846868e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.573299255940899075e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.835977016340221799e-03 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.010521095724061652e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.038114555182889295e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.066392792672938086e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.095370789691819773e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.125063800074625406e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.155487353506534989e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.186657259044252705e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.218589608645846006e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.251300780707362281e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.284807443605659634e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.319126559245862619e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.354275386612736540e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.390271485324815794e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.427132719189450581e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.464877259758593994e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.503523589883107303e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.543090507265122528e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.583597128006451749e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.625062890152159656e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.667507557227920420e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.710951221769434205e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.755414308842943860e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.800917579554914619e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.847482134549957231e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.895129417494697405e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.943881218547138801e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.993759677808687805e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.044787288758420640e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.096986901667016734e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.150381726989364362e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.204995338733868604e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.260851677806583609e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.317975055328797343e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.376390155926124889e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.436122040987061602e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.497196151889729057e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.559638313194300546e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.623474735799630544e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.688732020062424566e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.755437158875984061e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.823617540707961532e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.893300952593811162e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.964515583085113731e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.037290025149574912e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.111653279021451765e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.187634755000221670e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.265264276194813908e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.344572081212053571e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.425588826786436086e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.508345590349488952e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.592873872536573449e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.679205599628338624e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.767373125925305849e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.857409236052693896e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.949347147193637414e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.043220511248239724e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.139063416916287375e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.236910391700993150e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.336796403832025165e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.438756864104484445e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.542827627632645138e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.649044995514838019e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.757445716408129077e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.868066988009438212e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.980946458441441738e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.096122227540358235e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.213632848043155132e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.333517326672085335e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.455815125113627068e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.580566160889600946e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.707810808118029405e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.837589898160953916e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.969944720157322610e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.104917021437621799e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.242549007818455620e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.382883343774306550e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.525963152484175189e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.671832015750060740e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.820533973785831983e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.972113524872693147e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.126615624880225375e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.284085686649298397e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.444569579235123247e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.608113627007889734e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.774764608608446259e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.944569755756682172e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.117576751910210442e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.293833730771182911e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.473389274638486179e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.656292412603094899e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.842592618585139175e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.032339809208506098e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.225584341512994835e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.422377010499909111e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.622769046509986601e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.826812112431108914e-02 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.003455830073357175e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.024606013033130397e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.046137054326602978e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.068054290121346339e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.090363098180851670e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.113068897478845798e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.136177147795133513e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.159693349292828662e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.183623042076773213e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.207971805732974274e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.232745258848865072e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.257949058514259977e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.283588899802801109e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.309670515233752053e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.336199674214005872e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.363182182460129233e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.390623881400347428e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.418530647556249524e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.446908391904197788e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.475763059216247119e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.505100627380449863e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.534927106700492705e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.565248539174548814e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.596070997753154808e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.627400585576219694e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.659243435188866023e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.691605707736217323e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.724493592136918663e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.757913304235463048e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.791871085933146868e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.826373204297714326e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.861425950651645345e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.897035639638940119e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.933208608270624573e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.969951214948705842e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.007269838468742906e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.045170877001037668e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.083660747050359308e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.122745882394377337e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.162432733000712037e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.202727763922705251e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.243637454174034762e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.285168295582085951e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.327326791620307478e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.370119456219578757e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.413552812558631133e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.457633391833766723e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.502367732007836909e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.547762376538768581e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.593823873087605092e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.640558772206351712e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.687973626005781824e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.736074986803201381e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.784869405750624582e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.834363431443342463e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.884563608509119192e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.935476476178393024e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.987108566835436907e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.039466404551018353e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.092556503596527451e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.146385366940023243e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.200959484724428816e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.256285332728060533e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.312369370807964342e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.369218041326168533e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.426837767559301473e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.485234952091895710e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.544415975193622170e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.604387193180924043e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.665154936763348470e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.726725509374896328e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.789105185490952987e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.852300208930957703e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.916316791147438914e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.981161109501680229e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.046839305526477304e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.113357483176559581e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.180721707066849535e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.248938000699374329e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.318012344678975323e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.387950674918463800e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.458758880833801896e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.530442803529520224e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.603008233975262598e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.676460911173642154e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.750806520320144388e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.826050690955621114e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.902198995111775592e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.979256945450387661e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.057229993396753498e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.136123527267844047e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.215942870396090836e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.296693279248885222e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.378379941544954024e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.461007974367843021e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.544582422277207767e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.629108255418782125e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.714590367633263224e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.801033574565200857e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.888442611772164437e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.976822132835090118e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.066176707470466445e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.156510819644825938e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.247828865692593991e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.340135152437625932e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.433433895319268236e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.527729216523850964e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.623025143121854530e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.719325605211997621e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.816634434072557092e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.914955360320802491e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.014292012081355665e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.114647913163980597e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.216026481251838209e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.318431026100656878e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.421864747749643554e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.526330734745125817e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.631831962377202405e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.738371290930653457e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.845951463950433524e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 7.954575106522763228e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.064244723572530082e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.174962698177601350e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.286731289901049236e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.399552633141798008e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.513428735504575684e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.628361476189956303e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.744352604405060125e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.861403737795964242e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 8.979516360902215499e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.098691823634380560e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.218931339775542355e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.340235985506994965e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.462606697959433655e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.586044273789982029e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.710549367785823449e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.836122491495479236e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 9.962764011887899063e-01 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.009047415004067139e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.021925297985757597e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.034910042681639553e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.048001626674776254e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.061200012464540876e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.074505147350896417e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.087916963321945873e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.101435376944848166e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.115060289260181525e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.128791585679758569e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.142629135888034941e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.156572793747108419e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.170622397205391296e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.184777768210047766e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.199038712623191394e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.213405020141967938e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.227876464222529274e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.242452802007974144e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.257133774260325687e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.271919105296557051e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.286808502928769693e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.301801658408528573e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.316898246375415971e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.332097924809886980e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.347400334990404014e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.362805101454968915e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.378311831967036882e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.393920117485881072e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.409629532141461361e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.425439633213788193e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.441349961116882294e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.457360039387303408e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.473469374677317312e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.489677456752741547e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.505983758495447189e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.522387735910622153e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.538888828138746057e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.555486457472347039e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.572180029377566290e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.588968932520502975e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.605852538798430151e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.622830203375830393e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.639901264725300400e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.657065044673355469e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.674320848451082977e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.691667964749735464e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.709105665781198047e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.726633207343367449e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.744249828890470422e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.761954753608253599e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.779747188494128718e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.797626324442197498e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.815591336333184591e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.833641383129287705e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.851775607973884297e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.869993138296145663e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.888293085920495606e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.906674547180906565e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.925136603040062289e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.943678319213281824e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.962298746297276963e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.980996919903643017e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 1.999771860797090017e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.018622575038409916e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.037548054132081177e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.056547275178562728e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.075619201031173144e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.094762780457547713e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.113976948305655412e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.133260625674279432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.152612720087986542e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.172032125676484071e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.191517723358339165e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.211068381029038576e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.230682953753273079e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.250360283961477137e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.270099201650493281e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.289898524588342532e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.309757058523065343e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.329673597395497175e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.349646923556016898e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.369675807985115679e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.389759010517761073e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.409895280071515877e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.430083354878262547e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.450321962719562485e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.470609821165494324e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.490945637816929459e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.511328110551202197e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.531755927771016434e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.552227768656605278e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.572742303420985532e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.593298193568254639e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.613894092154882109e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.634528644053824031e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.655200486221477085e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.675908247967306863e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.696650551226081216e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.717426010832665106e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.738233234799196669e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.759070824594652915e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.779937375426626556e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.800831476525258434e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.821751711429254073e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.842696658273816457e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.863664890080482195e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.884654975048696279e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.905665476849047746e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.926694954918098279e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.947741964754635013e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.968805058217322212e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 2.989882783823591073e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.010973687049678382e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.032076310631754978e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.053189194867952594e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.074310877921289098e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.095439896123296286e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.116574784278287158e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.137714075968181415e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.158856303857713765e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.180000000000000160e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.201143696142289219e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.222285924031821569e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.243425215721716270e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.264560103876707142e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.285689122078711222e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.306810805132050390e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.327923689368248450e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.349026312950325046e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.370117216176411912e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.391194941782678107e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.412258035245368859e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.433305045081905149e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.454334523150955683e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.475345024951306705e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.496335109919518569e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.517303341726186972e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.538248288570748912e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.559168523474744550e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.580062624573376873e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.600929175405347404e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.621766765200806759e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.642573989167337878e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.663349448773921768e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.684091752032696565e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.704799513778523234e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.725471355946179841e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.746105907845120875e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.766701806431748789e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.787257696579018340e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.807772231343395042e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.828244072228986994e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.848671889448800343e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.869054362183073525e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.889390178834509104e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.909678037280437835e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.929916645121740437e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.950104719928487107e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.970240989482241467e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 3.990324192014887306e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.010353076443982978e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.030326402604505809e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.050242941476938086e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.070101475411660452e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.089900798349510147e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.109639716038523183e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.129317046246729461e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.148931618970964408e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.168482276641664264e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.187967874323519801e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.207387279912014222e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.226739374325723553e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.246023051694347572e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.265237219542455271e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.284380798968830284e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.303452724821437592e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.322451945867921808e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.341377424961592624e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.360228139202913411e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.379003080096359746e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.397701253702723356e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.416321680786721160e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.434863396959941362e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.453325452819096419e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.471706914079507378e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.490006861703854213e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.508224392026118466e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.526358616870714613e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.544408663666818171e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.562373675557805264e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.580252811505871158e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.598045246391749608e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.615750171109532118e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.633366792656635980e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.650894334218805604e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.668332035250264411e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.685679151548920451e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.702934955326647959e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.720098735274702584e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.737169796624172591e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.754147461201570835e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.771031067479499121e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.787819970622436472e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.804513542527655723e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.821111171861256928e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.837612264089377945e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.854016241504554685e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.870322543247260327e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.886530625322683896e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.902639960612699355e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.918650038883118469e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.934560366786214125e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.950370467858541623e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.966079882514121024e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.981688168032965436e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 4.997194898545030739e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.012599665009598304e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.027902075190115561e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.043101753624585903e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.058198341591474190e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.073191497071230849e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.088080894703445267e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.102866225739676409e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.117547197992029062e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.132123535777472156e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.146594979858032382e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.160961287376811590e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.175222231789954108e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.189377602794611022e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.203427206252893455e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.217370864111965822e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.231208414320244415e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.244939710739821237e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.258564623055153930e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.272083036678056445e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.285494852649104125e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.298799987535461220e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.311998373325226730e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.325089957318362544e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.338074702014243833e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.350952584995932959e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.363723598811212412e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.376387750850454061e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.388945063221419751e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.401395572621003893e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.413739330204056621e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.425976401449302600e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.438106866022446972e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.450130817636563485e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.462048363909780768e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.473859626220403563e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.485564739559495528e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.497163852381006244e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.508657126449543640e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.520044736685822073e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.531326871009895285e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.542503730182242627e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.553575527642748533e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.564542489347725329e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.575404853604958078e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.586162870906934863e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.596816803762282078e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.607366926525489070e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.617813525225037630e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.628156897389936297e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.638397351874816721e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.648535208683603592e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.658570798791865641e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.668504463967922291e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.678336556592745943e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.688067439478800225e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.697697485687816865e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.707227078347616889e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.716656610468074717e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.725986484756239392e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.735217113430740810e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.744348918035519169e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.753382329252954897e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.762317786716492307e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.771155738822785430e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.779896642543480567e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.788540963236674664e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.797089174458123217e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.805541757772281208e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.813899202563217017e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.822162005845505028e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.830330672075112908e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.838405712960392790e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.846387647273217247e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.854277000660326635e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.862074305454961554e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.869780100488823038e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.877394930904439541e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.884919347967986880e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.892353908882637548e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.899699176602474004e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.906955719647048575e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.914124111916621906e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.921204932508155494e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.928198765532103565e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.935106199930062942e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.941927829293316421e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.948664251682345139e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.955316069447352589e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.961883889049833130e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.968368320885256040e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.974769979106905993e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.981089481450905687e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.987327449062512130e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.993484506323667027e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 5.999561280681907860e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.005558402480638769e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.011476504790811859e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.017316223244071338e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.023078195867384466e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.028763062919203719e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.034371466727194822e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.039904051527558160e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.045361463305998662e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.050744349640348574e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.056053359544899095e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.061289143316457739e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.066452352382161628e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.071543639149088456e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.076563656855666906e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.081513059424938028e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.086392501319680903e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.091202637399423025e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.095944122779365593e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.100617612691240588e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.105223762346123628e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.109763226799216795e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.114236660816624536e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.118644718744137734e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.122988054378042833e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.127267320837970210e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.131483170441792474e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.135636254582597537e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.139727223607730267e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.143756726699930226e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.147725411760562864e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.151633925294964556e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.155482912299897080e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.159273016153126612e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.163004878505129902e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.166679139172937418e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.170296436036106336e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.173857404934836701e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.177362679570228998e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.180812891406686660e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.184208669576453765e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.187550640786308342e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.190839429226379309e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.194075656481114578e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.197259941442378128e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.200392900224684922e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.203475146082546132e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.206507289329951327e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.209489937261956527e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.212423694078376357e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.215309160809580291e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.218146935244376117e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.220937611859965521e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.223681781753987785e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.226380032578600066e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.229032948476624476e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.231641110019721097e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.234205094148574489e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.236725474115114132e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.239202819426703961e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.241637695792322305e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.244030665070717134e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.246382285220486885e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.248693110252116156e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.250963690181915666e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.253194570987865575e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.255386294567339966e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.257539398696686739e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.259654416992664672e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.261731878875689716e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.263772309534900273e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.265776229895001492e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.267744156584870829e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.269676601907915092e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.271574073814149664e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.273437075873968816e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.275266107253615999e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.277061662692288380e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.278824232480897827e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.280554302442434178e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.282252353913916565e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.283918863729922144e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.285554304207649601e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.287159143133507655e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.288733843751198371e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.290278864751273069e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.291794660262143069e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.293281679842499088e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.294740368475158832e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.296171166562257504e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.297574509921815888e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.298950829785623817e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.300300552798427489e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.301624101018390434e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.302921891918820130e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.304194338391104324e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.305441848748864153e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.306664826733279661e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.307863671519569060e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.309038777724597757e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.310190535415586055e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.311319330119906645e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.312425542835919501e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.313509550044852148e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.314571723723674701e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.315612431358955448e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.316632035961680103e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.317630896082990333e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.318609365830837099e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.319567794887517742e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.320506528528063939e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.321425907639473429e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.322326268740747324e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.323207944003716996e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.324071261274634814e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.324916544096504722e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.325744111732135799e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.326554279187879715e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.327347357238052084e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.328123652449997749e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.328883467209785785e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.329627099748504904e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.330354844169149509e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.331066990474062628e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.331763824592920642e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.332445628411241145e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.333112679799375755e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.333765252642003851e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.334403616868057085e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.335028038481103074e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.335638779590129666e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.336236098440738651e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.336820249446712516e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.337391483221935573e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.337950046612662369e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.338496182730106732e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.339030130983330125e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.339552127112416002e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.340062403221913279e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.340561187814528488e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.341048705825053311e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.341525178654500827e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.341990824204450483e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.342445856911570701e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.342890487782305797e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.343324924427721001e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.343749371098478917e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.344164028719935899e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.344569094927349440e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.344964764101169052e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.345351227402414196e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.345728672808105486e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.346097285146751865e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.346457246133873298e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.346808734407542119e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.347151925563943919e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.347486992192926891e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.347814103913542283e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.348133427409558216e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.348445126464935306e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.348749361999253438e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.349046292103081690e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.349336072073270998e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.349618854448171312e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.349894789042759058e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.350164022983659784e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.350426700744059794e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.350682964178500534e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.350932952557546862e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.351176802602310545e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.351414648518832529e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.351646622032313338e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.351872852421172944e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.352093466550948975e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.352308588908015530e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.352518341633113685e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.352722844554696380e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.352922215222070790e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.353116568938339981e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.353306018793128729e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.353490675695098844e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.353670648404241561e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.353846043563931012e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354016965732768085e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354183517416157834e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354345799097670167e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354503909270136752e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354657944466499231e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354807999290410514e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.354954166446565189e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355096536770771465e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355235199259760215e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355370241100717799e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355501747700547099e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355629802714855003e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355754488076662767e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355875884024823286e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.355994069132174573e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356109120333387708e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356221112952541219e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356330120730395272e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356436215851384297e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356539468970309414e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356639949238740428e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356737724331121164e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356832860470579938e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.356925422454439811e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357015473679433981e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357103076166624511e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357188290586014645e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357271176280868019e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357351791291731224e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357430192380145506e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357506435052070692e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357580573581006256e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357652661030810393e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357722749278222452e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357790889035090487e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357857129870295942e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357921520231385237e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.357984107465910917e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358044937842461053e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358104056571417750e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358161507825404790e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358217334759449280e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358271579530862638e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358324283318814274e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358375486343638805e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358425227885840414e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358473546304822754e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358520479057334640e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358566062715633294e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358610332985369595e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358653324723198885e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358695071954115541e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358735607888508667e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358774964938957552e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358813174736750895e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358850268148141360e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358886275290335455e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358921225547222278e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358955147584842926e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.358988069366597884e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359020018168206612e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359051020592402459e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359081102583395761e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359110289441069597e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359138605834943725e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359166075817885400e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359192722839592804e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359218569759821804e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359243638861402204e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359267951862997315e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359291529931646814e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359314393695084000e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359336563253818575e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359358058193006258e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359378897594091917e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359399100046244868e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359418683657572124e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359437666066122929e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359456064450689006e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359473895541388977e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359491175630063609e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359507920580455220e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359524145838203246e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359539866440636402e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359555097026373005e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359569851844735666e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359584144764976799e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359597989285316721e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359611398541809457e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359624385317015793e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359636962048513809e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359649140837227321e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359660933455583809e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359672351355509790e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359683405676253010e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359694107252048312e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359704466619614749e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359714494025503484e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359724199433284042e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359733592530579571e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359742682735952002e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359751479205638880e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359759990840143651e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359768226290682946e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359776193965500646e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359783902036024728e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359791358442912212e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359798570901941339e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359805546909784724e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359812293749644851e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359818818496770554e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359825128023846474e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359831229006253750e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359837127927224998e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359842831082868742e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359848344587083702e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359853674376358512e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359858826214465743e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359863805697036021e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359868618256036221e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359873269164133980e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359877763538965390e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359882106347297892e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359886302409100800e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359890356401503020e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359894272862680609e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359898056195621763e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359901710671828745e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359905240434911455e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359908649504096623e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359911941777658839e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359915121036259222e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359918190946205030e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359921155062629339e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359924016832589899e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359926779598089830e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359929446599029035e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359932020976072131e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359934505773448876e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359936903941688868e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359939218340270983e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359941451740227514e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359943606826660378e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359945686201204929e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359947692384428031e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359949627818161311e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359951494867774890e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359953295824397834e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359955032907065764e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359956708264829395e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359958323978792905e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359959882064111447e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359961384471924717e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359962833091240775e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359964229750778131e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359965576220747430e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359966874214591392e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359968125390676796e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359969331353938493e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359970493657480795e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359971613804133561e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359972693247970987e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359973733395777096e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359974735608482810e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359975701202557730e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359976631451362827e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359977527586466728e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359978390798927350e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359979222240530028e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359980023025003426e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359980794229186607e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359981536894174781e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359982252026426863e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359982940598841061e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359983603551805587e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359984241794207627e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359984856204428105e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359985447631295585e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359986016895018857e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359986564788092878e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359987092076169191e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359987599498917454e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359988087770845233e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359988557582102686e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359989009599265053e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359989444466081387e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359989862804216187e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359990265213956384e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359990652274898792e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359991024546630456e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359991382569369023e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359991726864593353e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359992057935661691e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359992376268398750e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359992682331669478e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359992976577942159e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359993259443820435e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359993531350577989e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359993792704652371e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359994043898149485e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359994285309314321e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359994517302991035e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359994740231078580e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359994954432953485e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359995160235901501e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359995357955515516e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359995547896092560e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359995730351021059e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359995905603142319e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359996073925114679e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359996235579754575e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359996390820380263e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359996539891128009e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359996683027273612e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359996820455534383e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359996952394361358e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997079054228841e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997200637907966e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997317340735812e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997429350867648e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997536849535393e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997640011285647e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997739004210615e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997833990179039e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359997925125051133e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998012558894409e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998096436184412e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998176896003663e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998254072231738e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998328093734443e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998399084535237e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998467163994640e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998532446973663e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998595043995451e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998655061400719e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998712601499626e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998767762715666e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998820639726880e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998871323601755e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998919901929781e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359998966458946690e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999011075660569e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999053829966442e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999094796759955e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999134048049285e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999171653060834e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999207678339594e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999242187853064e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999275243080952e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999306903110217e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999337224723881e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999366262486298e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999394068827527e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999420694117056e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999446186752614e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999470593218795e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999493958174988e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999516324511326e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999537733422414e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999558224469496e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999577835641738e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999596603416627e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999614562820369e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999631747475846e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999648189663013e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999663920368640e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999678969334269e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999693365105955e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999707135079561e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999720305542503e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999732901723490e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999744947825384e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999756467071386e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999767481737898e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999778013197158e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999788081947436e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999797707650337e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999806909161002e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999815704562742e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999824111195466e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999832145684984e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999839823972323e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999847161340369e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999854172436962e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999860871307753e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999867271411311e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999873385649316e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999879226382546e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999884805459303e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999890134232281e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999895223575450e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999900083911584e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999904725221143e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999909157068032e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999913388610260e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999917428621252e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999921285503177e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999924967299378e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999928481715692e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999931836126663e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999935037595975e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999938092884442e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999941008465107e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999943790531240e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999946445014096e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999948977588247e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999951393684903e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999953698499908e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999955897007951e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999957993965225e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999959993923646e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999961901237953e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999963720073701e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999965454414372e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999967108070251e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999968684686422e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999970187746321e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999971620584169e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999972986382311e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999974288190749e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999975528920046e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999976711351977e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999977838149299e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999978911856644e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999979934900516e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999980909606165e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999981838194039e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999982722782441e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999983565399084e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999984367978421e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999985132371414e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999985860343763e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999986553581230e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999987213697636e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999987842231306e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999988440649510e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999989010359123e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999989552696853e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999990068943454e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999990560319283e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999991027990518e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999991473069159e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999991896617466e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999992299650629e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999992683133208e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999993047988909e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999993395097917e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999993725302225e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999994039403859e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999994338163987e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999994622314468e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999994892550745e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999995149535401e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999995393903482e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999995626255398e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999995847168464e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999996057191574e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999996256846089e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999996446631165e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999996627022867e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999996798474164e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999996961416713e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999997116261738e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999997263400928e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999997403209981e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999997536042393e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999997662240112e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999997782122882e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999997896001567e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998004169264e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998106903085e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998204472149e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998297126922e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998385109876e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998468651938e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998547970712e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998623274031e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998694760848e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998762619455e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998827029266e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998888163475e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999998946181066e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999001240134e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999053487230e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999103061796e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999150096173e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999194720921e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999237053281e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999277209604e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999315299135e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999351424904e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999385686387e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999418177730e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999448987751e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999478202604e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999505901336e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999532162107e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999557056860e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999580654872e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999603023646e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999624224465e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999644316837e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999663357606e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999681401839e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999698498385e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999714696983e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999730043818e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999744582411e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999758355393e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999771400070e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999783755520e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999795456382e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999806538185e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999817032013e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999826968953e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999836376539e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999845283192e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999853714669e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999861696729e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999869252463e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999876403187e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999883171107e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999889575761e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999895635803e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999901370771e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999906796653e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999911930324e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999916785995e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999921380542e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999925725511e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999929836001e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999933722670e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999937398840e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999940875171e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999944161431e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999947270055e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999950207261e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999952985483e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999955610939e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999958093397e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999960439077e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999962655970e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999964752071e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999966731821e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999968603213e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999970369799e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999972040463e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999973617868e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999975108231e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999976515994e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999977845597e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999979101482e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999980287200e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999981407193e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999982465013e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999983463326e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999984405683e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999985296526e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999986136743e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999986928998e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999987677732e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999988383834e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999989050856e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999989679687e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999990273878e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999990833430e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999991361896e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999991860165e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999992330899e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999992774100e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999993193320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999993587672e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999993959818e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999994310649e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999994641939e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999994953690e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999995248565e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999995524789e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999995785913e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999996033715e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999996264641e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999996484021e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999996690079e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999996884590e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999997068443e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999997240749e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999997403286e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999997556941e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999997700826e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999997836717e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999997965503e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998085407e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998199094e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998305675e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998406928e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998501963e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998590781e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998675158e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998754205e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998827924e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998898979e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999998965592e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999026876e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999085496e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999140563e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999192077e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999240927e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999286224e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999329745e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999370601e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999408793e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999444320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999478071e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999509157e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999539355e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999566889e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999593534e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999618403e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999641496e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999663700e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999684128e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999703668e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999722320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999739195e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999754294e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999770282e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999784492e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999796927e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999809361e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999821796e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999832454e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999843112e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999852882e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999861764e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999870646e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999878639e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999885745e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999892850e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999899956e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999905285e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999912390e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999917719e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999923048e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999927489e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999932818e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999936371e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999939924e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999943476e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999947917e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999950582e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999954134e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999956799e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999959464e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999962128e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999964793e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999967457e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999969233e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999971010e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999972786e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999974563e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999976339e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999978115e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999979003e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999980780e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999981668e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999983444e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999984333e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999985221e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999986109e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999987885e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999987885e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999988773e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999988773e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999990550e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999990550e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999991438e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999991438e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999992326e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999993214e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999993214e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999994102e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999994991e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999994991e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999994991e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999994991e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999995879e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999995879e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999995879e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999996767e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999996767e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999997655e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999997655e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999997655e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999997655e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999997655e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999997655e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999998543e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.359999999999999432e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 +2.499999999999857891e-02 6.360000000000000320e+00 0.000000000000000000e+00 0.000000000000000000e+00 diff --git a/tests/test_data/ORSO/test6.layers b/tests/test_data/ORSO/test6.layers new file mode 100644 index 00000000..c1726df0 --- /dev/null +++ b/tests/test_data/ORSO/test6.layers @@ -0,0 +1,3 @@ +0.00e+00 2.07e+00 0.00e+00 0 +1.20e+03 4.66e+00 1.60e-02 1.00e+01 +0.00e+00 6.36e+00 0.00e+00 3.00e+00 \ No newline at end of file diff --git a/tests/test_data/ORSO/test7.layers b/tests/test_data/ORSO/test7.layers new file mode 100644 index 00000000..24d0fe1e --- /dev/null +++ b/tests/test_data/ORSO/test7.layers @@ -0,0 +1,3 @@ +0.00e+00 0.0e+00 0.00e+00 0 +1.20e+03 4.66e+00 1.60e-02 1.00e+01 +0.00e+00 6.36e+00 0.00e+00 3.00e+00 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_0.dat b/tests/test_data/ORSO/test_0.dat new file mode 100644 index 00000000..48a86fa4 --- /dev/null +++ b/tests/test_data/ORSO/test_0.dat @@ -0,0 +1,1001 @@ +5.000000000000000104e-03 9.665000503913141472e-01 0.000000000000000000 +5.494999999999999885e-03 9.631253196322540067e-01 0.000000000000000000 +5.990000000000000532e-03 9.597294737770289963e-01 0.000000000000000000 +6.485000000000000313e-03 9.563106251913106037e-01 0.000000000000000000 +6.980000000000000093e-03 9.528673984908934136e-01 0.000000000000000000 +7.474999999999999874e-03 9.493991543655699861e-01 0.000000000000000000 +7.969999999999999654e-03 9.459063203571898004e-01 0.000000000000000000 +8.465000000000000302e-03 9.423908868167988340e-01 0.000000000000000000 +8.959999999999999215e-03 9.388571643538128342e-01 0.000000000000000000 +9.454999999999999863e-03 9.353129674107756308e-01 0.000000000000000000 +9.950000000000000511e-03 9.317715164887934165e-01 0.000000000000000000 +1.044499999999999942e-02 9.282546034828660364e-01 0.000000000000000000 +1.094000000000000007e-02 9.247980927595669254e-01 0.000000000000000000 +1.143500000000000072e-02 9.214620278002197962e-01 0.000000000000000000 +1.192999999999999963e-02 9.183506161388482747e-01 0.000000000000000000 +1.242500000000000028e-02 9.156560117476597593e-01 0.000000000000000000 +1.292000000000000093e-02 9.137702868564654413e-01 0.000000000000000000 +1.341499999999999984e-02 9.136604579104798951e-01 0.000000000000000000 +1.390999999999999875e-02 9.193730244525446516e-01 0.000000000000000000 +1.440500000000000114e-02 1.714921119790818738e-01 0.000000000000000000 +1.490000000000000005e-02 5.958306785378732207e-02 0.000000000000000000 +1.539499999999999896e-02 2.440450965112313589e-02 0.000000000000000000 +1.589000000000000135e-02 1.014502025760992410e-02 0.000000000000000000 +1.638500000000000026e-02 3.961444323231197613e-03 0.000000000000000000 +1.687999999999999917e-02 1.371705764215192186e-03 0.000000000000000000 +1.737500000000000155e-02 4.818508477945342042e-04 0.000000000000000000 +1.787000000000000047e-02 4.003359027260820725e-04 0.000000000000000000 +1.836499999999999938e-02 6.802583708794605975e-04 0.000000000000000000 +1.886000000000000176e-02 1.090520635705883538e-03 0.000000000000000000 +1.935500000000000068e-02 1.511449194473834384e-03 0.000000000000000000 +1.984999999999999959e-02 1.883360414698527843e-03 0.000000000000000000 +2.034499999999999850e-02 2.179699542647192591e-03 0.000000000000000000 +2.084000000000000088e-02 2.392376676912041054e-03 0.000000000000000000 +2.133499999999999980e-02 2.523487485224354225e-03 0.000000000000000000 +2.183000000000000218e-02 2.580522661338841353e-03 0.000000000000000000 +2.232500000000000109e-02 2.573551595853644080e-03 0.000000000000000000 +2.282000000000000001e-02 2.513555729898779654e-03 0.000000000000000000 +2.331500000000000239e-02 2.411447292832342298e-03 0.000000000000000000 +2.381000000000000130e-02 2.277504382024556594e-03 0.000000000000000000 +2.430500000000000022e-02 2.121062623333965121e-03 0.000000000000000000 +2.479999999999999913e-02 1.950366520437797060e-03 0.000000000000000000 +2.529500000000000151e-02 1.772520641534203883e-03 0.000000000000000000 +2.579000000000000042e-02 1.593503070502854876e-03 0.000000000000000000 +2.628499999999999934e-02 1.418217193744504643e-03 0.000000000000000000 +2.678000000000000172e-02 1.250566384455460353e-03 0.000000000000000000 +2.727500000000000063e-02 1.093541506008351280e-03 0.000000000000000000 +2.776999999999999955e-02 9.493145850412820601e-04 0.000000000000000000 +2.826500000000000193e-02 8.193342269235605758e-04 0.000000000000000000 +2.876000000000000084e-02 7.044198053791499462e-04 0.000000000000000000 +2.925499999999999975e-02 6.048524299928025559e-04 0.000000000000000000 +2.975000000000000214e-02 5.204613533678317978e-04 0.000000000000000000 +3.024500000000000105e-02 4.507049337130127368e-04 0.000000000000000000 +3.073999999999999996e-02 3.947455887741073248e-04 0.000000000000000000 +3.123500000000000235e-02 3.515184083403329464e-04 0.000000000000000000 +3.173000000000000126e-02 3.197932640750941681e-04 0.000000000000000000 +3.222499999999999670e-02 2.982303858893446983e-04 0.000000000000000000 +3.271999999999999909e-02 2.854294756210801393e-04 0.000000000000000000 +3.321500000000000147e-02 2.799725092666949179e-04 0.000000000000000000 +3.370999999999999691e-02 2.804604435445192095e-04 0.000000000000000000 +3.420499999999999929e-02 2.855440945196244295e-04 0.000000000000000000 +3.470000000000000168e-02 2.939494976267552329e-04 0.000000000000000000 +3.519499999999999712e-02 3.044980912426223417e-04 0.000000000000000000 +3.568999999999999950e-02 3.161220910911499292e-04 0.000000000000000000 +3.618500000000000189e-02 3.278754410636460425e-04 0.000000000000000000 +3.667999999999999733e-02 3.389407381872478506e-04 0.000000000000000000 +3.717499999999999971e-02 3.486325360684768590e-04 0.000000000000000000 +3.766999999999999515e-02 3.563974327048583229e-04 0.000000000000000000 +3.816499999999999754e-02 3.618113455851717760e-04 0.000000000000000000 +3.865999999999999992e-02 3.645743699498288511e-04 0.000000000000000000 +3.915499999999999536e-02 3.645036053936043501e-04 0.000000000000000000 +3.964999999999999775e-02 3.615243220799577053e-04 0.000000000000000000 +4.014500000000000013e-02 3.556598210955979038e-04 0.000000000000000000 +4.063999999999999557e-02 3.470203242833020015e-04 0.000000000000000000 +4.113499999999999795e-02 3.357912076109730612e-04 0.000000000000000000 +4.163000000000000034e-02 3.222208691102914540e-04 0.000000000000000000 +4.212499999999999578e-02 3.066084979808539161e-04 0.000000000000000000 +4.261999999999999816e-02 2.892919859252748036e-04 0.000000000000000000 +4.311500000000000055e-02 2.706361954674823579e-04 0.000000000000000000 +4.360999999999999599e-02 2.510217732128565697e-04 0.000000000000000000 +4.410499999999999837e-02 2.308346690288415966e-04 0.000000000000000000 +4.459999999999999382e-02 2.104564952457407172e-04 0.000000000000000000 +4.509499999999999620e-02 1.902558334786057812e-04 0.000000000000000000 +4.558999999999999858e-02 1.705805708219954757e-04 0.000000000000000000 +4.608499999999999402e-02 1.517513222282850882e-04 0.000000000000000000 +4.657999999999999641e-02 1.340559720911568679e-04 0.000000000000000000 +4.707499999999999879e-02 1.177453456456203256e-04 0.000000000000000000 +4.756999999999999423e-02 1.030299999709845217e-04 0.000000000000000000 +4.806499999999999662e-02 9.007810532588240212e-05 0.000000000000000000 +4.855999999999999900e-02 7.901437041068618591e-05 0.000000000000000000 +4.905499999999999444e-02 6.991995006796396326e-05 0.000000000000000000 +4.954999999999999682e-02 6.283326099029555058e-05 0.000000000000000000 +5.004499999999999921e-02 5.775162026674022879e-05 0.000000000000000000 +5.053999999999999465e-02 5.463361309070174530e-05 0.000000000000000000 +5.103499999999999703e-02 5.340208966396771921e-05 0.000000000000000000 +5.152999999999999942e-02 5.394768722199556134e-05 0.000000000000000000 +5.202499999999999486e-02 5.613277109949464449e-05 0.000000000000000000 +5.251999999999999724e-02 5.979568874819540477e-05 0.000000000000000000 +5.301499999999999962e-02 6.475523247915131251e-05 0.000000000000000000 +5.350999999999999507e-02 7.081521027445391464e-05 0.000000000000000000 +5.400499999999999745e-02 7.776902912331245198e-05 0.000000000000000000 +5.449999999999999983e-02 8.540420179439664689e-05 0.000000000000000000 +5.499499999999999528e-02 9.350669555859472530e-05 0.000000000000000000 +5.548999999999999766e-02 1.018650499152425407e-04 0.000000000000000000 +5.598500000000000004e-02 1.102741996387353746e-04 0.000000000000000000 +5.647999999999999549e-02 1.185389492412449700e-04 0.000000000000000000 +5.697499999999999787e-02 1.264770550353150119e-04 0.000000000000000000 +5.747000000000000025e-02 1.339218811803211009e-04 0.000000000000000000 +5.796499999999999569e-02 1.407246062229117710e-04 0.000000000000000000 +5.845999999999999808e-02 1.467559665211636000e-04 0.000000000000000000 +5.895500000000000046e-02 1.519075324182569508e-04 0.000000000000000000 +5.944999999999999590e-02 1.560925219644843662e-04 0.000000000000000000 +5.994499999999999829e-02 1.592461652548708088e-04 0.000000000000000000 +6.044000000000000067e-02 1.613256399517439183e-04 0.000000000000000000 +6.093499999999999611e-02 1.623096052144035433e-04 0.000000000000000000 +6.142999999999999849e-02 1.621973669988027592e-04 0.000000000000000000 +6.192499999999999394e-02 1.610077124750920654e-04 0.000000000000000000 +6.241999999999999632e-02 1.587774551151332710e-04 0.000000000000000000 +6.291499999999999870e-02 1.555597348187712529e-04 0.000000000000000000 +6.340999999999999415e-02 1.514221192869470343e-04 0.000000000000000000 +6.390500000000000347e-02 1.464445537375784641e-04 0.000000000000000000 +6.439999999999999891e-02 1.407172060372469439e-04 0.000000000000000000 +6.489499999999999436e-02 1.343382534416530676e-04 0.000000000000000000 +6.539000000000000368e-02 1.274116554659633432e-04 0.000000000000000000 +6.588499999999999912e-02 1.200449550176506186e-04 0.000000000000000000 +6.637999999999999456e-02 1.123471469027240621e-04 0.000000000000000000 +6.687500000000000389e-02 1.044266492511661411e-04 0.000000000000000000 +6.736999999999999933e-02 9.638940939376006427e-05 0.000000000000000000 +6.786500000000000865e-02 8.833717135741299159e-05 0.000000000000000000 +6.836000000000000409e-02 8.036592752861807301e-05 0.000000000000000000 +6.885499999999999954e-02 7.256457226265916713e-05 0.000000000000000000 +6.935000000000000886e-02 6.501377038540964931e-05 0.000000000000000000 +6.984500000000000430e-02 5.778504873719187746e-05 0.000000000000000000 +7.033999999999999975e-02 5.094011423086555388e-05 0.000000000000000000 +7.083500000000000907e-02 4.453039741930946583e-05 0.000000000000000000 +7.133000000000000451e-02 3.859681636316308570e-05 0.000000000000000000 +7.182499999999999996e-02 3.316975172203380300e-05 0.000000000000000000 +7.232000000000000928e-02 2.826922051555540405e-05 0.000000000000000000 +7.281500000000000472e-02 2.390523295898025743e-05 0.000000000000000000 +7.331000000000000016e-02 2.007831420536266930e-05 0.000000000000000000 +7.380500000000000949e-02 1.678017074613669021e-05 0.000000000000000000 +7.430000000000000493e-02 1.399447964675333721e-05 0.000000000000000000 +7.479500000000000037e-02 1.169777772672906321e-05 0.000000000000000000 +7.529000000000000969e-02 9.860427226689935383e-06 0.000000000000000000 +7.578500000000000514e-02 8.447634422427182380e-06 0.000000000000000000 +7.628000000000000058e-02 7.420498022782654379e-06 0.000000000000000000 +7.677500000000000990e-02 6.737064992173760663e-06 0.000000000000000000 +7.727000000000000535e-02 6.353372630793248100e-06 0.000000000000000000 +7.776500000000000079e-02 6.224457281953143957e-06 0.000000000000000000 +7.826000000000001011e-02 6.305311867958266546e-06 0.000000000000000000 +7.875500000000000556e-02 6.551776531896834452e-06 0.000000000000000000 +7.925000000000000100e-02 6.921348928898578023e-06 0.000000000000000000 +7.974500000000001032e-02 7.373903112575820720e-06 0.000000000000000000 +8.024000000000000576e-02 7.872308446066495828e-06 0.000000000000000000 +8.073500000000000121e-02 8.382942479538479453e-06 0.000000000000000000 +8.123000000000001053e-02 8.876094226448479849e-06 0.000000000000000000 +8.172500000000000597e-02 9.326256691630531844e-06 0.000000000000000000 +8.222000000000000142e-02 9.712309811688466126e-06 0.000000000000000000 +8.271500000000001074e-02 1.001759712282525315e-05 0.000000000000000000 +8.321000000000000618e-02 1.022990143889558785e-05 0.000000000000000000 +8.370500000000000163e-02 1.034132657422960483e-05 0.000000000000000000 +8.419999999999999707e-02 1.034809365837675406e-05 0.000000000000000000 +8.469500000000000639e-02 1.025026184608369174e-05 0.000000000000000000 +8.519000000000000183e-02 1.005138421396708656e-05 0.000000000000000000 +8.568499999999999728e-02 9.758110349881624041e-06 0.000000000000000000 +8.618000000000000660e-02 9.379747581882740334e-06 0.000000000000000000 +8.667500000000000204e-02 8.927792966247648286e-06 0.000000000000000000 +8.716999999999999749e-02 8.415448068688783707e-06 0.000000000000000000 +8.766500000000000681e-02 7.857128244550779875e-06 0.000000000000000000 +8.816000000000000225e-02 7.267977571487112315e-06 0.000000000000000000 +8.865499999999999770e-02 6.663399834385784171e-06 0.000000000000000000 +8.915000000000000702e-02 6.058615032598972787e-06 0.000000000000000000 +8.964500000000000246e-02 5.468249801604943446e-06 0.000000000000000000 +9.013999999999999790e-02 4.905968944441799803e-06 0.000000000000000000 +9.063500000000000723e-02 4.384153983009630694e-06 0.000000000000000000 +9.113000000000000267e-02 3.913633296325915168e-06 0.000000000000000000 +9.162499999999999811e-02 3.503467042538443262e-06 0.000000000000000000 +9.212000000000000743e-02 3.160788693495074921e-06 0.000000000000000000 +9.261500000000000288e-02 2.890703673092192125e-06 0.000000000000000000 +9.310999999999999832e-02 2.696244309777646360e-06 0.000000000000000000 +9.360500000000000764e-02 2.578379113289906022e-06 0.000000000000000000 +9.410000000000000309e-02 2.536073287138565627e-06 0.000000000000000000 +9.459499999999999853e-02 2.566396409606154249e-06 0.000000000000000000 +9.509000000000000785e-02 2.664672371932071160e-06 0.000000000000000000 +9.558500000000000330e-02 2.824665964299255494e-06 0.000000000000000000 +9.607999999999999874e-02 3.038799956057515098e-06 0.000000000000000000 +9.657500000000000806e-02 3.298396130733936035e-06 0.000000000000000000 +9.707000000000000350e-02 3.593933509565863661e-06 0.000000000000000000 +9.756499999999999895e-02 3.915316927231527681e-06 0.000000000000000000 +9.806000000000000827e-02 4.252149204441249631e-06 0.000000000000000000 +9.855500000000000371e-02 4.594000385719410066e-06 0.000000000000000000 +9.904999999999999916e-02 4.930667865946074680e-06 0.000000000000000000 +9.954500000000000848e-02 5.252421702749102437e-06 0.000000000000000000 +1.000400000000000039e-01 5.550229988457076520e-06 0.000000000000000000 +1.005349999999999994e-01 5.815959818366009312e-06 0.000000000000000000 +1.010300000000000087e-01 6.042550123744568202e-06 0.000000000000000000 +1.015250000000000041e-01 6.224153419938869278e-06 0.000000000000000000 +1.020199999999999996e-01 6.356244333330188696e-06 0.000000000000000000 +1.025150000000000089e-01 6.435693597268485328e-06 0.000000000000000000 +1.030100000000000043e-01 6.460807028298937111e-06 0.000000000000000000 +1.035049999999999998e-01 6.431329792845432285e-06 0.000000000000000000 +1.040000000000000091e-01 6.348417034915222302e-06 0.000000000000000000 +1.044950000000000045e-01 6.214572642797414859e-06 0.000000000000000000 +1.049900000000000000e-01 6.033558574171867219e-06 0.000000000000000000 +1.054850000000000093e-01 5.810277723578255693e-06 0.000000000000000000 +1.059800000000000048e-01 5.550633794791104459e-06 0.000000000000000000 +1.064750000000000002e-01 5.261372026501575741e-06 0.000000000000000000 +1.069700000000000095e-01 4.949904908204729818e-06 0.000000000000000000 +1.074650000000000050e-01 4.624127211890433264e-06 0.000000000000000000 +1.079600000000000004e-01 4.292224753836244784e-06 0.000000000000000000 +1.084550000000000097e-01 3.962481291326354775e-06 0.000000000000000000 +1.089500000000000052e-01 3.643087855352604564e-06 0.000000000000000000 +1.094450000000000006e-01 3.341958627924044645e-06 0.000000000000000000 +1.099400000000000099e-01 3.066557198858582194e-06 0.000000000000000000 +1.104350000000000054e-01 2.823736690580863076e-06 0.000000000000000000 +1.109300000000000008e-01 2.619596830440908198e-06 0.000000000000000000 +1.114250000000000101e-01 2.459360589287039759e-06 0.000000000000000000 +1.119200000000000056e-01 2.347272504039111063e-06 0.000000000000000000 +1.124150000000000010e-01 2.286520272812265947e-06 0.000000000000000000 +1.129100000000000104e-01 2.279180665880931823e-06 0.000000000000000000 +1.134050000000000058e-01 2.326190246513927334e-06 0.000000000000000000 +1.139000000000000012e-01 2.427340854132424923e-06 0.000000000000000000 +1.143950000000000106e-01 2.581299279528182420e-06 0.000000000000000000 +1.148900000000000060e-01 2.785650068288720069e-06 0.000000000000000000 +1.153850000000000015e-01 3.036959933576395465e-06 0.000000000000000000 +1.158800000000000108e-01 3.330861851142939722e-06 0.000000000000000000 +1.163750000000000062e-01 3.662156554965000084e-06 0.000000000000000000 +1.168700000000000017e-01 4.024928856718445573e-06 0.000000000000000000 +1.173649999999999971e-01 4.412675980672368633e-06 0.000000000000000000 +1.178600000000000064e-01 4.818444940134443894e-06 0.000000000000000000 +1.183550000000000019e-01 5.234975883600831529e-06 0.000000000000000000 +1.188499999999999973e-01 5.654848307947394972e-06 0.000000000000000000 +1.193450000000000066e-01 6.070627070821400986e-06 0.000000000000000000 +1.198400000000000021e-01 6.475005231849424831e-06 0.000000000000000000 +1.203349999999999975e-01 6.860940908263738515e-06 0.000000000000000000 +1.208300000000000068e-01 7.221785539885778135e-06 0.000000000000000000 +1.213250000000000023e-01 7.551401214889840919e-06 0.000000000000000000 +1.218199999999999977e-01 7.844265004563152514e-06 0.000000000000000000 +1.223150000000000071e-01 8.095558584822332352e-06 0.000000000000000000 +1.228100000000000025e-01 8.301241776636406514e-06 0.000000000000000000 +1.233049999999999979e-01 8.458109008549570250e-06 0.000000000000000000 +1.238000000000000073e-01 8.563828083965509540e-06 0.000000000000000000 +1.242950000000000027e-01 8.616961015592759134e-06 0.000000000000000000 +1.247899999999999981e-01 8.616967061619456886e-06 0.000000000000000000 +1.252850000000000075e-01 8.564188455302446071e-06 0.000000000000000000 +1.257800000000000029e-01 8.459819654887802570e-06 0.000000000000000000 +1.262749999999999984e-01 8.305861247906351610e-06 0.000000000000000000 +1.267699999999999938e-01 8.105059917511166478e-06 0.000000000000000000 +1.272649999999999892e-01 7.860836114135193775e-06 0.000000000000000000 +1.277599999999999847e-01 7.577201269758093117e-06 0.000000000000000000 +1.282550000000000079e-01 7.258666541857485466e-06 0.000000000000000000 +1.287500000000000033e-01 6.910145178129714948e-06 0.000000000000000000 +1.292449999999999988e-01 6.536850650648383778e-06 0.000000000000000000 +1.297399999999999942e-01 6.144192719724897499e-06 0.000000000000000000 +1.302350000000000174e-01 5.737673554619307002e-06 0.000000000000000000 +1.307300000000000129e-01 5.322785962672806524e-06 0.000000000000000000 +1.312250000000000083e-01 4.904915663368263668e-06 0.000000000000000000 +1.317200000000000037e-01 4.489249393036131954e-06 0.000000000000000000 +1.322149999999999992e-01 4.080690443733145887e-06 0.000000000000000000 +1.327099999999999946e-01 3.683783031084570475e-06 0.000000000000000000 +1.332049999999999901e-01 3.302646655837594763e-06 0.000000000000000000 +1.337000000000000133e-01 2.940921378021860989e-06 0.000000000000000000 +1.341950000000000087e-01 2.601724666608497793e-06 0.000000000000000000 +1.346900000000000042e-01 2.287620227028509563e-06 0.000000000000000000 +1.351849999999999996e-01 2.000598949486405553e-06 0.000000000000000000 +1.356799999999999951e-01 1.742071867957836217e-06 0.000000000000000000 +1.361749999999999905e-01 1.512874778200590678e-06 0.000000000000000000 +1.366700000000000137e-01 1.313283937608676029e-06 0.000000000000000000 +1.371650000000000091e-01 1.143042064463222645e-06 0.000000000000000000 +1.376600000000000046e-01 1.001393672635612863e-06 0.000000000000000000 +1.381550000000000000e-01 8.871286230386589126e-07 0.000000000000000000 +1.386499999999999955e-01 7.986326473527051729e-07 0.000000000000000000 +1.391449999999999909e-01 7.339435044461783354e-07 0.000000000000000000 +1.396400000000000141e-01 6.908113662780594845e-07 0.000000000000000000 +1.401350000000000096e-01 6.667619982166363173e-07 0.000000000000000000 +1.406300000000000050e-01 6.591612980818231490e-07 0.000000000000000000 +1.411250000000000004e-01 6.652797878098401082e-07 0.000000000000000000 +1.416199999999999959e-01 6.823557096464559446e-07 0.000000000000000000 +1.421149999999999913e-01 7.076554630513800969e-07 0.000000000000000000 +1.426100000000000145e-01 7.385302262503321790e-07 0.000000000000000000 +1.431050000000000100e-01 7.724677345326453069e-07 0.000000000000000000 +1.436000000000000054e-01 8.071383324873717440e-07 0.000000000000000000 +1.440950000000000009e-01 8.404345757385826486e-07 0.000000000000000000 +1.445899999999999963e-01 8.705038255271385383e-07 0.000000000000000000 +1.450849999999999917e-01 8.957734528025810904e-07 0.000000000000000000 +1.455800000000000149e-01 9.149684434290505733e-07 0.000000000000000000 +1.460750000000000104e-01 9.271213689127427910e-07 0.000000000000000000 +1.465700000000000058e-01 9.315748540776084957e-07 0.000000000000000000 +1.470650000000000013e-01 9.279768310089414595e-07 0.000000000000000000 +1.475599999999999967e-01 9.162690142921175844e-07 0.000000000000000000 +1.480549999999999922e-01 8.966691633816720694e-07 0.000000000000000000 +1.485500000000000154e-01 8.696478115842969942e-07 0.000000000000000000 +1.490450000000000108e-01 8.359002357776614976e-07 0.000000000000000000 +1.495400000000000063e-01 7.963145152342271968e-07 0.000000000000000000 +1.500350000000000017e-01 7.519365809085332339e-07 0.000000000000000000 +1.505299999999999971e-01 7.039331878515760591e-07 0.000000000000000000 +1.510249999999999926e-01 6.535537531292294156e-07 0.000000000000000000 +1.515200000000000158e-01 6.020919902712146351e-07 0.000000000000000000 +1.520150000000000112e-01 5.508482398413202961e-07 0.000000000000000000 +1.525100000000000067e-01 5.010933455663838863e-07 0.000000000000000000 +1.530050000000000021e-01 4.540348583219919946e-07 0.000000000000000000 +1.534999999999999976e-01 4.107862681963696624e-07 0.000000000000000000 +1.539949999999999930e-01 3.723398701227520304e-07 0.000000000000000000 +1.544900000000000162e-01 3.395437636948939451e-07 0.000000000000000000 +1.549850000000000116e-01 3.130833753837486561e-07 0.000000000000000000 +1.554800000000000071e-01 2.934677741768251342e-07 0.000000000000000000 +1.559750000000000025e-01 2.810209323877752339e-07 0.000000000000000000 +1.564699999999999980e-01 2.758779647252070362e-07 0.000000000000000000 +1.569649999999999934e-01 2.779862632545462779e-07 0.000000000000000000 +1.574600000000000166e-01 2.871113360706200588e-07 0.000000000000000000 +1.579550000000000121e-01 3.028470555598597139e-07 0.000000000000000000 +1.584500000000000075e-01 3.246299300769666282e-07 0.000000000000000000 +1.589450000000000029e-01 3.517569323857624245e-07 0.000000000000000000 +1.594399999999999984e-01 3.834063507723731451e-07 0.000000000000000000 +1.599349999999999938e-01 4.186610753733210365e-07 0.000000000000000000 +1.604300000000000170e-01 4.565336937544804381e-07 0.000000000000000000 +1.609250000000000125e-01 4.959927465076154549e-07 0.000000000000000000 +1.614200000000000079e-01 5.359894856657390000e-07 0.000000000000000000 +1.619150000000000034e-01 5.754844857888850676e-07 0.000000000000000000 +1.624099999999999988e-01 6.134734790458202149e-07 0.000000000000000000 +1.629049999999999943e-01 6.490118206104414487e-07 0.000000000000000000 +1.633999999999999897e-01 6.812370380435290559e-07 0.000000000000000000 +1.638950000000000129e-01 7.093889766341250412e-07 0.000000000000000000 +1.643900000000000083e-01 7.328271203360174540e-07 0.000000000000000000 +1.648850000000000038e-01 7.510447431864785190e-07 0.000000000000000000 +1.653799999999999992e-01 7.636796270680945570e-07 0.000000000000000000 +1.658749999999999947e-01 7.705211664231386851e-07 0.000000000000000000 +1.663699999999999901e-01 7.715137670784514613e-07 0.000000000000000000 +1.668650000000000133e-01 7.667565327270775024e-07 0.000000000000000000 +1.673600000000000088e-01 7.564993169488874264e-07 0.000000000000000000 +1.678550000000000042e-01 7.411352991257035257e-07 0.000000000000000000 +1.683499999999999996e-01 7.211903175517308977e-07 0.000000000000000000 +1.688449999999999951e-01 6.973092609559167074e-07 0.000000000000000000 +1.693399999999999905e-01 6.702398792293577644e-07 0.000000000000000000 +1.698350000000000137e-01 6.408144242929899533e-07 0.000000000000000000 +1.703300000000000092e-01 6.099295718998973208e-07 0.000000000000000000 +1.708250000000000046e-01 5.785251041208233809e-07 0.000000000000000000 +1.713200000000000001e-01 5.475618499638148071e-07 0.000000000000000000 +1.718149999999999955e-01 5.179993879173844923e-07 0.000000000000000000 +1.723099999999999909e-01 4.907740093341187940e-07 0.000000000000000000 +1.728050000000000141e-01 4.667774258689090864e-07 0.000000000000000000 +1.733000000000000096e-01 4.468366782629765882e-07 0.000000000000000000 +1.737950000000000050e-01 4.316956684436242317e-07 0.000000000000000000 +1.742900000000000005e-01 4.219986931792096364e-07 0.000000000000000000 +1.747849999999999959e-01 4.182763065525390247e-07 0.000000000000000000 +1.752799999999999914e-01 4.209337815667329124e-07 0.000000000000000000 +1.757750000000000146e-01 4.302423796660925423e-07 0.000000000000000000 +1.762700000000000100e-01 4.463335722664827997e-07 0.000000000000000000 +1.767650000000000055e-01 4.691962920328160567e-07 0.000000000000000000 +1.772600000000000009e-01 4.986772250770226727e-07 0.000000000000000000 +1.777549999999999963e-01 5.344840899283003740e-07 0.000000000000000000 +1.782499999999999918e-01 5.761917864122179475e-07 0.000000000000000000 +1.787450000000000150e-01 6.232512387570358719e-07 0.000000000000000000 +1.792400000000000104e-01 6.750007035021761932e-07 0.000000000000000000 +1.797350000000000059e-01 7.306792651294629603e-07 0.000000000000000000 +1.802300000000000013e-01 7.894422016581250095e-07 0.000000000000000000 +1.807249999999999968e-01 8.503778694400008144e-07 0.000000000000000000 +1.812199999999999922e-01 9.125257315781544134e-07 0.000000000000000000 +1.817150000000000154e-01 9.748951381101131382e-07 0.000000000000000000 +1.822100000000000108e-01 1.036484458477129741e-06 0.000000000000000000 +1.827050000000000063e-01 1.096300167801006937e-06 0.000000000000000000 +1.832000000000000017e-01 1.153375497887055247e-06 0.000000000000000000 +1.836949999999999972e-01 1.206788281239166297e-06 0.000000000000000000 +1.841899999999999926e-01 1.255677641175201563e-06 0.000000000000000000 +1.846850000000000158e-01 1.299259212638049646e-06 0.000000000000000000 +1.851800000000000113e-01 1.336838615683788791e-06 0.000000000000000000 +1.856750000000000067e-01 1.367822945962577100e-06 0.000000000000000000 +1.861700000000000021e-01 1.391730092759206693e-06 0.000000000000000000 +1.866649999999999976e-01 1.408195744262683065e-06 0.000000000000000000 +1.871599999999999930e-01 1.416977990579310967e-06 0.000000000000000000 +1.876550000000000162e-01 1.417959486455905757e-06 0.000000000000000000 +1.881500000000000117e-01 1.411147186675485260e-06 0.000000000000000000 +1.886450000000000071e-01 1.396669716512313003e-06 0.000000000000000000 +1.891400000000000026e-01 1.374772486532716477e-06 0.000000000000000000 +1.896349999999999980e-01 1.345810704446789728e-06 0.000000000000000000 +1.901299999999999935e-01 1.310240475840981255e-06 0.000000000000000000 +1.906250000000000167e-01 1.268608219743216434e-06 0.000000000000000000 +1.911200000000000121e-01 1.221538653494193117e-06 0.000000000000000000 +1.916150000000000075e-01 1.169721623875224513e-06 0.000000000000000000 +1.921100000000000030e-01 1.113898077553873310e-06 0.000000000000000000 +1.926049999999999984e-01 1.054845473494751245e-06 0.000000000000000000 +1.930999999999999939e-01 9.933629429997963193e-07 0.000000000000000000 +1.935950000000000171e-01 9.302564996243403346e-07 0.000000000000000000 +1.940900000000000125e-01 8.663245915905477929e-07 0.000000000000000000 +1.945850000000000080e-01 8.023442738701147131e-07 0.000000000000000000 +1.950800000000000034e-01 7.390582563153525120e-07 0.000000000000000000 +1.955749999999999988e-01 6.771630586704946436e-07 0.000000000000000000 +1.960699999999999943e-01 6.172984736576098790e-07 0.000000000000000000 +1.965649999999999897e-01 5.600385063495729965e-07 0.000000000000000000 +1.970600000000000129e-01 5.058839225057216701e-07 0.000000000000000000 +1.975550000000000084e-01 4.552565012700060733e-07 0.000000000000000000 +1.980500000000000038e-01 4.084950494642577245e-07 0.000000000000000000 +1.985449999999999993e-01 3.658531964759427938e-07 0.000000000000000000 +1.990399999999999947e-01 3.274989512522766344e-07 0.000000000000000000 +1.995349999999999902e-01 2.935159669515498531e-07 0.000000000000000000 +2.000300000000000133e-01 2.639064250766419108e-07 0.000000000000000000 +2.005250000000000088e-01 2.385954200782702267e-07 0.000000000000000000 +2.010200000000000042e-01 2.174366980513574669e-07 0.000000000000000000 +2.015149999999999997e-01 2.002195797129620680e-07 0.000000000000000000 +2.020099999999999951e-01 1.866768787503766731e-07 0.000000000000000000 +2.025049999999999906e-01 1.764936121339090143e-07 0.000000000000000000 +2.030000000000000138e-01 1.693162892740693107e-07 0.000000000000000000 +2.034950000000000092e-01 1.647625620289037854e-07 0.000000000000000000 +2.039900000000000047e-01 1.624310175105519041e-07 0.000000000000000000 +2.044850000000000001e-01 1.619109002352719055e-07 0.000000000000000000 +2.049799999999999955e-01 1.627915591914925843e-07 0.000000000000000000 +2.054749999999999910e-01 1.646714285272923795e-07 0.000000000000000000 +2.059700000000000142e-01 1.671663673773533474e-07 0.000000000000000000 +2.064650000000000096e-01 1.699172043940377659e-07 0.000000000000000000 +2.069600000000000051e-01 1.725963552794117210e-07 0.000000000000000000 +2.074550000000000005e-01 1.749134064663755894e-07 0.000000000000000000 +2.079499999999999960e-01 1.766195844686593351e-07 0.000000000000000000 +2.084449999999999914e-01 1.775110576851685795e-07 0.000000000000000000 +2.089400000000000146e-01 1.774310449962093689e-07 0.000000000000000000 +2.094350000000000100e-01 1.762707327088914932e-07 0.000000000000000000 +2.099300000000000055e-01 1.739690277202610263e-07 0.000000000000000000 +2.104250000000000009e-01 1.705111996201750424e-07 0.000000000000000000 +2.109199999999999964e-01 1.659264873508179579e-07 0.000000000000000000 +2.114149999999999918e-01 1.602847665364869854e-07 0.000000000000000000 +2.119100000000000150e-01 1.536923913135634573e-07 0.000000000000000000 +2.124050000000000105e-01 1.462873391241233119e-07 0.000000000000000000 +2.129000000000000059e-01 1.382337982538248583e-07 0.000000000000000000 +2.133950000000000014e-01 1.297163457450835877e-07 0.000000000000000000 +2.138899999999999968e-01 1.209338676284841367e-07 0.000000000000000000 +2.143849999999999922e-01 1.120933741971231917e-07 0.000000000000000000 +2.148800000000000154e-01 1.034038603850666826e-07 0.000000000000000000 +2.153750000000000109e-01 9.507035536026284004e-08 0.000000000000000000 +2.158700000000000063e-01 8.728829643305758068e-08 0.000000000000000000 +2.163650000000000018e-01 8.023835059615854957e-08 0.000000000000000000 +2.168599999999999972e-01 7.408179279769844078e-08 0.000000000000000000 +2.173549999999999927e-01 6.895653378549319787e-08 0.000000000000000000 +2.178500000000000159e-01 6.497387246792377290e-08 0.000000000000000000 +2.183450000000000113e-01 6.221602866347468889e-08 0.000000000000000000 +2.188400000000000067e-01 6.073449231052076084e-08 0.000000000000000000 +2.193350000000000022e-01 6.054920514231316621e-08 0.000000000000000000 +2.198299999999999976e-01 6.164857096378309851e-08 0.000000000000000000 +2.203249999999999931e-01 6.399027142437959652e-08 0.000000000000000000 +2.208200000000000163e-01 6.750284598719578962e-08 0.000000000000000000 +2.213150000000000117e-01 7.208797802538331722e-08 0.000000000000000000 +2.218100000000000072e-01 7.762341397162055742e-08 0.000000000000000000 +2.223050000000000026e-01 8.396642949571979216e-08 0.000000000000000000 +2.227999999999999980e-01 9.095774602690579448e-08 0.000000000000000000 +2.232949999999999935e-01 9.842579275264869848e-08 0.000000000000000000 +2.237900000000000167e-01 1.061912036356615096e-07 0.000000000000000000 +2.242850000000000121e-01 1.140714360555606989e-07 0.000000000000000000 +2.247800000000000076e-01 1.218853974046074359e-07 0.000000000000000000 +2.252750000000000030e-01 1.294579682847766425e-07 0.000000000000000000 +2.257699999999999985e-01 1.366243157577544810e-07 0.000000000000000000 +2.262649999999999939e-01 1.432338972168728807e-07 0.000000000000000000 +2.267600000000000171e-01 1.491540646725311707e-07 0.000000000000000000 +2.272550000000000125e-01 1.542731903097046225e-07 0.000000000000000000 +2.277500000000000080e-01 1.585032468002478424e-07 0.000000000000000000 +2.282450000000000034e-01 1.617817897149352884e-07 0.000000000000000000 +2.287399999999999989e-01 1.640733041420296182e-07 0.000000000000000000 +2.292349999999999943e-01 1.653698929315150702e-07 0.000000000000000000 +2.297299999999999898e-01 1.656912994927389679e-07 0.000000000000000000 +2.302250000000000130e-01 1.650842734267576539e-07 0.000000000000000000 +2.307200000000000084e-01 1.636213021365346074e-07 0.000000000000000000 +2.312150000000000039e-01 1.613987456054476658e-07 0.000000000000000000 +2.317099999999999993e-01 1.585344244749948595e-07 0.000000000000000000 +2.322049999999999947e-01 1.551647231198324521e-07 0.000000000000000000 +2.326999999999999902e-01 1.514412793862683773e-07 0.000000000000000000 +2.331950000000000134e-01 1.475273408413232940e-07 0.000000000000000000 +2.336900000000000088e-01 1.435938736279390323e-07 0.000000000000000000 +2.341850000000000043e-01 1.398155142425697717e-07 0.000000000000000000 +2.346799999999999997e-01 1.363664566898842263e-07 0.000000000000000000 +2.351749999999999952e-01 1.334163675218042077e-07 0.000000000000000000 +2.356699999999999906e-01 1.311264192771908341e-07 0.000000000000000000 +2.361650000000000138e-01 1.296455288869103354e-07 0.000000000000000000 +2.366600000000000092e-01 1.291068818253618056e-07 0.000000000000000000 +2.371550000000000047e-01 1.296248153333861478e-07 0.000000000000000000 +2.376500000000000001e-01 1.312921251136448344e-07 0.000000000000000000 +2.381449999999999956e-01 1.341778497200433660e-07 0.000000000000000000 +2.386399999999999910e-01 1.383255756880041633e-07 0.000000000000000000 +2.391350000000000142e-01 1.437522945349044397e-07 0.000000000000000000 +2.396300000000000097e-01 1.504478303819828652e-07 0.000000000000000000 +2.401250000000000051e-01 1.583748443820877517e-07 0.000000000000000000 +2.406200000000000006e-01 1.674694096641629315e-07 0.000000000000000000 +2.411149999999999960e-01 1.776421383871583465e-07 0.000000000000000000 +2.416099999999999914e-01 1.887798309984000303e-07 0.000000000000000000 +2.421050000000000146e-01 2.007476071339980670e-07 0.000000000000000000 +2.426000000000000101e-01 2.133914680164706732e-07 0.000000000000000000 +2.430950000000000055e-01 2.265412318610952635e-07 0.000000000000000000 +2.435900000000000010e-01 2.400137768652760541e-07 0.000000000000000000 +2.440849999999999964e-01 2.536165209440037603e-07 0.000000000000000000 +2.445799999999999919e-01 2.671510635638228207e-07 0.000000000000000000 +2.450750000000000151e-01 2.804169128867386099e-07 0.000000000000000000 +2.455700000000000105e-01 2.932152209493872963e-07 0.000000000000000000 +2.460650000000000059e-01 3.053524507741491616e-07 0.000000000000000000 +2.465600000000000014e-01 3.166439020583791269e-07 0.000000000000000000 +2.470549999999999968e-01 3.269170263355468380e-07 0.000000000000000000 +2.475499999999999923e-01 3.360144681192449913e-07 0.000000000000000000 +2.480450000000000155e-01 3.437967753831660433e-07 0.000000000000000000 +2.485400000000000109e-01 3.501447306242482370e-07 0.000000000000000000 +2.490350000000000064e-01 3.549612625088479711e-07 0.000000000000000000 +2.495300000000000018e-01 3.581729075151094754e-07 0.000000000000000000 +2.500249999999999972e-01 3.597308008369024822e-07 0.000000000000000000 +2.505199999999999649e-01 3.596111858920031830e-07 0.000000000000000000 +2.510149999999999881e-01 3.578154418612221155e-07 0.000000000000000000 +2.515100000000000113e-01 3.543696385556993795e-07 0.000000000000000000 +2.520049999999999790e-01 3.493236373731821415e-07 0.000000000000000000 +2.525000000000000022e-01 3.427497659588049961e-07 0.000000000000000000 +2.529949999999999699e-01 3.347411022651280546e-07 0.000000000000000000 +2.534899999999999931e-01 3.254094108536514815e-07 0.000000000000000000 +2.539850000000000163e-01 3.148827803686610821e-07 0.000000000000000000 +2.544799999999999840e-01 3.033030160378932411e-07 0.000000000000000000 +2.549750000000000072e-01 2.908228447380034481e-07 0.000000000000000000 +2.554700000000000304e-01 2.776029925562102184e-07 0.000000000000000000 +2.559649999999999981e-01 2.638091958678441987e-07 0.000000000000000000 +2.564600000000000213e-01 2.496092067331897089e-07 0.000000000000000000 +2.569549999999999890e-01 2.351698519427563222e-07 0.000000000000000000 +2.574500000000000122e-01 2.206542023609525852e-07 0.000000000000000000 +2.579449999999999799e-01 2.062189054282013083e-07 0.000000000000000000 +2.584400000000000031e-01 1.920117288817375068e-07 0.000000000000000000 +2.589350000000000263e-01 1.781693580820991321e-07 0.000000000000000000 +2.594299999999999939e-01 1.648154829163869845e-07 0.000000000000000000 +2.599250000000000171e-01 1.520592032604092885e-07 0.000000000000000000 +2.604199999999999848e-01 1.399937745669751651e-07 0.000000000000000000 +2.609150000000000080e-01 1.286957074891519705e-07 0.000000000000000000 +2.614099999999999757e-01 1.182242277084878080e-07 0.000000000000000000 +2.619049999999999989e-01 1.086210944834820922e-07 0.000000000000000000 +2.624000000000000221e-01 9.991076902879992382e-08 0.000000000000000000 +2.628949999999999898e-01 9.210091683026240794e-08 0.000000000000000000 +2.633900000000000130e-01 8.518322153214401226e-08 0.000000000000000000 +2.638849999999999807e-01 7.913448222603720113e-08 0.000000000000000000 +2.643800000000000039e-01 7.391796093111346204e-08 0.000000000000000000 +2.648750000000000271e-01 6.948494287257691111e-08 0.000000000000000000 +2.653699999999999948e-01 6.577646890053292112e-08 0.000000000000000000 +2.658650000000000180e-01 6.272519709451340610e-08 0.000000000000000000 +2.663599999999999857e-01 6.025734928742395826e-08 0.000000000000000000 +2.668550000000000089e-01 5.829469792569614226e-08 0.000000000000000000 +2.673499999999999766e-01 5.675654932617621010e-08 0.000000000000000000 +2.678449999999999998e-01 5.556168096847991786e-08 0.000000000000000000 +2.683400000000000230e-01 5.463019290113967996e-08 0.000000000000000000 +2.688349999999999906e-01 5.388523657253900830e-08 0.000000000000000000 +2.693300000000000138e-01 5.325458832655081902e-08 0.000000000000000000 +2.698249999999999815e-01 5.267203932322533012e-08 0.000000000000000000 +2.703200000000000047e-01 5.207857864294553063e-08 0.000000000000000000 +2.708150000000000279e-01 5.142335168470370786e-08 0.000000000000000000 +2.713099999999999956e-01 5.066438154887696793e-08 0.000000000000000000 +2.718050000000000188e-01 4.976904677260103406e-08 0.000000000000000000 +2.722999999999999865e-01 4.871431443614565165e-08 0.000000000000000000 +2.727950000000000097e-01 4.748673315633127725e-08 0.000000000000000000 +2.732899999999999774e-01 4.608219571222300289e-08 0.000000000000000000 +2.737850000000000006e-01 4.450548590171156393e-08 0.000000000000000000 +2.742800000000000238e-01 4.276962860735554401e-08 0.000000000000000000 +2.747749999999999915e-01 4.089506587418590604e-08 0.000000000000000000 +2.752700000000000147e-01 3.890868499970547411e-08 0.000000000000000000 +2.757649999999999824e-01 3.684272715583101052e-08 0.000000000000000000 +2.762600000000000056e-01 3.473360686475024807e-08 0.000000000000000000 +2.767550000000000288e-01 3.262067371725050256e-08 0.000000000000000000 +2.772499999999999964e-01 3.054494804663442116e-08 0.000000000000000000 +2.777450000000000196e-01 2.854786187097238529e-08 0.000000000000000000 +2.782399999999999873e-01 2.667003531582894765e-08 0.000000000000000000 +2.787350000000000105e-01 2.495011697313786149e-08 0.000000000000000000 +2.792299999999999782e-01 2.342371430044138201e-08 0.000000000000000000 +2.797250000000000014e-01 2.212243727898790507e-08 0.000000000000000000 +2.802200000000000246e-01 2.107307521675029191e-08 0.000000000000000000 +2.807149999999999923e-01 2.029692288371895798e-08 0.000000000000000000 +2.812100000000000155e-01 1.980926819695495132e-08 0.000000000000000000 +2.817049999999999832e-01 1.961904952857326623e-08 0.000000000000000000 +2.822000000000000064e-01 1.972868648938899510e-08 0.000000000000000000 +2.826950000000000296e-01 2.013408383661252640e-08 0.000000000000000000 +2.831899999999999973e-01 2.082480407130054674e-08 0.000000000000000000 +2.836850000000000205e-01 2.178440040555468355e-08 0.000000000000000000 +2.841799999999999882e-01 2.299089818535655183e-08 0.000000000000000000 +2.846750000000000114e-01 2.441740962009672132e-08 0.000000000000000000 +2.851699999999999791e-01 2.603286386244853487e-08 0.000000000000000000 +2.856650000000000023e-01 2.780283215228305768e-08 0.000000000000000000 +2.861600000000000255e-01 2.969042593159395003e-08 0.000000000000000000 +2.866549999999999931e-01 3.165724457899208611e-08 0.000000000000000000 +2.871500000000000163e-01 3.366434872044360989e-08 0.000000000000000000 +2.876449999999999840e-01 3.567323494970259796e-08 0.000000000000000000 +2.881400000000000072e-01 3.764678822821058603e-08 0.000000000000000000 +2.886350000000000304e-01 3.955018920582269726e-08 0.000000000000000000 +2.891299999999999981e-01 4.135175518042980009e-08 0.000000000000000000 +2.896250000000000213e-01 4.302369534911431124e-08 0.000000000000000000 +2.901199999999999890e-01 4.454276334339993952e-08 0.000000000000000000 +2.906150000000000122e-01 4.589079272701187627e-08 0.000000000000000000 +2.911099999999999799e-01 4.705510409480653850e-08 0.000000000000000000 +2.916050000000000031e-01 4.802877557796328056e-08 0.000000000000000000 +2.921000000000000263e-01 4.881077185464113210e-08 0.000000000000000000 +2.925949999999999940e-01 4.940593011226651778e-08 0.000000000000000000 +2.930900000000000172e-01 4.982480473004944680e-08 0.000000000000000000 +2.935849999999999849e-01 5.008337567496295167e-08 0.000000000000000000 +2.940800000000000081e-01 5.020262866030345885e-08 0.000000000000000000 +2.945749999999999758e-01 5.020801793871705487e-08 0.000000000000000000 +2.950699999999999990e-01 5.012882513116714697e-08 0.000000000000000000 +2.955650000000000222e-01 4.999742968030015832e-08 0.000000000000000000 +2.960599999999999898e-01 4.984850831805449965e-08 0.000000000000000000 +2.965550000000000130e-01 4.971818231968933293e-08 0.000000000000000000 +2.970499999999999807e-01 4.964313225808193827e-08 0.000000000000000000 +2.975450000000000039e-01 4.965970045832412095e-08 0.000000000000000000 +2.980400000000000271e-01 4.980300138338575625e-08 0.000000000000000000 +2.985349999999999948e-01 5.010605976225426768e-08 0.000000000000000000 +2.990300000000000180e-01 5.059899542092764685e-08 0.000000000000000000 +2.995249999999999857e-01 5.130827252084771200e-08 0.000000000000000000 +3.000200000000000089e-01 5.225602928235692504e-08 0.000000000000000000 +3.005149999999999766e-01 5.345950231690924802e-08 0.000000000000000000 +3.010099999999999998e-01 5.493055745788405302e-08 0.000000000000000000 +3.015050000000000230e-01 5.667533652106124858e-08 0.000000000000000000 +3.019999999999999907e-01 5.869402679821528632e-08 0.000000000000000000 +3.024950000000000139e-01 6.098075735608050194e-08 0.000000000000000000 +3.029899999999999816e-01 6.352362343093326867e-08 0.000000000000000000 +3.034850000000000048e-01 6.630483744636865637e-08 0.000000000000000000 +3.039800000000000280e-01 6.930100249350715044e-08 0.000000000000000000 +3.044749999999999956e-01 7.248350155561192896e-08 0.000000000000000000 +3.049700000000000188e-01 7.581899338879230494e-08 0.000000000000000000 +3.054649999999999865e-01 7.927000383111037433e-08 0.000000000000000000 +3.059600000000000097e-01 8.279559944983727826e-08 0.000000000000000000 +3.064549999999999774e-01 8.635212888352076323e-08 0.000000000000000000 +3.069500000000000006e-01 8.989401601773107563e-08 0.000000000000000000 +3.074450000000000238e-01 9.337458827772847315e-08 0.000000000000000000 +3.079399999999999915e-01 9.674692283012004946e-08 0.000000000000000000 +3.084350000000000147e-01 9.996469336922015975e-08 0.000000000000000000 +3.089299999999999824e-01 1.029830004167963952e-07 0.000000000000000000 +3.094250000000000056e-01 1.057591686681371154e-07 0.000000000000000000 +3.099200000000000288e-01 1.082534958638745486e-07 0.000000000000000000 +3.104149999999999965e-01 1.104299389148882970e-07 0.000000000000000000 +3.109100000000000197e-01 1.122567245390141693e-07 0.000000000000000000 +3.114049999999999874e-01 1.137068734326969240e-07 0.000000000000000000 +3.119000000000000106e-01 1.147586289641110085e-07 0.000000000000000000 +3.123949999999999783e-01 1.153957834868586861e-07 0.000000000000000000 +3.128900000000000015e-01 1.156078975877370465e-07 0.000000000000000000 +3.133850000000000247e-01 1.153904098518046454e-07 0.000000000000000000 +3.138799999999999923e-01 1.147446369987451798e-07 0.000000000000000000 +3.143750000000000155e-01 1.136776664746141729e-07 0.000000000000000000 +3.148699999999999832e-01 1.122021457208702330e-07 0.000000000000000000 +3.153650000000000064e-01 1.103359743456424890e-07 0.000000000000000000 +3.158600000000000296e-01 1.081019072565954537e-07 0.000000000000000000 +3.163549999999999973e-01 1.055270784362617595e-07 0.000000000000000000 +3.168500000000000205e-01 1.026424564278367652e-07 0.000000000000000000 +3.173449999999999882e-01 9.948224372407782834e-08 0.000000000000000000 +3.178400000000000114e-01 9.608323309787939415e-08 0.000000000000000000 +3.183349999999999791e-01 9.248413446691503307e-08 0.000000000000000000 +3.188300000000000023e-01 8.872488614524009637e-08 0.000000000000000000 +3.193250000000000255e-01 8.484596429947868206e-08 0.000000000000000000 +3.198199999999999932e-01 8.088770410537438045e-08 0.000000000000000000 +3.203150000000000164e-01 7.688964550851964941e-08 0.000000000000000000 +3.208099999999999841e-01 7.288991564335235635e-08 0.000000000000000000 +3.213050000000000073e-01 6.892465889020185596e-08 0.000000000000000000 +3.217999999999999750e-01 6.502752427176795239e-08 0.000000000000000000 +3.222949999999999982e-01 6.122921844363642630e-08 0.000000000000000000 +3.227900000000000214e-01 5.755713095539548577e-08 0.000000000000000000 +3.232849999999999890e-01 5.403503677983761710e-08 0.000000000000000000 +3.237800000000000122e-01 5.068287937419286739e-08 0.000000000000000000 +3.242749999999999799e-01 4.751663578026204217e-08 0.000000000000000000 +3.247700000000000031e-01 4.454826353184982771e-08 0.000000000000000000 +3.252650000000000263e-01 4.178572745536348647e-08 0.000000000000000000 +3.257599999999999940e-01 3.923310285127587169e-08 0.000000000000000000 +3.262550000000000172e-01 3.689075007132369693e-08 0.000000000000000000 +3.267499999999999849e-01 3.475555417812694628e-08 0.000000000000000000 +3.272450000000000081e-01 3.282122222138029072e-08 0.000000000000000000 +3.277399999999999758e-01 3.107862970302026735e-08 0.000000000000000000 +3.282349999999999990e-01 2.951620705340836634e-08 0.000000000000000000 +3.287300000000000222e-01 2.812035640469401585e-08 0.000000000000000000 +3.292249999999999899e-01 2.687588864140881645e-08 0.000000000000000000 +3.297200000000000131e-01 2.576647062086454076e-08 0.000000000000000000 +3.302149999999999808e-01 2.477507259379541267e-08 0.000000000000000000 +3.307100000000000040e-01 2.388440620186704369e-08 0.000000000000000000 +3.312050000000000272e-01 2.307734397242664822e-08 0.000000000000000000 +3.316999999999999948e-01 2.233731195651392766e-08 0.000000000000000000 +3.321950000000000180e-01 2.164864803928930012e-08 0.000000000000000000 +3.326899999999999857e-01 2.099691947188361994e-08 0.000000000000000000 +3.331850000000000089e-01 2.036919430201140482e-08 0.000000000000000000 +3.336799999999999766e-01 1.975426259152155132e-08 0.000000000000000000 +3.341749999999999998e-01 1.914280457142530912e-08 0.000000000000000000 +3.346700000000000230e-01 1.852750417149897549e-08 0.000000000000000000 +3.351649999999999907e-01 1.790310764230426592e-08 0.000000000000000000 +3.356600000000000139e-01 1.726642823396807068e-08 0.000000000000000000 +3.361549999999999816e-01 1.661629908279854995e-08 0.000000000000000000 +3.366500000000000048e-01 1.595347755869347287e-08 0.000000000000000000 +3.371450000000000280e-01 1.528050531973779909e-08 0.000000000000000000 +3.376399999999999957e-01 1.460152919013509477e-08 0.000000000000000000 +3.381350000000000189e-01 1.392208870259843802e-08 0.000000000000000000 +3.386299999999999866e-01 1.324887671956536469e-08 0.000000000000000000 +3.391250000000000098e-01 1.258947995626008243e-08 0.000000000000000000 +3.396199999999999775e-01 1.195210647101936588e-08 0.000000000000000000 +3.401150000000000007e-01 1.134530726171616917e-08 0.000000000000000000 +3.406100000000000239e-01 1.077769901589524886e-08 0.000000000000000000 +3.411049999999999915e-01 1.025769481133655026e-08 0.000000000000000000 +3.416000000000000147e-01 9.793249165186949612e-09 0.000000000000000000 +3.420949999999999824e-01 9.391623293917409771e-09 0.000000000000000000 +3.425900000000000056e-01 9.059175792067207276e-09 0.000000000000000000 +3.430850000000000288e-01 8.801183179381491931e-09 0.000000000000000000 +3.435799999999999965e-01 8.621693927028023361e-09 0.000000000000000000 +3.440750000000000197e-01 8.523418672149286122e-09 0.000000000000000000 +3.445699999999999874e-01 8.507658389987899617e-09 0.000000000000000000 +3.450650000000000106e-01 8.574271336865750805e-09 0.000000000000000000 +3.455599999999999783e-01 8.721678624791400757e-09 0.000000000000000000 +3.460550000000000015e-01 8.946907365361574522e-09 0.000000000000000000 +3.465500000000000247e-01 9.245669442817675334e-09 0.000000000000000000 +3.470449999999999924e-01 9.612473166232856799e-09 0.000000000000000000 +3.475400000000000156e-01 1.004076432306006305e-08 0.000000000000000000 +3.480349999999999833e-01 1.052309252713271758e-08 0.000000000000000000 +3.485300000000000065e-01 1.105129823396793024e-08 0.000000000000000000 +3.490250000000000297e-01 1.161671539729180009e-08 0.000000000000000000 +3.495199999999999974e-01 1.221038446536266215e-08 0.000000000000000000 +3.500150000000000206e-01 1.282327027100933641e-08 0.000000000000000000 +3.505099999999999882e-01 1.344647935416390465e-08 0.000000000000000000 +3.510050000000000114e-01 1.407147136811586052e-08 0.000000000000000000 +3.514999999999999791e-01 1.469025945369796586e-08 0.000000000000000000 +3.519950000000000023e-01 1.529559481573492077e-08 0.000000000000000000 +3.524900000000000255e-01 1.588113118730360861e-08 0.000000000000000000 +3.529849999999999932e-01 1.644156541118762740e-08 0.000000000000000000 +3.534800000000000164e-01 1.697275098992543236e-08 0.000000000000000000 +3.539749999999999841e-01 1.747178213761023576e-08 0.000000000000000000 +3.544700000000000073e-01 1.793704659545164024e-08 0.000000000000000000 +3.549649999999999750e-01 1.836824622744469649e-08 0.000000000000000000 +3.554599999999999982e-01 1.876638517907206361e-08 0.000000000000000000 +3.559550000000000214e-01 1.913372613876507314e-08 0.000000000000000000 +3.564499999999999891e-01 1.947371597602423778e-08 0.000000000000000000 +3.569450000000000123e-01 1.979088272266642200e-08 0.000000000000000000 +3.574399999999999800e-01 2.009070650087254166e-08 0.000000000000000000 +3.579350000000000032e-01 2.037946757103567218e-08 0.000000000000000000 +3.584300000000000264e-01 2.066407515964299919e-08 0.000000000000000000 +3.589249999999999940e-01 2.095188112733686151e-08 0.000000000000000000 +3.594200000000000172e-01 2.125048283744856414e-08 0.000000000000000000 +3.599149999999999849e-01 2.156751978501948854e-08 0.000000000000000000 +3.604100000000000081e-01 2.191046864075705769e-08 0.000000000000000000 +3.609049999999999758e-01 2.228644135279893046e-08 0.000000000000000000 +3.613999999999999990e-01 2.270199083563226480e-08 0.000000000000000000 +3.618950000000000222e-01 2.316292856262320288e-08 0.000000000000000000 +3.623899999999999899e-01 2.367415807203139547e-08 0.000000000000000000 +3.628850000000000131e-01 2.423952800857445738e-08 0.000000000000000000 +3.633799999999999808e-01 2.486170785652935833e-08 0.000000000000000000 +3.638750000000000040e-01 2.554208899546158417e-08 0.000000000000000000 +3.643700000000000272e-01 2.628071313179934573e-08 0.000000000000000000 +3.648649999999999949e-01 2.707622954598928570e-08 0.000000000000000000 +3.653600000000000181e-01 2.792588195901891497e-08 0.000000000000000000 +3.658549999999999858e-01 2.882552517708983040e-08 0.000000000000000000 +3.663500000000000090e-01 2.976967103447278733e-08 0.000000000000000000 +3.668449999999999767e-01 3.075156253477281760e-08 0.000000000000000000 +3.673399999999999999e-01 3.176327450413345569e-08 0.000000000000000000 +3.678350000000000231e-01 3.279583852824928444e-08 0.000000000000000000 +3.683299999999999907e-01 3.383938945731988208e-08 0.000000000000000000 +3.688250000000000139e-01 3.488333034306978554e-08 0.000000000000000000 +3.693199999999999816e-01 3.591651232336546174e-08 0.000000000000000000 +3.698150000000000048e-01 3.692742570031571376e-08 0.000000000000000000 +3.703100000000000280e-01 3.790439827374823150e-08 0.000000000000000000 +3.708049999999999957e-01 3.883579689160558677e-08 0.000000000000000000 +3.713000000000000189e-01 3.971022816674681611e-08 0.000000000000000000 +3.717949999999999866e-01 4.051673438306160370e-08 0.000000000000000000 +3.722900000000000098e-01 4.124498076717833711e-08 0.000000000000000000 +3.727849999999999775e-01 4.188543053599052995e-08 0.000000000000000000 +3.732800000000000007e-01 4.242950443301410598e-08 0.000000000000000000 +3.737750000000000239e-01 4.286972183235922621e-08 0.000000000000000000 +3.742699999999999916e-01 4.319982091058997701e-08 0.000000000000000000 +3.747650000000000148e-01 4.341485585106263247e-08 0.000000000000000000 +3.752599999999999825e-01 4.351126954364792197e-08 0.000000000000000000 +3.757550000000000057e-01 4.348694076337917760e-08 0.000000000000000000 +3.762500000000000289e-01 4.334120534276358832e-08 0.000000000000000000 +3.767449999999999966e-01 4.307485138322552084e-08 0.000000000000000000 +3.772400000000000198e-01 4.269008907044460582e-08 0.000000000000000000 +3.777349999999999874e-01 4.219049615455987723e-08 0.000000000000000000 +3.782300000000000106e-01 4.158094062024585214e-08 0.000000000000000000 +3.787249999999999783e-01 4.086748249469892492e-08 0.000000000000000000 +3.792200000000000015e-01 4.005725711405962215e-08 0.000000000000000000 +3.797150000000000247e-01 3.915834248677704539e-08 0.000000000000000000 +3.802099999999999924e-01 3.817961364641245335e-08 0.000000000000000000 +3.807050000000000156e-01 3.713058707749278197e-08 0.000000000000000000 +3.811999999999999833e-01 3.602125841936853833e-08 0.000000000000000000 +3.816950000000000065e-01 3.486193670539177112e-08 0.000000000000000000 +3.821900000000000297e-01 3.366307838024691399e-08 0.000000000000000000 +3.826849999999999974e-01 3.243512425532141799e-08 0.000000000000000000 +3.831800000000000206e-01 3.118834241748837597e-08 0.000000000000000000 +3.836749999999999883e-01 2.993267990292510549e-08 0.000000000000000000 +3.841700000000000115e-01 2.867762569123941143e-08 0.000000000000000000 +3.846649999999999792e-01 2.743208727305183217e-08 0.000000000000000000 +3.851600000000000024e-01 2.620428270345172217e-08 0.000000000000000000 +3.856550000000000256e-01 2.500164968300175967e-08 0.000000000000000000 +3.861499999999999932e-01 2.383077281516078181e-08 0.000000000000000000 +3.866450000000000164e-01 2.269732978374304613e-08 0.000000000000000000 +3.871399999999999841e-01 2.160605678563854971e-08 0.000000000000000000 +3.876350000000000073e-01 2.056073314903509522e-08 0.000000000000000000 +3.881299999999999750e-01 1.956418467742543376e-08 0.000000000000000000 +3.886249999999999982e-01 1.861830489030515331e-08 0.000000000000000000 +3.891200000000000214e-01 1.772409299071463983e-08 0.000000000000000000 +3.896149999999999891e-01 1.688170708422905335e-08 0.000000000000000000 +3.901100000000000123e-01 1.609053090956924816e-08 0.000000000000000000 +3.906049999999999800e-01 1.534925212084473633e-08 0.000000000000000000 +3.911000000000000032e-01 1.465594999061976486e-08 0.000000000000000000 +3.915950000000000264e-01 1.400819028276227887e-08 0.000000000000000000 +3.920899999999999941e-01 1.340312497558415398e-08 0.000000000000000000 +3.925850000000000173e-01 1.283759450004609082e-08 0.000000000000000000 +3.930799999999999850e-01 1.230823019163286365e-08 0.000000000000000000 +3.935750000000000082e-01 1.181155473798613268e-08 0.000000000000000000 +3.940699999999999759e-01 1.134407853276911474e-08 0.000000000000000000 +3.945649999999999991e-01 1.090239001545729004e-08 0.000000000000000000 +3.950600000000000223e-01 1.048323828301218696e-08 0.000000000000000000 +3.955549999999999899e-01 1.008360649539456917e-08 0.000000000000000000 +3.960500000000000131e-01 9.700774858472852878e-09 0.000000000000000000 +3.965449999999999808e-01 9.332372246622308054e-09 0.000000000000000000 +3.970400000000000040e-01 8.976415818174406079e-09 0.000000000000000000 +3.975350000000000272e-01 8.631338272437599152e-09 0.000000000000000000 +3.980299999999999949e-01 8.296002689667833716e-09 0.000000000000000000 +3.985250000000000181e-01 7.969705181024683436e-09 0.000000000000000000 +3.990199999999999858e-01 7.652165845375051603e-09 0.000000000000000000 +3.995150000000000090e-01 7.343508780417073927e-09 0.000000000000000000 +4.000099999999999767e-01 7.044232120494151201e-09 0.000000000000000000 +4.005049999999999999e-01 6.755169269409685663e-09 0.000000000000000000 +4.010000000000000231e-01 6.477442659479981512e-09 0.000000000000000000 +4.014949999999999908e-01 6.212411494797449313e-09 0.000000000000000000 +4.019900000000000140e-01 5.961615027059779816e-09 0.000000000000000000 +4.024849999999999817e-01 5.726712963250029767e-09 0.000000000000000000 +4.029800000000000049e-01 5.509424617239932481e-09 0.000000000000000000 +4.034750000000000281e-01 5.311468393076287309e-09 0.000000000000000000 +4.039699999999999958e-01 5.134503126165067520e-09 0.000000000000000000 +4.044650000000000190e-01 4.980072714861337590e-09 0.000000000000000000 +4.049599999999999866e-01 4.849555349235844055e-09 0.000000000000000000 +4.054550000000000098e-01 4.744118492205433960e-09 0.000000000000000000 +4.059499999999999775e-01 4.664680593739816733e-09 0.000000000000000000 +4.064450000000000007e-01 4.611880325831865455e-09 0.000000000000000000 +4.069400000000000239e-01 4.586053920308072653e-09 0.000000000000000000 +4.074349999999999916e-01 4.587220977924695275e-09 0.000000000000000000 +4.079300000000000148e-01 4.615078899378049320e-09 0.000000000000000000 +4.084249999999999825e-01 4.669005875256890160e-09 0.000000000000000000 +4.089200000000000057e-01 4.748072163309128833e-09 0.000000000000000000 +4.094150000000000289e-01 4.851059185191857083e-09 0.000000000000000000 +4.099099999999999966e-01 4.976485794904445368e-09 0.000000000000000000 +4.104050000000000198e-01 5.122640910039118327e-09 0.000000000000000000 +4.108999999999999875e-01 5.287621558921616948e-09 0.000000000000000000 +4.113950000000000107e-01 5.469375284613462609e-09 0.000000000000000000 +4.118899999999999784e-01 5.665745761639552971e-09 0.000000000000000000 +4.123850000000000016e-01 5.874520425188240073e-09 0.000000000000000000 +4.128800000000000248e-01 6.093478886063645317e-09 0.000000000000000000 +4.133749999999999925e-01 6.320440907901102260e-09 0.000000000000000000 +4.138700000000000156e-01 6.553312753988550385e-09 0.000000000000000000 +4.143649999999999833e-01 6.790130771367156588e-09 0.000000000000000000 +4.148600000000000065e-01 7.029101163410273193e-09 0.000000000000000000 +4.153550000000000297e-01 7.268635010600130017e-09 0.000000000000000000 +4.158499999999999974e-01 7.507377726671668201e-09 0.000000000000000000 +4.163450000000000206e-01 7.744232281709863047e-09 0.000000000000000000 +4.168399999999999883e-01 7.978375682144205689e-09 0.000000000000000000 +4.173350000000000115e-01 8.209268363850622799e-09 0.000000000000000000 +4.178299999999999792e-01 8.436656327499291240e-09 0.000000000000000000 +4.183250000000000024e-01 8.660566018637588098e-09 0.000000000000000000 +4.188200000000000256e-01 8.881292125676694436e-09 0.000000000000000000 +4.193149999999999933e-01 9.099378633848062782e-09 0.000000000000000000 +4.198100000000000165e-01 9.315593626627259896e-09 0.000000000000000000 +4.203049999999999842e-01 9.530898467515246062e-09 0.000000000000000000 +4.208000000000000074e-01 9.746412118950913698e-09 0.000000000000000000 +4.212949999999999751e-01 9.963371460286649087e-09 0.000000000000000000 +4.217899999999999983e-01 1.018308855181658974e-08 0.000000000000000000 +4.222850000000000215e-01 1.040690585266617756e-08 0.000000000000000000 +4.227799999999999891e-01 1.063615043926497002e-08 0.000000000000000000 +4.232750000000000123e-01 1.087208828519019441e-08 0.000000000000000000 +4.237699999999999800e-01 1.111587965289071394e-08 0.000000000000000000 +4.242650000000000032e-01 1.136853661583180541e-08 0.000000000000000000 +4.247600000000000264e-01 1.163088367279463618e-08 0.000000000000000000 +4.252549999999999941e-01 1.190352234130271635e-08 0.000000000000000000 +4.257500000000000173e-01 1.218680052197535278e-08 0.000000000000000000 +4.262449999999999850e-01 1.248078731469023245e-08 0.000000000000000000 +4.267400000000000082e-01 1.278525384311730212e-08 0.000000000000000000 +4.272349999999999759e-01 1.309966050910587465e-08 0.000000000000000000 +4.277299999999999991e-01 1.342315095589872567e-08 0.000000000000000000 +4.282250000000000223e-01 1.375455287205582836e-08 0.000000000000000000 +4.287199999999999900e-01 1.409238562079113363e-08 0.000000000000000000 +4.292150000000000132e-01 1.443487453314645187e-08 0.000000000000000000 +4.297099999999999809e-01 1.477997156373545718e-08 0.000000000000000000 +4.302050000000000041e-01 1.512538187580669995e-08 0.000000000000000000 +4.307000000000000273e-01 1.546859580133828023e-08 0.000000000000000000 +4.311949999999999950e-01 1.580692551463737943e-08 0.000000000000000000 +4.316900000000000182e-01 1.613754566577390438e-08 0.000000000000000000 +4.321849999999999858e-01 1.645753714599011433e-08 0.000000000000000000 +4.326800000000000090e-01 1.676393310002758873e-08 0.000000000000000000 +4.331749999999999767e-01 1.705376626490258598e-08 0.000000000000000000 +4.336699999999999999e-01 1.732411669653720288e-08 0.000000000000000000 +4.341650000000000231e-01 1.757215894925126622e-08 0.000000000000000000 +4.346599999999999908e-01 1.779520779548350610e-08 0.000000000000000000 +4.351550000000000140e-01 1.799076161362543704e-08 0.000000000000000000 +4.356499999999999817e-01 1.815654263086063115e-08 0.000000000000000000 +4.361450000000000049e-01 1.829053328157484957e-08 0.000000000000000000 +4.366400000000000281e-01 1.839100803044917176e-08 0.000000000000000000 +4.371349999999999958e-01 1.845656010927652435e-08 0.000000000000000000 +4.376300000000000190e-01 1.848612272608700538e-08 0.000000000000000000 +4.381249999999999867e-01 1.847898442161774779e-08 0.000000000000000000 +4.386200000000000099e-01 1.843479836949822567e-08 0.000000000000000000 +4.391149999999999776e-01 1.835358553896912584e-08 0.000000000000000000 +4.396100000000000008e-01 1.823573176129404449e-08 0.000000000000000000 +4.401050000000000240e-01 1.808197885939603732e-08 0.000000000000000000 +4.405999999999999917e-01 1.789341011348342798e-08 0.000000000000000000 +4.410950000000000149e-01 1.767143044023607812e-08 0.000000000000000000 +4.415899999999999825e-01 1.741774175811971450e-08 0.000000000000000000 +4.420850000000000057e-01 1.713431409473244335e-08 0.000000000000000000 +4.425800000000000289e-01 1.682335306189678160e-08 0.000000000000000000 +4.430749999999999966e-01 1.648726438020696314e-08 0.000000000000000000 +4.435700000000000198e-01 1.612861617500588260e-08 0.000000000000000000 +4.440649999999999875e-01 1.575009979047387784e-08 0.000000000000000000 +4.445600000000000107e-01 1.535448987805421877e-08 0.000000000000000000 +4.450549999999999784e-01 1.494460450820156242e-08 0.000000000000000000 +4.455500000000000016e-01 1.452326603333806454e-08 0.000000000000000000 +4.460450000000000248e-01 1.409326339387842717e-08 0.000000000000000000 +4.465399999999999925e-01 1.365731651025635248e-08 0.000000000000000000 +4.470350000000000157e-01 1.321804334286182776e-08 0.000000000000000000 +4.475299999999999834e-01 1.277793013177696666e-08 0.000000000000000000 +4.480250000000000066e-01 1.233930524775555563e-08 0.000000000000000000 +4.485200000000000298e-01 1.190431700117814050e-08 0.000000000000000000 +4.490149999999999975e-01 1.147491566480354247e-08 0.000000000000000000 +4.495100000000000207e-01 1.105283987343516414e-08 0.000000000000000000 +4.500049999999999883e-01 1.063960747044149186e-08 0.000000000000000000 +4.505000000000000115e-01 1.023651077918770782e-08 0.000000000000000000 +4.509949999999999792e-01 9.844616188803198748e-09 0.000000000000000000 +4.514900000000000024e-01 9.464767861106116008e-09 0.000000000000000000 +4.519850000000000256e-01 9.097595288108603557e-09 0.000000000000000000 +4.524799999999999933e-01 8.743524362105601483e-09 0.000000000000000000 +4.529750000000000165e-01 8.402791560871834732e-09 0.000000000000000000 +4.534699999999999842e-01 8.075460802443148244e-09 0.000000000000000000 +4.539650000000000074e-01 7.761442486046111164e-09 0.000000000000000000 +4.544599999999999751e-01 7.460514210424042824e-09 0.000000000000000000 +4.549549999999999983e-01 7.172342646170907000e-09 0.000000000000000000 +4.554500000000000215e-01 6.896506036714323153e-09 0.000000000000000000 +4.559449999999999892e-01 6.632516811281122672e-09 0.000000000000000000 +4.564400000000000124e-01 6.379843812657275924e-09 0.000000000000000000 +4.569349999999999801e-01 6.137933673162139564e-09 0.000000000000000000 +4.574300000000000033e-01 5.906230910290281566e-09 0.000000000000000000 +4.579250000000000265e-01 5.684196360615556579e-09 0.000000000000000000 +4.584199999999999942e-01 5.471323624331185598e-09 0.000000000000000000 +4.589150000000000174e-01 5.267153250837432023e-09 0.000000000000000000 +4.594099999999999850e-01 5.071284459126574927e-09 0.000000000000000000 +4.599050000000000082e-01 4.883384250931931307e-09 0.000000000000000000 +4.603999999999999759e-01 4.703193840668581048e-09 0.000000000000000000 +4.608949999999999991e-01 4.530532390899307624e-09 0.000000000000000000 +4.613900000000000223e-01 4.365298105153216542e-09 0.000000000000000000 +4.618849999999999900e-01 4.207466789022336332e-09 0.000000000000000000 +4.623800000000000132e-01 4.057088045494296224e-09 0.000000000000000000 +4.628749999999999809e-01 3.914279319195624469e-09 0.000000000000000000 +4.633700000000000041e-01 3.779218046709925823e-09 0.000000000000000000 +4.638650000000000273e-01 3.652132205013703572e-09 0.000000000000000000 +4.643599999999999950e-01 3.533289576706884067e-09 0.000000000000000000 +4.648550000000000182e-01 3.422986069808274892e-09 0.000000000000000000 +4.653499999999999859e-01 3.321533439416051253e-09 0.000000000000000000 +4.658450000000000091e-01 3.229246760435336710e-09 0.000000000000000000 +4.663399999999999768e-01 3.146431993994970754e-09 0.000000000000000000 +4.668350000000000000e-01 3.073373975345013034e-09 0.000000000000000000 +4.673300000000000232e-01 3.010325129642277786e-09 0.000000000000000000 +4.678249999999999909e-01 2.957495193257146136e-09 0.000000000000000000 +4.683200000000000141e-01 2.915042184678358687e-09 0.000000000000000000 +4.688149999999999817e-01 2.883064829842742190e-09 0.000000000000000000 +4.693100000000000049e-01 2.861596604193283212e-09 0.000000000000000000 +4.698050000000000281e-01 2.850601508972300431e-09 0.000000000000000000 +4.702999999999999958e-01 2.849971651914613278e-09 0.000000000000000000 +4.707950000000000190e-01 2.859526656006997309e-09 0.000000000000000000 +4.712899999999999867e-01 2.879014873141595932e-09 0.000000000000000000 +4.717850000000000099e-01 2.908116335166235172e-09 0.000000000000000000 +4.722799999999999776e-01 2.946447332886401864e-09 0.000000000000000000 +4.727750000000000008e-01 2.993566475442111645e-09 0.000000000000000000 +4.732700000000000240e-01 3.048982048894810377e-09 0.000000000000000000 +4.737649999999999917e-01 3.112160464332474383e-09 0.000000000000000000 +4.742600000000000149e-01 3.182535562880660334e-09 0.000000000000000000 +4.747549999999999826e-01 3.259518528611297958e-09 0.000000000000000000 +4.752500000000000058e-01 3.342508149576631695e-09 0.000000000000000000 +4.757450000000000290e-01 3.430901163840657496e-09 0.000000000000000000 +4.762399999999999967e-01 3.524102429278429806e-09 0.000000000000000000 +4.767350000000000199e-01 3.621534665102449216e-09 0.000000000000000000 +4.772299999999999875e-01 3.722647527460664005e-09 0.000000000000000000 +4.777250000000000107e-01 3.826925801322355374e-09 0.000000000000000000 +4.782199999999999784e-01 3.933896515816877786e-09 0.000000000000000000 +4.787150000000000016e-01 4.043134819189915393e-09 0.000000000000000000 +4.792100000000000248e-01 4.154268481635412397e-09 0.000000000000000000 +4.797049999999999925e-01 4.266980929593508030e-09 0.000000000000000000 +4.802000000000000157e-01 4.381012751424321055e-09 0.000000000000000000 +4.806949999999999834e-01 4.496161652199732591e-09 0.000000000000000000 +4.811900000000000066e-01 4.612280872640621975e-09 0.000000000000000000 +4.816849999999999743e-01 4.729276124038926593e-09 0.000000000000000000 +4.821799999999999975e-01 4.847101125726263636e-09 0.000000000000000000 +4.826750000000000207e-01 4.965751864300368648e-09 0.000000000000000000 +4.831699999999999884e-01 5.085259722846209651e-09 0.000000000000000000 +4.836650000000000116e-01 5.205683653909438055e-09 0.000000000000000000 +4.841599999999999793e-01 5.327101591364630244e-09 0.000000000000000000 +4.846550000000000025e-01 5.449601312131226840e-09 0.000000000000000000 +4.851500000000000257e-01 5.573270970900816755e-09 0.000000000000000000 +4.856449999999999934e-01 5.698189536512434654e-09 0.000000000000000000 +4.861400000000000166e-01 5.824417359925500247e-09 0.000000000000000000 +4.866349999999999842e-01 5.951987099613675371e-09 0.000000000000000000 +4.871300000000000074e-01 6.080895220433315428e-09 0.000000000000000000 +4.876249999999999751e-01 6.211094268638991865e-09 0.000000000000000000 +4.881199999999999983e-01 6.342486106845018088e-09 0.000000000000000000 +4.886150000000000215e-01 6.474916270754308835e-09 0.000000000000000000 +4.891099999999999892e-01 6.608169583862010463e-09 0.000000000000000000 +4.896050000000000124e-01 6.741967137986912580e-09 0.000000000000000000 +4.900999999999999801e-01 6.875964717127975807e-09 0.000000000000000000 +4.905950000000000033e-01 7.009752710491016055e-09 0.000000000000000000 +4.910900000000000265e-01 7.142857528022041833e-09 0.000000000000000000 +4.915849999999999942e-01 7.274744499695702001e-09 0.000000000000000000 +4.920800000000000174e-01 7.404822208039219847e-09 0.000000000000000000 +4.925749999999999851e-01 7.532448173396777785e-09 0.000000000000000000 +4.930700000000000083e-01 7.656935783228315582e-09 0.000000000000000000 +4.935649999999999760e-01 7.777562331712137321e-09 0.000000000000000000 +4.940599999999999992e-01 7.893578012955520028e-09 0.000000000000000000 +4.945550000000000224e-01 8.004215693228740211e-09 0.000000000000000000 +4.950499999999999901e-01 8.108701272028350674e-09 0.000000000000000000 +4.955450000000000133e-01 8.206264431718087464e-09 0.000000000000000000 +4.960399999999999809e-01 8.296149568706190762e-09 0.000000000000000000 +4.965350000000000041e-01 8.377626697440333365e-09 0.000000000000000000 +4.970300000000000273e-01 8.450002120679014276e-09 0.000000000000000000 +4.975249999999999950e-01 8.512628666134923592e-09 0.000000000000000000 +4.980200000000000182e-01 8.564915300040312215e-09 0.000000000000000000 +4.985149999999999859e-01 8.606335942736847812e-09 0.000000000000000000 +4.990100000000000091e-01 8.636437328660788286e-09 0.000000000000000000 +4.995049999999999768e-01 8.654845773786825943e-09 0.000000000000000000 +5.000000000000000000e-01 8.661272736629355656e-09 0.000000000000000000 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_1.dat b/tests/test_data/ORSO/test_1.dat new file mode 100644 index 00000000..14642ec9 --- /dev/null +++ b/tests/test_data/ORSO/test_1.dat @@ -0,0 +1,1998 @@ +7.120926687274507999e-04 9.999999999999996669e-01 0.000000000000000000 +1.068139001396520987e-03 1.000000000000000888e+00 0.000000000000000000 +1.424185332032005527e-03 1.000000000000000444e+00 0.000000000000000000 +1.780231659956042463e-03 9.999999999999997780e-01 0.000000000000000000 +2.136277984490769083e-03 1.000000000000000000e+00 0.000000000000000000 +2.492324304958323973e-03 1.000000000000000444e+00 0.000000000000000000 +2.848370620680845938e-03 9.999999999999993339e-01 0.000000000000000000 +3.204416930980470962e-03 9.999999999999993339e-01 0.000000000000000000 +3.560463235179339367e-03 1.000000000000000000e+00 0.000000000000000000 +3.916509532599587139e-03 9.999999999999998890e-01 0.000000000000000000 +4.272555822563354165e-03 1.000000000000000444e+00 0.000000000000000000 +4.628602104392778166e-03 9.999999999999994449e-01 0.000000000000000000 +4.984648377409996861e-03 9.999999999999996669e-01 0.000000000000000000 +5.340694640937147103e-03 9.999999999999996669e-01 0.000000000000000000 +5.696740894296370081e-03 1.000000000000000222e+00 0.000000000000000000 +6.052787136809801780e-03 9.999999999999991118e-01 0.000000000000000000 +6.408833367799581654e-03 1.000000000000000222e+00 0.000000000000000000 +6.764879586587847424e-03 9.999999999999997780e-01 0.000000000000000000 +7.120925792496735074e-03 1.000000000000000888e+00 0.000000000000000000 +7.476971984848386661e-03 9.999999999999997780e-01 0.000000000000000000 +7.833018162964939038e-03 1.000000000000000222e+00 0.000000000000000000 +8.189064326168529057e-03 9.999999999999995559e-01 0.000000000000000000 +8.545110473781298774e-03 1.000000000000000888e+00 0.000000000000000000 +8.901156605125380705e-03 9.999999999999990008e-01 0.000000000000000000 +9.257202719522919510e-03 9.999999999999997780e-01 0.000000000000000000 +9.613248816296047702e-03 9.999999999999992228e-01 0.000000000000000000 +9.969294894766909942e-03 1.000000000000000222e+00 0.000000000000000000 +1.032534095425764221e-02 9.999992503238016583e-01 0.000000000000000000 +1.068138699409038050e-02 9.999980643079933174e-01 0.000000000000000000 +1.103743301358726427e-02 9.999966126029437019e-01 0.000000000000000000 +1.139347901207043469e-02 9.999945750665667488e-01 0.000000000000000000 +1.174952498886202776e-02 9.999916063279130629e-01 0.000000000000000000 +1.210557094328418640e-02 9.999871933535626756e-01 0.000000000000000000 +1.246161687465904312e-02 9.999805294321724158e-01 0.000000000000000000 +1.281766278230874086e-02 9.999703119118247274e-01 0.000000000000000000 +1.317370866555541732e-02 9.999543902597648470e-01 0.000000000000000000 +1.352975452372121370e-02 9.999291324755025245e-01 0.000000000000000000 +1.388580035612826426e-02 9.998882494422177691e-01 0.000000000000000000 +1.424184616209871364e-02 9.998205409439229197e-01 0.000000000000000000 +1.459789194095469610e-02 9.997054114424506199e-01 0.000000000000000000 +1.495393769201834935e-02 9.995035606107141035e-01 0.000000000000000000 +1.530998341461181980e-02 9.991366701847683718e-01 0.000000000000000000 +1.566602910805724169e-02 9.984403861412076697e-01 0.000000000000000000 +1.602207477167675448e-02 9.970474634133739134e-01 0.000000000000000000 +1.637812040479250109e-02 9.940708597801094504e-01 0.000000000000000000 +1.673416600672661750e-02 9.871457348401537768e-01 0.000000000000000000 +1.709021157680123623e-02 9.691155171813401470e-01 0.000000000000000000 +1.744625711433850715e-02 9.146714791553381962e-01 0.000000000000000000 +1.780230261866056971e-02 7.235824663202072848e-01 0.000000000000000000 +1.815834808908955642e-02 1.982172144901543087e-01 0.000000000000000000 +1.851439352494761714e-02 5.368656202412908779e-02 0.000000000000000000 +1.887043892555688440e-02 2.826235383946479884e-01 0.000000000000000000 +1.922648429023949418e-02 3.875217379569827481e-01 0.000000000000000000 +1.958252961831759634e-02 3.916784480059969931e-01 0.000000000000000000 +1.993857490911332339e-02 3.310002219487748754e-01 0.000000000000000000 +2.029462016194881133e-02 2.272914448127881237e-01 0.000000000000000000 +2.065066537614621694e-02 1.112565297862627839e-01 0.000000000000000000 +2.100671055102766582e-02 2.688746936767203236e-02 0.000000000000000000 +2.136275568591530089e-02 3.822708968259131909e-03 0.000000000000000000 +2.171880078013126505e-02 3.222404371616335167e-02 0.000000000000000000 +2.207484583299769779e-02 8.026862564036112146e-02 0.000000000000000000 +2.243089084383674200e-02 1.225273725226444926e-01 0.000000000000000000 +2.278693581197053369e-02 1.473760379764722239e-01 0.000000000000000000 +2.314298073672121578e-02 1.523081321702720592e-01 0.000000000000000000 +2.349902561741092424e-02 1.392821746311279085e-01 0.000000000000000000 +2.385507045336181242e-02 1.126622529182146754e-01 0.000000000000000000 +2.421111524389600242e-02 7.861467279052444801e-02 0.000000000000000000 +2.456715998833565104e-02 4.455798023951239306e-02 0.000000000000000000 +2.492320468600290120e-02 1.778995627595785986e-02 0.000000000000000000 +2.527924933621987849e-02 3.395073093927740340e-03 0.000000000000000000 +2.563529393830873276e-02 2.595774676754369469e-03 0.000000000000000000 +2.599133849159160695e-02 1.275152602517853721e-02 0.000000000000000000 +2.634738299539064049e-02 2.895359745352929851e-02 0.000000000000000000 +2.670342744902797633e-02 4.602963456971208983e-02 0.000000000000000000 +2.705947185182575390e-02 5.990089564089792068e-02 0.000000000000000000 +2.741551620310611614e-02 6.806634079247522728e-02 0.000000000000000000 +2.777156050219120598e-02 6.953268660952754976e-02 0.000000000000000000 +2.812760474840316285e-02 6.455321611687926675e-02 0.000000000000000000 +2.848364894106412623e-02 5.436137845621738518e-02 0.000000000000000000 +2.883969307949624944e-02 4.092087484200730013e-02 0.000000000000000000 +2.919573716302166153e-02 2.663426033083630268e-02 0.000000000000000000 +2.955178119096250888e-02 1.395760727452293425e-02 0.000000000000000000 +2.990782516264093790e-02 4.940537297759796907e-03 0.000000000000000000 +3.026386907737909499e-02 8.038319201654679867e-04 0.000000000000000000 +3.061991293449910570e-02 1.708620388673709424e-03 0.000000000000000000 +3.097595673332313032e-02 6.811949263714371823e-03 0.000000000000000000 +3.133200047317330483e-02 1.457483812733798012e-02 0.000000000000000000 +3.168804415337176522e-02 2.318514893188180007e-02 0.000000000000000000 +3.204408777324066482e-02 3.094512785677362016e-02 0.000000000000000000 +3.240013133210215002e-02 3.653622957946371652e-02 0.000000000000000000 +3.275617482927836027e-02 3.914963327880489896e-02 0.000000000000000000 +3.311221826409141422e-02 3.851481114579176357e-02 0.000000000000000000 +3.346826163586349295e-02 3.486474359367892212e-02 0.000000000000000000 +3.382430494391673592e-02 2.886145256362034062e-02 0.000000000000000000 +3.418034818757326176e-02 2.148792850395982168e-02 0.000000000000000000 +3.453639136615522381e-02 1.390413248740521995e-02 0.000000000000000000 +3.489243447898477540e-02 7.270110580682173120e-03 0.000000000000000000 +3.524847752538406292e-02 2.555702842096856196e-03 0.000000000000000000 +3.560452050467521889e-02 3.740565631443482628e-04 0.000000000000000000 +3.596056341618038277e-02 8.818651216682591408e-04 0.000000000000000000 +3.631660625922172175e-02 3.774815561286619554e-03 0.000000000000000000 +3.667264903312136837e-02 8.376908074210839480e-03 0.000000000000000000 +3.702869173720146900e-02 1.379291825993611900e-02 0.000000000000000000 +3.738473437078415618e-02 1.907949142362600978e-02 0.000000000000000000 +3.774077693319158322e-02 2.339598362662987860e-02 0.000000000000000000 +3.809681942374590347e-02 2.611330228093514810e-02 0.000000000000000000 +3.845286184176926331e-02 2.687623558768857668e-02 0.000000000000000000 +3.880890418658378832e-02 2.562490347851576616e-02 0.000000000000000000 +3.916494645751164572e-02 2.258313239139892598e-02 0.000000000000000000 +3.952098865387497495e-02 1.821896548411633399e-02 0.000000000000000000 +3.987703077499590854e-02 1.317946753385513398e-02 0.000000000000000000 +4.023307282019660674e-02 8.201854622170537054e-03 0.000000000000000000 +4.058911478879920903e-02 4.007143453574814329e-03 0.000000000000000000 +4.094515668012587567e-02 1.189698981073644083e-03 0.000000000000000000 +4.130119849349873917e-02 1.224908690321959781e-04 0.000000000000000000 +4.165724022823994593e-02 8.989246294339966244e-04 0.000000000000000000 +4.201328188367164235e-02 3.325234142660786658e-03 0.000000000000000000 +4.236932345911597481e-02 6.964416333509426855e-03 0.000000000000000000 +4.272536495389510358e-02 1.121916028646527050e-02 0.000000000000000000 +4.308140636733116119e-02 1.543308351017479846e-02 0.000000000000000000 +4.343744769874631484e-02 1.898937468850776106e-02 0.000000000000000000 +4.379348894746269011e-02 2.139184438746310687e-02 0.000000000000000000 +4.414953011280244033e-02 2.232123954774985555e-02 0.000000000000000000 +4.450557119408771189e-02 2.166580616421132782e-02 0.000000000000000000 +4.486161219064066508e-02 1.952791764179004005e-02 0.000000000000000000 +4.521765310178343933e-02 1.620864628817681591e-02 0.000000000000000000 +4.557369392683818798e-02 1.217116170030136703e-02 0.000000000000000000 +4.592973466512705744e-02 7.983720670709770414e-03 0.000000000000000000 +4.628577531597218020e-02 4.245096364625116844e-03 0.000000000000000000 +4.664181587869571655e-02 1.499662726512367974e-03 0.000000000000000000 +4.699785635261983369e-02 1.545027354873637127e-04 0.000000000000000000 +4.735389673706665026e-02 4.141355837711353186e-04 0.000000000000000000 +4.770993703135834041e-02 2.247168622565268344e-03 0.000000000000000000 +4.806597723481704360e-02 5.392666820119029931e-03 0.000000000000000000 +4.842201734676489927e-02 9.404372644912777079e-03 0.000000000000000000 +4.877805736652407465e-02 1.372202677205701035e-02 0.000000000000000000 +4.913409729341672305e-02 1.775440026889581191e-02 0.000000000000000000 +4.949013712676497007e-02 2.095931024224749126e-02 0.000000000000000000 +4.984617686589098984e-02 2.291029585609997282e-02 0.000000000000000000 +5.020221651011690794e-02 2.334497783304607249e-02 0.000000000000000000 +5.055825605876489853e-02 2.219404885039374942e-02 0.000000000000000000 +5.091429551115710106e-02 1.959135400128038731e-02 0.000000000000000000 +5.127033486661566886e-02 1.586501758945364771e-02 0.000000000000000000 +5.162637412446277607e-02 1.150836376986204453e-02 0.000000000000000000 +5.198241328402053441e-02 7.129105837473640080e-03 0.000000000000000000 +5.233845234461111107e-02 3.377320603196695345e-03 0.000000000000000000 +5.269449130555668021e-02 8.575130055426591737e-04 0.000000000000000000 +5.305053016617936046e-02 3.647209063101535984e-05 0.000000000000000000 +5.340656892580131904e-02 1.163857944713281691e-03 0.000000000000000000 +5.376260758374470927e-02 4.223231029490143000e-03 0.000000000000000000 +5.411864613933167756e-02 8.925724651729985415e-03 0.000000000000000000 +5.447468459188439110e-02 1.474812225204646075e-02 0.000000000000000000 +5.483072294072498243e-02 2.100598463112585829e-02 0.000000000000000000 +5.518676118517561874e-02 2.694540653430236438e-02 0.000000000000000000 +5.554279932455844643e-02 3.183636109342779380e-02 0.000000000000000000 +5.589883735819563965e-02 3.505540309109209801e-02 0.000000000000000000 +5.625487528540931703e-02 3.615250239324107467e-02 0.000000000000000000 +5.661091310552165967e-02 3.490258163056411678e-02 0.000000000000000000 +5.696695081785480008e-02 3.134484432943147880e-02 0.000000000000000000 +5.732298842173092629e-02 2.581165665858425537e-02 0.000000000000000000 +5.767902591647214999e-02 1.894420382277415063e-02 0.000000000000000000 +5.803506330140065922e-02 1.168589120710910277e-02 0.000000000000000000 +5.839110057583860036e-02 5.239071212323875154e-03 0.000000000000000000 +5.874713773910812675e-02 9.699661692567669710e-04 0.000000000000000000 +5.910317479053139172e-02 2.548571947934354402e-04 0.000000000000000000 +5.945921172943054861e-02 4.279563213805427473e-03 0.000000000000000000 +5.981524855512776462e-02 1.382936523764148433e-02 0.000000000000000000 +6.017128526694519308e-02 2.912530634580091926e-02 0.000000000000000000 +6.052732186420497346e-02 4.976035489709161597e-02 0.000000000000000000 +6.088335834622928683e-02 7.475990790658799956e-02 0.000000000000000000 +6.123939471234027265e-02 1.027476759571164938e-01 0.000000000000000000 +6.159543096186008426e-02 1.321634319850614470e-01 0.000000000000000000 +6.195146709411090274e-02 1.614707216140106316e-01 0.000000000000000000 +6.230750310841486755e-02 1.893099215347545106e-01 0.000000000000000000 +6.266353900409413202e-02 2.145805097230245873e-01 0.000000000000000000 +6.301957478047087724e-02 2.364605236578511682e-01 0.000000000000000000 +6.337561043686723572e-02 2.543834511500450701e-01 0.000000000000000000 +6.373164597260537467e-02 2.679941669489654954e-01 0.000000000000000000 +6.408768138700744743e-02 2.771008025286855192e-01 0.000000000000000000 +6.444371667939563508e-02 2.816331303301823907e-01 0.000000000000000000 +6.479975184909207708e-02 2.816127054877834435e-01 0.000000000000000000 +6.515578689541892676e-02 2.771363892317091904e-01 0.000000000000000000 +6.551182181769835133e-02 2.683727121290661599e-01 0.000000000000000000 +6.586785661525253188e-02 2.555692006368687763e-01 0.000000000000000000 +6.622389128740358011e-02 2.390676879866036886e-01 0.000000000000000000 +6.657992583347371873e-02 2.193233636074038151e-01 0.000000000000000000 +6.693596025278504558e-02 1.969217972999726951e-01 0.000000000000000000 +6.729199454465978336e-02 1.725867214819165052e-01 0.000000000000000000 +6.764802870842004379e-02 1.471707263969875557e-01 0.000000000000000000 +6.800406274338798018e-02 1.216222784467115708e-01 0.000000000000000000 +6.836009664888580140e-02 9.692650349357995188e-02 0.000000000000000000 +6.871613042423563300e-02 7.402395197622313461e-02 0.000000000000000000 +6.907216406875968384e-02 5.371945996552492802e-02 0.000000000000000000 +6.942819758178006562e-02 3.659914943369632634e-02 0.000000000000000000 +6.978423096261893166e-02 2.297434648199053742e-02 0.000000000000000000 +7.014026421059849081e-02 1.286540951239448748e-02 0.000000000000000000 +7.049629732504089641e-02 6.027982687480571908e-03 0.000000000000000000 +7.085233030526828790e-02 2.013275425197893088e-03 0.000000000000000000 +7.120836315060283250e-02 2.468755563170781488e-04 0.000000000000000000 +7.156439586036672518e-02 1.093047733947922145e-04 0.000000000000000000 +7.192042843388209150e-02 1.005124351334935138e-03 0.000000000000000000 +7.227646087047111256e-02 2.413304299788868439e-03 0.000000000000000000 +7.263249316945594170e-02 3.917201295728916545e-03 0.000000000000000000 +7.298852533015878774e-02 5.216361638169828702e-03 0.000000000000000000 +7.334455735190174852e-02 6.124202100679557170e-03 0.000000000000000000 +7.370058923400707451e-02 6.555911045997408343e-03 0.000000000000000000 +7.405662097579682190e-02 6.510363841711615251e-03 0.000000000000000000 +7.441265257659324117e-02 6.049045190383253723e-03 0.000000000000000000 +7.476868403571845789e-02 5.274253535248039047e-03 0.000000000000000000 +7.512471535249466703e-02 4.308339791017238261e-03 0.000000000000000000 +7.548074652624400804e-02 3.275368027027975634e-03 0.000000000000000000 +7.583677755628866202e-02 2.286281923377684027e-03 0.000000000000000000 +7.619280844195079616e-02 1.428327001933368898e-03 0.000000000000000000 +7.654883918255257769e-02 7.590718926671823031e-04 0.000000000000000000 +7.690486977741615993e-02 3.049095232574781629e-04 0.000000000000000000 +7.726090022586373784e-02 6.346498439523581814e-05 0.000000000000000000 +7.761693052721746477e-02 8.971312499623633620e-06 0.000000000000000000 +7.797296068079949405e-02 9.946193680944292851e-05 0.000000000000000000 +7.832899068593204839e-02 2.845955828948539749e-04 0.000000000000000000 +7.868502054193722561e-02 5.130601042093955316e-04 0.000000000000000000 +7.904105024813724845e-02 7.387486163540610056e-04 0.000000000000000000 +7.939707980385422859e-02 9.252041386305923576e-04 0.000000000000000000 +7.975310920841041651e-02 1.048132033417172471e-03 0.000000000000000000 +8.010913846112791004e-02 1.096042544049322933e-03 0.000000000000000000 +8.046516756132893189e-02 1.069286418981557803e-03 0.000000000000000000 +8.082119650833562152e-02 9.778778225035848152e-04 0.000000000000000000 +8.117722530147016002e-02 8.385631428781712771e-04 0.000000000000000000 +8.153325394005471460e-02 6.715996891405033890e-04 0.000000000000000000 +8.188928242341148023e-02 4.976646626575670406e-04 0.000000000000000000 +8.224531075086258247e-02 3.352335337838832446e-04 0.000000000000000000 +8.260133892173024406e-02 1.986606514487722309e-04 0.000000000000000000 +8.295736693533657669e-02 9.707735928655198581e-05 0.000000000000000000 +8.331339479100383083e-02 3.410829710717231935e-05 0.000000000000000000 +8.366942248805409044e-02 8.308033604611576680e-06 0.000000000000000000 +8.402545002580961986e-02 1.414786716311659249e-05 0.000000000000000000 +8.438147740359254467e-02 4.334227498273019591e-05 0.000000000000000000 +8.473750462072503209e-02 8.629674991516118009e-05 0.000000000000000000 +8.509353167652927707e-02 1.334796499856705525e-04 0.000000000000000000 +8.544955857032743296e-02 1.765628259126242967e-04 0.000000000000000000 +8.580558530144170859e-02 2.092301378552286167e-04 0.000000000000000000 +8.616161186919424342e-02 2.276104714561805978e-04 0.000000000000000000 +8.651763827290724629e-02 2.303447594084227854e-04 0.000000000000000000 +8.687366451190285666e-02 2.183391277391872134e-04 0.000000000000000000 +8.722969058550328336e-02 1.942852890145829780e-04 0.000000000000000000 +8.758571649303067974e-02 1.620436259952447969e-04 0.000000000000000000 +8.794174223380724076e-02 1.259848982617479073e-04 0.000000000000000000 +8.829776780715511975e-02 9.037547505689172065e-05 0.000000000000000000 +8.865379321239652555e-02 5.887172066550819168e-05 0.000000000000000000 +8.900981844885362537e-02 3.416534252355031038e-05 0.000000000000000000 +8.936584351584860031e-02 1.779680742061332706e-05 0.000000000000000000 +8.972186841270360369e-02 1.013149623178605324e-05 0.000000000000000000 +9.007789313874083048e-02 1.047544159156060060e-05 0.000000000000000000 +9.043391769328244789e-02 1.729561252381977442e-05 0.000000000000000000 +9.078994207565069252e-02 2.850409080344256811e-05 0.000000000000000000 +9.114596628516766219e-02 4.176555482191795913e-05 0.000000000000000000 +9.150199032115559350e-02 5.479204031225699107e-05 0.000000000000000000 +9.185801418293662590e-02 6.559644639526214483e-05 0.000000000000000000 +9.221403786983298212e-02 7.268513659439882304e-05 0.000000000000000000 +9.257006138116681548e-02 7.517890428405253655e-05 0.000000000000000000 +9.292608471626032096e-02 7.285956334126011643e-05 0.000000000000000000 +9.328210787443567964e-02 6.614595182554889089e-05 0.000000000000000000 +9.363813085501505873e-02 5.600805815264254205e-05 0.000000000000000000 +9.399415365732066707e-02 4.383144435331396506e-05 0.000000000000000000 +9.435017628067465800e-02 3.124644879350179061e-05 0.000000000000000000 +9.470619872439926812e-02 1.993810949992266325e-05 0.000000000000000000 +9.506222098781658136e-02 1.145356365488822627e-05 0.000000000000000000 +9.541824307024888985e-02 7.023886535066620586e-06 0.000000000000000000 +9.577426497101829139e-02 7.416800595041411032e-06 0.000000000000000000 +9.613028668944702260e-02 1.283516013789619059e-05 0.000000000000000000 +9.648630822485723679e-02 2.287332276312405784e-05 0.000000000000000000 +9.684232957657118446e-02 3.653927002790868079e-05 0.000000000000000000 +9.719835074391096341e-02 5.234464934130625532e-05 0.000000000000000000 +9.755437172619881026e-02 6.845806277362821528e-05 0.000000000000000000 +9.791039252275690608e-02 8.290950695128456913e-05 0.000000000000000000 +9.826641313290743196e-02 9.382670782815655361e-05 0.000000000000000000 +9.862243355597255512e-02 9.967818875406802962e-05 0.000000000000000000 +9.897845379127453991e-02 9.949426899230886189e-05 0.000000000000000000 +9.933447383813544251e-02 9.303667249708322978e-05 0.000000000000000000 +9.969049369587758280e-02 8.089058319673479410e-05 0.000000000000000000 +1.000465133638230725e-01 6.445992151903826971e-05 0.000000000000000000 +1.004025328412940926e-01 4.585692330584841258e-05 0.000000000000000000 +1.007585521276129076e-01 2.768982607827679971e-05 0.000000000000000000 +1.011145712221016152e-01 1.276618442061887835e-05 0.000000000000000000 +1.014705901240824798e-01 3.742288566040074791e-06 0.000000000000000000 +1.018266088328776409e-01 2.759468808386639137e-06 0.000000000000000000 +1.021826273478093211e-01 1.111399388889338987e-05 0.000000000000000000 +1.025386456681996877e-01 2.900749403134073737e-05 0.000000000000000000 +1.028946637933709773e-01 5.541871035227143385e-05 0.000000000000000000 +1.032506817226453294e-01 8.812509142791419042e-05 0.000000000000000000 +1.036066994553449527e-01 1.238854304385895945e-04 0.000000000000000000 +1.039627169907920423e-01 1.587742902448870791e-04 0.000000000000000000 +1.043187343283087792e-01 1.886379263912715994e-04 0.000000000000000000 +1.046747514672173585e-01 2.096225884859581991e-04 0.000000000000000000 +1.050307684068400166e-01 2.187121503802830170e-04 0.000000000000000000 +1.053867851464988792e-01 2.142052049765487008e-04 0.000000000000000000 +1.057428016855162245e-01 1.960634957971946234e-04 0.000000000000000000 +1.060988180232141503e-01 1.660742922637250716e-04 0.000000000000000000 +1.064548341589149211e-01 1.277884105978826699e-04 0.000000000000000000 +1.068108500919407039e-01 8.622132208667974192e-05 0.000000000000000000 +1.071668658216137077e-01 4.733449434705914880e-05 0.000000000000000000 +1.075228813472561273e-01 1.734434760081200050e-05 0.000000000000000000 +1.078788966681901579e-01 1.933118656369010416e-06 0.000000000000000000 +1.082349117837379943e-01 5.455659258887862833e-06 0.000000000000000000 +1.085909266932218176e-01 3.024542857905961391e-05 0.000000000000000000 +1.089469413959638505e-01 7.611941956014601899e-05 0.000000000000000000 +1.093029558912862742e-01 1.401647771652088912e-04 0.000000000000000000 +1.096589701785113113e-01 2.168605424404625908e-04 0.000000000000000000 +1.100149842569611430e-01 2.985492361386503043e-04 0.000000000000000000 +1.103709981259579642e-01 3.762293309851267903e-04 0.000000000000000000 +1.107270117848239699e-01 4.405964106256916196e-04 0.000000000000000000 +1.110830252328813966e-01 4.832234871945571223e-04 0.000000000000000000 +1.114390384694523978e-01 4.977444658418705547e-04 0.000000000000000000 +1.117950514938592238e-01 4.808928316538502406e-04 0.000000000000000000 +1.121510643054240280e-01 4.332524663460849768e-04 0.000000000000000000 +1.125070769034690332e-01 3.595995585983343063e-04 0.000000000000000000 +1.128630892873164482e-01 2.687526470951428549e-04 0.000000000000000000 +1.132191014562884679e-01 1.728991032888055270e-04 0.000000000000000000 +1.135751134097072873e-01 8.642644558309738555e-05 0.000000000000000000 +1.139311251468951292e-01 2.434995658576660226e-05 0.000000000000000000 +1.142871366671741884e-01 4.871332911674904110e-07 0.000000000000000000 +1.146431479698666461e-01 2.557686056594543939e-05 0.000000000000000000 +1.149991590542947528e-01 1.055694366321243013e-04 0.000000000000000000 +1.153551699197806757e-01 2.403167539066789686e-04 0.000000000000000000 +1.157111805656466652e-01 4.228669098875471291e-04 0.000000000000000000 +1.160671909912148747e-01 6.395149834138812422e-04 0.000000000000000000 +1.164232011958075269e-01 8.706865365835499094e-04 0.000000000000000000 +1.167792111787468445e-01 1.092641079005167524e-03 0.000000000000000000 +1.171352209393550226e-01 1.279889917418906668e-03 0.000000000000000000 +1.174912304769542698e-01 1.408137396975669194e-03 0.000000000000000000 +1.178472397908667951e-01 1.457485765100531442e-03 0.000000000000000000 +1.182032488804148213e-01 1.415598123074409071e-03 0.000000000000000000 +1.185592577449205293e-01 1.280494398398293598e-03 0.000000000000000000 +1.189152663837061141e-01 1.062662707987248713e-03 0.000000000000000000 +1.192712747960938680e-01 7.862023083468068062e-04 0.000000000000000000 +1.196272829814059163e-01 4.887737236485311439e-04 0.000000000000000000 +1.199832909389645097e-01 2.202159189247301777e-04 0.000000000000000000 +1.203392986680918431e-01 3.979830839398972161e-05 0.000000000000000000 +1.206953061681101530e-01 1.220350711631287037e-05 0.000000000000000000 +1.210513134383415929e-01 2.024772858306064501e-04 0.000000000000000000 +1.214073204781084547e-01 6.703215492764690161e-04 0.000000000000000000 +1.217633272867328920e-01 1.464224940939182554e-03 0.000000000000000000 +1.221193338635371411e-01 2.616001291675263546e-03 0.000000000000000000 +1.224753402078434111e-01 4.136317795377386815e-03 0.000000000000000000 +1.228313463189739246e-01 6.011729879899218969e-03 0.000000000000000000 +1.231873521962508905e-01 8.203599311089578364e-03 0.000000000000000000 +1.235433578389965176e-01 1.064907325468252182e-02 0.000000000000000000 +1.238993632465330147e-01 1.326407565021464098e-02 0.000000000000000000 +1.242553684181826323e-01 1.594804589567879946e-02 0.000000000000000000 +1.246113733532675794e-01 1.858998840281154974e-02 0.000000000000000000 +1.249673780511100230e-01 2.107529362738292181e-02 0.000000000000000000 +1.253233825110322275e-01 2.329276398118123453e-02 0.000000000000000000 +1.256793867323563740e-01 2.514131773352146215e-02 0.000000000000000000 +1.260353907144047547e-01 2.653593029410738352e-02 0.000000000000000000 +1.263913944564994951e-01 2.741248045644777837e-02 0.000000000000000000 +1.267473979579628873e-01 2.773127720409010108e-02 0.000000000000000000 +1.271034012181170847e-01 2.747913598426924078e-02 0.000000000000000000 +1.274594042362844071e-01 2.666994684051260736e-02 0.000000000000000000 +1.278154070117869523e-01 2.534373397932043748e-02 0.000000000000000000 +1.281714095439470125e-01 2.356425644370230624e-02 0.000000000000000000 +1.285274118320868242e-01 2.141525350765790051e-02 0.000000000000000000 +1.288834138755285685e-01 1.899550465513106731e-02 0.000000000000000000 +1.292394156735944544e-01 1.641295502586023747e-02 0.000000000000000000 +1.295954172256067738e-01 1.377824733243297045e-02 0.000000000000000000 +1.299514185308876801e-01 1.119808666537737939e-02 0.000000000000000000 +1.303074195887594100e-01 8.768925840754077800e-03 0.000000000000000000 +1.306634203985442555e-01 6.571475698095328305e-03 0.000000000000000000 +1.310194209595643700e-01 4.666501959614566611e-03 0.000000000000000000 +1.313754212711419622e-01 3.092263662854505268e-03 0.000000000000000000 +1.317314213325993244e-01 1.863787371175296007e-03 0.000000000000000000 +1.320874211432586653e-01 9.739788607820338857e-04 0.000000000000000000 +1.324434207024421384e-01 3.963802668736982667e-04 0.000000000000000000 +1.327994200094720634e-01 8.921674493044612559e-05 0.000000000000000000 +1.331554190636706492e-01 2.665952073295560575e-07 0.000000000000000000 +1.335114178643601046e-01 7.204451553262165473e-05 0.000000000000000000 +1.338674164108626385e-01 2.468079355140588354e-04 0.000000000000000000 +1.342234147025005153e-01 4.709691611840681100e-04 0.000000000000000000 +1.345794127385959993e-01 6.986031137617786492e-04 0.000000000000000000 +1.349354105184712160e-01 8.938625339974852696e-04 0.000000000000000000 +1.352914080414484854e-01 1.032233272837267991e-03 0.000000000000000000 +1.356474053068499885e-01 1.100670165759236405e-03 0.000000000000000000 +1.360034023139979620e-01 1.096742387334400607e-03 0.000000000000000000 +1.363593990622146979e-01 1.026983290192023382e-03 0.000000000000000000 +1.367153955508223495e-01 9.046829782939392077e-04 0.000000000000000000 +1.370713917791431813e-01 7.473826517818878959e-04 0.000000000000000000 +1.374273877464994298e-01 5.743288455797241135e-04 0.000000000000000000 +1.377833834522133039e-01 4.041242294020531349e-04 0.000000000000000000 +1.381393788956070956e-01 2.527717022236912470e-04 0.000000000000000000 +1.384953740760029861e-01 1.322536032598316106e-04 0.000000000000000000 +1.388513689927232952e-01 4.972316958766892492e-05 0.000000000000000000 +1.392073636450900931e-01 7.317517967114064301e-06 0.000000000000000000 +1.395633580324257550e-01 2.537677108587326546e-06 0.000000000000000000 +1.399193521540525176e-01 2.908835027570081237e-05 0.000000000000000000 +1.402753460092925342e-01 7.803339032303392069e-05 0.000000000000000000 +1.406313395974680969e-01 1.391053081044480594e-04 0.000000000000000000 +1.409873329179014423e-01 2.020087466444986369e-04 0.000000000000000000 +1.413433259699148070e-01 2.575765483758868835e-04 0.000000000000000000 +1.416993187528304277e-01 2.986688295301005150e-04 0.000000000000000000 +1.420553112659705131e-01 3.207453690561380731e-04 0.000000000000000000 +1.424113035086573553e-01 3.220844265491808384e-04 0.000000000000000000 +1.427672954802131633e-01 3.036620472458394096e-04 0.000000000000000000 +1.431232871799602568e-01 2.687410374968812179e-04 0.000000000000000000 +1.434792786072207338e-01 2.222451849224639628e-04 0.000000000000000000 +1.438352697613169140e-01 1.700101604961256198e-04 0.000000000000000000 +1.441912606415710896e-01 1.180072167506263824e-04 0.000000000000000000 +1.445472512473053861e-01 7.162973129632132499e-05 0.000000000000000000 +1.449032415778421790e-01 3.511730379804545903e-05 0.000000000000000000 +1.452592316325035937e-01 1.116983220888827088e-05 0.000000000000000000 +1.456152214106120057e-01 7.777283395139781894e-07 0.000000000000000000 +1.459712109114895129e-01 3.267429409928755642e-06 0.000000000000000000 +1.463272001344584627e-01 1.653676404955362850e-05 0.000000000000000000 +1.466831890788410642e-01 3.743519360125543239e-05 0.000000000000000000 +1.470391777439595815e-01 6.223132893986060073e-05 0.000000000000000000 +1.473951661291362514e-01 8.710529387389396986e-05 0.000000000000000000 +1.477511542336933659e-01 1.086063318426373905e-04 0.000000000000000000 +1.481071420569531061e-01 1.240255000048975584e-04 0.000000000000000000 +1.484631295982377364e-01 1.316476568555218331e-04 0.000000000000000000 +1.488191168568695488e-01 1.308641240165144915e-04 0.000000000000000000 +1.491751038321706968e-01 1.221451788117454299e-04 0.000000000000000000 +1.495310905234635834e-01 1.068878480401105961e-04 0.000000000000000000 +1.498870769300703343e-01 8.716761338618064802e-05 0.000000000000000000 +1.502430630513132692e-01 6.543138988379636754e-05 0.000000000000000000 +1.505990488865145693e-01 4.417286511353148116e-05 0.000000000000000000 +1.509550344349965822e-01 2.562995585053618792e-05 0.000000000000000000 +1.513110196960814890e-01 1.153828666902127318e-05 0.000000000000000000 +1.516670046690915818e-01 2.965235759156494224e-06 0.000000000000000000 +1.520229893533490695e-01 2.375799839852772526e-07 0.000000000000000000 +1.523789737481762996e-01 2.963620748559541254e-06 0.000000000000000000 +1.527349578528954532e-01 1.013937457113441147e-05 0.000000000000000000 +1.530909416668287393e-01 2.031925017450853009e-05 0.000000000000000000 +1.534469251892985331e-01 3.182553792128342513e-05 0.000000000000000000 +1.538029084196269880e-01 4.296849512713465805e-05 0.000000000000000000 +1.541588913571364794e-01 5.224984095593289532e-05 0.000000000000000000 +1.545148740011491328e-01 5.852666389340268379e-05 0.000000000000000000 +1.548708563509873237e-01 6.111933592639955343e-05 0.000000000000000000 +1.552268384059732331e-01 5.985504110310268079e-05 0.000000000000000000 +1.555828201654291809e-01 5.504689643007802332e-05 0.000000000000000000 +1.559388016286773482e-01 4.741635006511724901e-05 0.000000000000000000 +1.562947827950400825e-01 3.797272496357615167e-05 0.000000000000000000 +1.566507636638395928e-01 2.786782030213914843e-05 0.000000000000000000 +1.570067442343981712e-01 1.824507016429453263e-05 0.000000000000000000 +1.573627245060380819e-01 1.010188399731723001e-05 0.000000000000000000 +1.577187044780815062e-01 4.180743690407739994e-06 0.000000000000000000 +1.580746841498507915e-01 8.999352539747241527e-07 0.000000000000000000 +1.584306635206682023e-01 3.291384610701385866e-07 0.000000000000000000 +1.587866425898560307e-01 2.209243188621883886e-06 0.000000000000000000 +1.591426213567364301e-01 6.010435270108753439e-06 0.000000000000000000 +1.594985998206318034e-01 1.101840877966192323e-05 0.000000000000000000 +1.598545779808643041e-01 1.643594171742741798e-05 0.000000000000000000 +1.602105558367562799e-01 2.148621869868597563e-05 0.000000000000000000 +1.605665333876299672e-01 2.550516468535396394e-05 0.000000000000000000 +1.609225106328075749e-01 2.801242400403508741e-05 0.000000000000000000 +1.612784875716115063e-01 2.875407056220063696e-05 0.000000000000000000 +1.616344642033639145e-01 2.771415921962680788e-05 0.000000000000000000 +1.619904405273871473e-01 2.509628534763581434e-05 0.000000000000000000 +1.623464165430034134e-01 2.127990839067300612e-05 0.000000000000000000 +1.627023922495350050e-01 1.675891059642977993e-05 0.000000000000000000 +1.630583676463042420e-01 1.207143716837361807e-05 0.000000000000000000 +1.634143427326333609e-01 7.730392826651313014e-06 0.000000000000000000 +1.637703175078445705e-01 4.163108299111086397e-06 0.000000000000000000 +1.641262919712602741e-01 1.666838683256887413e-06 0.000000000000000000 +1.644822661222026805e-01 3.842230227906430383e-07 0.000000000000000000 +1.648382399599940262e-01 2.999926007570094749e-07 0.000000000000000000 +1.651942134839566589e-01 1.257447392305794977e-06 0.000000000000000000 +1.655501866934127597e-01 2.990870497965352064e-06 0.000000000000000000 +1.659061595876847317e-01 5.168384013160258488e-06 0.000000000000000000 +1.662621321660947560e-01 7.438923370792001123e-06 0.000000000000000000 +1.666181044279652079e-01 9.477057076390020565e-06 0.000000000000000000 +1.669740763726181854e-01 1.102022537901142458e-05 0.000000000000000000 +1.673300479993762024e-01 1.189443856190296805e-05 0.000000000000000000 +1.676860193075613570e-01 1.202632073413337422e-05 0.000000000000000000 +1.680419902964960521e-01 1.144133631291558719e-05 0.000000000000000000 +1.683979609655024134e-01 1.024983018201071423e-05 0.000000000000000000 +1.687539313139028996e-01 8.623927379987487136e-06 0.000000000000000000 +1.691099013410197471e-01 6.769220795462518602e-06 0.000000000000000000 +1.694658710461751094e-01 4.895455609086372992e-06 0.000000000000000000 +1.698218404286914729e-01 3.190113289274418335e-06 0.000000000000000000 +1.701778094878909353e-01 1.797999666524523074e-06 0.000000000000000000 +1.705337782230959276e-01 8.088040545546147058e-07 0.000000000000000000 +1.708897466336286308e-01 2.533065822331901015e-07 0.000000000000000000 +1.712457147188113649e-01 1.076615254951338627e-07 0.000000000000000000 +1.716016824779664218e-01 3.041465350388869230e-07 0.000000000000000000 +1.719576499104161771e-01 7.460681489742753102e-07 0.000000000000000000 +1.723136170154827285e-01 1.324220752222025398e-06 0.000000000000000000 +1.726695837924885624e-01 1.932412544855609679e-06 0.000000000000000000 +1.730255502407558044e-01 2.480040996392723469e-06 0.000000000000000000 +1.733815163596068576e-01 2.900416708919564217e-06 0.000000000000000000 +1.737374821483639864e-01 3.154364580513317717e-06 0.000000000000000000 +1.740934476063493996e-01 3.229433683842765013e-06 0.000000000000000000 +1.744494127328855004e-01 3.135696362522462666e-06 0.000000000000000000 +1.748053775272945531e-01 2.899520308567937198e-06 0.000000000000000000 +1.751613419888988221e-01 2.556808738275931952e-06 0.000000000000000000 +1.755173061170206272e-01 2.147028597314123673e-06 0.000000000000000000 +1.758732699109822051e-01 1.708938832546787614e-06 0.000000000000000000 +1.762292333701059310e-01 1.278382022611821128e-06 0.000000000000000000 +1.765851964937140972e-01 8.879267397751094873e-07 0.000000000000000000 +1.769411592811289125e-01 5.676610123502146731e-07 0.000000000000000000 +1.772971217316727521e-01 3.461380276079722355e-07 0.000000000000000000 +1.776530838446679084e-01 2.504285056077941324e-07 0.000000000000000000 +1.780090456194367010e-01 3.044590868243752206e-07 0.000000000000000000 +1.783650070553013389e-01 5.252816802839334994e-07 0.000000000000000000 +1.787209681515841975e-01 9.175475618961617589e-07 0.000000000000000000 +1.790769289076075133e-01 1.467139141091585756e-06 0.000000000000000000 +1.794328893226936616e-01 2.135510314238924347e-06 0.000000000000000000 +1.797888493961649348e-01 2.856673998169197392e-06 0.000000000000000000 +1.801448091273435692e-01 3.538847147317965509e-06 0.000000000000000000 +1.805007685155519126e-01 4.072456084991282567e-06 0.000000000000000000 +1.808567275601123125e-01 4.345511017452451744e-06 0.000000000000000000 +1.812126862603470057e-01 4.266332661519509790e-06 0.000000000000000000 +1.815686446155782841e-01 3.792369439228995033e-06 0.000000000000000000 +1.819246026251284953e-01 2.962541342940312717e-06 0.000000000000000000 +1.822805602883199871e-01 1.929374983339477777e-06 0.000000000000000000 +1.826365176044749405e-01 9.863455918093047055e-07 0.000000000000000000 +1.829924745729158142e-01 5.854847547471093298e-07 0.000000000000000000 +1.833484311929647892e-01 1.340567785800901897e-06 0.000000000000000000 +1.837043874639442409e-01 4.012113124293805079e-06 0.000000000000000000 +1.840603433851764892e-01 9.471977045142035314e-06 0.000000000000000000 +1.844162989559837984e-01 1.864739378685414768e-05 0.000000000000000000 +1.847722541756884607e-01 3.244669916381921401e-05 0.000000000000000000 +1.851282090436128791e-01 5.167142943140016906e-05 0.000000000000000000 +1.854841635590793736e-01 7.692171728882853034e-05 0.000000000000000000 +1.858401177214100697e-01 1.085036232282542834e-04 0.000000000000000000 +1.861960715299275093e-01 1.463479876901880596e-04 0.000000000000000000 +1.865520249839538180e-01 1.899503815588748370e-04 0.000000000000000000 +1.869079780828115100e-01 2.383406806231707503e-04 0.000000000000000000 +1.872639308258226554e-01 2.900887201006568700e-04 0.000000000000000000 +1.876198832123097959e-01 3.433495442083197473e-04 0.000000000000000000 +1.879758352415951128e-01 3.959482084958235496e-04 0.000000000000000000 +1.883317869130010092e-01 4.455002596893518235e-04 0.000000000000000000 +1.886877382258497493e-01 4.895602988239268613e-04 0.000000000000000000 +1.890436891794636254e-01 5.257878247229267775e-04 0.000000000000000000 +1.893996397731650405e-01 5.521172150073502208e-04 0.000000000000000000 +1.897555900062762591e-01 5.669175114659875166e-04 0.000000000000000000 +1.901115398781196564e-01 5.691278069494392364e-04 0.000000000000000000 +1.904674893880174136e-01 5.583555238115983340e-04 0.000000000000000000 +1.908234385352920170e-01 5.349276354955198511e-04 0.000000000000000000 +1.911793873192657034e-01 4.998886906644803415e-04 0.000000000000000000 +1.915353357392608480e-01 4.549440213965135621e-04 0.000000000000000000 +1.918912837945997152e-01 4.023513415116584816e-04 0.000000000000000000 +1.922472314846046526e-01 3.447686135888582875e-04 0.000000000000000000 +1.926031788085980079e-01 2.850701290599796153e-04 0.000000000000000000 +1.929591257659021009e-01 2.261457947346995421e-04 0.000000000000000000 +1.933150723558391959e-01 1.707003281964997101e-04 0.000000000000000000 +1.936710185777317517e-01 1.210692346449203718e-04 0.000000000000000000 +1.940269644309019492e-01 7.906702003329146627e-05 0.000000000000000000 +1.943829099146722750e-01 4.588020246837628760e-05 0.000000000000000000 +1.947388550283649100e-01 2.201358390830739767e-05 0.000000000000000000 +1.950947997713022575e-01 7.293336045823737323e-06 0.000000000000000000 +1.954507441428066372e-01 9.252262154856471493e-07 0.000000000000000000 +1.958066881422003969e-01 1.601285880002985206e-06 0.000000000000000000 +1.961626317688058563e-01 7.643908463132016528e-06 0.000000000000000000 +1.965185750219453076e-01 1.717318009637506531e-05 0.000000000000000000 +1.968745179009412094e-01 2.828149786008608612e-05 0.000000000000000000 +1.972304604051157706e-01 3.919936309822959257e-05 0.000000000000000000 +1.975864025337913388e-01 4.843763436167945491e-05 0.000000000000000000 +1.979423442862902893e-01 5.489430848521220793e-05 0.000000000000000000 +1.982982856619349699e-01 5.791775658249328481e-05 0.000000000000000000 +1.986542266600476725e-01 5.732286218237246401e-05 0.000000000000000000 +1.990101672799508281e-01 5.336122393788524332e-05 0.000000000000000000 +1.993661075209666733e-01 4.665102050553604859e-05 0.000000000000000000 +1.997220473824175557e-01 3.807585502049723106e-05 0.000000000000000000 +2.000779868636259062e-01 2.866454745669817108e-05 0.000000000000000000 +2.004339259639139614e-01 1.946518700320736041e-05 0.000000000000000000 +2.007898646826041245e-01 1.142669354877474980e-05 0.000000000000000000 +2.011458030190187152e-01 5.299714736438235724e-06 0.000000000000000000 +2.015017409724800812e-01 1.566091146902458539e-06 0.000000000000000000 +2.018576785423105702e-01 4.026651359075934996e-07 0.000000000000000000 +2.022136157278325297e-01 1.681282151611436078e-06 0.000000000000000000 +2.025695525283682796e-01 5.002871589409538899e-06 0.000000000000000000 +2.029254889432401954e-01 9.759924382879398998e-06 0.000000000000000000 +2.032814249717706800e-01 1.521887858564278347e-05 0.000000000000000000 +2.036373606132819980e-01 2.061215906995900928e-05 0.000000000000000000 +2.039932958670964691e-01 2.522904682399217829e-05 0.000000000000000000 +2.043492307325364965e-01 2.849519450012334441e-05 0.000000000000000000 +2.047051652089245111e-01 3.003234163810449768e-05 0.000000000000000000 +2.050610992955826661e-01 2.969238316629291735e-05 0.000000000000000000 +2.054170329918335314e-01 2.756308974279663603e-05 0.000000000000000000 +2.057729662969992601e-01 2.394610083840538576e-05 0.000000000000000000 +2.061288992104023665e-01 1.931093645612241421e-05 0.000000000000000000 +2.064848317313651704e-01 1.423135979906144990e-05 0.000000000000000000 +2.068407638592099085e-01 9.312199466116636372e-06 0.000000000000000000 +2.071966955932590670e-01 5.115531919461725959e-06 0.000000000000000000 +2.075526269328349105e-01 2.094873713437147655e-06 0.000000000000000000 +2.079085578772599530e-01 5.447979266944590749e-07 0.000000000000000000 +2.082644884258563478e-01 5.713400269409196353e-07 0.000000000000000000 +2.086204185779465814e-01 2.085953357441809966e-06 0.000000000000000000 +2.089763483328529181e-01 4.822929335948564482e-06 0.000000000000000000 +2.093322776898979276e-01 8.377447909787557340e-06 0.000000000000000000 +2.096882066484037077e-01 1.225908591020606872e-05 0.000000000000000000 +2.100441352076927726e-01 1.595394496079915217e-05 0.000000000000000000 +2.104000633670873865e-01 1.898774205519814144e-05 0.000000000000000000 +2.107559911259100360e-01 2.098230745250231360e-05 0.000000000000000000 +2.111119184834830409e-01 2.169892021507130244e-05 0.000000000000000000 +2.114678454391286933e-01 2.106364413376642772e-05 0.000000000000000000 +2.118237719921693962e-01 1.917208556424397550e-05 0.000000000000000000 +2.121796981419276085e-01 1.627350379474826734e-05 0.000000000000000000 +2.125356238877255666e-01 1.273666512882906154e-05 0.000000000000000000 +2.128915492288856737e-01 9.001956836942117556e-06 0.000000000000000000 +2.132474741647303329e-01 5.525823850136786935e-06 0.000000000000000000 +2.136033986945818919e-01 2.724388402501055755e-06 0.000000000000000000 +2.139593228177627815e-01 9.230799063256901580e-07 0.000000000000000000 +2.143152465335952384e-01 3.182568425487276085e-07 0.000000000000000000 +2.146711698414017766e-01 9.552574446170507813e-07 0.000000000000000000 +2.150270927405046328e-01 2.725265626615183525e-06 0.000000000000000000 +2.153830152302263212e-01 5.381074428354149575e-06 0.000000000000000000 +2.157389373098891061e-01 8.569549490893455884e-06 0.000000000000000000 +2.160948589788154184e-01 1.187661135574279510e-05 0.000000000000000000 +2.164507802363275779e-01 1.487910039621436682e-05 0.000000000000000000 +2.168067010817480433e-01 1.719712856117240743e-05 0.000000000000000000 +2.171626215143991900e-01 1.854053957493135123e-05 0.000000000000000000 +2.175185415336032269e-01 1.874388224981669699e-05 0.000000000000000000 +2.178744611386827512e-01 1.778574805647824546e-05 0.000000000000000000 +2.182303803289600275e-01 1.579025471339463242e-05 0.000000000000000000 +2.185862991037574588e-01 1.301063764277111631e-05 0.000000000000000000 +2.189422174623973927e-01 9.797078719471988956e-06 0.000000000000000000 +2.192981354042022601e-01 6.552798316362948958e-06 0.000000000000000000 +2.196540529284944920e-01 3.683837366356750384e-06 0.000000000000000000 +2.200099700345962972e-01 1.548695982552249733e-06 0.000000000000000000 +2.203658867218302175e-01 4.139881502624459350e-07 0.000000000000000000 +2.207218029895186284e-01 4.215213494170291030e-07 0.000000000000000000 +2.210777188369837942e-01 1.570807714703152636e-06 0.000000000000000000 +2.214336342635482846e-01 3.719129414464846040e-06 0.000000000000000000 +2.217895492685343084e-01 6.599142829491929937e-06 0.000000000000000000 +2.221454638512643243e-01 9.851871607361456580e-06 0.000000000000000000 +2.225013780110607908e-01 1.307106478734194164e-05 0.000000000000000000 +2.228572917472460002e-01 1.585350836065541267e-05 0.000000000000000000 +2.232132050591423833e-01 1.784914374214487015e-05 0.000000000000000000 +2.235691179460722877e-01 1.880485329805080074e-05 0.000000000000000000 +2.239250304073581443e-01 1.859652137021163115e-05 0.000000000000000000 +2.242809424423224396e-01 1.724538094034458823e-05 0.000000000000000000 +2.246368540502874100e-01 1.491654525518869076e-05 0.000000000000000000 +2.249927652305755144e-01 1.189977625366486847e-05 0.000000000000000000 +2.253486759825091001e-01 8.574701332865957782e-06 0.000000000000000000 +2.257045863054106816e-01 5.364598503175520927e-06 0.000000000000000000 +2.260604961986025507e-01 2.684296998205506907e-06 0.000000000000000000 +2.264164056614071663e-01 8.885109021706287485e-07 0.000000000000000000 +2.267723146931468481e-01 2.269387755172305801e-07 0.000000000000000000 +2.271282232931441103e-01 8.117130274576717298e-07 0.000000000000000000 +2.274841314607211895e-01 2.601350541286858548e-06 0.000000000000000000 +2.278400391952006554e-01 5.403405051271055218e-06 0.000000000000000000 +2.281959464959048556e-01 8.895780203323300507e-06 0.000000000000000000 +2.285518533621561377e-01 1.266439565916192375e-05 0.000000000000000000 +2.289077597932770158e-01 1.625287851587211947e-05 0.000000000000000000 +2.292636657885897267e-01 1.921842375589885143e-05 0.000000000000000000 +2.296195713474168398e-01 2.118711963628318900e-05 0.000000000000000000 +2.299754764690806474e-01 2.190197743659813359e-05 0.000000000000000000 +2.303313811529036359e-01 2.125765812816730969e-05 0.000000000000000000 +2.306872853982081806e-01 1.931737449380772429e-05 0.000000000000000000 +2.310431892043166846e-01 1.630950214887374417e-05 0.000000000000000000 +2.313990925705515234e-01 1.260382386764334503e-05 0.000000000000000000 +2.317549954962352110e-01 8.669782561512120501e-06 0.000000000000000000 +2.321108979806900952e-01 5.021341101723627460e-06 0.000000000000000000 +2.324668000232385512e-01 2.154774729344937035e-06 0.000000000000000000 +2.328227016232030655e-01 4.867389736402934433e-07 0.000000000000000000 +2.331786027799059857e-01 3.001259223516114284e-07 0.000000000000000000 +2.335345034926697427e-01 1.704503440762166951e-06 0.000000000000000000 +2.338904037608167397e-01 4.616387714822101882e-06 0.000000000000000000 +2.342463035836694629e-01 8.762389837498357379e-06 0.000000000000000000 +2.346022029605502601e-01 1.370564444212667862e-05 0.000000000000000000 +2.349581018907815899e-01 1.889317020500523808e-05 0.000000000000000000 +2.353140003736858554e-01 2.371924749966310597e-05 0.000000000000000000 +2.356698984085854320e-01 2.759783143302083051e-05 0.000000000000000000 +2.360257959948028339e-01 3.003570209926986591e-05 0.000000000000000000 +2.363816931316604086e-01 3.069766081847430963e-05 0.000000000000000000 +2.367375898184805871e-01 2.945568273778616204e-05 0.000000000000000000 +2.370934860545858003e-01 2.641549295136802239e-05 0.000000000000000000 +2.374493818392984790e-01 2.191639744937105749e-05 0.000000000000000000 +2.378052771719410818e-01 1.650312997341350603e-05 0.000000000000000000 +2.381611720518359565e-01 1.087165997853145378e-05 0.000000000000000000 +2.385170664783056171e-01 5.793996854177354880e-06 0.000000000000000000 +2.388729604506723836e-01 2.029672430229204538e-06 0.000000000000000000 +2.392288539682587978e-01 2.334762818299180701e-07 0.000000000000000000 +2.395847470303871796e-01 8.699179991498312256e-07 0.000000000000000000 +2.399406396363800431e-01 4.144660474612152276e-06 0.000000000000000000 +2.402965317855597915e-01 9.961791541408701635e-06 0.000000000000000000 +2.406524234772489113e-01 1.791338702387342853e-05 0.000000000000000000 +2.410083147107696944e-01 2.730459304993447634e-05 0.000000000000000000 +2.413642054854447105e-01 3.721374143640554153e-05 0.000000000000000000 +2.417200958005962796e-01 4.658319308735471689e-05 0.000000000000000000 +2.420759856555469991e-01 5.433308529352394223e-05 0.000000000000000000 +2.424318750496191055e-01 5.948732099064817986e-05 0.000000000000000000 +2.427877639821351963e-01 6.129929832590169875e-05 0.000000000000000000 +2.431436524524176190e-01 5.936425581594036036e-05 0.000000000000000000 +2.434995404597888602e-01 5.370579915080085409e-05 0.000000000000000000 +2.438554280035713229e-01 4.482614607596483542e-05 0.000000000000000000 +2.442113150830874935e-01 3.371271321212440799e-05 0.000000000000000000 +2.445672016976597751e-01 2.179759754490732802e-05 0.000000000000000000 +2.449230878466105987e-01 1.087091256722121274e-05 0.000000000000000000 +2.452789735292624784e-01 2.953407623529836242e-06 0.000000000000000000 +2.456348587449377341e-01 1.378965095403991584e-07 0.000000000000000000 +2.459907434929589354e-01 4.412341088162594809e-06 0.000000000000000000 +2.463466277726484299e-01 1.747963651819163614e-05 0.000000000000000000 +2.467025115833287874e-01 4.058998672819138994e-05 0.000000000000000000 +2.470583949243223276e-01 7.440113038936007023e-05 0.000000000000000000 +2.474142777949515648e-01 1.188796107863463163e-04 0.000000000000000000 +2.477701601945389021e-01 1.732529536870416789e-04 0.000000000000000000 +2.481260421224068813e-01 2.360183303176609216e-04 0.000000000000000000 +2.484819235778777946e-01 3.050084408937693602e-04 0.000000000000000000 +2.488378045602742950e-01 3.775104169066744483e-04 0.000000000000000000 +2.491936850689187022e-01 4.504289736652605097e-04 0.000000000000000000 +2.495495651031335027e-01 5.204812724094251422e-04 0.000000000000000000 +2.499054446622411274e-01 5.844083121543468783e-04 0.000000000000000000 +2.502613237455640349e-01 6.391863863911446952e-04 0.000000000000000000 +2.506172023524247394e-01 6.822222950896620307e-04 0.000000000000000000 +2.509730804821456718e-01 7.115175474495154598e-04 0.000000000000000000 +2.513289581340492629e-01 7.257895500113648079e-04 0.000000000000000000 +2.516848353074579991e-01 7.245414708931537757e-04 0.000000000000000000 +2.520407120016943114e-01 7.080767557977541088e-04 0.000000000000000000 +2.523965882160806307e-01 6.774587599310439049e-04 0.000000000000000000 +2.527524639499395542e-01 6.344202646996567390e-04 0.000000000000000000 +2.531083392025934575e-01 5.812314118152217676e-04 0.000000000000000000 +2.534642139733647159e-01 5.205375116692655037e-04 0.000000000000000000 +2.538200882615759268e-01 4.551800505310196515e-04 0.000000000000000000 +2.541759620665495212e-01 3.880149129923076800e-04 0.000000000000000000 +2.545318353876079298e-01 3.217413387649486643e-04 0.000000000000000000 +2.548877082240736391e-01 2.587535382368726274e-04 0.000000000000000000 +2.552435805752691356e-01 2.010243859077969072e-04 0.000000000000000000 +2.555994524405169055e-01 1.500274575711582690e-04 0.000000000000000000 +2.559553238191393243e-01 1.067001875450348863e-04 0.000000000000000000 +2.563111947104590449e-01 7.144742543980928595e-05 0.000000000000000000 +2.566670651137983872e-01 4.418148121403505301e-05 0.000000000000000000 +2.570229350284797820e-01 2.439212957370051342e-05 0.000000000000000000 +2.573788044538258268e-01 1.123819615210764163e-05 0.000000000000000000 +2.577346733891588970e-01 3.651377769462780292e-06 0.000000000000000000 +2.580905418338016455e-01 4.428748279827912932e-07 0.000000000000000000 +2.584464097870762811e-01 4.041659086940563928e-07 0.000000000000000000 +2.588022772483055678e-01 2.394690110333204590e-06 0.000000000000000000 +2.591581442168117699e-01 5.411126126420877825e-06 0.000000000000000000 +2.595140106919174294e-01 8.635144417758657128e-06 0.000000000000000000 +2.598698766729450327e-01 1.145873217275213932e-05 0.000000000000000000 +2.602257421592170661e-01 1.348824097373507993e-05 0.000000000000000000 +2.605816071500560716e-01 1.453001254346222851e-05 0.000000000000000000 +2.609374716447844245e-01 1.456167744160321416e-05 0.000000000000000000 +2.612933356427246112e-01 1.369393122354649354e-05 0.000000000000000000 +2.616491991431992847e-01 1.212776634161773513e-05 0.000000000000000000 +2.620050621455306539e-01 1.011182265544068162e-05 0.000000000000000000 +2.623609246490414826e-01 7.903804347304775398e-06 0.000000000000000000 +2.627167866530541462e-01 5.738915397532913392e-06 0.000000000000000000 +2.630726481568910202e-01 3.807123161115975743e-06 0.000000000000000000 +2.634285091598748130e-01 2.239902932464384948e-06 0.000000000000000000 +2.637843696613278444e-01 1.106064262284895556e-06 0.000000000000000000 +2.641402296605725453e-01 4.154055390482466289e-07 0.000000000000000000 +2.644960891569317352e-01 1.283479844538967136e-07 0.000000000000000000 +2.648519481497275674e-01 1.693895833381682224e-07 0.000000000000000000 +2.652078066382826393e-01 4.421855803582058112e-07 0.000000000000000000 +2.655636646219196040e-01 8.442681586998003212e-07 0.000000000000000000 +2.659195220999608367e-01 1.279805684329238197e-06 0.000000000000000000 +2.662753790717287128e-01 1.669301341198835630e-06 0.000000000000000000 +2.666312355365458853e-01 1.955669443602227276e-06 0.000000000000000000 +2.669870914937347295e-01 2.106638625176283343e-06 0.000000000000000000 +2.673429469426180094e-01 2.113860849524210864e-06 0.000000000000000000 +2.676988018825179338e-01 1.989417564585745452e-06 0.000000000000000000 +2.680546563127571558e-01 1.760592384013312853e-06 0.000000000000000000 +2.684105102326581060e-01 1.463825009865333994e-06 0.000000000000000000 +2.687663636415433821e-01 1.138690952369575721e-06 0.000000000000000000 +2.691222165387354148e-01 8.225944216121352054e-07 0.000000000000000000 +2.694780689235566906e-01 5.466520236472639533e-07 0.000000000000000000 +2.698339207953296959e-01 3.330177657028442152e-07 0.000000000000000000 +2.701897721533771946e-01 1.936866186863442292e-07 0.000000000000000000 +2.705456229970213400e-01 1.306383756205589873e-07 0.000000000000000000 +2.709014733255848406e-01 1.370603049970941533e-07 0.000000000000000000 +2.712573231383901273e-01 1.993209001818383826e-07 0.000000000000000000 +2.716131724347597975e-01 2.993539208881253968e-07 0.000000000000000000 +2.719690212140163377e-01 4.171413717783399900e-07 0.000000000000000000 +2.723248694754821786e-01 5.330417195243628955e-07 0.000000000000000000 +2.726807172184800288e-01 6.297802913672740836e-07 0.000000000000000000 +2.730365644423320970e-01 6.939889455432200900e-07 0.000000000000000000 +2.733924111463612583e-01 7.172419463966876585e-07 0.000000000000000000 +2.737482573298897215e-01 6.965793810952710754e-07 0.000000000000000000 +2.741041029922401950e-01 6.345379895852175783e-07 0.000000000000000000 +2.744599481327350543e-01 5.387253599863911556e-07 0.000000000000000000 +2.748157927506970077e-01 4.209828298957167418e-07 0.000000000000000000 +2.751716368454484862e-01 2.961914239939332171e-07 0.000000000000000000 +2.755274804163119207e-01 1.807888081972191381e-07 0.000000000000000000 +2.758833234626099640e-01 9.108598633582704498e-08 0.000000000000000000 +2.762391659836649915e-01 4.149936874993870342e-08 0.000000000000000000 +2.765950079787997673e-01 4.284260706090866919e-08 0.000000000000000000 +2.769508494473366667e-01 1.008463400533703195e-07 0.000000000000000000 +2.773066903885982315e-01 2.150846751737722855e-07 0.000000000000000000 +2.776625308019069482e-01 3.784773645911775979e-07 0.000000000000000000 +2.780183706865854143e-01 5.775011393897619779e-07 0.000000000000000000 +2.783742100419561161e-01 7.931813542898681220e-07 0.000000000000000000 +2.787300488673416510e-01 1.002849593991517249e-06 0.000000000000000000 +2.790858871620645054e-01 1.182552745946481302e-06 0.000000000000000000 +2.794417249254471658e-01 1.309896939472225696e-06 0.000000000000000000 +2.797975621568122850e-01 1.367020915003293640e-06 0.000000000000000000 +2.801533988554822940e-01 1.343333370951616153e-06 0.000000000000000000 +2.805092350207796792e-01 1.237630997235039906e-06 0.000000000000000000 +2.808650706520272600e-01 1.059246980603195153e-06 0.000000000000000000 +2.812209057485471897e-01 8.279659293138247783e-07 0.000000000000000000 +2.815767403096623434e-01 5.725749114887673110e-07 0.000000000000000000 +2.819325743346951518e-01 3.280884244629944250e-07 0.000000000000000000 +2.822884078229679905e-01 1.318678369264864515e-07 0.000000000000000000 +2.826442407738036233e-01 1.902906699676500189e-08 0.000000000000000000 +2.830000731865244812e-01 1.767063186496526808e-08 0.000000000000000000 +2.833559050604531060e-01 1.445346953632103439e-07 0.000000000000000000 +2.837117363949121507e-01 4.017191631161880995e-07 0.000000000000000000 +2.840675671892240461e-01 7.749808928305430438e-07 0.000000000000000000 +2.844233974427113898e-01 1.234011200423702327e-06 0.000000000000000000 +2.847792271546967235e-01 1.734839009403498591e-06 0.000000000000000000 +2.851350563245025338e-01 2.224248681802033589e-06 0.000000000000000000 +2.854908849514516400e-01 2.645821274249989942e-06 0.000000000000000000 +2.858467130348661400e-01 2.946956387901472803e-06 0.000000000000000000 +2.862025405740689643e-01 3.086043165975969531e-06 0.000000000000000000 +2.865583675683825438e-01 3.038854138485934867e-06 0.000000000000000000 +2.869141940171294758e-01 2.803255276438101838e-06 0.000000000000000000 +2.872700199196321913e-01 2.401466921066061765e-06 0.000000000000000000 +2.876258452752133432e-01 1.879364672651541047e-06 0.000000000000000000 +2.879816700831954734e-01 1.302652615367303123e-06 0.000000000000000000 +2.883374943429012349e-01 7.501354771282871334e-07 0.000000000000000000 +2.886933180536529475e-01 3.047138153896334636e-07 0.000000000000000000 +2.890491412147734862e-01 4.307525183489898607e-08 0.000000000000000000 +2.894049638255851153e-01 2.530565284298806053e-08 0.000000000000000000 +2.897607858854106544e-01 2.857564616730391576e-07 0.000000000000000000 +2.901166073935724232e-01 8.264525758712525465e-07 0.000000000000000000 +2.904724283493931858e-01 1.614103052506884620e-06 0.000000000000000000 +2.908282487521953730e-01 2.581399933099753418e-06 0.000000000000000000 +2.911840686013016932e-01 3.632795187953028304e-06 0.000000000000000000 +2.915398878960346329e-01 4.654386718200645332e-06 0.000000000000000000 +2.918957066357167340e-01 5.526988270841967471e-06 0.000000000000000000 +2.922515248196707605e-01 6.140976291762791942e-06 0.000000000000000000 +2.926073424472189211e-01 6.411166195033439170e-06 0.000000000000000000 +2.929631595176840908e-01 6.289825251788085086e-06 0.000000000000000000 +2.933189760303886451e-01 5.776012526604314983e-06 0.000000000000000000 +2.936747919846554589e-01 4.919754875370242965e-06 0.000000000000000000 +2.940306073798067410e-01 3.820099785938308823e-06 0.000000000000000000 +2.943864222151653109e-01 2.616780325112386209e-06 0.000000000000000000 +2.947422364900537106e-01 1.476010201605695031e-06 0.000000000000000000 +2.950980502037944819e-01 5.717070691808662942e-07 0.000000000000000000 +2.954538633557101668e-01 6.412240753057372628e-08 0.000000000000000000 +2.958096759451234181e-01 7.834452550070047346e-08 0.000000000000000000 +2.961654879713568334e-01 6.853621931580115660e-07 0.000000000000000000 +2.965212994337328989e-01 1.888282195828092748e-06 0.000000000000000000 +2.968771103315741566e-01 3.615871908319725428e-06 0.000000000000000000 +2.972329206642034261e-01 5.724874174167235370e-06 0.000000000000000000 +2.975887304309431380e-01 8.011581401171847166e-06 0.000000000000000000 +2.979445396311158900e-01 1.023205738041955132e-05 0.000000000000000000 +2.983003482640443904e-01 1.212928128217131382e-05 0.000000000000000000 +2.986561563290510146e-01 1.346449172054411452e-05 0.000000000000000000 +2.990119638254584711e-01 1.404925845060793942e-05 0.000000000000000000 +2.993677707525893572e-01 1.377441398177880147e-05 0.000000000000000000 +2.997235771097662149e-01 1.263201197269311112e-05 0.000000000000000000 +3.000793828963118082e-01 1.072697358919602690e-05 0.000000000000000000 +3.004351881115484568e-01 8.276015589527190502e-06 0.000000000000000000 +3.007909927547989803e-01 5.592750990357599034e-06 0.000000000000000000 +3.011467968253859206e-01 3.059393608156355916e-06 0.000000000000000000 +3.015026003226318752e-01 1.087123523656169138e-06 0.000000000000000000 +3.018584032458593858e-01 6.870198431207566763e-08 0.000000000000000000 +3.022142055943911054e-01 3.281790484155284290e-07 0.000000000000000000 +3.025700073675495760e-01 2.073350572859191871e-06 0.000000000000000000 +3.029258085646575061e-01 5.356865534108479539e-06 0.000000000000000000 +3.032816091850374374e-01 1.005148707042055369e-05 0.000000000000000000 +3.036374092280120229e-01 1.584396421990267640e-05 0.000000000000000000 +3.039932086929038602e-01 2.225034066105107379e-05 0.000000000000000000 +3.043490075790354354e-01 2.865344506829487289e-05 0.000000000000000000 +3.047048058857294572e-01 3.436096620741153359e-05 0.000000000000000000 +3.050606036123086340e-01 3.868014611235645562e-05 0.000000000000000000 +3.054164007580953966e-01 4.100297537632336065e-05 0.000000000000000000 +3.057721973224123979e-01 4.089408605212581843e-05 0.000000000000000000 +3.061279933045822910e-01 3.817251605849881054e-05 0.000000000000000000 +3.064837887039277287e-01 3.297831357451005545e-05 0.000000000000000000 +3.068395835197713084e-01 2.581563543152805653e-05 0.000000000000000000 +3.071953777514356276e-01 1.756555963009633845e-05 0.000000000000000000 +3.075511713982432838e-01 9.464180675485895627e-06 0.000000000000000000 +3.079069644595169297e-01 3.044507034260995551e-06 0.000000000000000000 +3.082627569345790519e-01 4.398340847757714896e-08 0.000000000000000000 +3.086185488227524698e-01 2.282819034545636383e-06 0.000000000000000000 +3.089743401233597253e-01 1.152139686764456422e-05 0.000000000000000000 +3.093301308357235269e-01 2.930755494398151056e-05 0.000000000000000000 +3.096859209591663609e-01 5.682619693770850583e-05 0.000000000000000000 +3.100417104930108247e-01 9.476429902232491598e-05 0.000000000000000000 +3.103974994365796825e-01 1.432038230053431064e-04 0.000000000000000000 +3.107532877891955869e-01 2.015533195975139941e-04 0.000000000000000000 +3.111090755501809135e-01 2.685262243218171406e-04 0.000000000000000000 +3.114648627188585928e-01 3.421702341225852360e-04 0.000000000000000000 +3.118206492945510555e-01 4.199480162276016310e-04 0.000000000000000000 +3.121764352765810657e-01 4.988652118315280420e-04 0.000000000000000000 +3.125322206642711653e-01 5.756376463806531490e-04 0.000000000000000000 +3.128880054569440627e-01 6.468862174276704315e-04 0.000000000000000000 +3.132437896539224109e-01 7.093454156871356522e-04 0.000000000000000000 +3.135995732545286963e-01 7.600700738443550613e-04 0.000000000000000000 +3.139553562580856272e-01 7.966248527656674423e-04 0.000000000000000000 +3.143111386639159122e-01 8.172421725655580138e-04 0.000000000000000000 +3.146669204713421486e-01 8.209366706577928387e-04 0.000000000000000000 +3.150227016796869894e-01 8.075676150994425461e-04 0.000000000000000000 +3.153784822882730321e-01 7.778447348757390120e-04 0.000000000000000000 +3.157342622964229295e-01 7.332773113879679887e-04 0.000000000000000000 +3.160900417034595011e-01 6.760707442142153967e-04 0.000000000000000000 +3.164458205087051224e-01 6.089788000728341925e-04 0.000000000000000000 +3.168015987114825016e-01 5.351230501558338921e-04 0.000000000000000000 +3.171573763111144584e-01 4.577933297993463740e-04 0.000000000000000000 +3.175131533069234790e-01 3.802442295203863802e-04 0.000000000000000000 +3.178689296982322166e-01 3.055025600714749053e-04 0.000000000000000000 +3.182247054843633793e-01 2.361994466883514886e-04 0.000000000000000000 +3.185804806646397314e-01 1.744383275514083456e-04 0.000000000000000000 +3.189362552383837590e-01 1.217068847718338990e-04 0.000000000000000000 +3.192920292049181707e-01 7.883712602652217594e-05 0.000000000000000000 +3.196478025635655640e-01 4.601381190489314436e-05 0.000000000000000000 +3.200035753136487027e-01 2.282755119373516877e-05 0.000000000000000000 +3.203593474544901287e-01 8.365502742461869900e-06 0.000000000000000000 +3.207151189854126061e-01 1.330009667573684608e-06 0.000000000000000000 +3.210708899057387877e-01 1.738469328049556589e-07 0.000000000000000000 +3.214266602147912155e-01 3.240183989730661379e-06 0.000000000000000000 +3.217824299118927089e-01 8.895842451567237172e-06 0.000000000000000000 +3.221381989963659209e-01 1.564785868691668445e-05 0.000000000000000000 +3.224939674675335044e-01 2.223555480820218057e-05 0.000000000000000000 +3.228497353247179458e-01 2.769303224896247327e-05 0.000000000000000000 +3.232055025672420645e-01 3.137995208037116482e-05 0.000000000000000000 +3.235612691944285690e-01 3.298137419949766995e-05 0.000000000000000000 +3.239170352056000568e-01 3.248003513699595433e-05 0.000000000000000000 +3.242728006000791807e-01 3.010653800462737939e-05 0.000000000000000000 +3.246285653771887048e-01 2.627435601011819143e-05 0.000000000000000000 +3.249843295362513929e-01 2.150723245195658117e-05 0.000000000000000000 +3.253400930765895649e-01 1.636648913494628371e-05 0.000000000000000000 +3.256958559975262069e-01 1.138499635688629140e-05 0.000000000000000000 +3.260516182983839162e-01 7.013236135102983471e-06 0.000000000000000000 +3.264073799784854013e-01 3.581176347718683289e-06 0.000000000000000000 +3.267631410371532041e-01 1.277763075330528838e-06 0.000000000000000000 +3.271189014737100886e-01 1.479328792824541110e-07 0.000000000000000000 +3.274746612874787632e-01 1.053320521965737384e-07 0.000000000000000000 +3.278304204777819919e-01 9.575590643975668771e-07 0.000000000000000000 +3.281861790439423165e-01 2.439826246235408288e-06 0.000000000000000000 +3.285419369852824456e-01 4.252519956621929194e-06 0.000000000000000000 +3.288976943011250875e-01 6.098222393826246475e-06 0.000000000000000000 +3.292534509907929507e-01 7.714289113043314497e-06 0.000000000000000000 +3.296092070536086882e-01 8.897959065905971439e-06 0.000000000000000000 +3.299649624888950639e-01 9.522085115205666551e-06 0.000000000000000000 +3.303207172959746751e-01 9.540775877614321489e-06 0.000000000000000000 +3.306764714741703415e-01 8.985399923042071508e-06 0.000000000000000000 +3.310322250228045493e-01 7.952402348351219591e-06 0.000000000000000000 +3.313879779412001736e-01 6.585130224865954192e-06 0.000000000000000000 +3.317437302286799228e-01 5.052300637397182621e-06 0.000000000000000000 +3.320994818845662833e-01 3.525854030780806291e-06 0.000000000000000000 +3.324552329081821855e-01 2.160734207667600466e-06 0.000000000000000000 +3.328109832988502270e-01 1.078674408943095866e-06 0.000000000000000000 +3.331667330558931162e-01 3.574203688512575689e-07 0.000000000000000000 +3.335224821786336169e-01 2.607413953109771505e-08 0.000000000000000000 +3.338782306663943267e-01 6.648829611264919592e-08 0.000000000000000000 +3.342339785184980649e-01 4.199633949175347683e-07 0.000000000000000000 +3.345897257342674291e-01 9.979710384795665384e-07 0.000000000000000000 +3.349454723130251832e-01 1.695287220028348825e-06 0.000000000000000000 +3.353012182540939801e-01 2.403796805788598601e-06 0.000000000000000000 +3.356569635567965837e-01 3.025315219469268861e-06 0.000000000000000000 +3.360127082204557580e-01 3.482039556639474930e-06 0.000000000000000000 +3.363684522443941005e-01 3.723642275852057921e-06 0.000000000000000000 +3.367241956279344306e-01 3.730498681319971658e-06 0.000000000000000000 +3.370799383703995122e-01 3.513033107142893611e-06 0.000000000000000000 +3.374356804711117763e-01 3.107619939100319320e-06 0.000000000000000000 +3.377914219293941533e-01 2.569836059633062670e-06 0.000000000000000000 +3.381471627445694628e-01 1.966097199253590031e-06 0.000000000000000000 +3.385029029159602465e-01 1.364805482573432649e-06 0.000000000000000000 +3.388586424428891020e-01 8.280903745782109270e-07 0.000000000000000000 +3.392143813246790707e-01 4.050576360073813127e-07 0.000000000000000000 +3.395701195606526945e-01 1.272009971664955400e-07 0.000000000000000000 +3.399258571501328485e-01 6.317538587169728130e-09 0.000000000000000000 +3.402815940924420191e-01 3.494179267865054903e-08 0.000000000000000000 +3.406373303869030811e-01 1.890148627414501095e-07 0.000000000000000000 +3.409930660328387431e-01 4.322663449509891600e-07 0.000000000000000000 +3.413488010295717134e-01 7.216315554566167344e-07 0.000000000000000000 +3.417045353764247562e-01 1.012965676041129043e-06 0.000000000000000000 +3.420602690727206907e-01 1.266348898552882102e-06 0.000000000000000000 +3.424160021177820035e-01 1.450390361708279202e-06 0.000000000000000000 +3.427717345109315694e-01 1.545112831212648782e-06 0.000000000000000000 +3.431274662514922635e-01 1.543208409701329951e-06 0.000000000000000000 +3.434831973387865722e-01 1.449669975753089475e-06 0.000000000000000000 +3.438389277721373705e-01 1.279997158619713115e-06 0.000000000000000000 +3.441946575508673112e-01 1.057327847579578195e-06 0.000000000000000000 +3.445503866742993249e-01 8.089418971523142475e-07 0.000000000000000000 +3.449061151417559534e-01 5.626163868030299670e-07 0.000000000000000000 +3.452618429525600163e-01 3.432833550452891393e-07 0.000000000000000000 +3.456175701060342220e-01 1.703605056084287724e-07 0.000000000000000000 +3.459732966015015010e-01 5.600768684618338659e-08 0.000000000000000000 +3.463290224382843951e-01 4.424931741379965395e-09 0.000000000000000000 +3.466847476157056129e-01 1.217019990778858870e-08 0.000000000000000000 +3.470404721330880293e-01 6.935370169823737015e-08 0.000000000000000000 +3.473961959897544083e-01 1.614741752560913656e-07 0.000000000000000000 +3.477519191850273472e-01 2.716091001561150535e-07 0.000000000000000000 +3.481076417182297766e-01 3.826583444097986574e-07 0.000000000000000000 +3.484633635886843495e-01 4.793665139293721604e-07 0.000000000000000000 +3.488190847957139962e-01 5.499060975039306139e-07 0.000000000000000000 +3.491748053386413142e-01 5.868809668708009384e-07 0.000000000000000000 +3.495305252167889565e-01 5.876959450836271488e-07 0.000000000000000000 +3.498862444294797980e-01 5.543211978082490599e-07 0.000000000000000000 +3.502419629760367137e-01 4.925500096613590698e-07 0.000000000000000000 +3.505976808557822455e-01 4.108977901007903930e-07 0.000000000000000000 +3.509533980680393794e-01 3.193151133294547723e-07 0.000000000000000000 +3.513091146121306574e-01 2.278880577661219552e-07 0.000000000000000000 +3.516648304873790654e-01 1.456781394357662547e-07 0.000000000000000000 +3.520205456931073118e-01 7.981725480975271201e-08 0.000000000000000000 +3.523762602286379941e-01 3.492719962042973633e-08 0.000000000000000000 +3.527319740932940983e-01 1.288572747968084380e-08 0.000000000000000000 +3.530876872863982774e-01 1.291819944494828076e-08 0.000000000000000000 +3.534433998072732397e-01 3.196049965851401878e-08 0.000000000000000000 +3.537991116552418602e-01 6.521780633286415526e-08 0.000000000000000000 +3.541548228296270140e-01 1.068355484364506463e-07 0.000000000000000000 +3.545105333297512984e-01 1.506020003284180606e-07 0.000000000000000000 +3.548662431549375884e-01 1.906135627075649902e-07 0.000000000000000000 +3.552219523045087035e-01 2.218501836439769351e-07 0.000000000000000000 +3.555776607777871856e-01 2.406259164864611462e-07 0.000000000000000000 +3.559333685740961317e-01 2.448952845644259314e-07 0.000000000000000000 +3.562890756927580282e-01 2.344080629599235168e-07 0.000000000000000000 +3.566447821330959167e-01 2.107127943063855377e-07 0.000000000000000000 +3.570004878944324500e-01 1.770136189345231823e-07 0.000000000000000000 +3.573561929760903921e-01 1.378875675534673035e-07 0.000000000000000000 +3.577118973773926180e-01 9.887251627813323997e-08 0.000000000000000000 +3.580676010976618917e-01 6.594153480189665209e-08 0.000000000000000000 +3.584233041362209771e-01 4.488859638175557491e-08 0.000000000000000000 +3.587790064923925826e-01 4.066358372350814281e-08 0.000000000000000000 +3.591347081654997497e-01 5.670983067791766599e-08 0.000000000000000000 +3.594904091548650205e-01 9.437238041185259996e-08 0.000000000000000000 +3.598461094598112697e-01 1.524560761811534110e-07 0.000000000000000000 +3.602018090796613170e-01 2.270155856088429442e-07 0.000000000000000000 +3.605575080137380373e-01 3.114510245556564805e-07 0.000000000000000000 +3.609132062613640279e-01 3.969608064539795251e-07 0.000000000000000000 +3.612689038218623305e-01 4.733674852298133184e-07 0.000000000000000000 +3.616246006945555425e-01 5.302848867845921634e-07 0.000000000000000000 +3.619802968787665942e-01 5.585404383634335394e-07 0.000000000000000000 +3.623359923738181942e-01 5.517121859915188679e-07 0.000000000000000000 +3.626916871790332175e-01 5.075938604008694404e-07 0.000000000000000000 +3.630473812937344835e-01 4.293722050597392659e-07 0.000000000000000000 +3.634030747172447562e-01 3.262963926035103313e-07 0.000000000000000000 +3.637587674488868550e-01 2.136452555297714929e-07 0.000000000000000000 +3.641144594879835994e-01 1.118563391667006283e-07 0.000000000000000000 +3.644701508338578089e-01 4.476927194426336868e-08 0.000000000000000000 +3.648258414858323029e-01 3.704784833312698697e-08 0.000000000000000000 +3.651815314432297344e-01 1.109693951515426210e-07 0.000000000000000000 +3.655372207053732003e-01 2.828918625967232155e-07 0.000000000000000000 +3.658929092715854092e-01 5.598121167912022869e-07 0.000000000000000000 +3.662485971411891250e-01 9.364965665689122057e-07 0.000000000000000000 +3.666042843135071672e-01 1.393683148003502224e-06 0.000000000000000000 +3.669599707878624661e-01 1.897811733783449531e-06 0.000000000000000000 +3.673156565635776749e-01 2.402634287333163100e-06 0.000000000000000000 +3.676713416399758350e-01 2.852889994529023483e-06 0.000000000000000000 +3.680270260163794882e-01 3.190015486214992219e-06 0.000000000000000000 +3.683827096921117872e-01 3.359614808837336454e-06 0.000000000000000000 +3.687383926664952738e-01 3.320162672191834438e-06 0.000000000000000000 +3.690940749388529341e-01 3.052186046609207450e-06 0.000000000000000000 +3.694497565085075319e-01 2.566992473201096908e-06 0.000000000000000000 +3.698054373747819978e-01 1.913914988121897946e-06 0.000000000000000000 +3.701611175369990403e-01 1.185043953483522797e-06 0.000000000000000000 +3.705167969944815343e-01 5.165271291903117811e-07 0.000000000000000000 +3.708724757465524657e-01 8.574182318949783467e-08 0.000000000000000000 +3.712281537925343766e-01 1.039656391150682944e-07 0.000000000000000000 +3.715838311317504195e-01 8.045719712357218184e-07 0.000000000000000000 +3.719395077635231917e-01 2.427219291460662701e-06 0.000000000000000000 +3.722951836871756792e-01 5.198948048028036066e-06 0.000000000000000000 +3.726508589020308126e-01 9.313500383653400445e-06 0.000000000000000000 +3.730065334074110783e-01 1.491049125934540941e-05 0.000000000000000000 +3.733622072026396288e-01 2.205624574872812327e-05 0.000000000000000000 +3.737178802870392280e-01 3.072814702908325911e-05 0.000000000000000000 +3.740735526599326954e-01 4.080419746910782876e-05 0.000000000000000000 +3.744292243206429616e-01 5.205918201281495999e-05 0.000000000000000000 +3.747848952684927348e-01 6.416835683033329297e-05 0.000000000000000000 +3.751405655028050568e-01 7.671900138768749961e-05 0.000000000000000000 +3.754962350229026358e-01 8.922951688373978462e-05 0.000000000000000000 +3.758519038281084579e-01 1.011750861797404064e-04 0.000000000000000000 +3.762075719177452315e-01 1.120182918414781457e-04 0.000000000000000000 +3.765632392911358317e-01 1.212425797986380987e-04 0.000000000000000000 +3.769189059476031889e-01 1.283861085671017066e-04 0.000000000000000000 +3.772745718864701781e-01 1.330733768013294413e-04 0.000000000000000000 +3.776302371070596742e-01 1.350420964145651191e-04 0.000000000000000000 +3.779859016086944412e-01 1.341630757350874411e-04 0.000000000000000000 +3.783415653906972986e-01 1.304513774748465344e-04 0.000000000000000000 +3.786972284523913990e-01 1.240676805287288585e-04 0.000000000000000000 +3.790528907930993952e-01 1.153095474682144968e-04 0.000000000000000000 +3.794085524121439956e-01 1.045931143860401292e-04 0.000000000000000000 +3.797642133088482974e-01 9.242650455555936006e-05 0.000000000000000000 +3.801198734825353420e-01 7.937695166102082755e-05 0.000000000000000000 +3.804755329325276159e-01 6.603413968138079938e-05 0.000000000000000000 +3.808311916581481604e-01 5.297257655123509246e-05 0.000000000000000000 +3.811868496587199617e-01 4.071588810764252049e-05 0.000000000000000000 +3.815425069335656727e-01 2.970574020930361525e-05 0.000000000000000000 +3.818981634820084459e-01 2.027768593801681135e-05 0.000000000000000000 +3.822538193033709342e-01 1.264562882748508832e-05 0.000000000000000000 +3.826094743969760681e-01 6.895847739550726173e-06 0.000000000000000000 +3.829651287621468891e-01 2.990712881674291635e-06 0.000000000000000000 +3.833207823982059947e-01 7.814103533743625335e-07 0.000000000000000000 +3.836764353044764819e-01 2.825830193953688667e-08 0.000000000000000000 +3.840320874802811701e-01 4.266067991471513432e-07 0.000000000000000000 +3.843877389249429899e-01 1.635916922019445182e-06 0.000000000000000000 +3.847433896377847606e-01 3.309443924535430398e-06 0.000000000000000000 +3.850990396181294684e-01 5.122014455172035639e-06 0.000000000000000000 +3.854546888652999326e-01 6.793675582512761987e-06 0.000000000000000000 +3.858103373786190282e-01 8.107470216963528188e-06 0.000000000000000000 +3.861659851574096858e-01 8.920208620013377282e-06 0.000000000000000000 +3.865216322009948358e-01 9.165796671134573921e-06 0.000000000000000000 +3.868772785086974642e-01 8.851380715886959644e-06 0.000000000000000000 +3.872329240798401684e-01 8.047209865310652198e-06 0.000000000000000000 +3.875885689137461565e-01 6.871641097465341151e-06 0.000000000000000000 +3.879442130097381924e-01 5.473075265997156527e-06 0.000000000000000000 +3.882998563671392067e-01 4.010785317230856067e-06 0.000000000000000000 +3.886554989852719633e-01 2.636573375576141611e-06 0.000000000000000000 +3.890111408634595591e-01 1.478982367802183436e-06 0.000000000000000000 +3.893667820010249248e-01 6.314200147001840859e-07 0.000000000000000000 +3.897224223972907686e-01 1.450722793696093082e-07 0.000000000000000000 +3.900780620515802433e-01 2.694321508231597951e-08 0.000000000000000000 +3.904337009632160016e-01 2.428158555352135424e-07 0.000000000000000000 +3.907893391315212517e-01 7.244393574375254894e-07 0.000000000000000000 +3.911449765558186464e-01 1.379858248570811129e-06 0.000000000000000000 +3.915006132354312274e-01 2.105545166836161007e-06 0.000000000000000000 +3.918562491696819250e-01 2.798898187648370571e-06 0.000000000000000000 +3.922118843578935588e-01 3.369720112390561608e-06 0.000000000000000000 +3.925675187993891702e-01 3.749495855656401992e-06 0.000000000000000000 +3.929231524934915787e-01 3.897596958315291011e-06 0.000000000000000000 +3.932787854395238814e-01 3.803930200648835265e-06 0.000000000000000000 +3.936344176368087866e-01 3.487965107200239915e-06 0.000000000000000000 +3.939900490846692804e-01 2.994476561238153772e-06 0.000000000000000000 +3.943456797824283488e-01 2.386681411705897317e-06 0.000000000000000000 +3.947013097294089778e-01 1.737697740508298500e-06 0.000000000000000000 +3.950569389249338759e-01 1.121389811844372166e-06 0.000000000000000000 +3.954125673683261399e-01 6.036716188500071956e-07 0.000000000000000000 +3.957681950589087005e-01 2.352322978855664252e-07 0.000000000000000000 +3.961238219960045437e-01 4.643527595075079844e-08 0.000000000000000000 +3.964794481789364888e-01 4.485803482753671181e-08 0.000000000000000000 +3.968350736070275220e-01 2.156159022387486820e-07 0.000000000000000000 +3.971906982796005736e-01 5.242891685490664411e-07 0.000000000000000000 +3.975463221959786297e-01 9.219844043230975303e-07 0.000000000000000000 +3.979019453554845098e-01 1.351838949382799242e-06 0.000000000000000000 +3.982575677574412554e-01 1.756144272911112141e-06 0.000000000000000000 +3.986131894011718524e-01 2.083230535169551150e-06 0.000000000000000000 +3.989688102859991758e-01 2.293320791889986261e-06 0.000000000000000000 +3.993244304112460452e-01 2.362717249930910011e-06 0.000000000000000000 +3.996800497762358351e-01 2.285902710879557621e-06 0.000000000000000000 +4.000356683802910318e-01 2.075399981414209593e-06 0.000000000000000000 +4.003912862227348435e-01 1.759499372815496532e-06 0.000000000000000000 +4.007469033028899785e-01 1.378208522689532031e-06 0.000000000000000000 +4.011025196200798115e-01 9.779724834814673137e-07 0.000000000000000000 +4.014581351736268844e-01 6.058348872801351951e-07 0.000000000000000000 +4.018137499628543496e-01 3.037513848372950806e-07 0.000000000000000000 +4.021693639870851933e-01 1.037226923184815984e-07 0.000000000000000000 +4.025249772456424013e-01 2.429442716946531876e-08 0.000000000000000000 +4.028805897378487377e-01 6.879096476438050340e-08 0.000000000000000000 +4.032362014630272440e-01 2.254336626393015285e-07 0.000000000000000000 +4.035918124205009616e-01 4.692663947786272162e-07 0.000000000000000000 +4.039474226095929321e-01 7.656002373561609821e-07 0.000000000000000000 +4.043030320296259195e-01 1.074518475153850660e-06 0.000000000000000000 +4.046586406799229652e-01 1.355871575682607467e-06 0.000000000000000000 +4.050142485598071662e-01 1.574150712082092990e-06 0.000000000000000000 +4.053698556686013976e-01 1.702660596667376855e-06 0.000000000000000000 +4.057254620056285344e-01 1.726511999275805487e-06 0.000000000000000000 +4.060810675702117289e-01 1.644107851805160571e-06 0.000000000000000000 +4.064366723616739119e-01 1.466984833016855353e-06 0.000000000000000000 +4.067922763793379026e-01 1.218071810561058374e-06 0.000000000000000000 +4.071478796225269092e-01 9.286137433350256450e-07 0.000000000000000000 +4.075034820905637512e-01 6.341628752616245574e-07 0.000000000000000000 +4.078590837827715254e-01 3.701410266053757913e-07 0.000000000000000000 +4.082146846984731070e-01 1.675166504761680198e-07 0.000000000000000000 +4.085702848369915929e-01 4.911473036417218732e-08 0.000000000000000000 +4.089258841976499692e-01 2.699096187502378372e-08 0.000000000000000000 +4.092814827797710553e-01 1.011654801289741868e-07 0.000000000000000000 +4.096370805826779482e-01 2.598427518917470782e-07 0.000000000000000000 +4.099926776056936895e-01 4.810637268023040598e-07 0.000000000000000000 +4.103482738481413206e-01 7.355655291835660116e-07 0.000000000000000000 +4.107038693093437165e-01 9.904829326026218095e-07 0.000000000000000000 +4.110594639886238078e-01 1.213430798805664933e-06 0.000000000000000000 +4.114150578853046358e-01 1.376468095981564293e-06 0.000000000000000000 +4.117706509987095198e-01 1.459465725093900414e-06 0.000000000000000000 +4.121262433281610571e-01 1.452478712505188800e-06 0.000000000000000000 +4.124818348729823447e-01 1.356848272330167787e-06 0.000000000000000000 +4.128374256324964242e-01 1.184915349208938003e-06 0.000000000000000000 +4.131930156060264481e-01 9.583956000239150549e-07 0.000000000000000000 +4.135486047928950692e-01 7.056262356370750265e-07 0.000000000000000000 +4.139041931924256068e-01 4.580287640402134143e-07 0.000000000000000000 +4.142597808039410467e-01 2.462228744358057969e-07 0.000000000000000000 +4.146153676267643196e-01 9.626506355102191712e-08 0.000000000000000000 +4.149709536602183002e-01 2.646705077338114691e-08 0.000000000000000000 +4.153265389036263078e-01 4.517622899398817427e-08 0.000000000000000000 +4.156821233563112172e-01 1.497824031262526863e-07 0.000000000000000000 +4.160377070175959036e-01 3.270661915385643299e-07 0.000000000000000000 +4.163932898868034638e-01 5.548425642647716937e-07 0.000000000000000000 +4.167488719632571059e-01 8.046973466467927772e-07 0.000000000000000000 +4.171044532462796495e-01 1.045483561974146509e-06 0.000000000000000000 +4.174600337351942470e-01 1.247153653392108502e-06 0.000000000000000000 +4.178156134293237178e-01 1.384463552529197987e-06 0.000000000000000000 +4.181711923279914367e-01 1.440099874809658628e-06 0.000000000000000000 +4.185267704305199454e-01 1.406850316541905431e-06 0.000000000000000000 +4.188823477362327297e-01 1.288551423655530982e-06 0.000000000000000000 +4.192379242444525533e-01 1.099693808311253075e-06 0.000000000000000000 +4.195934999545026245e-01 8.637253996008082035e-07 0.000000000000000000 +4.199490748657058181e-01 6.102495108734476940e-07 0.000000000000000000 +4.203046489773852312e-01 3.714479644689056146e-07 0.000000000000000000 +4.206602222888640719e-01 1.781544444826542668e-07 0.000000000000000000 +4.210157947994650485e-01 5.604832791898397735e-08 0.000000000000000000 +4.213713665085113691e-01 2.242893952061704409e-08 0.000000000000000000 +4.217269374153261308e-01 8.396538951196736575e-08 0.000000000000000000 +4.220825075192322640e-01 2.357051390056722686e-07 0.000000000000000000 +4.224380768195528657e-01 4.614779753594248125e-07 0.000000000000000000 +4.227936453156110885e-01 7.356680195934601181e-07 0.000000000000000000 +4.231492130067298074e-01 1.026163721871216185e-06 0.000000000000000000 +4.235047798922321749e-01 1.298153484415789150e-06 0.000000000000000000 +4.238603459714412325e-01 1.518329324929950909e-06 0.000000000000000000 +4.242159112436799107e-01 1.659005453906985410e-06 0.000000000000000000 +4.245714757082713620e-01 1.701659776068872395e-06 0.000000000000000000 +4.249270393645387944e-01 1.639464694765798013e-06 0.000000000000000000 +4.252826022118049165e-01 1.478483218063546968e-06 0.000000000000000000 +4.256381642493931028e-01 1.237355357306488869e-06 0.000000000000000000 +4.259937254766262282e-01 9.454716992468190786e-07 0.000000000000000000 +4.263492858928275009e-01 6.398065772428534852e-07 0.000000000000000000 +4.267048454973199068e-01 3.607425938485194593e-07 0.000000000000000000 +4.270604042894264318e-01 1.473430795562211982e-07 0.000000000000000000 +4.274159622684702842e-01 3.260478420126560006e-08 0.000000000000000000 +4.277715194337743387e-01 3.924037324604156029e-08 0.000000000000000000 +4.281270757846618591e-01 1.764962160182985160e-07 0.000000000000000000 +4.284826313204558867e-01 4.384093503582473349e-07 0.000000000000000000 +4.288381860404794632e-01 8.037586306771793350e-07 0.000000000000000000 +4.291937399440555745e-01 1.237784479515538720e-06 0.000000000000000000 +4.295492930305074841e-01 1.695558587246551313e-06 0.000000000000000000 +4.299048452991581226e-01 2.126700142585162750e-06 0.000000000000000000 +4.302603967493306425e-01 2.480978857419584025e-06 0.000000000000000000 +4.306159473803479742e-01 2.714234444667615487e-06 0.000000000000000000 +4.309714971915332704e-01 2.793989853349957369e-06 0.000000000000000000 +4.313270461822099056e-01 2.704147894465562304e-06 0.000000000000000000 +4.316825943517004771e-01 2.448237526420163159e-06 0.000000000000000000 +4.320381416993284152e-01 2.050809840510539825e-06 0.000000000000000000 +4.323936882244167057e-01 1.556761479859658387e-06 0.000000000000000000 +4.327492339262884458e-01 1.028566961762167756e-06 0.000000000000000000 +4.331047788042666769e-01 5.416104873553339844e-07 0.000000000000000000 +4.334603228576746070e-01 1.780010178811160334e-07 0.000000000000000000 +4.338158660858351667e-01 1.941196507400915054e-08 0.000000000000000000 +4.341714084880715641e-01 1.395927025062533572e-07 0.000000000000000000 +4.345269500637068405e-01 5.972424495164063513e-07 0.000000000000000000 +4.348824908120642041e-01 1.429913468563890590e-06 0.000000000000000000 +4.352380307324666409e-01 2.649522291109147683e-06 0.000000000000000000 +4.355935698242373588e-01 4.239903676261069155e-06 0.000000000000000000 +4.359491080866992330e-01 6.156656565291469703e-06 0.000000000000000000 +4.363046455191755824e-01 8.329322776808783117e-06 0.000000000000000000 +4.366601821209895595e-01 1.066572802236432625e-05 0.000000000000000000 +4.370157178914641505e-01 1.305812141316229239e-05 0.000000000000000000 +4.373712528299223967e-01 1.539059228446236399e-05 0.000000000000000000 +4.377267869356875618e-01 1.754713629499684411e-05 0.000000000000000000 +4.380823202080826317e-01 1.941969550919575300e-05 0.000000000000000000 +4.384378526464309811e-01 2.091551263213001869e-05 0.000000000000000000 +4.387933842500553738e-01 2.196321463139480320e-05 0.000000000000000000 +4.391489150182791290e-01 2.251716682832167655e-05 0.000000000000000000 +4.395044449504252881e-01 2.255980170365015064e-05 0.000000000000000000 +4.398599740458170038e-01 2.210181051791195952e-05 0.000000000000000000 +4.402155023037774284e-01 2.118027238618788873e-05 0.000000000000000000 +4.405710297236297701e-01 1.985496711762554960e-05 0.000000000000000000 +4.409265563046969039e-01 1.820325956409611973e-05 0.000000000000000000 +4.412820820463021487e-01 1.631404266897297931e-05 0.000000000000000000 +4.416376069477686572e-01 1.428127674639221193e-05 0.000000000000000000 +4.419931310084194709e-01 1.219766175371391640e-05 0.000000000000000000 +4.423486542275775757e-01 1.014893051957592798e-05 0.000000000000000000 +4.427041766045663462e-01 8.209161630290013963e-06 0.000000000000000000 +4.430596981387089905e-01 6.437392032412252927e-06 0.000000000000000000 +4.434152188293282726e-01 4.875674633252669459e-06 0.000000000000000000 +4.437707386757476780e-01 3.548589239852201363e-06 0.000000000000000000 +4.441262576772901927e-01 2.464089281386492051e-06 0.000000000000000000 +4.444817758332790802e-01 1.615463064405061411e-06 0.000000000000000000 +4.448372931430373267e-01 9.841149068830808675e-07 0.000000000000000000 +4.451928096058881401e-01 5.428327945135981842e-07 0.000000000000000000 +4.455483252211546175e-01 2.592057401671960534e-07 0.000000000000000000 +4.459038399881600778e-01 9.888271315383753221e-08 0.000000000000000000 +4.462593539062274517e-01 2.841972928710609103e-08 0.000000000000000000 +4.466148669746800581e-01 1.753422394399019979e-08 0.000000000000000000 +4.469703791928409942e-01 4.066687379768543509e-08 0.000000000000000000 +4.473258905600334123e-01 7.783132623673237654e-08 0.000000000000000000 +4.476814010755804651e-01 1.148036128189290779e-07 0.000000000000000000 +4.480369107388051941e-01 1.427589825661378983e-07 0.000000000000000000 +4.483924195490310849e-01 1.575004873471197338e-07 0.000000000000000000 +4.487479275055809014e-01 1.584394739050627530e-07 0.000000000000000000 +4.491034346077780182e-01 1.474842686391492427e-07 0.000000000000000000 +4.494589408549456433e-01 1.279729791491896671e-07 0.000000000000000000 +4.498144462464068738e-01 1.037541964240810477e-07 0.000000000000000000 +4.501699507814848067e-01 7.848097535800238119e-08 0.000000000000000000 +4.505254544595028166e-01 5.514435553885443344e-08 0.000000000000000000 +4.508809572797838894e-01 3.583777262481576580e-08 0.000000000000000000 +4.512364592416512332e-01 2.171673093073071309e-08 0.000000000000000000 +4.515919603444279451e-01 1.310126000169013627e-08 0.000000000000000000 +4.519474605874373996e-01 9.662520362135993957e-09 0.000000000000000000 +4.523029599700026382e-01 1.063848463514328415e-08 0.000000000000000000 +4.526584584914469245e-01 1.503470246366209938e-08 0.000000000000000000 +4.530139561510933000e-01 2.178178027859237438e-08 0.000000000000000000 +4.533694529482650837e-01 2.983811587189905443e-08 0.000000000000000000 +4.537249488822854282e-01 3.824159958933605769e-08 0.000000000000000000 +4.540804439524774860e-01 4.612506459353170090e-08 0.000000000000000000 +4.544359381581645208e-01 5.271583124996346210e-08 0.000000000000000000 +4.547914314986695183e-01 5.733942976645156886e-08 0.000000000000000000 +4.551469239733159644e-01 5.944223700002027910e-08 0.000000000000000000 +4.555024155814267339e-01 5.863891812972829075e-08 0.000000000000000000 +4.558579063223253125e-01 5.478034742874018498e-08 0.000000000000000000 +4.562133961953347971e-01 4.802836921788963717e-08 0.000000000000000000 +4.565688851997783959e-01 3.891737966638151439e-08 0.000000000000000000 +4.569243733349790948e-01 2.838070523941004073e-08 0.000000000000000000 +4.572798606002603794e-01 1.772274202155022524e-08 0.000000000000000000 +4.576353469949453467e-01 8.525493237508245431e-09 0.000000000000000000 +4.579908325183571494e-01 2.489314309723645914e-09 0.000000000000000000 +4.583463171698189953e-01 1.220473658615476664e-09 0.000000000000000000 +4.587018009486542591e-01 5.990307144295503266e-09 0.000000000000000000 +4.590572838541859824e-01 1.750001232798627313e-08 0.000000000000000000 +4.594127658857374286e-01 3.568958424707874015e-08 0.000000000000000000 +4.597682470426318058e-01 5.962781561784359318e-08 0.000000000000000000 +4.601237273241923775e-01 8.751236942928215896e-08 0.000000000000000000 +4.604792067297421854e-01 1.167953923988647846e-07 0.000000000000000000 +4.608346852586046039e-01 1.444326392725710941e-07 0.000000000000000000 +4.611901629101028410e-01 1.672350315930169861e-07 0.000000000000000000 +4.615456396835601605e-01 1.822838065259814444e-07 0.000000000000000000 +4.619011155782996036e-01 1.873567551138942862e-07 0.000000000000000000 +4.622565905936446007e-01 1.813059180270696272e-07 0.000000000000000000 +4.626120647289183041e-01 1.643281075109256732e-07 0.000000000000000000 +4.629675379834438664e-01 1.380792715856193417e-07 0.000000000000000000 +4.633230103565444957e-01 1.056012922565860734e-07 0.000000000000000000 +4.636784818475435666e-01 7.105339228527581322e-08 0.000000000000000000 +4.640339524557642870e-01 3.926699563207291785e-08 0.000000000000000000 +4.643894221805298095e-01 1.516908547831722462e-08 0.000000000000000000 +4.647448910211634532e-01 3.141098362343917982e-09 0.000000000000000000 +4.651003589769883706e-01 6.394794456871191003e-09 0.000000000000000000 +4.654558260473278808e-01 2.645080236646428772e-08 0.000000000000000000 +4.658112922315051918e-01 6.279834594836479413e-08 0.000000000000000000 +4.661667575288434562e-01 1.127962126486206553e-07 0.000000000000000000 +4.665222219386659930e-01 1.718470693312717028e-07 0.000000000000000000 +4.668776854602961768e-01 2.338429346237037478e-07 0.000000000000000000 +4.672331480930571046e-01 2.918431995063168645e-07 0.000000000000000000 +4.675886098362719845e-01 3.389128224014940686e-07 0.000000000000000000 +4.679440706892640800e-01 3.690219194053525713e-07 0.000000000000000000 +4.682995306513569878e-01 3.778929315508253624e-07 0.000000000000000000 +4.686549897218734162e-01 3.636806086297762160e-07 0.000000000000000000 +4.690104479001370175e-01 3.273842190446843386e-07 0.000000000000000000 +4.693659051854708886e-01 2.729197485577245796e-07 0.000000000000000000 +4.697213615771982376e-01 2.068195284378954437e-07 0.000000000000000000 +4.700768170746424945e-01 1.375732157735331682e-07 0.000000000000000000 +4.704322716771267565e-01 7.467165809605995387e-08 0.000000000000000000 +4.707877253839744536e-01 2.745775605424428615e-08 0.000000000000000000 +4.711431781945087383e-01 3.920137721467226756e-09 0.000000000000000000 +4.714986301080528741e-01 9.581502794204269406e-09 0.000000000000000000 +4.718540811239301802e-01 4.663087116929062306e-08 0.000000000000000000 +4.722095312414638646e-01 1.134269116433501193e-07 0.000000000000000000 +4.725649804599772463e-01 2.044597342637353353e-07 0.000000000000000000 +4.729204287787935890e-01 3.108050879864997087e-07 0.000000000000000000 +4.732758761972362671e-01 4.210438832359786350e-07 0.000000000000000000 +4.736313227146283777e-01 5.225587398857735017e-07 0.000000000000000000 +4.739867683302932955e-01 6.030656673567305378e-07 0.000000000000000000 +4.743422130435543949e-01 6.522003008034031337e-07 0.000000000000000000 +4.746976568537348284e-01 6.629601381382001747e-07 0.000000000000000000 +4.750530997601578598e-01 6.328104296400525398e-07 0.000000000000000000 +4.754085417621468634e-01 5.642923729288309265e-07 0.000000000000000000 +4.757639828590249920e-01 4.650255633309030831e-07 0.000000000000000000 +4.761194230501157865e-01 3.470667886024187181e-07 0.000000000000000000 +4.764748623347422884e-01 2.256663549909615972e-07 0.000000000000000000 +4.768303007122279835e-01 1.175417383366281090e-07 0.000000000000000000 +4.771857381818961352e-01 3.885655237987243722e-08 0.000000000000000000 +4.775411747430698961e-01 3.141449466589613392e-09 0.000000000000000000 +4.778966103950725852e-01 1.941538495266626609e-08 0.000000000000000000 +4.782520451372276327e-01 9.075639674577749321e-08 0.000000000000000000 +4.786074789688583575e-01 2.135300223087796743e-07 0.000000000000000000 +4.789629118892878012e-01 3.774139582891510553e-07 0.000000000000000000 +4.793183438978396160e-01 5.662665469681741883e-07 0.000000000000000000 +4.796737749938369544e-01 7.597841949101129317e-07 0.000000000000000000 +4.800292051766030244e-01 9.357909270195469974e-07 0.000000000000000000 +4.803846344454613115e-01 1.072914603029309734e-06 0.000000000000000000 +4.807400627997350240e-01 1.153340616848146571e-06 0.000000000000000000 +4.810954902387474807e-01 1.165304510942202751e-06 0.000000000000000000 +4.814509167618220009e-01 1.104995547280542237e-06 0.000000000000000000 +4.818063423682819590e-01 9.775949979815834186e-07 0.000000000000000000 +4.821617670574505632e-01 7.972619141424027438e-07 0.000000000000000000 +4.825171908286513545e-01 5.859967983775801941e-07 0.000000000000000000 +4.828726136812074299e-01 3.714473538108323349e-07 0.000000000000000000 +4.832280356144422195e-01 1.838550235386639373e-07 0.000000000000000000 +4.835834566276789870e-01 5.246007664103314381e-08 0.000000000000000000 +4.839388767202411068e-01 1.771138369161038603e-09 0.000000000000000000 +4.842942958914519536e-01 4.814968960615295786e-08 0.000000000000000000 +4.846497141406346798e-01 1.971530153567530390e-07 0.000000000000000000 +4.850051314671129377e-01 4.420178892310001806e-07 0.000000000000000000 +4.853605478702097131e-01 7.635557729870845032e-07 0.000000000000000000 +4.857159633492485473e-01 1.131578538338854011e-06 0.000000000000000000 +4.860713779035527593e-01 1.507797126818346210e-06 0.000000000000000000 +4.864267915324456681e-01 1.849953486757044708e-06 0.000000000000000000 +4.867822042352505929e-01 2.116779749106213189e-06 0.000000000000000000 +4.871376160112908527e-01 2.273248596734296455e-06 0.000000000000000000 +4.874930268598898775e-01 2.295502871312581224e-06 0.000000000000000000 +4.878484367803710420e-01 2.174843209385597620e-06 0.000000000000000000 +4.882038457720576097e-01 1.920215556181015545e-06 0.000000000000000000 +4.885592538342727886e-01 1.558773465161453583e-06 0.000000000000000000 +4.889146609663402865e-01 1.134282687422472369e-06 0.000000000000000000 +4.892700671675832558e-01 7.033697742002953981e-07 0.000000000000000000 +4.896254724373250711e-01 3.298684826120591000e-07 0.000000000000000000 +4.899808767748889404e-01 7.776037911000820668e-08 0.000000000000000000 +4.903362801795985715e-01 3.411176641095765047e-09 0.000000000000000000 +4.906916826507769502e-01 1.479464028882873123e-07 0.000000000000000000 +4.910470841877476733e-01 5.306687164134530613e-07 0.000000000000000000 +4.914024847898340598e-01 1.144382197095129539e-06 0.000000000000000000 +4.917578844563594842e-01 1.953353565509562970e-06 0.000000000000000000 +4.921132831866473767e-01 2.894414390779074731e-06 0.000000000000000000 +4.924686809800208898e-01 3.881410040957273238e-06 0.000000000000000000 +4.928240778358036200e-01 4.812857381723305568e-06 0.000000000000000000 +4.931794737533187756e-01 5.582317436969448734e-06 0.000000000000000000 +4.935348687318898420e-01 6.090657997305091923e-06 0.000000000000000000 +4.938902627708400828e-01 6.259110613024774220e-06 0.000000000000000000 +4.942456558694931501e-01 6.041848350222915101e-06 0.000000000000000000 +4.946010480271720300e-01 5.436749128693112121e-06 0.000000000000000000 +4.949564392432004856e-01 4.493077768711678829e-06 0.000000000000000000 +4.953118295169017249e-01 3.315018947528392533e-06 0.000000000000000000 +4.956672188475991225e-01 2.060310899757753805e-06 0.000000000000000000 +4.960226072346160531e-01 9.336412603333653863e-07 0.000000000000000000 +4.963779946772758911e-01 1.749368468727900783e-07 0.000000000000000000 +4.967333811749020667e-01 4.316591838060171268e-08 0.000000000000000000 +4.970887667268181764e-01 7.967285609878296016e-07 0.000000000000000000 +4.974441513323472619e-01 2.671893295680360283e-06 0.000000000000000000 +4.977995349908129752e-01 5.861006120123578346e-06 0.000000000000000000 +4.981549177015386354e-01 1.049232179075205171e-05 0.000000000000000000 +4.985102994638475615e-01 1.661326875678320435e-05 0.000000000000000000 +4.988656802770632392e-01 2.417875614389178456e-05 0.000000000000000000 +4.992210601405089876e-01 3.304577644319349857e-05 0.000000000000000000 +4.995764390535085142e-01 4.297507866439970902e-05 0.000000000000000000 +4.999318170153848606e-01 5.364012359314078904e-05 0.000000000000000000 +5.002871940254615124e-01 6.464293414593171884e-05 0.000000000000000000 +5.006425700830620107e-01 7.553587257457403874e-05 0.000000000000000000 +5.009979451875098411e-01 8.584786461065854724e-05 0.000000000000000000 +5.013533193381281006e-01 9.511319501886554030e-05 0.000000000000000000 +5.017086925342405523e-01 1.029007557696417282e-04 0.000000000000000000 +5.020640647751702934e-01 1.088415598947611797e-04 0.000000000000000000 +5.024194360602410869e-01 1.126524481082640552e-04 0.000000000000000000 +5.027748063887760299e-01 1.141542021862283768e-04 0.000000000000000000 +5.031301757600986635e-01 1.132827142336810051e-04 0.000000000000000000 +5.034855441735326398e-01 1.100924065861112982e-04 0.000000000000000000 +5.038409116284010558e-01 1.047517059284283164e-04 0.000000000000000000 +5.041962781240275637e-01 9.753099479446994033e-05 0.000000000000000000 +5.045516436597354826e-01 8.878404106356167205e-05 0.000000000000000000 +5.049070082348482424e-01 7.892439285388931733e-05 0.000000000000000000 +5.052623718486892734e-01 6.839858243628690827e-05 0.000000000000000000 +5.056177345005821167e-01 5.765818067891420866e-05 0.000000000000000000 +5.059730961898502022e-01 4.713276973999451074e-05 0.000000000000000000 +5.063284569158168491e-01 3.720575831985868274e-05 0.000000000000000000 +5.066838166778055985e-01 2.819466775326767664e-05 0.000000000000000000 +5.070391754751398805e-01 2.033709863337896940e-05 0.000000000000000000 +5.073945333071430142e-01 1.378308658415959779e-05 0.000000000000000000 +5.077498901731386516e-01 8.594018378079283735e-06 0.000000000000000000 +5.081052460724502229e-01 4.747753602831922439e-06 0.000000000000000000 +5.084606010044010471e-01 2.149127436915237620e-06 0.000000000000000000 +5.088159549683146654e-01 6.446348103444160907e-07 0.000000000000000000 +5.091713079635145078e-01 3.984312954695506769e-08 0.000000000000000000 +5.095266599893238935e-01 1.179653188520227918e-07 0.000000000000000000 +5.098820110450665855e-01 6.580494302105423640e-07 0.000000000000000000 +5.102373611300659029e-01 1.451394955570976866e-06 0.000000000000000000 +5.105927102436452758e-01 2.315067541057765070e-06 0.000000000000000000 +5.109480583851281343e-01 3.101722815644790442e-06 0.000000000000000000 +5.113034055538379086e-01 3.705331050630431903e-06 0.000000000000000000 +5.116587517490982506e-01 4.062780300110130791e-06 0.000000000000000000 +5.120140969702328126e-01 4.151691451361341718e-06 0.000000000000000000 +5.123694412165643586e-01 3.985074306038405260e-06 0.000000000000000000 +5.127247844874170957e-01 3.603667143713819481e-06 0.000000000000000000 +5.130801267821141209e-01 3.066920189016125059e-06 0.000000000000000000 +5.134354680999788645e-01 2.443602917294917904e-06 0.000000000000000000 +5.137908084403349784e-01 1.802942632447226608e-06 0.000000000000000000 +5.141461478025060039e-01 1.207051938160951283e-06 0.000000000000000000 +5.145014861858152599e-01 7.051965640478476917e-07 0.000000000000000000 +5.148568235895862877e-01 3.302172315404854924e-07 0.000000000000000000 +5.152121600131426282e-01 9.717564429177106188e-08 0.000000000000000000 +5.155674954558076006e-01 4.069488942222941613e-09 0.000000000000000000 +5.159228299169049681e-01 3.427489806011555759e-08 0.000000000000000000 +5.162781633957580496e-01 1.602419176778044232e-07 0.000000000000000000 +5.166334958916902753e-01 3.478972478484937128e-07 0.000000000000000000 +5.169888274040252973e-01 5.612000596623017566e-07 0.000000000000000000 +5.173441579320866568e-01 7.663457215606076105e-07 0.000000000000000000 +5.176994874751976727e-01 9.352080749538885055e-07 0.000000000000000000 +5.180548160326818863e-01 1.047738929311404056e-06 0.000000000000000000 +5.184101436038628385e-01 1.093187148364550845e-06 0.000000000000000000 +5.187654701880640706e-01 1.070142426929611339e-06 0.000000000000000000 +5.191207957846091237e-01 9.855356328076274987e-07 0.000000000000000000 +5.194761203928213167e-01 8.528265353239900210e-07 0.000000000000000000 +5.198314440120244129e-01 6.896730800119970670e-07 0.000000000000000000 +5.201867666415417313e-01 5.154008785137433543e-07 0.000000000000000000 +5.205420882806968130e-01 3.485785454283366516e-07 0.000000000000000000 +5.208974089288131992e-01 2.049591677157010706e-07 0.000000000000000000 +5.212527285852146530e-01 9.597880360430736003e-08 0.000000000000000000 +5.216080472492242714e-01 2.791958963700704424e-08 0.000000000000000000 +5.219633649201658177e-01 1.758462582826448919e-09 0.000000000000000000 +5.223186815973629438e-01 1.364268095268559424e-08 0.000000000000000000 +5.226739972801388578e-01 5.586853642329606625e-08 0.000000000000000000 +5.230293119678172120e-01 1.181956620969015219e-07 0.000000000000000000 +5.233846256597216584e-01 1.893090417174680161e-07 0.000000000000000000 +5.237399383551755161e-01 2.582441043684730694e-07 0.000000000000000000 +5.240952500535024372e-01 3.156143777762950561e-07 0.000000000000000000 +5.244505607540259629e-01 3.545211868510523188e-07 0.000000000000000000 +5.248058704560697452e-01 3.710745908755473329e-07 0.000000000000000000 +5.251611791589573253e-01 3.645074195817125629e-07 0.000000000000000000 +5.255164868620119112e-01 3.369134877981779005e-07 0.000000000000000000 +5.258717935645573771e-01 2.926814726582823392e-07 0.000000000000000000 +5.262270992659172641e-01 2.377237248647651285e-07 0.000000000000000000 +5.265824039654148914e-01 1.786125145567391886e-07 0.000000000000000000 +5.269377076623737999e-01 1.217348485594300857e-07 0.000000000000000000 +5.272930103561179749e-01 7.256272897846305802e-08 0.000000000000000000 +5.276483120459702914e-01 3.511159651028639038e-08 0.000000000000000000 +5.280036127312551786e-01 1.162961488257664832e-08 0.000000000000000000 +5.283589124112954005e-01 2.528608934239516956e-09 0.000000000000000000 +5.287142110854147203e-01 6.537839974442226560e-09 0.000000000000000000 +5.290695087529370122e-01 2.103767382954850094e-08 0.000000000000000000 +5.294248054131855952e-01 4.251384216807760996e-08 0.000000000000000000 +5.297801010654838993e-01 6.706550635385340809e-08 0.000000000000000000 +5.301353957091556879e-01 9.090160520040974112e-08 0.000000000000000000 +5.304906893435248350e-01 1.107688538567185972e-07 0.000000000000000000 +5.308459819679142155e-01 1.242693172221489730e-07 0.000000000000000000 +5.312012735816479259e-01 1.300432985526712808e-07 0.000000000000000000 +5.315565641840493960e-01 1.278118383292428196e-07 0.000000000000000000 +5.319118537744420561e-01 1.182900982787083105e-07 0.000000000000000000 +5.322671423521496692e-01 1.029964746519141071e-07 0.000000000000000000 +5.326224299164956655e-01 8.399125566372632153e-08 0.000000000000000000 +5.329777164668038081e-01 6.358253975450874878e-08 0.000000000000000000 +5.333330020023976381e-01 4.403617820426607344e-08 0.000000000000000000 +5.336882865226005856e-01 2.732147861699862508e-08 0.000000000000000000 +5.340435700267366359e-01 1.491647493550943453e-08 0.000000000000000000 +5.343988525141287749e-01 7.687087598421340105e-09 0.000000000000000000 +5.347541339841010988e-01 5.844796496759625044e-09 0.000000000000000000 +5.351094144359769267e-01 8.978669970143985722e-09 0.000000000000000000 +5.354646938690800217e-01 1.615056435974732372e-08 0.000000000000000000 +5.358199722827339251e-01 2.603749182283217817e-08 0.000000000000000000 +5.361752496762620668e-01 3.710264865995068443e-08 0.000000000000000000 +5.365305260489883210e-01 4.777619952785105826e-08 0.000000000000000000 +5.368858014002362289e-01 5.662821559725726611e-08 0.000000000000000000 +5.372410757293293315e-01 6.251866328412636341e-08 0.000000000000000000 +5.375963490355910590e-01 6.471254198246048687e-08 0.000000000000000000 +5.379516213183452855e-01 6.295177432054326809e-08 0.000000000000000000 +5.383068925769156632e-01 5.747899897974179530e-08 0.000000000000000000 +5.386621628106255111e-01 4.901188461741618392e-08 0.000000000000000000 +5.390174320187987034e-01 3.866996392649106288e-08 0.000000000000000000 +5.393727002007586702e-01 2.785931877057018161e-08 0.000000000000000000 +5.397279673558293966e-01 1.812374830397954429e-08 0.000000000000000000 +5.400832334833340909e-01 1.097425283175474643e-08 0.000000000000000000 +5.404384985825965160e-01 7.711568555180349724e-09 0.000000000000000000 +5.407937626529405462e-01 9.258757182882143171e-09 0.000000000000000000 +5.411490256936892784e-01 1.602205045329230772e-08 0.000000000000000000 +5.415042877041665870e-01 2.779780003141316738e-08 0.000000000000000000 +5.418595486836963460e-01 4.374107953450975505e-08 0.000000000000000000 +5.422148086316018745e-01 6.240699252121553845e-08 0.000000000000000000 +5.425700675472069356e-01 8.186909588997306142e-08 0.000000000000000000 +5.429253254298352926e-01 9.991093164606391332e-08 0.000000000000000000 +5.432805822788103756e-01 1.142772126711774720e-07 0.000000000000000000 +5.436358380934558365e-01 1.229617933160216958e-07 0.000000000000000000 +5.439910928730954387e-01 1.245014563756426982e-07 0.000000000000000000 +5.443463466170528342e-01 1.182391098120244031e-07 0.000000000000000000 +5.447015993246515642e-01 1.045184229820992780e-07 0.000000000000000000 +5.450568509952152807e-01 8.477511882775591434e-08 0.000000000000000000 +5.454121016280676360e-01 6.149842692846236301e-08 0.000000000000000000 +5.457673512225323931e-01 3.804928372343702930e-08 0.000000000000000000 +5.461225997779333152e-01 1.833871369299138075e-08 0.000000000000000000 +5.464778472935934994e-01 6.388732365258210851e-09 0.000000000000000000 +5.468330937688372639e-01 5.816834533679286728e-09 0.000000000000000000 +5.471883392029879278e-01 1.930112444437385104e-08 0.000000000000000000 +5.475435835953690322e-01 4.809387452564117136e-08 0.000000000000000000 +5.478988269453045623e-01 9.165459004710275194e-08 0.000000000000000000 +5.482540692521181702e-01 1.474680354034504768e-07 0.000000000000000000 +5.486093105151332860e-01 2.110976612192607152e-07 0.000000000000000000 +5.489645507336736729e-01 2.765011592002896653e-07 0.000000000000000000 +5.493197899070632051e-01 3.366043985402819793e-07 0.000000000000000000 +5.496750280346252016e-01 3.840958314887903904e-07 0.000000000000000000 +5.500302651156836475e-01 4.123695334208518463e-07 0.000000000000000000 +5.503855011495618621e-01 4.165157642580528355e-07 0.000000000000000000 +5.507407361355840525e-01 3.942376551345655092e-07 0.000000000000000000 +5.510959700730733157e-01 3.465650799567433566e-07 0.000000000000000000 +5.514512029613537480e-01 2.782445577422907543e-07 0.000000000000000000 +5.518064347997490016e-01 1.977081331264959453e-07 0.000000000000000000 +5.521616655875826174e-01 1.165636752213546533e-07 0.000000000000000000 +5.525168953241783587e-01 4.860098969352259141e-08 0.000000000000000000 +5.528721240088597666e-01 8.367760998585424341e-09 0.000000000000000000 +5.532273516409508263e-01 9.430353101122091145e-09 0.000000000000000000 +5.535825782197750788e-01 6.248973475763105519e-08 0.000000000000000000 +5.539378037446562875e-01 1.735649745308116899e-07 0.000000000000000000 +5.542930282149178822e-01 3.424793142509701248e-07 0.000000000000000000 +5.546482516298839593e-01 5.618817927608130284e-07 0.000000000000000000 +5.550034739888780599e-01 8.170080788678706437e-07 0.000000000000000000 +5.553586952912237251e-01 1.086327752288006408e-06 0.000000000000000000 +5.557139155362449401e-01 1.343145011339269744e-06 0.000000000000000000 +5.560691347232651349e-01 1.558121973119186577e-06 0.000000000000000000 +5.564243528516082948e-01 1.702587243794158192e-06 0.000000000000000000 +5.567795699205979609e-01 1.752387985796346793e-06 0.000000000000000000 +5.571347859295578964e-01 1.691952820165713121e-06 0.000000000000000000 +5.574900008778118643e-01 1.518166720582494084e-06 0.000000000000000000 +5.578452147646836279e-01 1.243627103419817056e-06 0.000000000000000000 +5.582004275894966172e-01 8.988593382997276616e-07 0.000000000000000000 +5.585556393515749285e-01 5.331229183700368738e-07 0.000000000000000000 +5.589108500502421029e-01 2.135352329213494017e-07 0.000000000000000000 +5.592660596848220145e-01 2.237245332480038751e-08 0.000000000000000000 +5.596212682546380934e-01 5.256641249082886638e-08 0.000000000000000000 +5.599764757590142139e-01 4.015889629583112437e-07 0.000000000000000000 +5.603316821972743611e-01 1.164085226527194772e-06 0.000000000000000000 +5.606868875687419651e-01 2.423767606860195418e-06 0.000000000000000000 +5.610420918727407891e-01 4.245197401551981539e-06 0.000000000000000000 +5.613972951085947072e-01 6.666146730012677022e-06 0.000000000000000000 +5.617524972756273716e-01 9.691240636485898844e-06 0.000000000000000000 +5.621076983731625454e-01 1.328752310894187334e-05 0.000000000000000000 +5.624628984005241028e-01 1.738247270140474960e-05 0.000000000000000000 +5.628180973570354739e-01 2.186482080552924000e-05 0.000000000000000000 +5.631732952420209770e-01 2.658831131842155624e-05 0.000000000000000000 +5.635284920548035981e-01 3.137830199983121976e-05 0.000000000000000000 +5.638836877947076553e-01 3.604086576498851611e-05 0.000000000000000000 +5.642388824610570230e-01 4.037382626781467471e-05 0.000000000000000000 +5.645940760531749092e-01 4.417897727819636593e-05 0.000000000000000000 +5.649492685703852990e-01 4.727460753994559964e-05 0.000000000000000000 +5.653044600120120666e-01 4.950739531450985820e-05 0.000000000000000000 +5.656596503773789753e-01 5.076275689797175454e-05 0.000000000000000000 +5.660148396658096770e-01 5.097283136458282044e-05 0.000000000000000000 +5.663700278766280460e-01 5.012145288217879707e-05 0.000000000000000000 +5.667252150091578455e-01 4.824568880927998244e-05 0.000000000000000000 +5.670804010627228386e-01 4.543378761611116231e-05 0.000000000000000000 +5.674355860366465665e-01 4.181966286648011033e-05 0.000000000000000000 +5.677907699302532363e-01 3.757431369748243566e-05 0.000000000000000000 +5.681459527428662781e-01 3.289482456900954204e-05 0.000000000000000000 +5.685011344738097883e-01 2.799177633316403453e-05 0.000000000000000000 +5.688563151224071968e-01 2.307602038306005098e-05 0.000000000000000000 +5.692114946879824888e-01 1.834580747694843569e-05 0.000000000000000000 +5.695666731698596497e-01 1.397521968928968294e-05 0.000000000000000000 +5.699218505673619983e-01 1.010473218642439027e-05 0.000000000000000000 +5.702770268798136311e-01 6.834542598810351446e-06 0.000000000000000000 +5.706322021065380889e-01 4.221067071540306012e-06 0.000000000000000000 +5.709873762468596903e-01 2.276735332538790033e-06 0.000000000000000000 +5.713425493001019762e-01 9.729462724315820966e-07 0.000000000000000000 +5.716977212655882656e-01 2.457944946245843366e-07 0.000000000000000000 +5.720528921426430990e-01 3.968706046638148174e-09 0.000000000000000000 +5.724080619305896844e-01 1.380720442778640443e-07 0.000000000000000000 +5.727632306287523400e-01 5.305340249631355537e-07 0.000000000000000000 +5.731183982364544960e-01 1.065278520825731126e-06 0.000000000000000000 +5.734735647530203595e-01 1.636379772908109541e-06 0.000000000000000000 +5.738287301777731386e-01 2.155069962917634422e-06 0.000000000000000000 +5.741838945100372626e-01 2.554642812821457152e-06 0.000000000000000000 +5.745390577491360506e-01 2.793009438712501159e-06 0.000000000000000000 +5.748942198943938209e-01 2.852884527770904297e-06 0.000000000000000000 +5.752493809451340034e-01 2.739791978271238505e-06 0.000000000000000000 +5.756045409006803615e-01 2.478260476923418210e-06 0.000000000000000000 +5.759596997603573243e-01 2.106715752156362338e-06 0.000000000000000000 +5.763148575234880999e-01 1.671657070079121494e-06 0.000000000000000000 +5.766700141893965625e-01 1.221726338257173734e-06 0.000000000000000000 +5.770251697574069194e-01 8.022403399100469323e-07 0.000000000000000000 +5.773803242268427116e-01 4.506671227127235789e-07 0.000000000000000000 +5.777354775970277023e-01 1.933980666431630193e-07 0.000000000000000000 +5.780906298672860988e-01 4.401262235227615587e-08 0.000000000000000000 +5.784457810369414421e-01 3.069791506412061400e-09 0.000000000000000000 +5.788009311053174955e-01 5.930569947955459364e-08 0.000000000000000000 +5.791560800717384661e-01 1.919849538166339636e-07 0.000000000000000000 +5.795112279355278950e-01 3.740566181750995670e-07 0.000000000000000000 +5.798663746960098786e-01 5.757111207604499255e-07 0.000000000000000000 +5.802215203525079579e-01 7.679250892288131867e-07 0.000000000000000000 +5.805766649043461181e-01 9.256150144514058985e-07 0.000000000000000000 +5.809318083508484554e-01 1.030091518218040927e-06 0.000000000000000000 +5.812869506913382889e-01 1.070604105679546085e-06 0.000000000000000000 +5.816420919251400479e-01 1.044879630936900765e-06 0.000000000000000000 +5.819972320515772735e-01 9.586734108407089225e-07 0.000000000000000000 +5.823523710699739508e-01 8.244576098605085741e-07 0.000000000000000000 +5.827075089796537322e-01 6.594565901354358784e-07 0.000000000000000000 +5.830626457799410467e-01 4.832955827134131369e-07 0.000000000000000000 +5.834177814701591025e-01 3.155529781886816642e-07 0.000000000000000000 +5.837729160496319958e-01 1.734972033053205203e-07 0.000000000000000000 +5.841280495176837118e-01 7.024960603823802908e-08 0.000000000000000000 +5.844831818736380136e-01 1.355117066974925709e-08 0.000000000000000000 +5.848383131168189975e-01 5.231646658483380718e-09 0.000000000000000000 +5.851934432465499825e-01 4.139445213949721264e-08 0.000000000000000000 +5.855485722621556199e-01 1.132492706768242678e-07 0.000000000000000000 +5.859037001629591179e-01 2.084554044988801242e-07 0.000000000000000000 +5.862588269482849057e-01 3.127896081962887065e-07 0.000000000000000000 +5.866139526174566354e-01 4.119266904076093740e-07 0.000000000000000000 +5.869690771697980702e-01 4.931211280501292892e-07 0.000000000000000000 +5.873242006046331953e-01 5.466018666620154117e-07 0.000000000000000000 +5.876793229212859959e-01 5.665363548072090036e-07 0.000000000000000000 +5.880344441190803462e-01 5.514776299888961305e-07 0.000000000000000000 +5.883895641973397872e-01 5.042726427583313958e-07 0.000000000000000000 +5.887446831553889703e-01 4.314733143395663393e-07 0.000000000000000000 +5.890998009925512147e-01 3.423469248657454971e-07 0.000000000000000000 +5.894549177081503943e-01 2.476234717293410357e-07 0.000000000000000000 +5.898100333015108276e-01 1.581406599529662958e-07 0.000000000000000000 +5.901651477719559447e-01 8.355047699320131675e-08 0.000000000000000000 +5.905202611188101747e-01 3.123548673909274376e-08 0.000000000000000000 +5.908753733413971698e-01 5.550829446517932527e-09 0.000000000000000000 +5.912304844390405822e-01 7.463950214674967116e-09 0.000000000000000000 +5.915855944110647302e-01 3.461395275187763592e-08 0.000000000000000000 +5.919407032567934879e-01 8.176228253046440707e-08 0.000000000000000000 +5.922958109755506184e-01 1.415620004793798655e-07 0.000000000000000000 +5.926509175666601070e-01 2.055390976517006177e-07 0.000000000000000000 +5.930060230294459389e-01 2.651595515562552045e-07 0.000000000000000000 +5.933611273632317662e-01 3.128517805912988746e-07 0.000000000000000000 +5.937162305673420182e-01 3.428655634929768786e-07 0.000000000000000000 +5.940713326411000139e-01 3.518733218726289231e-07 0.000000000000000000 +5.944264335838304047e-01 3.392544111246220884e-07 0.000000000000000000 +5.947815333948567318e-01 3.070432225060939968e-07 0.000000000000000000 +5.951366320735027582e-01 2.595625256559252980e-07 0.000000000000000000 +5.954917296190926912e-01 2.027997918868187191e-07 0.000000000000000000 +5.958468260309504050e-01 1.436121571067611870e-07 0.000000000000000000 +5.962019213083999958e-01 8.886228507389958148e-08 0.000000000000000000 +5.965570154507651157e-01 4.459119989464450971e-08 0.000000000000000000 +5.969121084573697500e-01 1.532525539227711285e-08 0.000000000000000000 +5.972672003275382169e-01 3.594371291710108674e-09 0.000000000000000000 +5.976222910605941685e-01 9.710310954815937794e-09 0.000000000000000000 +5.979773806558615901e-01 3.182078810096570803e-08 0.000000000000000000 +5.983324691126644668e-01 6.622165643929785402e-08 0.000000000000000000 +5.986875564303267838e-01 1.078793474086084133e-07 0.000000000000000000 +5.990426426081723044e-01 1.510925076619811829e-07 0.000000000000000000 +5.993977276455254577e-01 1.902079367556136187e-07 0.000000000000000000 +5.997528115417097849e-01 2.203027229412409921e-07 0.000000000000000000 +6.001078942960493823e-01 2.377518991009780282e-07 0.000000000000000000 +6.004629759078682349e-01 2.406177120932415508e-07 0.000000000000000000 +6.008180563764903281e-01 2.288203765903281190e-07 0.000000000000000000 +6.011731357012397581e-01 2.040778821159689532e-07 0.000000000000000000 +6.015282138814402879e-01 1.696305980459083549e-07 0.000000000000000000 +6.018832909164160139e-01 1.297916995675552685e-07 0.000000000000000000 +6.022383668054908101e-01 8.938390458878155905e-08 0.000000000000000000 +6.025934415479888839e-01 5.313454619682417894e-08 0.000000000000000000 +6.029485151432339984e-01 2.510350336706501463e-08 0.000000000000000000 +6.033035875905502499e-01 8.211983994774108679e-09 0.000000000000000000 +6.036586588892616234e-01 3.925684546299965943e-09 0.000000000000000000 +6.040137290386919933e-01 1.212543663294888145e-08 0.000000000000000000 +6.043687980381656777e-01 3.117473372649500105e-08 0.000000000000000000 +6.047238658870061068e-01 5.816946122348397297e-08 0.000000000000000000 +6.050789325845380429e-01 8.933362804047829995e-08 0.000000000000000000 +6.054339981300849161e-01 1.205084197393921003e-07 0.000000000000000000 +6.057890625229709336e-01 1.476722815269256049e-07 0.000000000000000000 +6.061441257625198586e-01 1.674279356704786550e-07 0.000000000000000000 +6.064991878480563425e-01 1.773982191775640313e-07 0.000000000000000000 +6.068542487789035933e-01 1.764854388634637543e-07 0.000000000000000000 +6.072093085543860402e-01 1.649668365156935220e-07 0.000000000000000000 +6.075643671738278906e-01 1.444194324690211976e-07 0.000000000000000000 +6.079194246365526855e-01 1.174884005266132424e-07 0.000000000000000000 +6.082744809418847431e-01 8.753169842753077014e-08 0.000000000000000000 +6.086295360891479378e-01 5.818776293652670453e-08 0.000000000000000000 +6.089845900776666987e-01 3.292110407111610624e-08 0.000000000000000000 +6.093396429067645670e-01 1.460179799887659025e-08 0.000000000000000000 +6.096946945757656389e-01 5.169228961318951754e-09 0.000000000000000000 +6.100497450839942326e-01 5.418832463221475358e-09 0.000000000000000000 +6.104047944307741114e-01 1.493460369477177727e-08 0.000000000000000000 +6.107598426154294824e-01 3.217180383015590700e-08 0.000000000000000000 +6.111148896372842199e-01 5.467589936047240389e-08 0.000000000000000000 +6.114699354956625310e-01 7.940753315753586485e-08 0.000000000000000000 +6.118249801898882900e-01 1.031311614235340368e-07 0.000000000000000000 +6.121800237192857042e-01 1.228182705728388879e-07 0.000000000000000000 +6.125350660831785365e-01 1.360154944467403528e-07 0.000000000000000000 +6.128901072808914385e-01 1.411334110249803310e-07 0.000000000000000000 +6.132451473117479512e-01 1.376225055695315520e-07 0.000000000000000000 +6.136001861750719488e-01 1.260173248398855709e-07 0.000000000000000000 +6.139552238701880826e-01 1.078463649424724593e-07 0.000000000000000000 +6.143102603964201158e-01 8.542168580387930961e-08 0.000000000000000000 +6.146652957530919226e-01 6.153663365791806754e-08 0.000000000000000000 +6.150203299395279322e-01 3.911067741617503879e-08 0.000000000000000000 +6.153753629550520188e-01 2.082601508102251189e-08 0.000000000000000000 +6.157303947989879456e-01 8.800699592306875260e-09 0.000000000000000000 +6.160854254706605859e-01 4.337671601725734574e-09 0.000000000000000000 +6.164404549693931479e-01 7.779030207735163843e-09 0.000000000000000000 +6.167954832945102828e-01 1.848143588459323187e-08 0.000000000000000000 +6.171505104453358648e-01 3.491342101186632433e-08 0.000000000000000000 +6.175055364211936570e-01 5.486045234043456016e-08 0.000000000000000000 +6.178605612214085330e-01 7.571065844854521093e-08 0.000000000000000000 +6.182155848453037006e-01 9.478474002640195863e-08 0.000000000000000000 +6.185706072922038112e-01 1.096688014451697396e-07 0.000000000000000000 +6.189256285614329611e-01 1.185091793312379582e-07 0.000000000000000000 +6.192806486523148024e-01 1.202336691788801304e-07 0.000000000000000000 +6.196356675641737644e-01 1.146731327774274321e-07 0.000000000000000000 +6.199906852963338322e-01 1.025700714165373497e-07 0.000000000000000000 +6.203457018481191021e-01 8.547479006590840982e-08 0.000000000000000000 +6.207007172188536703e-01 6.554352431670386034e-08 0.000000000000000000 +6.210557314078619662e-01 4.526468590535363813e-08 0.000000000000000000 +6.214107444144674197e-01 2.714779910370142789e-08 0.000000000000000000 +6.217657562379947933e-01 1.341377424901839325e-08 0.000000000000000000 +6.221207668777678501e-01 5.724463152620582700e-09 0.000000000000000000 +6.224757763331105753e-01 4.984117501160354466e-09 0.000000000000000000 +6.228307846033475093e-01 1.123613866110955925e-08 0.000000000000000000 +6.231857916878023040e-01 2.366654387982076812e-08 0.000000000000000000 +6.235407975857995000e-01 4.071237424968245054e-08 0.000000000000000000 +6.238958022966629713e-01 6.026045908988496155e-08 0.000000000000000000 +6.242508058197168141e-01 7.991108644256738377e-08 0.000000000000000000 +6.246058081542852358e-01 9.727351059472338928e-08 0.000000000000000000 +6.249608092996924436e-01 1.102567441778984028e-07 0.000000000000000000 +6.253158092552624225e-01 1.173201094727000962e-07 0.000000000000000000 +6.256708080203193800e-01 1.176533822713431772e-07 0.000000000000000000 +6.260258055941873012e-01 1.112653475027756747e-07 0.000000000000000000 +6.263808019761903934e-01 9.897105998834258918e-08 0.000000000000000000 +6.267357971656530857e-01 8.228063628771186367e-08 0.000000000000000000 +6.270907911618989194e-01 6.320445064534374103e-08 0.000000000000000000 +6.274457839642527679e-01 4.399970062873813791e-08 0.000000000000000000 +6.278007755720382832e-01 2.689023043781056004e-08 0.000000000000000000 +6.281557659845794506e-01 1.379443530623955978e-08 0.000000000000000000 +6.285107552012010323e-01 6.094697104895225460e-09 0.000000000000000000 +6.288657432212267917e-01 4.476327327905971895e-09 0.000000000000000000 +6.292207300439807138e-01 8.855127379127930071e-09 0.000000000000000000 +6.295757156687872280e-01 1.840153550282695006e-08 0.000000000000000000 +6.299307000949706525e-01 3.165730291529897918e-08 0.000000000000000000 +6.302856833218546395e-01 4.672921527884810356e-08 0.000000000000000000 +6.306406653487638403e-01 6.153495222151182057e-08 0.000000000000000000 +6.309956461750222401e-01 7.406990467197694917e-08 0.000000000000000000 +6.313506257999537130e-01 8.266140081759297709e-08 0.000000000000000000 +6.317056042228827994e-01 8.617859577559573058e-08 0.000000000000000000 +6.320605814431335956e-01 8.417201209513729616e-08 0.000000000000000000 +6.324155574600303087e-01 7.692565018355481670e-08 0.000000000000000000 +6.327705322728970350e-01 6.541560083438141149e-08 0.000000000000000000 +6.331255058810578706e-01 5.118081507944576529e-08 0.000000000000000000 +6.334804782838371340e-01 3.612266531120729090e-08 0.000000000000000000 +6.338354494805591433e-01 2.225880747262750249e-08 0.000000000000000000 +6.341904194705477726e-01 1.146253101085765795e-08 0.000000000000000000 +6.345453882531273404e-01 5.220561992614700117e-09 0.000000000000000000 +6.349003558276220538e-01 4.439948366344225791e-09 0.000000000000000000 +6.352553221933558980e-01 9.328496650380643250e-09 0.000000000000000000 +6.356102873496536354e-01 1.936401084035280249e-08 0.000000000000000000 +6.359652512958385850e-01 3.335645030283580740e-08 0.000000000000000000 +6.363202140312358424e-01 4.959545529518608308e-08 0.000000000000000000 +6.366751755551693925e-01 6.606493627224355835e-08 0.000000000000000000 +6.370301358669627767e-01 8.069792581265687441e-08 0.000000000000000000 +6.373850949659409793e-01 9.163971369705191680e-08 0.000000000000000000 +6.377400528514277633e-01 9.748608269300368168e-08 0.000000000000000000 +6.380950095227476693e-01 9.746640138882521307e-08 0.000000000000000000 +6.384499649792244602e-01 9.154806513423569480e-08 0.000000000000000000 +6.388049192201827875e-01 8.044848914982932258e-08 0.000000000000000000 +6.391598722449467473e-01 6.555235826522582039e-08 0.000000000000000000 +6.395148240528405470e-01 4.874370636458737423e-08 0.000000000000000000 +6.398697746431881717e-01 3.217316169338512918e-08 0.000000000000000000 +6.402247240153141616e-01 1.798900492051849606e-08 0.000000000000000000 +6.405796721685426132e-01 8.065492364087766319e-09 0.000000000000000000 +6.409346191021977335e-01 3.762570208815701187e-09 0.000000000000000000 +6.412895648156039519e-01 5.747526567247088872e-09 0.000000000000000000 +6.416445093080851425e-01 1.390170217390238753e-08 0.000000000000000000 +6.419994525789658457e-01 2.732499274696444072e-08 0.000000000000000000 +6.423543946275701577e-01 4.443878722298027856e-08 0.000000000000000000 +6.427093354532223968e-01 6.317568004293899849e-08 0.000000000000000000 +6.430642750552468812e-01 8.123329873889953593e-08 0.000000000000000000 +6.434192134329674850e-01 9.636128114331919095e-08 0.000000000000000000 +6.437741505857088598e-01 1.066458832425271056e-07 0.000000000000000000 +6.441290865127949905e-01 1.107565106699341337e-07 0.000000000000000000 +6.444840212135504176e-01 1.081227231040403778e-07 0.000000000000000000 +6.448389546872991263e-01 9.901849165593755111e-08 0.000000000000000000 +6.451938869333654347e-01 8.454172731914613854e-08 0.000000000000000000 +6.455488179510737723e-01 6.648999150234111047e-08 0.000000000000000000 +6.459037477397481242e-01 4.714627215159521186e-08 0.000000000000000000 +6.462586762987130307e-01 2.900015336888334227e-08 0.000000000000000000 +6.466136036272923659e-01 1.443818058172094096e-08 0.000000000000000000 +6.469685297248108924e-01 5.441630509742956471e-09 0.000000000000000000 +6.473234545905924842e-01 3.329624374088330823e-09 0.000000000000000000 +6.476783782239616816e-01 8.580531263148812898e-09 0.000000000000000000 +6.480333006242425808e-01 2.075543598661902307e-08 0.000000000000000000 +6.483882217907596113e-01 3.853515705535421956e-08 0.000000000000000000 +6.487431417228369801e-01 5.986836331024574575e-08 0.000000000000000000 +6.490980604197988946e-01 8.221444870608610374e-08 0.000000000000000000 +6.494529778809697840e-01 1.028527043215601761e-07 0.000000000000000000 +6.498078941056737445e-01 1.192205080003383579e-07 0.000000000000000000 +6.501628090932354276e-01 1.292388891021710243e-07 0.000000000000000000 +6.505177228429784853e-01 1.315845446022088043e-07 0.000000000000000000 +6.508726353542280130e-01 1.258731944175723080e-07 0.000000000000000000 +6.512275466263075518e-01 1.127294518104190726e-07 0.000000000000000000 +6.515824566585418642e-01 9.373196841044034780e-08 0.000000000000000000 +6.519373654502552684e-01 7.123788213981573281e-08 0.000000000000000000 +6.522922730007718606e-01 4.810569860883418370e-08 0.000000000000000000 +6.526471793094159590e-01 2.734880252541571376e-08 0.000000000000000000 +6.530020843755118820e-01 1.176116632854932189e-08 0.000000000000000000 +6.533569881983841698e-01 3.561258563619280753e-09 0.000000000000000000 +6.537118907773566967e-01 4.098994565910464977e-09 0.000000000000000000 +6.540667921117543360e-01 1.366383070031492727e-08 0.000000000000000000 +6.544216922009007398e-01 3.142048169315009995e-08 0.000000000000000000 +6.547765910441210035e-01 5.548355608344123529e-08 0.000000000000000000 +6.551314886407390015e-01 8.312544435393015685e-08 0.000000000000000000 +6.554863849900788297e-01 1.110951058843428562e-07 0.000000000000000000 +6.558412800914653618e-01 1.360110489170399042e-07 0.000000000000000000 +6.561961739442224717e-01 1.547816105973593756e-07 0.000000000000000000 +6.565510665476746999e-01 1.650009845447776883e-07 0.000000000000000000 +6.569059579011463645e-01 1.652710300355077810e-07 0.000000000000000000 +6.572608480039618950e-01 1.554067003978299151e-07 0.000000000000000000 +6.576157368554454985e-01 1.364961557632102358e-07 0.000000000000000000 +6.579706244549214933e-01 1.108037976726447674e-07 0.000000000000000000 +6.583255108017141977e-01 8.152357742416220072e-08 0.000000000000000000 +6.586803958951480409e-01 5.240869074727435336e-08 0.000000000000000000 +6.590352797345476743e-01 2.731986218629269564e-08 0.000000000000000000 +6.593901623192366390e-01 9.745788787154113946e-09 0.000000000000000000 +6.597450436485402525e-01 2.354419110044078995e-09 0.000000000000000000 +6.600999237217821669e-01 6.631776331329846291e-09 0.000000000000000000 +6.604548025382869225e-01 2.265602042100949857e-08 0.000000000000000000 +6.608096800973791707e-01 4.903927339417317206e-08 0.000000000000000000 +6.611645563983830076e-01 8.305007186344925178e-08 0.000000000000000000 +6.615194314406226406e-01 1.209074302475650294e-07 0.000000000000000000 +6.618743052234228319e-01 1.582160051892335234e-07 0.000000000000000000 +6.622291777461075668e-01 1.904933909474218586e-07 0.000000000000000000 +6.625840490080014966e-01 2.137275054116740506e-07 0.000000000000000000 +6.629389190084290506e-01 2.248961251132224782e-07 0.000000000000000000 +6.632937877467142140e-01 2.223828588568259199e-07 0.000000000000000000 +6.636486552221817492e-01 2.062342196579201290e-07 0.000000000000000000 +6.640035214341560854e-01 1.782199806524107402e-07 0.000000000000000000 +6.643583863819609858e-01 1.416817968783782871e-07 0.000000000000000000 +6.647132500649217679e-01 1.011805508266665232e-07 0.000000000000000000 +6.650681124823617507e-01 6.197802923628726556e-08 0.000000000000000000 +6.654229736336063628e-01 2.941028854323340630e-08 0.000000000000000000 +6.657778335179794782e-01 8.225644685096029698e-09 0.000000000000000000 +6.661326921348054153e-01 1.967503333423111422e-09 0.000000000000000000 +6.664875494834090475e-01 1.248002739516622158e-08 0.000000000000000000 +6.668424055631140268e-01 3.960282037727276565e-08 0.000000000000000000 +6.671972603732453377e-01 8.110044180849870854e-08 0.000000000000000000 +6.675521139131271875e-01 1.328457893591700800e-07 0.000000000000000000 +6.679069661820842274e-01 1.892461618199566402e-07 0.000000000000000000 +6.682618171794402206e-01 2.438706685603150612e-07 0.000000000000000000 +6.686166669045205957e-01 2.902112164315921054e-07 0.000000000000000000 +6.689715153566486716e-01 3.224899275935096047e-07 0.000000000000000000 +6.693263625351496549e-01 3.364161559102603232e-07 0.000000000000000000 +6.696812084393478637e-01 3.297978596050759916e-07 0.000000000000000000 +6.700360530685670613e-01 3.029252578647283393e-07 0.000000000000000000 +6.703908964221327871e-01 2.586683852843770093e-07 0.000000000000000000 +6.707457384993684713e-01 2.022619994419817766e-07 0.000000000000000000 +6.711005792995989871e-01 1.407878607034080007e-07 0.000000000000000000 +6.714554188221486530e-01 8.240154572640456607e-08 0.000000000000000000 +6.718102570663422313e-01 3.538427990954685801e-08 0.000000000000000000 +6.721650940315034850e-01 7.125634921383378850e-09 0.000000000000000000 +6.725199297169576207e-01 3.156940779817525424e-09 0.000000000000000000 +6.728747641220286235e-01 2.635569243891584593e-08 0.000000000000000000 +6.732295972460408118e-01 7.642736291402532864e-08 0.000000000000000000 +6.735844290883191698e-01 1.497437830908723426e-07 0.000000000000000000 +6.739392596481875719e-01 2.395791338845689048e-07 0.000000000000000000 +6.742940889249708913e-01 3.367395276775452159e-07 0.000000000000000000 +6.746489169179933354e-01 4.305350395032131612e-07 0.000000000000000000 +6.750037436265796664e-01 5.099992694355774644e-07 0.000000000000000000 +6.753585690500539807e-01 5.652263436602756905e-07 0.000000000000000000 +6.757133931877408184e-01 5.886732348689778454e-07 0.000000000000000000 +6.760682160389648310e-01 5.762696683775752839e-07 0.000000000000000000 +6.764230376030502256e-01 5.281902375824515451e-07 0.000000000000000000 +6.767778578793219868e-01 4.491732775261142066e-07 0.000000000000000000 +6.771326768671038776e-01 3.483161263401599753e-07 0.000000000000000000 +6.774874945657207714e-01 2.383323967867089020e-07 0.000000000000000000 +6.778423109744969866e-01 1.343180954835292866e-07 0.000000000000000000 +6.781971260927572853e-01 5.213329714928292602e-08 0.000000000000000000 +6.785519399198258750e-01 6.557842614936761977e-09 0.000000000000000000 +6.789067524550272958e-01 9.416960829089678940e-09 0.000000000000000000 +6.792615636976863103e-01 6.789084335766930541e-08 0.000000000000000000 +6.796163736471270145e-01 1.832179000018432771e-07 0.000000000000000000 +6.799711823026739488e-01 3.499738433880298899e-07 0.000000000000000000 +6.803259896636518755e-01 5.560595033261273928e-07 0.000000000000000000 +6.806807957293848910e-01 7.834633774959268025e-07 0.000000000000000000 +6.810356004991979795e-01 1.009786484082793178e-06 0.000000000000000000 +6.813904039724152373e-01 1.210434718682093645e-06 0.000000000000000000 +6.817452061483614267e-01 1.361306040239262548e-06 0.000000000000000000 +6.821000070263608661e-01 1.441734761401513620e-06 0.000000000000000000 +6.824548066057383178e-01 1.437410401516072747e-06 0.000000000000000000 +6.828096048858179890e-01 1.342969637729787250e-06 0.000000000000000000 +6.831644018659246420e-01 1.163970131324562443e-06 0.000000000000000000 +6.835191975453825952e-01 9.179948683779298552e-07 0.000000000000000000 +6.838739919235164999e-01 6.347026298881030801e-07 0.000000000000000000 +6.842287849996507854e-01 3.547289803235549456e-07 0.000000000000000000 +6.845835767731099919e-01 1.274450490429754141e-07 0.000000000000000000 +6.849383672432189929e-01 7.689013104348961068e-09 0.000000000000000000 +6.852931564093017736e-01 5.168741132194243346e-08 0.000000000000000000 +6.856479442706829852e-01 3.124702498300443199e-07 0.000000000000000000 +6.860027308266875012e-01 8.351464894336527380e-07 0.000000000000000000 +6.863575160766395289e-01 1.652438186092146679e-06 0.000000000000000000 +6.867123000198634974e-01 2.780868306576662507e-06 0.000000000000000000 +6.870670826556845023e-01 4.217958294192426203e-06 0.000000000000000000 +6.874218639834266398e-01 5.940719399286303381e-06 0.000000000000000000 +6.877766440024144501e-01 7.905622364402147082e-06 0.000000000000000000 +6.881314227119726956e-01 1.005011167531458192e-05 0.000000000000000000 +6.884862001114256946e-01 1.229560356406208357e-05 0.000000000000000000 +6.888409762000983205e-01 1.455178252378887522e-05 0.000000000000000000 +6.891957509773147805e-01 1.672190039569084494e-05 0.000000000000000000 +6.895505244423998370e-01 1.870869507805675487e-05 0.000000000000000000 +6.899052965946781413e-01 2.042049044340849492e-05 0.000000000000000000 +6.902600674334740116e-01 2.177702014935189832e-05 0.000000000000000000 +6.906148369581120994e-01 2.271453740307057415e-05 0.000000000000000000 +6.909696051679170559e-01 2.318982865287496010e-05 0.000000000000000000 +6.913243720622134214e-01 2.318283662343840706e-05 0.000000000000000000 +6.916791376403257363e-01 2.269770929951792711e-05 0.000000000000000000 +6.920339019015785409e-01 2.176221657248429041e-05 0.000000000000000000 +6.923886648452962644e-01 2.042560436325823535e-05 0.000000000000000000 +6.927434264708041134e-01 1.875507610052542674e-05 0.000000000000000000 +6.930981867774258509e-01 1.683119335314874388e-05 0.000000000000000000 +6.934529457644867945e-01 1.474256290245099887e-05 0.000000000000000000 +6.938077034313111513e-01 1.258022083866049750e-05 0.000000000000000000 +6.941624597772233507e-01 1.043213262203711571e-05 0.000000000000000000 +6.945172148015482660e-01 8.378201881748441741e-06 0.000000000000000000 +6.948719685036103266e-01 6.486123495259529022e-06 0.000000000000000000 +6.952267208827344058e-01 4.808334292377077544e-06 0.000000000000000000 +6.955814719382448219e-01 3.380215641939625228e-06 0.000000000000000000 +6.959362216694663372e-01 2.219595461493938630e-06 0.000000000000000000 +6.962909700757234921e-01 1.327492376218807748e-06 0.000000000000000000 +6.966457171563408268e-01 6.899507705571123048e-07 0.000000000000000000 +6.970004629106431038e-01 2.807398465524255528e-07 0.000000000000000000 +6.973552073379547522e-01 6.463801578872321338e-08 0.000000000000000000 +6.977099504376007566e-01 9.990546426951016417e-10 0.000000000000000000 +6.980646922089053241e-01 4.729889433496456379e-08 0.000000000000000000 +6.984194326511931061e-01 1.623896488439826829e-07 0.000000000000000000 +6.987741717637889760e-01 3.092362898077472084e-07 0.000000000000000000 +6.991289095460176961e-01 4.569753992960879823e-07 0.000000000000000000 +6.994836459972032516e-01 5.822078170711355135e-07 0.000000000000000000 +6.998383811166707380e-01 6.695106122036307051e-07 0.000000000000000000 +7.001931149037448066e-01 7.112219213820162719e-07 0.000000000000000000 +7.005478473577498866e-01 7.066090981626248295e-07 0.000000000000000000 +7.009025784780108514e-01 6.605720895669835783e-07 0.000000000000000000 +7.012573082638521305e-01 5.820575662663225347e-07 0.000000000000000000 +7.016120367145987080e-01 4.823645348587461643e-07 0.000000000000000000 +7.019667638295746803e-01 3.735102060393759349e-07 0.000000000000000000 +7.023214896081051428e-01 2.667985645742724157e-07 0.000000000000000000 +7.026762140495145248e-01 1.716973072981499932e-07 0.000000000000000000 +7.030309371531275886e-01 9.508616308080831059e-08 0.000000000000000000 +7.033856589182690966e-01 4.089581191802170028e-08 0.000000000000000000 +7.037403793442632560e-01 1.011607147464398172e-08 0.000000000000000000 +7.040950984304352733e-01 1.118364062367043026e-09 0.000000000000000000 +7.044498161761095778e-01 1.021331209054640798e-08 0.000000000000000000 +7.048045325806109318e-01 3.235101525108101128e-08 0.000000000000000000 +7.051592476432638756e-01 6.186927241594258659e-08 0.000000000000000000 +7.055139613633929496e-01 9.320271810906388317e-08 0.000000000000000000 +7.058686737403232492e-01 1.214816128081553766e-07 0.000000000000000000 +7.062233847733789815e-01 1.429702890574333918e-07 0.000000000000000000 +7.065780944618853532e-01 1.553191412659423236e-07 0.000000000000000000 +7.069328028051664603e-01 1.576277197123771287e-07 0.000000000000000000 +7.072875098025475094e-01 1.503374458555530972e-07 0.000000000000000000 +7.076422154533528186e-01 1.349887723810438449e-07 0.000000000000000000 +7.079969197569071504e-01 1.138880527102133007e-07 0.000000000000000000 +7.083516227125353781e-01 8.973352248045353983e-08 0.000000000000000000 +7.087063243195621531e-01 6.524793349596863932e-08 0.000000000000000000 +7.090610245773119047e-01 4.285845144187631695e-08 0.000000000000000000 +7.094157234851096172e-01 2.445382165863092364e-08 0.000000000000000000 +7.097704210422800530e-01 1.123616269676962751e-08 0.000000000000000000 +7.101251172481475304e-01 3.671743197969824324e-09 0.000000000000000000 +7.104798121020371449e-01 1.533254517962277503e-09 0.000000000000000000 +7.108345056032734366e-01 4.016616402417570813e-09 0.000000000000000000 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_2.dat b/tests/test_data/ORSO/test_2.dat new file mode 100644 index 00000000..5cfc9e61 --- /dev/null +++ b/tests/test_data/ORSO/test_2.dat @@ -0,0 +1,1001 @@ +5.000000000000000104e-03 1.000000000000000222e+00 0.000000000000000000 +5.995000000000000329e-03 1.000000000000000222e+00 0.000000000000000000 +6.989999999999999686e-03 1.000000000000000222e+00 0.000000000000000000 +7.984999999999999043e-03 1.000000000000000000e+00 0.000000000000000000 +8.980000000000000135e-03 9.999999999999996669e-01 0.000000000000000000 +9.975000000000001227e-03 1.000000000000000222e+00 0.000000000000000000 +1.097000000000000058e-02 9.999999999999998890e-01 0.000000000000000000 +1.196499999999999994e-02 1.000000000000000222e+00 0.000000000000000000 +1.295999999999999930e-02 9.999999999999998890e-01 0.000000000000000000 +1.395499999999999866e-02 1.000000000000000000e+00 0.000000000000000000 +1.495000000000000148e-02 9.999999999999997780e-01 0.000000000000000000 +1.594500000000000084e-02 1.000000000000000222e+00 0.000000000000000000 +1.694000000000000020e-02 9.999999999999995559e-01 0.000000000000000000 +1.793499999999999955e-02 7.302544119277273316e-01 0.000000000000000000 +1.892999999999999891e-02 2.552815931521527082e-01 0.000000000000000000 +1.992500000000000174e-02 1.500207458923263903e-01 0.000000000000000000 +2.092000000000000109e-02 9.997793399278399884e-02 0.000000000000000000 +2.191500000000000045e-02 7.123912062170954795e-02 0.000000000000000000 +2.290999999999999981e-02 5.301614647186881496e-02 0.000000000000000000 +2.390500000000000264e-02 4.070644982790416755e-02 0.000000000000000000 +2.490000000000000199e-02 3.201044658983939750e-02 0.000000000000000000 +2.589500000000000135e-02 2.565627153557500234e-02 0.000000000000000000 +2.689000000000000071e-02 2.088803389193751026e-02 0.000000000000000000 +2.788500000000000006e-02 1.723156075999391149e-02 0.000000000000000000 +2.887999999999999942e-02 1.437654145720755616e-02 0.000000000000000000 +2.987500000000000225e-02 1.211283187244694554e-02 0.000000000000000000 +3.087000000000000161e-02 1.029403083215324477e-02 0.000000000000000000 +3.186499999999999749e-02 8.815675506561536021e-03 0.000000000000000000 +3.286000000000000032e-02 7.601682608979293439e-03 0.000000000000000000 +3.385499999999999621e-02 6.595641840799377348e-03 0.000000000000000000 +3.484999999999999903e-02 5.755068914451989294e-03 0.000000000000000000 +3.584500000000000186e-02 5.047520223740087873e-03 0.000000000000000000 +3.683999999999999775e-02 4.447910330864589430e-03 0.000000000000000000 +3.783500000000000058e-02 3.936625104166304942e-03 0.000000000000000000 +3.882999999999999646e-02 3.498172265099319146e-03 0.000000000000000000 +3.982499999999999929e-02 3.120201746921682021e-03 0.000000000000000000 +4.081999999999999518e-02 2.792784835982658510e-03 0.000000000000000000 +4.181499999999999800e-02 2.507877168229455909e-03 0.000000000000000000 +4.281000000000000083e-02 2.258914162673223303e-03 0.000000000000000000 +4.380499999999999672e-02 2.040503064564099227e-03 0.000000000000000000 +4.479999999999999954e-02 1.848186284179480438e-03 0.000000000000000000 +4.579499999999999543e-02 1.678257914894290374e-03 0.000000000000000000 +4.678999999999999826e-02 1.527620311455636605e-03 0.000000000000000000 +4.778500000000000109e-02 1.393671123873522957e-03 0.000000000000000000 +4.877999999999999697e-02 1.274213683683264901e-03 0.000000000000000000 +4.977499999999999980e-02 1.167385439427427989e-03 0.000000000000000000 +5.076999999999999569e-02 1.071600447070272973e-03 0.000000000000000000 +5.176499999999999851e-02 9.855028819590074245e-04 0.000000000000000000 +5.275999999999999440e-02 9.079292507786222884e-04 0.000000000000000000 +5.375499999999999723e-02 8.378775137522353079e-04 0.000000000000000000 +5.475000000000000006e-02 7.744817278207360121e-04 0.000000000000000000 +5.574499999999999594e-02 7.169911253934479513e-04 0.000000000000000000 +5.673999999999999877e-02 6.647527754462639578e-04 0.000000000000000000 +5.773499999999999466e-02 6.171971523537961302e-04 0.000000000000000000 +5.872999999999999748e-02 5.738260761141945280e-04 0.000000000000000000 +5.972500000000000031e-02 5.342025953163497161e-04 0.000000000000000000 +6.071999999999999620e-02 4.979424685541384383e-04 0.000000000000000000 +6.171499999999999903e-02 4.647069664291461882e-04 0.000000000000000000 +6.271000000000000185e-02 4.341967688803725391e-04 0.000000000000000000 +6.370499999999999774e-02 4.061467744268355633e-04 0.000000000000000000 +6.470000000000000751e-02 3.803216713614568584e-04 0.000000000000000000 +6.569500000000000339e-02 3.565121477980526233e-04 0.000000000000000000 +6.668999999999999928e-02 3.345316391388566393e-04 0.000000000000000000 +6.768500000000000905e-02 3.142135290765838492e-04 0.000000000000000000 +6.868000000000000493e-02 2.954087345123552772e-04 0.000000000000000000 +6.967500000000000082e-02 2.779836164163030222e-04 0.000000000000000000 +7.067000000000001059e-02 2.618181681981876160e-04 0.000000000000000000 +7.166500000000000647e-02 2.468044409991756983e-04 0.000000000000000000 +7.266000000000000236e-02 2.328451717867457689e-04 0.000000000000000000 +7.365499999999999825e-02 2.198525854904882944e-04 0.000000000000000000 +7.465000000000000802e-02 2.077473468635113445e-04 0.000000000000000000 +7.564500000000000390e-02 1.964576414578978456e-04 0.000000000000000000 +7.663999999999999979e-02 1.859183681963245624e-04 0.000000000000000000 +7.763500000000000956e-02 1.760704286136114403e-04 0.000000000000000000 +7.863000000000000544e-02 1.668601000190766644e-04 0.000000000000000000 +7.962500000000000133e-02 1.582384816641631969e-04 0.000000000000000000 +8.062000000000001110e-02 1.501610045482572255e-04 0.000000000000000000 +8.161500000000000699e-02 1.425869968064864129e-04 0.000000000000000000 +8.261000000000000287e-02 1.354792977357120428e-04 0.000000000000000000 +8.360499999999999876e-02 1.288039144612181271e-04 0.000000000000000000 +8.460000000000000853e-02 1.225297160532930944e-04 0.000000000000000000 +8.559500000000000441e-02 1.166281605923794913e-04 0.000000000000000000 +8.659000000000000030e-02 1.110730512716228780e-04 0.000000000000000000 +8.758500000000001007e-02 1.058403181323294158e-04 0.000000000000000000 +8.858000000000000596e-02 1.009078224632976368e-04 0.000000000000000000 +8.957500000000000184e-02 9.625518127027844306e-05 0.000000000000000000 +9.057000000000001161e-02 9.186360954578184804e-05 0.000000000000000000 +9.156500000000000750e-02 8.771577834949046066e-05 0.000000000000000000 +9.256000000000000338e-02 8.379568695238581060e-05 0.000000000000000000 +9.355499999999999927e-02 8.008854750826035064e-05 0.000000000000000000 +9.455000000000000904e-02 7.658068089951252906e-05 0.000000000000000000 +9.554500000000000492e-02 7.325942256365089748e-05 0.000000000000000000 +9.654000000000000081e-02 7.011303724606809810e-05 0.000000000000000000 +9.753500000000001058e-02 6.713064174628380202e-05 0.000000000000000000 +9.853000000000000647e-02 6.430213483124872734e-05 0.000000000000000000 +9.952500000000000235e-02 6.161813358258931778e-05 0.000000000000000000 +1.005199999999999982e-01 5.906991552652936407e-05 0.000000000000000000 +1.015150000000000080e-01 5.664936596722652709e-05 0.000000000000000000 +1.025100000000000039e-01 5.434893000757861324e-05 0.000000000000000000 +1.035049999999999998e-01 5.216156879745617451e-05 0.000000000000000000 +1.045000000000000095e-01 5.008071959859009475e-05 0.000000000000000000 +1.054950000000000054e-01 4.810025929894232714e-05 0.000000000000000000 +1.064900000000000013e-01 4.621447104794872937e-05 0.000000000000000000 +1.074850000000000111e-01 4.441801371822664884e-05 0.000000000000000000 +1.084800000000000070e-01 4.270589392966370960e-05 0.000000000000000000 +1.094750000000000029e-01 4.107344039873492037e-05 0.000000000000000000 +1.104699999999999988e-01 3.951628039990539470e-05 0.000000000000000000 +1.114650000000000085e-01 3.803031814727148062e-05 0.000000000000000000 +1.124600000000000044e-01 3.661171492366325104e-05 0.000000000000000000 +1.134550000000000003e-01 3.525687080139357449e-05 0.000000000000000000 +1.144500000000000101e-01 3.396240781400948852e-05 0.000000000000000000 +1.154450000000000059e-01 3.272515445200561756e-05 0.000000000000000000 +1.164400000000000018e-01 3.154213136757109493e-05 0.000000000000000000 +1.174350000000000116e-01 3.041053818437549486e-05 0.000000000000000000 +1.184300000000000075e-01 2.932774131814763082e-05 0.000000000000000000 +1.194250000000000034e-01 2.829126272259308120e-05 0.000000000000000000 +1.204199999999999993e-01 2.729876948309178597e-05 0.000000000000000000 +1.214150000000000090e-01 2.634806418770863114e-05 0.000000000000000000 +1.224100000000000049e-01 2.543707601145856189e-05 0.000000000000000000 +1.234050000000000008e-01 2.456385245553760122e-05 0.000000000000000000 +1.244000000000000106e-01 2.372655168842050194e-05 0.000000000000000000 +1.253950000000000065e-01 2.292343544045605906e-05 0.000000000000000000 +1.263900000000000023e-01 2.215286240780996405e-05 0.000000000000000000 +1.273849999999999982e-01 2.141328212547069355e-05 0.000000000000000000 +1.283799999999999941e-01 2.070322927252014994e-05 0.000000000000000000 +1.293749999999999900e-01 2.002131837599849124e-05 0.000000000000000000 +1.303700000000000137e-01 1.936623888259802600e-05 0.000000000000000000 +1.313650000000000095e-01 1.873675056998053514e-05 0.000000000000000000 +1.323600000000000054e-01 1.813167927190132041e-05 0.000000000000000000 +1.333550000000000013e-01 1.754991289344203385e-05 0.000000000000000000 +1.343499999999999972e-01 1.699039769464770946e-05 0.000000000000000000 +1.353449999999999931e-01 1.645213482259845323e-05 0.000000000000000000 +1.363400000000000167e-01 1.593417707359521767e-05 0.000000000000000000 +1.373350000000000126e-01 1.543562586860838427e-05 0.000000000000000000 +1.383300000000000085e-01 1.495562842648808664e-05 0.000000000000000000 +1.393250000000000044e-01 1.449337512065626627e-05 0.000000000000000000 +1.403200000000000003e-01 1.404809700615483821e-05 0.000000000000000000 +1.413149999999999962e-01 1.361906350491213202e-05 0.000000000000000000 +1.423099999999999921e-01 1.320558023807027655e-05 0.000000000000000000 +1.433050000000000157e-01 1.280698699505669096e-05 0.000000000000000000 +1.443000000000000116e-01 1.242265582987766277e-05 0.000000000000000000 +1.452950000000000075e-01 1.205198927583547193e-05 0.000000000000000000 +1.462900000000000034e-01 1.169441867055197280e-05 0.000000000000000000 +1.472849999999999993e-01 1.134940258375420816e-05 0.000000000000000000 +1.482799999999999951e-01 1.101642534088488612e-05 0.000000000000000000 +1.492750000000000188e-01 1.069499563607656409e-05 0.000000000000000000 +1.502700000000000147e-01 1.038464522852731763e-05 0.000000000000000000 +1.512650000000000106e-01 1.008492771673922509e-05 0.000000000000000000 +1.522600000000000064e-01 9.795417385487658167e-06 0.000000000000000000 +1.532550000000000023e-01 9.515708120754915602e-06 0.000000000000000000 +1.542499999999999982e-01 9.245412388214926215e-06 0.000000000000000000 +1.552449999999999941e-01 8.984160271147430192e-06 0.000000000000000000 +1.562400000000000178e-01 8.731598563979155208e-06 0.000000000000000000 +1.572350000000000136e-01 8.487389917891189619e-06 0.000000000000000000 +1.582300000000000095e-01 8.251212035195819211e-06 0.000000000000000000 +1.592250000000000054e-01 8.022756909411819735e-06 0.000000000000000000 +1.602200000000000013e-01 7.801730108172303166e-06 0.000000000000000000 +1.612149999999999972e-01 7.587850096304319501e-06 0.000000000000000000 +1.622099999999999931e-01 7.380847596593427883e-06 0.000000000000000000 +1.632050000000000167e-01 7.180464985919699528e-06 0.000000000000000000 +1.642000000000000126e-01 6.986455724602389345e-06 0.000000000000000000 +1.651950000000000085e-01 6.798583816938923489e-06 0.000000000000000000 +1.661900000000000044e-01 6.616623301054710733e-06 0.000000000000000000 +1.671850000000000003e-01 6.440357766307891073e-06 0.000000000000000000 +1.681799999999999962e-01 6.269579896604869611e-06 0.000000000000000000 +1.691749999999999921e-01 6.104091038089564868e-06 0.000000000000000000 +1.701700000000000157e-01 5.943700789772575947e-06 0.000000000000000000 +1.711650000000000116e-01 5.788226615756587192e-06 0.000000000000000000 +1.721600000000000075e-01 5.637493477799012715e-06 0.000000000000000000 +1.731550000000000034e-01 5.491333487035706967e-06 0.000000000000000000 +1.741499999999999992e-01 5.349585573761062137e-06 0.000000000000000000 +1.751449999999999951e-01 5.212095174233773578e-06 0.000000000000000000 +1.761400000000000188e-01 5.078713933538307867e-06 0.000000000000000000 +1.771350000000000147e-01 4.949299423590993852e-06 0.000000000000000000 +1.781300000000000106e-01 4.823714875442655119e-06 0.000000000000000000 +1.791250000000000064e-01 4.701828925074577255e-06 0.000000000000000000 +1.801200000000000023e-01 4.583515371940636223e-06 0.000000000000000000 +1.811149999999999982e-01 4.468652949545531132e-06 0.000000000000000000 +1.821099999999999941e-01 4.357125107399881593e-06 0.000000000000000000 +1.831050000000000177e-01 4.248819803728705652e-06 0.000000000000000000 +1.841000000000000136e-01 4.143629308349770852e-06 0.000000000000000000 +1.850950000000000095e-01 4.041450015165261868e-06 0.000000000000000000 +1.860900000000000054e-01 3.942182263758992194e-06 0.000000000000000000 +1.870850000000000013e-01 3.845730169599192739e-06 0.000000000000000000 +1.880799999999999972e-01 3.752001462399423300e-06 0.000000000000000000 +1.890749999999999931e-01 3.660907332198875170e-06 0.000000000000000000 +1.900700000000000167e-01 3.572362282757150113e-06 0.000000000000000000 +1.910650000000000126e-01 3.486283991877368194e-06 0.000000000000000000 +1.920600000000000085e-01 3.402593178302982697e-06 0.000000000000000000 +1.930550000000000044e-01 3.321213474835895762e-06 0.000000000000000000 +1.940500000000000003e-01 3.242071307366984273e-06 0.000000000000000000 +1.950449999999999962e-01 3.165095779504616941e-06 0.000000000000000000 +1.960399999999999920e-01 3.090218562523206605e-06 0.000000000000000000 +1.970350000000000157e-01 3.017373790355003906e-06 0.000000000000000000 +1.980300000000000116e-01 2.946497959373940888e-06 0.000000000000000000 +1.990250000000000075e-01 2.877529832728726358e-06 0.000000000000000000 +2.000200000000000033e-01 2.810410348997253469e-06 0.000000000000000000 +2.010149999999999992e-01 2.745082534945871258e-06 0.000000000000000000 +2.020099999999999951e-01 2.681491422194076088e-06 0.000000000000000000 +2.030050000000000188e-01 2.619583967585816721e-06 0.000000000000000000 +2.040000000000000147e-01 2.559308977088196519e-06 0.000000000000000000 +2.049950000000000105e-01 2.500617033048890839e-06 0.000000000000000000 +2.059900000000000064e-01 2.443460424640982012e-06 0.000000000000000000 +2.069850000000000023e-01 2.387793081346400505e-06 0.000000000000000000 +2.079799999999999982e-01 2.333570509331725681e-06 0.000000000000000000 +2.089749999999999941e-01 2.280749730574460933e-06 0.000000000000000000 +2.099700000000000177e-01 2.229289224610072797e-06 0.000000000000000000 +2.109650000000000136e-01 2.179148872777007317e-06 0.000000000000000000 +2.119600000000000095e-01 2.130289904837552500e-06 0.000000000000000000 +2.129550000000000054e-01 2.082674847866944899e-06 0.000000000000000000 +2.139500000000000013e-01 2.036267477302419947e-06 0.000000000000000000 +2.149449999999999972e-01 1.991032770050237681e-06 0.000000000000000000 +2.159399999999999931e-01 1.946936859557188785e-06 0.000000000000000000 +2.169350000000000167e-01 1.903946992756716464e-06 0.000000000000000000 +2.179300000000000126e-01 1.862031488799201211e-06 0.000000000000000000 +2.189250000000000085e-01 1.821159699489077939e-06 0.000000000000000000 +2.199200000000000044e-01 1.781301971348607896e-06 0.000000000000000000 +2.209150000000000003e-01 1.742429609236075048e-06 0.000000000000000000 +2.219099999999999961e-01 1.704514841445228144e-06 0.000000000000000000 +2.229050000000000198e-01 1.667530786223389054e-06 0.000000000000000000 +2.239000000000000157e-01 1.631451419641829289e-06 0.000000000000000000 +2.248950000000000116e-01 1.596251544758542627e-06 0.000000000000000000 +2.258900000000000075e-01 1.561906762016576218e-06 0.000000000000000000 +2.268850000000000033e-01 1.528393440823871229e-06 0.000000000000000000 +2.278799999999999992e-01 1.495688692261441789e-06 0.000000000000000000 +2.288749999999999951e-01 1.463770342870089032e-06 0.000000000000000000 +2.298700000000000188e-01 1.432616909471420088e-06 0.000000000000000000 +2.308650000000000146e-01 1.402207574973502849e-06 0.000000000000000000 +2.318600000000000105e-01 1.372522165124398464e-06 0.000000000000000000 +2.328550000000000064e-01 1.343541126166518876e-06 0.000000000000000000 +2.338500000000000023e-01 1.315245503359037064e-06 0.000000000000000000 +2.348449999999999982e-01 1.287616920326394123e-06 0.000000000000000000 +2.358399999999999941e-01 1.260637559201489898e-06 0.000000000000000000 +2.368350000000000177e-01 1.234290141526865827e-06 0.000000000000000000 +2.378300000000000136e-01 1.208557909884525645e-06 0.000000000000000000 +2.388250000000000095e-01 1.183424610222043002e-06 0.000000000000000000 +2.398200000000000054e-01 1.158874474846250690e-06 0.000000000000000000 +2.408150000000000013e-01 1.134892206056985017e-06 0.000000000000000000 +2.418099999999999972e-01 1.111462960394385494e-06 0.000000000000000000 +2.428049999999999931e-01 1.088572333473516146e-06 0.000000000000000000 +2.438000000000000167e-01 1.066206345383700941e-06 0.000000000000000000 +2.447950000000000126e-01 1.044351426627338742e-06 0.000000000000000000 +2.457900000000000085e-01 1.022994404578400489e-06 0.000000000000000000 +2.467850000000000044e-01 1.002122490437704232e-06 0.000000000000000000 +2.477800000000000002e-01 9.817232666657718879e-07 0.000000000000000000 +2.487749999999999961e-01 9.617846748736519515e-07 0.000000000000000000 +2.497700000000000198e-01 9.422950041539083708e-07 0.000000000000000000 +2.507650000000000157e-01 9.232428798323453051e-07 0.000000000000000000 +2.517599999999999838e-01 9.046172526266390979e-07 0.000000000000000000 +2.527550000000000074e-01 8.864073881929345266e-07 0.000000000000000000 +2.537499999999999756e-01 8.686028570467542300e-07 0.000000000000000000 +2.547449999999999992e-01 8.511935248416559944e-07 0.000000000000000000 +2.557400000000000229e-01 8.341695429956798617e-07 0.000000000000000000 +2.567349999999999910e-01 8.175213396454100065e-07 0.000000000000000000 +2.577300000000000146e-01 8.012396109212888927e-07 0.000000000000000000 +2.587249999999999828e-01 7.853153125282533498e-07 0.000000000000000000 +2.597200000000000064e-01 7.697396516203173399e-07 0.000000000000000000 +2.607150000000000301e-01 7.545040789584628936e-07 0.000000000000000000 +2.617099999999999982e-01 7.396002813402122049e-07 0.000000000000000000 +2.627050000000000218e-01 7.250201742916859191e-07 0.000000000000000000 +2.636999999999999900e-01 7.107558950102262601e-07 0.000000000000000000 +2.646950000000000136e-01 6.967997955505304836e-07 0.000000000000000000 +2.656899999999999817e-01 6.831444362421918255e-07 0.000000000000000000 +2.666850000000000054e-01 6.697825793328290410e-07 0.000000000000000000 +2.676800000000000290e-01 6.567071828464906383e-07 0.000000000000000000 +2.686749999999999972e-01 6.439113946490282237e-07 0.000000000000000000 +2.696700000000000208e-01 6.313885467153174819e-07 0.000000000000000000 +2.706649999999999889e-01 6.191321495868240811e-07 0.000000000000000000 +2.716600000000000126e-01 6.071358870161023394e-07 0.000000000000000000 +2.726549999999999807e-01 5.953936107895076103e-07 0.000000000000000000 +2.736500000000000044e-01 5.838993357212978451e-07 0.000000000000000000 +2.746450000000000280e-01 5.726472348147212419e-07 0.000000000000000000 +2.756399999999999961e-01 5.616316345813571775e-07 0.000000000000000000 +2.766350000000000198e-01 5.508470105157720654e-07 0.000000000000000000 +2.776299999999999879e-01 5.402879827167730058e-07 0.000000000000000000 +2.786250000000000115e-01 5.299493116534244488e-07 0.000000000000000000 +2.796199999999999797e-01 5.198258940675015360e-07 0.000000000000000000 +2.806150000000000033e-01 5.099127590094127535e-07 0.000000000000000000 +2.816100000000000270e-01 5.002050640022411882e-07 0.000000000000000000 +2.826049999999999951e-01 4.906980913288911179e-07 0.000000000000000000 +2.836000000000000187e-01 4.813872444391793366e-07 0.000000000000000000 +2.845949999999999869e-01 4.722680444710293888e-07 0.000000000000000000 +2.855900000000000105e-01 4.633361268832067542e-07 0.000000000000000000 +2.865850000000000342e-01 4.545872381946849999e-07 0.000000000000000000 +2.875800000000000023e-01 4.460172328274867991e-07 0.000000000000000000 +2.885750000000000259e-01 4.376220700492397344e-07 0.000000000000000000 +2.895699999999999941e-01 4.293978110113955783e-07 0.000000000000000000 +2.905650000000000177e-01 4.213406158812215202e-07 0.000000000000000000 +2.915599999999999858e-01 4.134467410625320186e-07 0.000000000000000000 +2.925550000000000095e-01 4.057125365037572669e-07 0.000000000000000000 +2.935500000000000331e-01 3.981344430887845665e-07 0.000000000000000000 +2.945450000000000013e-01 3.907089901094955503e-07 0.000000000000000000 +2.955400000000000249e-01 3.834327928155199364e-07 0.000000000000000000 +2.965349999999999930e-01 3.763025500396661164e-07 0.000000000000000000 +2.975300000000000167e-01 3.693150418962285531e-07 0.000000000000000000 +2.985249999999999848e-01 3.624671275491292328e-07 0.000000000000000000 +2.995200000000000085e-01 3.557557430487765712e-07 0.000000000000000000 +3.005150000000000321e-01 3.491778992339947667e-07 0.000000000000000000 +3.015100000000000002e-01 3.427306796976922247e-07 0.000000000000000000 +3.025050000000000239e-01 3.364112388139378583e-07 0.000000000000000000 +3.034999999999999920e-01 3.302167998242062930e-07 0.000000000000000000 +3.044950000000000156e-01 3.241446529812717644e-07 0.000000000000000000 +3.054899999999999838e-01 3.181921537481003399e-07 0.000000000000000000 +3.064850000000000074e-01 3.123567210511762908e-07 0.000000000000000000 +3.074800000000000311e-01 3.066358355846650517e-07 0.000000000000000000 +3.084749999999999992e-01 3.010270381660337490e-07 0.000000000000000000 +3.094700000000000228e-01 2.955279281388950346e-07 0.000000000000000000 +3.104649999999999910e-01 2.901361618240254941e-07 0.000000000000000000 +3.114600000000000146e-01 2.848494510149534469e-07 0.000000000000000000 +3.124549999999999828e-01 2.796655615181440895e-07 0.000000000000000000 +3.134500000000000064e-01 2.745823117354215134e-07 0.000000000000000000 +3.144450000000000300e-01 2.695975712878325508e-07 0.000000000000000000 +3.154399999999999982e-01 2.647092596790410133e-07 0.000000000000000000 +3.164350000000000218e-01 2.599153449978837568e-07 0.000000000000000000 +3.174299999999999899e-01 2.552138426577992562e-07 0.000000000000000000 +3.184250000000000136e-01 2.506028141727277769e-07 0.000000000000000000 +3.194199999999999817e-01 2.460803659680998870e-07 0.000000000000000000 +3.204150000000000054e-01 2.416446482256505412e-07 0.000000000000000000 +3.214100000000000290e-01 2.372938537613893963e-07 0.000000000000000000 +3.224049999999999971e-01 2.330262169348859350e-07 0.000000000000000000 +3.234000000000000208e-01 2.288400125900244041e-07 0.000000000000000000 +3.243949999999999889e-01 2.247335550253473878e-07 0.000000000000000000 +3.253900000000000126e-01 2.207051969933976064e-07 0.000000000000000000 +3.263849999999999807e-01 2.167533287283641152e-07 0.000000000000000000 +3.273800000000000043e-01 2.128763770004190671e-07 0.000000000000000000 +3.283750000000000280e-01 2.090728041971626540e-07 0.000000000000000000 +3.293699999999999961e-01 2.053411074299329102e-07 0.000000000000000000 +3.303650000000000198e-01 2.016798176654320889e-07 0.000000000000000000 +3.313599999999999879e-01 1.980874988810449717e-07 0.000000000000000000 +3.323550000000000115e-01 1.945627472435601437e-07 0.000000000000000000 +3.333499999999999797e-01 1.911041903105379646e-07 0.000000000000000000 +3.343450000000000033e-01 1.877104862536845619e-07 0.000000000000000000 +3.353400000000000269e-01 1.843803231029639430e-07 0.000000000000000000 +3.363349999999999951e-01 1.811124180120913374e-07 0.000000000000000000 +3.373300000000000187e-01 1.779055165433834375e-07 0.000000000000000000 +3.383249999999999869e-01 1.747583919723379171e-07 0.000000000000000000 +3.393200000000000105e-01 1.716698446108473038e-07 0.000000000000000000 +3.403150000000000341e-01 1.686387011487514324e-07 0.000000000000000000 +3.413100000000000023e-01 1.656638140131796811e-07 0.000000000000000000 +3.423050000000000259e-01 1.627440607449233080e-07 0.000000000000000000 +3.432999999999999940e-01 1.598783433915807615e-07 0.000000000000000000 +3.442950000000000177e-01 1.570655879169011439e-07 0.000000000000000000 +3.452899999999999858e-01 1.543047436258950896e-07 0.000000000000000000 +3.462850000000000095e-01 1.515947826050264808e-07 0.000000000000000000 +3.472800000000000331e-01 1.489346991773542697e-07 0.000000000000000000 +3.482750000000000012e-01 1.463235093721429985e-07 0.000000000000000000 +3.492700000000000249e-01 1.437602504082063715e-07 0.000000000000000000 +3.502649999999999930e-01 1.412439801910185004e-07 0.000000000000000000 +3.512600000000000167e-01 1.387737768228775831e-07 0.000000000000000000 +3.522549999999999848e-01 1.363487381259259015e-07 0.000000000000000000 +3.532500000000000084e-01 1.339679811775864490e-07 0.000000000000000000 +3.542450000000000321e-01 1.316306418580024381e-07 0.000000000000000000 +3.552400000000000002e-01 1.293358744093316699e-07 0.000000000000000000 +3.562350000000000239e-01 1.270828510063341282e-07 0.000000000000000000 +3.572299999999999920e-01 1.248707613379087200e-07 0.000000000000000000 +3.582250000000000156e-01 1.226988121998597123e-07 0.000000000000000000 +3.592199999999999838e-01 1.205662270974316575e-07 0.000000000000000000 +3.602150000000000074e-01 1.184722458585421587e-07 0.000000000000000000 +3.612100000000000311e-01 1.164161242567355819e-07 0.000000000000000000 +3.622049999999999992e-01 1.143971336435086992e-07 0.000000000000000000 +3.632000000000000228e-01 1.124145605904174832e-07 0.000000000000000000 +3.641949999999999910e-01 1.104677065397677744e-07 0.000000000000000000 +3.651900000000000146e-01 1.085558874643744278e-07 0.000000000000000000 +3.661849999999999827e-01 1.066784335360411807e-07 0.000000000000000000 +3.671800000000000064e-01 1.048346888019738436e-07 0.000000000000000000 +3.681750000000000300e-01 1.030240108696256120e-07 0.000000000000000000 +3.691699999999999982e-01 1.012457705992769268e-07 0.000000000000000000 +3.701650000000000218e-01 9.949935180445753679e-08 0.000000000000000000 +3.711599999999999899e-01 9.778415095948028884e-08 0.000000000000000000 +3.721550000000000136e-01 9.609957691461342208e-08 0.000000000000000000 +3.731499999999999817e-01 9.444505061804599980e-08 0.000000000000000000 +3.741450000000000053e-01 9.282000484481748754e-08 0.000000000000000000 +3.751400000000000290e-01 9.122388393244832792e-08 0.000000000000000000 +3.761349999999999971e-01 8.965614352301605240e-08 0.000000000000000000 +3.771300000000000208e-01 8.811625031155657185e-08 0.000000000000000000 +3.781249999999999889e-01 8.660368180062064381e-08 0.000000000000000000 +3.791200000000000125e-01 8.511792606090979959e-08 0.000000000000000000 +3.801149999999999807e-01 8.365848149753766865e-08 0.000000000000000000 +3.811100000000000043e-01 8.222485662219406386e-08 0.000000000000000000 +3.821050000000000280e-01 8.081656983069726827e-08 0.000000000000000000 +3.830999999999999961e-01 7.943314918590569788e-08 0.000000000000000000 +3.840950000000000197e-01 7.807413220591217810e-08 0.000000000000000000 +3.850899999999999879e-01 7.673906565739948301e-08 0.000000000000000000 +3.860850000000000115e-01 7.542750535373204618e-08 0.000000000000000000 +3.870799999999999796e-01 7.413901595817632364e-08 0.000000000000000000 +3.880750000000000033e-01 7.287317079158164557e-08 0.000000000000000000 +3.890700000000000269e-01 7.162955164475418635e-08 0.000000000000000000 +3.900649999999999951e-01 7.040774859527686503e-08 0.000000000000000000 +3.910600000000000187e-01 6.920735982860711948e-08 0.000000000000000000 +3.920549999999999868e-01 6.802799146356765812e-08 0.000000000000000000 +3.930500000000000105e-01 6.686925738177639130e-08 0.000000000000000000 +3.940450000000000341e-01 6.573077906118054173e-08 0.000000000000000000 +3.950400000000000023e-01 6.461218541347500975e-08 0.000000000000000000 +3.960350000000000259e-01 6.351311262541379473e-08 0.000000000000000000 +3.970299999999999940e-01 6.243320400370203637e-08 0.000000000000000000 +3.980250000000000177e-01 6.137210982358970926e-08 0.000000000000000000 +3.990199999999999858e-01 6.032948718098469951e-08 0.000000000000000000 +4.000150000000000095e-01 5.930499984799508768e-08 0.000000000000000000 +4.010100000000000331e-01 5.829831813179890142e-08 0.000000000000000000 +4.020050000000000012e-01 5.730911873679025764e-08 0.000000000000000000 +4.030000000000000249e-01 5.633708462991893812e-08 0.000000000000000000 +4.039949999999999930e-01 5.538190490915735624e-08 0.000000000000000000 +4.049900000000000166e-01 5.444327467487663858e-08 0.000000000000000000 +4.059849999999999848e-01 5.352089490429422662e-08 0.000000000000000000 +4.069800000000000084e-01 5.261447232878746078e-08 0.000000000000000000 +4.079750000000000321e-01 5.172371931388542301e-08 0.000000000000000000 +4.089700000000000002e-01 5.084835374211253429e-08 0.000000000000000000 +4.099650000000000238e-01 4.998809889844755150e-08 0.000000000000000000 +4.109599999999999920e-01 4.914268335846344356e-08 0.000000000000000000 +4.119550000000000156e-01 4.831184087875673132e-08 0.000000000000000000 +4.129499999999999837e-01 4.749531029020172877e-08 0.000000000000000000 +4.139450000000000074e-01 4.669283539330103853e-08 0.000000000000000000 +4.149400000000000310e-01 4.590416485605566593e-08 0.000000000000000000 +4.159349999999999992e-01 4.512905211408358873e-08 0.000000000000000000 +4.169300000000000228e-01 4.436725527296136481e-08 0.000000000000000000 +4.179249999999999909e-01 4.361853701276109034e-08 0.000000000000000000 +4.189200000000000146e-01 4.288266449474032394e-08 0.000000000000000000 +4.199149999999999827e-01 4.215940926999557206e-08 0.000000000000000000 +4.209100000000000064e-01 4.144854719035587216e-08 0.000000000000000000 +4.219050000000000300e-01 4.074985832100385988e-08 0.000000000000000000 +4.228999999999999981e-01 4.006312685518982154e-08 0.000000000000000000 +4.238950000000000218e-01 3.938814103081402333e-08 0.000000000000000000 +4.248899999999999899e-01 3.872469304875328655e-08 0.000000000000000000 +4.258850000000000136e-01 3.807257899308821213e-08 0.000000000000000000 +4.268799999999999817e-01 3.743159875300075409e-08 0.000000000000000000 +4.278750000000000053e-01 3.680155594641652206e-08 0.000000000000000000 +4.288700000000000290e-01 3.618225784535955942e-08 0.000000000000000000 +4.298649999999999971e-01 3.557351530280438460e-08 0.000000000000000000 +4.308600000000000207e-01 3.497514268124120271e-08 0.000000000000000000 +4.318549999999999889e-01 3.438695778272888431e-08 0.000000000000000000 +4.328500000000000125e-01 3.380878178052697901e-08 0.000000000000000000 +4.338449999999999807e-01 3.324043915208500011e-08 0.000000000000000000 +4.348400000000000043e-01 3.268175761362234442e-08 0.000000000000000000 +4.358350000000000279e-01 3.213256805597840426e-08 0.000000000000000000 +4.368299999999999961e-01 3.159270448196308571e-08 0.000000000000000000 +4.378250000000000197e-01 3.106200394495490724e-08 0.000000000000000000 +4.388199999999999878e-01 3.054030648889349978e-08 0.000000000000000000 +4.398150000000000115e-01 3.002745508947083052e-08 0.000000000000000000 +4.408100000000000351e-01 2.952329559662719818e-08 0.000000000000000000 +4.418050000000000033e-01 2.902767667829952025e-08 0.000000000000000000 +4.428000000000000269e-01 2.854044976526795720e-08 0.000000000000000000 +4.437949999999999950e-01 2.806146899727338396e-08 0.000000000000000000 +4.447900000000000187e-01 2.759059117018932799e-08 0.000000000000000000 +4.457849999999999868e-01 2.712767568439074514e-08 0.000000000000000000 +4.467800000000000105e-01 2.667258449415284049e-08 0.000000000000000000 +4.477750000000000341e-01 2.622518205811867270e-08 0.000000000000000000 +4.487700000000000022e-01 2.578533529082613517e-08 0.000000000000000000 +4.497650000000000259e-01 2.535291351522951938e-08 0.000000000000000000 +4.507599999999999940e-01 2.492778841627287470e-08 0.000000000000000000 +4.517550000000000177e-01 2.450983399531671096e-08 0.000000000000000000 +4.527499999999999858e-01 2.409892652562846511e-08 0.000000000000000000 +4.537450000000000094e-01 2.369494450875368376e-08 0.000000000000000000 +4.547400000000000331e-01 2.329776863176683936e-08 0.000000000000000000 +4.557350000000000012e-01 2.290728172544141217e-08 0.000000000000000000 +4.567300000000000249e-01 2.252336872328070319e-08 0.000000000000000000 +4.577249999999999930e-01 2.214591662139746355e-08 0.000000000000000000 +4.587200000000000166e-01 2.177481443920168254e-08 0.000000000000000000 +4.597149999999999848e-01 2.140995318088074199e-08 0.000000000000000000 +4.607100000000000084e-01 2.105122579775599487e-08 0.000000000000000000 +4.617050000000000320e-01 2.069852715129059986e-08 0.000000000000000000 +4.627000000000000002e-01 2.035175397696612041e-08 0.000000000000000000 +4.636950000000000238e-01 2.001080484878018436e-08 0.000000000000000000 +4.646899999999999920e-01 1.967558014460917590e-08 0.000000000000000000 +4.656850000000000156e-01 1.934598201213554117e-08 0.000000000000000000 +4.666799999999999837e-01 1.902191433555517809e-08 0.000000000000000000 +4.676750000000000074e-01 1.870328270293666115e-08 0.000000000000000000 +4.686700000000000310e-01 1.838999437423243993e-08 0.000000000000000000 +4.696649999999999991e-01 1.808195824993965897e-08 0.000000000000000000 +4.706600000000000228e-01 1.777908484038484727e-08 0.000000000000000000 +4.716549999999999909e-01 1.748128623567682730e-08 0.000000000000000000 +4.726500000000000146e-01 1.718847607616211987e-08 0.000000000000000000 +4.736449999999999827e-01 1.690056952359754085e-08 0.000000000000000000 +4.746400000000000063e-01 1.661748323278907984e-08 0.000000000000000000 +4.756350000000000300e-01 1.633913532386936203e-08 0.000000000000000000 +4.766299999999999981e-01 1.606544535509242241e-08 0.000000000000000000 +4.776250000000000218e-01 1.579633429619561801e-08 0.000000000000000000 +4.786199999999999899e-01 1.553172450226774170e-08 0.000000000000000000 +4.796150000000000135e-01 1.527153968812958752e-08 0.000000000000000000 +4.806099999999999817e-01 1.501570490329198411e-08 0.000000000000000000 +4.816050000000000053e-01 1.476414650728518093e-08 0.000000000000000000 +4.826000000000000290e-01 1.451679214561021136e-08 0.000000000000000000 +4.835949999999999971e-01 1.427357072605299284e-08 0.000000000000000000 +4.845900000000000207e-01 1.403441239554192092e-08 0.000000000000000000 +4.855849999999999889e-01 1.379924851741501211e-08 0.000000000000000000 +4.865800000000000125e-01 1.356801164916471703e-08 0.000000000000000000 +4.875749999999999806e-01 1.334063552058006977e-08 0.000000000000000000 +4.885700000000000043e-01 1.311705501236100186e-08 0.000000000000000000 +4.895650000000000279e-01 1.289720613511240166e-08 0.000000000000000000 +4.905599999999999961e-01 1.268102600878624253e-08 0.000000000000000000 +4.915550000000000197e-01 1.246845284246573869e-08 0.000000000000000000 +4.925499999999999878e-01 1.225942591461487445e-08 0.000000000000000000 +4.935450000000000115e-01 1.205388555364954470e-08 0.000000000000000000 +4.945400000000000351e-01 1.185177311892213667e-08 0.000000000000000000 +4.955350000000000033e-01 1.165303098206406425e-08 0.000000000000000000 +4.965300000000000269e-01 1.145760250866327575e-08 0.000000000000000000 +4.975249999999999950e-01 1.126543204035432285e-08 0.000000000000000000 +4.985200000000000187e-01 1.107646487718022137e-08 0.000000000000000000 +4.995149999999999868e-01 1.089064726035936574e-08 0.000000000000000000 +5.005100000000000104e-01 1.070792635533893917e-08 0.000000000000000000 +5.015049999999999786e-01 1.052825023518430476e-08 0.000000000000000000 +5.024999999999999467e-01 1.035156786429983128e-08 0.000000000000000000 +5.034950000000000259e-01 1.017782908245194928e-08 0.000000000000000000 +5.044899999999999940e-01 1.000698458908213401e-08 0.000000000000000000 +5.054849999999999621e-01 9.838985927942606211e-09 0.000000000000000000 +5.064800000000000413e-01 9.673785472016118153e-09 0.000000000000000000 +5.074750000000000094e-01 9.511336408707597594e-09 0.000000000000000000 +5.084699999999999775e-01 9.351592725336316339e-09 0.000000000000000000 +5.094650000000000567e-01 9.194509194901617369e-09 0.000000000000000000 +5.104600000000000248e-01 9.040041362103622041e-09 0.000000000000000000 +5.114549999999999930e-01 8.888145529627538254e-09 0.000000000000000000 +5.124499999999999611e-01 8.738778744717595970e-09 0.000000000000000000 +5.134450000000000403e-01 8.591898785946051782e-09 0.000000000000000000 +5.144400000000000084e-01 8.447464150305248862e-09 0.000000000000000000 +5.154349999999999765e-01 8.305434040478789650e-09 0.000000000000000000 +5.164300000000000557e-01 8.165768352358212425e-09 0.000000000000000000 +5.174250000000000238e-01 8.028427662851563377e-09 0.000000000000000000 +5.184199999999999919e-01 7.893373217842216118e-09 0.000000000000000000 +5.194149999999999601e-01 7.760566920435978511e-09 0.000000000000000000 +5.204100000000000392e-01 7.629971319358478376e-09 0.000000000000000000 +5.214050000000000074e-01 7.501549597652244998e-09 0.000000000000000000 +5.223999999999999755e-01 7.375265561526750397e-09 0.000000000000000000 +5.233950000000000546e-01 7.251083629405264984e-09 0.000000000000000000 +5.243900000000000228e-01 7.128968821243475963e-09 0.000000000000000000 +5.253849999999999909e-01 7.008886747960125850e-09 0.000000000000000000 +5.263799999999999590e-01 6.890803601115932548e-09 0.000000000000000000 +5.273750000000000382e-01 6.774686142796504578e-09 0.000000000000000000 +5.283700000000000063e-01 6.660501695615936994e-09 0.000000000000000000 +5.293649999999999745e-01 6.548218132964528978e-09 0.000000000000000000 +5.303600000000000536e-01 6.437803869424564685e-09 0.000000000000000000 +5.313550000000000217e-01 6.329227851337567396e-09 0.000000000000000000 +5.323499999999999899e-01 6.222459547568204285e-09 0.000000000000000000 +5.333449999999999580e-01 6.117468940427315924e-09 0.000000000000000000 +5.343400000000000372e-01 6.014226516756166591e-09 0.000000000000000000 +5.353350000000000053e-01 5.912703259200147065e-09 0.000000000000000000 +5.363299999999999734e-01 5.812870637596286722e-09 0.000000000000000000 +5.373250000000000526e-01 5.714700600562036045e-09 0.000000000000000000 +5.383200000000000207e-01 5.618165567214210133e-09 0.000000000000000000 +5.393149999999999888e-01 5.523238419030037714e-09 0.000000000000000000 +5.403099999999999570e-01 5.429892491889169139e-09 0.000000000000000000 +5.413050000000000361e-01 5.338101568217842023e-09 0.000000000000000000 +5.423000000000000043e-01 5.247839869312100044e-09 0.000000000000000000 +5.432949999999999724e-01 5.159082047782700767e-09 0.000000000000000000 +5.442900000000000515e-01 5.071803180117107580e-09 0.000000000000000000 +5.452850000000000197e-01 4.985978759425942900e-09 0.000000000000000000 +5.462799999999999878e-01 4.901584688272952708e-09 0.000000000000000000 +5.472749999999999559e-01 4.818597271653313524e-09 0.000000000000000000 +5.482700000000000351e-01 4.736993210097703913e-09 0.000000000000000000 +5.492650000000000032e-01 4.656749592899734273e-09 0.000000000000000000 +5.502599999999999714e-01 4.577843891457445651e-09 0.000000000000000000 +5.512550000000000505e-01 4.500253952754923854e-09 0.000000000000000000 +5.522500000000000187e-01 4.423957992928620999e-09 0.000000000000000000 +5.532449999999999868e-01 4.348934590969638247e-09 0.000000000000000000 +5.542399999999999549e-01 4.275162682547729828e-09 0.000000000000000000 +5.552350000000000341e-01 4.202621553908566314e-09 0.000000000000000000 +5.562300000000000022e-01 4.131290835932150873e-09 0.000000000000000000 +5.572249999999999703e-01 4.061150498237967917e-09 0.000000000000000000 +5.582200000000000495e-01 3.992180843446344811e-09 0.000000000000000000 +5.592150000000000176e-01 3.924362501509357965e-09 0.000000000000000000 +5.602099999999999858e-01 3.857676424154716910e-09 0.000000000000000000 +5.612049999999999539e-01 3.792103879430714948e-09 0.000000000000000000 +5.622000000000000330e-01 3.727626446332447825e-09 0.000000000000000000 +5.631950000000000012e-01 3.664226009549415779e-09 0.000000000000000000 +5.641899999999999693e-01 3.601884754267642989e-09 0.000000000000000000 +5.651850000000000485e-01 3.540585161106631196e-09 0.000000000000000000 +5.661800000000000166e-01 3.480310001116348841e-09 0.000000000000000000 +5.671749999999999847e-01 3.421042330867932332e-09 0.000000000000000000 +5.681700000000000639e-01 3.362765487628045872e-09 0.000000000000000000 +5.691650000000000320e-01 3.305463084633811144e-09 0.000000000000000000 +5.701600000000000001e-01 3.249119006439248004e-09 0.000000000000000000 +5.711549999999999683e-01 3.193717404330445612e-09 0.000000000000000000 +5.721500000000000474e-01 3.139242691846669754e-09 0.000000000000000000 +5.731450000000000156e-01 3.085679540359040699e-09 0.000000000000000000 +5.741399999999999837e-01 3.033012874741313056e-09 0.000000000000000000 +5.751350000000000628e-01 2.981227869103609884e-09 0.000000000000000000 +5.761300000000000310e-01 2.930309942605486299e-09 0.000000000000000000 +5.771249999999999991e-01 2.880244755344017550e-09 0.000000000000000000 +5.781199999999999672e-01 2.831018204320024633e-09 0.000000000000000000 +5.791150000000000464e-01 2.782616419444479799e-09 0.000000000000000000 +5.801100000000000145e-01 2.735025759662029664e-09 0.000000000000000000 +5.811049999999999827e-01 2.688232809096205337e-09 0.000000000000000000 +5.821000000000000618e-01 2.642224373286249017e-09 0.000000000000000000 +5.830950000000000299e-01 2.596987475486436551e-09 0.000000000000000000 +5.840899999999999981e-01 2.552509353022799725e-09 0.000000000000000000 +5.850849999999999662e-01 2.508777453719068253e-09 0.000000000000000000 +5.860800000000000454e-01 2.465779432375947976e-09 0.000000000000000000 +5.870750000000000135e-01 2.423503147329195027e-09 0.000000000000000000 +5.880699999999999816e-01 2.381936657034776456e-09 0.000000000000000000 +5.890650000000000608e-01 2.341068216750600869e-09 0.000000000000000000 +5.900600000000000289e-01 2.300886275249319634e-09 0.000000000000000000 +5.910549999999999971e-01 2.261379471589899679e-09 0.000000000000000000 +5.920499999999999652e-01 2.222536631965092181e-09 0.000000000000000000 +5.930450000000000443e-01 2.184346766572887835e-09 0.000000000000000000 +5.940400000000000125e-01 2.146799066563923027e-09 0.000000000000000000 +5.950349999999999806e-01 2.109882901029975367e-09 0.000000000000000000 +5.960300000000000598e-01 2.073587814052807845e-09 0.000000000000000000 +5.970250000000000279e-01 2.037903521796197191e-09 0.000000000000000000 +5.980199999999999960e-01 2.002819909644348453e-09 0.000000000000000000 +5.990149999999999642e-01 1.968327029405863638e-09 0.000000000000000000 +6.000100000000000433e-01 1.934415096543460493e-09 0.000000000000000000 +6.010050000000000114e-01 1.901074487462710610e-09 0.000000000000000000 +6.019999999999999796e-01 1.868295736852988358e-09 0.000000000000000000 +6.029950000000000587e-01 1.836069535059167139e-09 0.000000000000000000 +6.039900000000000269e-01 1.804386725507524731e-09 0.000000000000000000 +6.049849999999999950e-01 1.773238302172079969e-09 0.000000000000000000 +6.059799999999999631e-01 1.742615407085404039e-09 0.000000000000000000 +6.069750000000000423e-01 1.712509327890016968e-09 0.000000000000000000 +6.079700000000000104e-01 1.682911495434136928e-09 0.000000000000000000 +6.089649999999999785e-01 1.653813481399450726e-09 0.000000000000000000 +6.099600000000000577e-01 1.625206995987396573e-09 0.000000000000000000 +6.109550000000000258e-01 1.597083885620513122e-09 0.000000000000000000 +6.119499999999999940e-01 1.569436130702139067e-09 0.000000000000000000 +6.129449999999999621e-01 1.542255843404127068e-09 0.000000000000000000 +6.139400000000000412e-01 1.515535265493257126e-09 0.000000000000000000 +6.149350000000000094e-01 1.489266766199405405e-09 0.000000000000000000 +6.159299999999999775e-01 1.463442840109179879e-09 0.000000000000000000 +6.169250000000000567e-01 1.438056105105303416e-09 0.000000000000000000 +6.179200000000000248e-01 1.413099300335438690e-09 0.000000000000000000 +6.189149999999999929e-01 1.388565284219914378e-09 0.000000000000000000 +6.199099999999999611e-01 1.364447032482016621e-09 0.000000000000000000 +6.209050000000000402e-01 1.340737636223382316e-09 0.000000000000000000 +6.219000000000000083e-01 1.317430300025572456e-09 0.000000000000000000 +6.228949999999999765e-01 1.294518340085705259e-09 0.000000000000000000 +6.238900000000000556e-01 1.271995182379897042e-09 0.000000000000000000 +6.248850000000000238e-01 1.249854360861907686e-09 0.000000000000000000 +6.258799999999999919e-01 1.228089515688482748e-09 0.000000000000000000 +6.268749999999999600e-01 1.206694391477565856e-09 0.000000000000000000 +6.278700000000000392e-01 1.185662835590238378e-09 0.000000000000000000 +6.288650000000000073e-01 1.164988796445623888e-09 0.000000000000000000 +6.298599999999999755e-01 1.144666321867794175e-09 0.000000000000000000 +6.308550000000000546e-01 1.124689557446997487e-09 0.000000000000000000 +6.318500000000000227e-01 1.105052744945311523e-09 0.000000000000000000 +6.328449999999999909e-01 1.085750220710908845e-09 0.000000000000000000 +6.338399999999999590e-01 1.066776414137267750e-09 0.000000000000000000 +6.348350000000000382e-01 1.048125846132423263e-09 0.000000000000000000 +6.358300000000000063e-01 1.029793127619577583e-09 0.000000000000000000 +6.368249999999999744e-01 1.011772958067064884e-09 0.000000000000000000 +6.378200000000000536e-01 9.940601240353204801e-10 0.000000000000000000 +6.388150000000000217e-01 9.766494977525064135e-10 0.000000000000000000 +6.398099999999999898e-01 9.595360357101928669e-10 0.000000000000000000 +6.408049999999999580e-01 9.427147772883389336e-10 0.000000000000000000 +6.418000000000000371e-01 9.261808433944503319e-10 0.000000000000000000 +6.427950000000000053e-01 9.099294351329261107e-10 0.000000000000000000 +6.437899999999999734e-01 8.939558324953548407e-10 0.000000000000000000 +6.447850000000000525e-01 8.782553930644280603e-10 0.000000000000000000 +6.457800000000000207e-01 8.628235507521241244e-10 0.000000000000000000 +6.467749999999999888e-01 8.476558145459802247e-10 0.000000000000000000 +6.477699999999999569e-01 8.327477672877727265e-10 0.000000000000000000 +6.487650000000000361e-01 8.180950644622847663e-10 0.000000000000000000 +6.497600000000000042e-01 8.036934330121838051e-10 0.000000000000000000 +6.507549999999999724e-01 7.895386701715532421e-10 0.000000000000000000 +6.517500000000000515e-01 7.756266423150475058e-10 0.000000000000000000 +6.527450000000000196e-01 7.619532838310401384e-10 0.000000000000000000 +6.537399999999999878e-01 7.485145960110557591e-10 0.000000000000000000 +6.547349999999999559e-01 7.353066459561349298e-10 0.000000000000000000 +6.557300000000000351e-01 7.223255655019091240e-10 0.000000000000000000 +6.567250000000000032e-01 7.095675501633230957e-10 0.000000000000000000 +6.577199999999999713e-01 6.970288580952831633e-10 0.000000000000000000 +6.587150000000000505e-01 6.847058090697376434e-10 0.000000000000000000 +6.597100000000000186e-01 6.725947834695765550e-10 0.000000000000000000 +6.607049999999999867e-01 6.606922213008890459e-10 0.000000000000000000 +6.616999999999999549e-01 6.489946212177306857e-10 0.000000000000000000 +6.626950000000000340e-01 6.374985395695149751e-10 0.000000000000000000 +6.636900000000000022e-01 6.262005894555813714e-10 0.000000000000000000 +6.646849999999999703e-01 6.150974398006807465e-10 0.000000000000000000 +6.656800000000000495e-01 6.041858144460597144e-10 0.000000000000000000 +6.666750000000000176e-01 5.934624912519768004e-10 0.000000000000000000 +6.676699999999999857e-01 5.829243012166442471e-10 0.000000000000000000 +6.686650000000000649e-01 5.725681276106499875e-10 0.000000000000000000 +6.696600000000000330e-01 5.623909051228168385e-10 0.000000000000000000 +6.706550000000000011e-01 5.523896190237439203e-10 0.000000000000000000 +6.716499999999999693e-01 5.425613043398145989e-10 0.000000000000000000 +6.726450000000000484e-01 5.329030450417581546e-10 0.000000000000000000 +6.736400000000000166e-01 5.234119732464745679e-10 0.000000000000000000 +6.746349999999999847e-01 5.140852684323522755e-10 0.000000000000000000 +6.756300000000000638e-01 5.049201566664096458e-10 0.000000000000000000 +6.766250000000000320e-01 4.959139098454811543e-10 0.000000000000000000 +6.776200000000000001e-01 4.870638449487790499e-10 0.000000000000000000 +6.786149999999999682e-01 4.783673233012896401e-10 0.000000000000000000 +6.796100000000000474e-01 4.698217498523995215e-10 0.000000000000000000 +6.806050000000000155e-01 4.614245724643800463e-10 0.000000000000000000 +6.815999999999999837e-01 4.531732812111723066e-10 0.000000000000000000 +6.825950000000000628e-01 4.450654076920853576e-10 0.000000000000000000 +6.835900000000000309e-01 4.370985243527584836e-10 0.000000000000000000 +6.845849999999999991e-01 4.292702438197627921e-10 0.000000000000000000 +6.855799999999999672e-01 4.215782182455686226e-10 0.000000000000000000 +6.865750000000000464e-01 4.140201386645318280e-10 0.000000000000000000 +6.875700000000000145e-01 4.065937343561940905e-10 0.000000000000000000 +6.885649999999999826e-01 3.992967722240903926e-10 0.000000000000000000 +6.895600000000000618e-01 3.921270561814422491e-10 0.000000000000000000 +6.905550000000000299e-01 3.850824265461304586e-10 0.000000000000000000 +6.915499999999999980e-01 3.781607594477758664e-10 0.000000000000000000 +6.925449999999999662e-01 3.713599662443719948e-10 0.000000000000000000 +6.935400000000000453e-01 3.646779929451460856e-10 0.000000000000000000 +6.945350000000000135e-01 3.581128196474731658e-10 0.000000000000000000 +6.955299999999999816e-01 3.516624599789905450e-10 0.000000000000000000 +6.965250000000000608e-01 3.453249605512386629e-10 0.000000000000000000 +6.975200000000000289e-01 3.390984004204496542e-10 0.000000000000000000 +6.985149999999999970e-01 3.329808905590815081e-10 0.000000000000000000 +6.995099999999999651e-01 3.269705733336090213e-10 0.000000000000000000 +7.005050000000000443e-01 3.210656219930606029e-10 0.000000000000000000 +7.015000000000000124e-01 3.152642401639120136e-10 0.000000000000000000 +7.024949999999999806e-01 3.095646613535301542e-10 0.000000000000000000 +7.034900000000000597e-01 3.039651484643836440e-10 0.000000000000000000 +7.044850000000000279e-01 2.984639933103836991e-10 0.000000000000000000 +7.054799999999999960e-01 2.930595161482421644e-10 0.000000000000000000 +7.064749999999999641e-01 2.877500652096199171e-10 0.000000000000000000 +7.074700000000000433e-01 2.825340162463892363e-10 0.000000000000000000 +7.084650000000000114e-01 2.774097720789625829e-10 0.000000000000000000 +7.094599999999999795e-01 2.723757621550416838e-10 0.000000000000000000 +7.104550000000000587e-01 2.674304421138305059e-10 0.000000000000000000 +7.114500000000000268e-01 2.625722933581207666e-10 0.000000000000000000 +7.124449999999999950e-01 2.577998226317362304e-10 0.000000000000000000 +7.134399999999999631e-01 2.531115616069366224e-10 0.000000000000000000 +7.144350000000000422e-01 2.485060664753810539e-10 0.000000000000000000 +7.154300000000000104e-01 2.439819175467779222e-10 0.000000000000000000 +7.164249999999999785e-01 2.395377188552389620e-10 0.000000000000000000 +7.174200000000000577e-01 2.351720977695691270e-10 0.000000000000000000 +7.184150000000000258e-01 2.308837046132094100e-10 0.000000000000000000 +7.194099999999999939e-01 2.266712122853988755e-10 0.000000000000000000 +7.204049999999999621e-01 2.225333158951815671e-10 0.000000000000000000 +7.214000000000000412e-01 2.184687323937923984e-10 0.000000000000000000 +7.223950000000000093e-01 2.144762002199834842e-10 0.000000000000000000 +7.233899999999999775e-01 2.105544789457397629e-10 0.000000000000000000 +7.243850000000000566e-01 2.067023489314449509e-10 0.000000000000000000 +7.253800000000000248e-01 2.029186109836347890e-10 0.000000000000000000 +7.263749999999999929e-01 1.992020860208143683e-10 0.000000000000000000 +7.273699999999999610e-01 1.955516147432110017e-10 0.000000000000000000 +7.283650000000000402e-01 1.919660573080928565e-10 0.000000000000000000 +7.293600000000000083e-01 1.884442930107386533e-10 0.000000000000000000 +7.303549999999999764e-01 1.849852199707302973e-10 0.000000000000000000 +7.313500000000000556e-01 1.815877548214458977e-10 0.000000000000000000 +7.323450000000000237e-01 1.782508324083276738e-10 0.000000000000000000 +7.333399999999999919e-01 1.749734054871994406e-10 0.000000000000000000 +7.343349999999999600e-01 1.717544444327696856e-10 0.000000000000000000 +7.353300000000000392e-01 1.685929369464436664e-10 0.000000000000000000 +7.363250000000000073e-01 1.654878877736655847e-10 0.000000000000000000 +7.373199999999999754e-01 1.624383184224845999e-10 0.000000000000000000 +7.383150000000000546e-01 1.594432668877642051e-10 0.000000000000000000 +7.393100000000000227e-01 1.565017873814703209e-10 0.000000000000000000 +7.403049999999999908e-01 1.536129500638754654e-10 0.000000000000000000 +7.412999999999999590e-01 1.507758407823909257e-10 0.000000000000000000 +7.422950000000000381e-01 1.479895608131337696e-10 0.000000000000000000 +7.432900000000000063e-01 1.452532266062458961e-10 0.000000000000000000 +7.442849999999999744e-01 1.425659695365616108e-10 0.000000000000000000 +7.452800000000000535e-01 1.399269356573926378e-10 0.000000000000000000 +7.462750000000000217e-01 1.373352854587497921e-10 0.000000000000000000 +7.472699999999999898e-01 1.347901936294661017e-10 0.000000000000000000 +7.482649999999999579e-01 1.322908488223341237e-10 0.000000000000000000 +7.492600000000000371e-01 1.298364534248632290e-10 0.000000000000000000 +7.502550000000000052e-01 1.274262233316630721e-10 0.000000000000000000 +7.512499999999999734e-01 1.250593877217680957e-10 0.000000000000000000 +7.522450000000000525e-01 1.227351888398047800e-10 0.000000000000000000 +7.532400000000000206e-01 1.204528817793964409e-10 0.000000000000000000 +7.542349999999999888e-01 1.182117342713846246e-10 0.000000000000000000 +7.552299999999999569e-01 1.160110264747073532e-10 0.000000000000000000 +7.562250000000000361e-01 1.138500507714065408e-10 0.000000000000000000 +7.572200000000000042e-01 1.117281115635054185e-10 0.000000000000000000 +7.582149999999999723e-01 1.096445250754567631e-10 0.000000000000000000 +7.592100000000000515e-01 1.075986191572987652e-10 0.000000000000000000 +7.602050000000000196e-01 1.055897330930012879e-10 0.000000000000000000 +7.611999999999999877e-01 1.036172174105339540e-10 0.000000000000000000 +7.621949999999999559e-01 1.016804336962519086e-10 0.000000000000000000 +7.631900000000000350e-01 9.977875441096356335e-11 0.000000000000000000 +7.641850000000000032e-01 9.791156271008344962e-11 0.000000000000000000 +7.651799999999999713e-01 9.607825226625470990e-11 0.000000000000000000 +7.661750000000000504e-01 9.427822709455359464e-11 0.000000000000000000 +7.671700000000000186e-01 9.251090138124984059e-11 0.000000000000000000 +7.681649999999999867e-01 9.077569931482582088e-11 0.000000000000000000 +7.691599999999999548e-01 8.907205491965810509e-11 0.000000000000000000 +7.701550000000000340e-01 8.739941189288420762e-11 0.000000000000000000 +7.711500000000000021e-01 8.575722344352985258e-11 0.000000000000000000 +7.721449999999999703e-01 8.414495213434765917e-11 0.000000000000000000 +7.731400000000000494e-01 8.256206972622971592e-11 0.000000000000000000 +7.741350000000000176e-01 8.100805702532533275e-11 0.000000000000000000 +7.751299999999999857e-01 7.948240373228508669e-11 0.000000000000000000 +7.761250000000000648e-01 7.798460829422891543e-11 0.000000000000000000 +7.771200000000000330e-01 7.651417775903194526e-11 0.000000000000000000 +7.781150000000000011e-01 7.507062763206356851e-11 0.000000000000000000 +7.791099999999999692e-01 7.365348173517222601e-11 0.000000000000000000 +7.801050000000000484e-01 7.226227206788986404e-11 0.000000000000000000 +7.811000000000000165e-01 7.089653867113503250e-11 0.000000000000000000 +7.820949999999999847e-01 6.955582949297110040e-11 0.000000000000000000 +7.830900000000000638e-01 6.823970025633168779e-11 0.000000000000000000 +7.840850000000000319e-01 6.694771432965168588e-11 0.000000000000000000 +7.850800000000000001e-01 6.567944259862998955e-11 0.000000000000000000 +7.860749999999999682e-01 6.443446334061711945e-11 0.000000000000000000 +7.870700000000000474e-01 6.321236210132198715e-11 0.000000000000000000 +7.880650000000000155e-01 6.201273157282145684e-11 0.000000000000000000 +7.890599999999999836e-01 6.083517147412531346e-11 0.000000000000000000 +7.900550000000000628e-01 5.967928843341275616e-11 0.000000000000000000 +7.910500000000000309e-01 5.854469587245565986e-11 0.000000000000000000 +7.920449999999999990e-01 5.743101389234423935e-11 0.000000000000000000 +7.930399999999999672e-01 5.633786916210906675e-11 0.000000000000000000 +7.940350000000000463e-01 5.526489480788727048e-11 0.000000000000000000 +7.950300000000000145e-01 5.421173030509729357e-11 0.000000000000000000 +7.960249999999999826e-01 5.317802137138497194e-11 0.000000000000000000 +7.970200000000000617e-01 5.216341986217019749e-11 0.000000000000000000 +7.980150000000000299e-01 5.116758366718568742e-11 0.000000000000000000 +7.990099999999999980e-01 5.019017660923670763e-11 0.000000000000000000 +8.000049999999999661e-01 4.923086834421724464e-11 0.000000000000000000 +8.010000000000000453e-01 4.828933426320927044e-11 0.000000000000000000 +8.019950000000000134e-01 4.736525539558188763e-11 0.000000000000000000 +8.029899999999999816e-01 4.645831831438245641e-11 0.000000000000000000 +8.039850000000000607e-01 4.556821504268652730e-11 0.000000000000000000 +8.049800000000000288e-01 4.469464296170416256e-11 0.000000000000000000 +8.059749999999999970e-01 4.383730472068802512e-11 0.000000000000000000 +8.069699999999999651e-01 4.299590814766838308e-11 0.000000000000000000 +8.079650000000000443e-01 4.217016616230079168e-11 0.000000000000000000 +8.089600000000000124e-01 4.135979668960845514e-11 0.000000000000000000 +8.099549999999999805e-01 4.056452257571198034e-11 0.000000000000000000 +8.109500000000000597e-01 3.978407150433260260e-11 0.000000000000000000 +8.119450000000000278e-01 3.901817591526678961e-11 0.000000000000000000 +8.129399999999999959e-01 3.826657292356815587e-11 0.000000000000000000 +8.139349999999999641e-01 3.752900424059828834e-11 0.000000000000000000 +8.149300000000000432e-01 3.680521609627443136e-11 0.000000000000000000 +8.159250000000000114e-01 3.609495916209530939e-11 0.000000000000000000 +8.169199999999999795e-01 3.539798847631480826e-11 0.000000000000000000 +8.179150000000000587e-01 3.471406336951419588e-11 0.000000000000000000 +8.189100000000000268e-01 3.404294739185910951e-11 0.000000000000000000 +8.199049999999999949e-01 3.338440824150709322e-11 0.000000000000000000 +8.208999999999999631e-01 3.273821769404085850e-11 0.000000000000000000 +8.218950000000000422e-01 3.210415153329436856e-11 0.000000000000000000 +8.228900000000000103e-01 3.148198948294768353e-11 0.000000000000000000 +8.238849999999999785e-01 3.087151513973246205e-11 0.000000000000000000 +8.248800000000000576e-01 3.027251590737155331e-11 0.000000000000000000 +8.258750000000000258e-01 2.968478293185995294e-11 0.000000000000000000 +8.268699999999999939e-01 2.910811103743564697e-11 0.000000000000000000 +8.278649999999999620e-01 2.854229866422437845e-11 0.000000000000000000 +8.288600000000000412e-01 2.798714780617325204e-11 0.000000000000000000 +8.298550000000000093e-01 2.744246395074316365e-11 0.000000000000000000 +8.308499999999999774e-01 2.690805601903921905e-11 0.000000000000000000 +8.318450000000000566e-01 2.638373630713539760e-11 0.000000000000000000 +8.328400000000000247e-01 2.586932042855219276e-11 0.000000000000000000 +8.338349999999999929e-01 2.536462725737758588e-11 0.000000000000000000 +8.348299999999999610e-01 2.486947887248887770e-11 0.000000000000000000 +8.358250000000000401e-01 2.438370050272607173e-11 0.000000000000000000 +8.368200000000000083e-01 2.390712047288832168e-11 0.000000000000000000 +8.378149999999999764e-01 2.343957015071224223e-11 0.000000000000000000 +8.388100000000000556e-01 2.298088389467405944e-11 0.000000000000000000 +8.398050000000000237e-01 2.253089900258152798e-11 0.000000000000000000 +8.407999999999999918e-01 2.208945566131302509e-11 0.000000000000000000 +8.417949999999999600e-01 2.165639689701962011e-11 0.000000000000000000 +8.427900000000000391e-01 2.123156852639565456e-11 0.000000000000000000 +8.437850000000000072e-01 2.081481910870578539e-11 0.000000000000000000 +8.447799999999999754e-01 2.040599989851381981e-11 0.000000000000000000 +8.457750000000000545e-01 2.000496479944291845e-11 0.000000000000000000 +8.467700000000000227e-01 1.961157031843802305e-11 0.000000000000000000 +8.477649999999999908e-01 1.922567552086915531e-11 0.000000000000000000 +8.487599999999999589e-01 1.884714198652079419e-11 0.000000000000000000 +8.497550000000000381e-01 1.847583376615353297e-11 0.000000000000000000 +8.507500000000000062e-01 1.811161733888242197e-11 0.000000000000000000 +8.517449999999999743e-01 1.775436157018041761e-11 0.000000000000000000 +8.527400000000000535e-01 1.740393767069240377e-11 0.000000000000000000 +8.537350000000000216e-01 1.706021915565210826e-11 0.000000000000000000 +8.547299999999999898e-01 1.672308180502099934e-11 0.000000000000000000 +8.557249999999999579e-01 1.639240362433276411e-11 0.000000000000000000 +8.567200000000000371e-01 1.606806480605511399e-11 0.000000000000000000 +8.577150000000000052e-01 1.574994769175799766e-11 0.000000000000000000 +8.587099999999999733e-01 1.543793673481743599e-11 0.000000000000000000 +8.597050000000000525e-01 1.513191846380246931e-11 0.000000000000000000 +8.607000000000000206e-01 1.483178144642076169e-11 0.000000000000000000 +8.616949999999999887e-01 1.453741625408964590e-11 0.000000000000000000 +8.626899999999999569e-01 1.424871542717199542e-11 0.000000000000000000 +8.636850000000000360e-01 1.396557344067323184e-11 0.000000000000000000 +8.646800000000000042e-01 1.368788667062002115e-11 0.000000000000000000 +8.656749999999999723e-01 1.341555336091990615e-11 0.000000000000000000 +8.666700000000000514e-01 1.314847359090981869e-11 0.000000000000000000 +8.676650000000000196e-01 1.288654924319432812e-11 0.000000000000000000 +8.686599999999999877e-01 1.262968397242288672e-11 0.000000000000000000 +8.696549999999999558e-01 1.237778317413847121e-11 0.000000000000000000 +8.706500000000000350e-01 1.213075395458402982e-11 0.000000000000000000 +8.716450000000000031e-01 1.188850510063939789e-11 0.000000000000000000 +8.726399999999999713e-01 1.165094705056480650e-11 0.000000000000000000 +8.736350000000000504e-01 1.141799186504683717e-11 0.000000000000000000 +8.746300000000000185e-01 1.118955319883575737e-11 0.000000000000000000 +8.756249999999999867e-01 1.096554627279212947e-11 0.000000000000000000 +8.766200000000000658e-01 1.074588784648897165e-11 0.000000000000000000 +8.776150000000000340e-01 1.053049619119633637e-11 0.000000000000000000 +8.786100000000000021e-01 1.031929106337711392e-11 0.000000000000000000 +8.796049999999999702e-01 1.011219367860600992e-11 0.000000000000000000 +8.806000000000000494e-01 9.909126685931416669e-12 0.000000000000000000 +8.815950000000000175e-01 9.710014142709092467e-12 0.000000000000000000 +8.825899999999999856e-01 9.514781489789963117e-12 0.000000000000000000 +8.835850000000000648e-01 9.323355527214140165e-12 0.000000000000000000 +8.845800000000000329e-01 9.135664390280521159e-12 0.000000000000000000 +8.855750000000000011e-01 8.951637525956803811e-12 0.000000000000000000 +8.865699999999999692e-01 8.771205669848477140e-12 0.000000000000000000 +8.875650000000000484e-01 8.594300823370846695e-12 0.000000000000000000 +8.885600000000000165e-01 8.420856231485389200e-12 0.000000000000000000 +8.895549999999999846e-01 8.250806360685502162e-12 0.000000000000000000 +8.905500000000000638e-01 8.084086877442745888e-12 0.000000000000000000 +8.915450000000000319e-01 7.920634626948725029e-12 0.000000000000000000 +8.925400000000000000e-01 7.760387612281252380e-12 0.000000000000000000 +8.935349999999999682e-01 7.603284973905482060e-12 0.000000000000000000 +8.945300000000000473e-01 7.449266969506496546e-12 0.000000000000000000 +8.955250000000000155e-01 7.298274954195714714e-12 0.000000000000000000 +8.965199999999999836e-01 7.150251361045872353e-12 0.000000000000000000 +8.975150000000000627e-01 7.005139681932871316e-12 0.000000000000000000 +8.985100000000000309e-01 6.862884448759745745e-12 0.000000000000000000 +8.995049999999999990e-01 6.723431214957391286e-12 0.000000000000000000 +9.004999999999999671e-01 6.586726537320808128e-12 0.000000000000000000 +9.014950000000000463e-01 6.452717958148575220e-12 0.000000000000000000 +9.024900000000000144e-01 6.321353987697752509e-12 0.000000000000000000 +9.034849999999999826e-01 6.192584086955323570e-12 0.000000000000000000 +9.044800000000000617e-01 6.066358650650915654e-12 0.000000000000000000 +9.054750000000000298e-01 5.942628990640109593e-12 0.000000000000000000 +9.064699999999999980e-01 5.821347319489051845e-12 0.000000000000000000 +9.074649999999999661e-01 5.702466734432494170e-12 0.000000000000000000 +9.084600000000000453e-01 5.585941201518969179e-12 0.000000000000000000 +9.094550000000000134e-01 5.471725540095875727e-12 0.000000000000000000 +9.104499999999999815e-01 5.359775407532663075e-12 0.000000000000000000 +9.114450000000000607e-01 5.250047284201808633e-12 0.000000000000000000 +9.124400000000000288e-01 5.142498458759478234e-12 0.000000000000000000 +9.134349999999999969e-01 5.037087013620237808e-12 0.000000000000000000 +9.144299999999999651e-01 4.933771810723792127e-12 0.000000000000000000 +9.154250000000000442e-01 4.832512477559490473e-12 0.000000000000000000 +9.164200000000000124e-01 4.733269393382690548e-12 0.000000000000000000 +9.174149999999999805e-01 4.636003675708210934e-12 0.000000000000000000 +9.184100000000000597e-01 4.540677167043161048e-12 0.000000000000000000 +9.194050000000000278e-01 4.447252421825848935e-12 0.000000000000000000 +9.203999999999999959e-01 4.355692693609114473e-12 0.000000000000000000 +9.213949999999999640e-01 4.265961922438394138e-12 0.000000000000000000 +9.223900000000000432e-01 4.178024722488739340e-12 0.000000000000000000 +9.233850000000000113e-01 4.091846369909820615e-12 0.000000000000000000 +9.243799999999999795e-01 4.007392790829750474e-12 0.000000000000000000 +9.253750000000000586e-01 3.924630549657840782e-12 0.000000000000000000 +9.263700000000000268e-01 3.843526837507154298e-12 0.000000000000000000 +9.273649999999999949e-01 3.764049460866051308e-12 0.000000000000000000 +9.283599999999999630e-01 3.686166830456769560e-12 0.000000000000000000 +9.293550000000000422e-01 3.609847950283756110e-12 0.000000000000000000 +9.303500000000000103e-01 3.535062406887417040e-12 0.000000000000000000 +9.313449999999999784e-01 3.461780358757763444e-12 0.000000000000000000 +9.323400000000000576e-01 3.389972525956962532e-12 0.000000000000000000 +9.333350000000000257e-01 3.319610179935919121e-12 0.000000000000000000 +9.343299999999999939e-01 3.250665133472402609e-12 0.000000000000000000 +9.353249999999999620e-01 3.183109730872174957e-12 0.000000000000000000 +9.363200000000000411e-01 3.116916838239753724e-12 0.000000000000000000 +9.373150000000000093e-01 3.052059834024750229e-12 0.000000000000000000 +9.383099999999999774e-01 2.988512599643348278e-12 0.000000000000000000 +9.393050000000000566e-01 2.926249510337346485e-12 0.000000000000000000 +9.403000000000000247e-01 2.865245426127051678e-12 0.000000000000000000 +9.412949999999999928e-01 2.805475682992718501e-12 0.000000000000000000 +9.422899999999999610e-01 2.746916084139481357e-12 0.000000000000000000 +9.432850000000000401e-01 2.689542891490299806e-12 0.000000000000000000 +9.442800000000000082e-01 2.633332817262948029e-12 0.000000000000000000 +9.452749999999999764e-01 2.578263015732237005e-12 0.000000000000000000 +9.462700000000000555e-01 2.524311075133569463e-12 0.000000000000000000 +9.472650000000000237e-01 2.471455009705816204e-12 0.000000000000000000 +9.482599999999999918e-01 2.419673251862030195e-12 0.000000000000000000 +9.492549999999999599e-01 2.368944644531134214e-12 0.000000000000000000 +9.502500000000000391e-01 2.319248433593288717e-12 0.000000000000000000 +9.512450000000000072e-01 2.270564260484504975e-12 0.000000000000000000 +9.522399999999999753e-01 2.222872154916162812e-12 0.000000000000000000 +9.532350000000000545e-01 2.176152527732621461e-12 0.000000000000000000 +9.542300000000000226e-01 2.130386163866658255e-12 0.000000000000000000 +9.552249999999999908e-01 2.085554215469351149e-12 0.000000000000000000 +9.562199999999999589e-01 2.041638195121339581e-12 0.000000000000000000 +9.572150000000000380e-01 1.998619969182224490e-12 0.000000000000000000 +9.582100000000000062e-01 1.956481751250051619e-12 0.000000000000000000 +9.592049999999999743e-01 1.915206095750555943e-12 0.000000000000000000 +9.602000000000000535e-01 1.874775891624738814e-12 0.000000000000000000 +9.611950000000000216e-01 1.835174356137109269e-12 0.000000000000000000 +9.621899999999999897e-01 1.796385028799102358e-12 0.000000000000000000 +9.631849999999999579e-01 1.758391765391040215e-12 0.000000000000000000 +9.641800000000000370e-01 1.721178732095956176e-12 0.000000000000000000 +9.651750000000000052e-01 1.684730399735976772e-12 0.000000000000000000 +9.661699999999999733e-01 1.649031538118635951e-12 0.000000000000000000 +9.671650000000000524e-01 1.614067210475218385e-12 0.000000000000000000 +9.681600000000000206e-01 1.579822768003402259e-12 0.000000000000000000 +9.691549999999999887e-01 1.546283844509766956e-12 0.000000000000000000 +9.701499999999999568e-01 1.513436351142013283e-12 0.000000000000000000 +9.711450000000000360e-01 1.481266471218146186e-12 0.000000000000000000 +9.721400000000000041e-01 1.449760655162423748e-12 0.000000000000000000 +9.731349999999999723e-01 1.418905615502230981e-12 0.000000000000000000 +9.741300000000000514e-01 1.388688321986862196e-12 0.000000000000000000 +9.751250000000000195e-01 1.359095996768790642e-12 0.000000000000000000 +9.761199999999999877e-01 1.330116109690863912e-12 0.000000000000000000 +9.771150000000000668e-01 1.301736373650612545e-12 0.000000000000000000 +9.781100000000000350e-01 1.273944740041217820e-12 0.000000000000000000 +9.791050000000000031e-01 1.246729394289011297e-12 0.000000000000000000 +9.800999999999999712e-01 1.220078751455892882e-12 0.000000000000000000 +9.810950000000000504e-01 1.193981451939975580e-12 0.000000000000000000 +9.820900000000000185e-01 1.168426357233797262e-12 0.000000000000000000 +9.830849999999999866e-01 1.143402545775898413e-12 0.000000000000000000 +9.840800000000000658e-01 1.118899308866149742e-12 0.000000000000000000 +9.850750000000000339e-01 1.094906146664561621e-12 0.000000000000000000 +9.860700000000000021e-01 1.071412764247475544e-12 0.000000000000000000 +9.870649999999999702e-01 1.048409067760837229e-12 0.000000000000000000 +9.880600000000000493e-01 1.025885160616447765e-12 0.000000000000000000 +9.890550000000000175e-01 1.003831339770924548e-12 0.000000000000000000 +9.900499999999999856e-01 9.822380920748707792e-13 0.000000000000000000 +9.910450000000000648e-01 9.610960906801041221e-13 0.000000000000000000 +9.920400000000000329e-01 9.403961915179023274e-13 0.000000000000000000 +9.930350000000000010e-01 9.201294298374636062e-13 0.000000000000000000 +9.940299999999999692e-01 9.002870168152242337e-13 0.000000000000000000 +9.950250000000000483e-01 8.808603362145260253e-13 0.000000000000000000 +9.960200000000000164e-01 8.618409411153087119e-13 0.000000000000000000 +9.970149999999999846e-01 8.432205507020908809e-13 0.000000000000000000 +9.980100000000000637e-01 8.249910471071539138e-13 0.000000000000000000 +9.990050000000000319e-01 8.071444723139599604e-13 0.000000000000000000 +1.000000000000000000e+00 7.896730251172689431e-13 0.000000000000000000 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_3.dat b/tests/test_data/ORSO/test_3.dat new file mode 100644 index 00000000..5cfc9e61 --- /dev/null +++ b/tests/test_data/ORSO/test_3.dat @@ -0,0 +1,1001 @@ +5.000000000000000104e-03 1.000000000000000222e+00 0.000000000000000000 +5.995000000000000329e-03 1.000000000000000222e+00 0.000000000000000000 +6.989999999999999686e-03 1.000000000000000222e+00 0.000000000000000000 +7.984999999999999043e-03 1.000000000000000000e+00 0.000000000000000000 +8.980000000000000135e-03 9.999999999999996669e-01 0.000000000000000000 +9.975000000000001227e-03 1.000000000000000222e+00 0.000000000000000000 +1.097000000000000058e-02 9.999999999999998890e-01 0.000000000000000000 +1.196499999999999994e-02 1.000000000000000222e+00 0.000000000000000000 +1.295999999999999930e-02 9.999999999999998890e-01 0.000000000000000000 +1.395499999999999866e-02 1.000000000000000000e+00 0.000000000000000000 +1.495000000000000148e-02 9.999999999999997780e-01 0.000000000000000000 +1.594500000000000084e-02 1.000000000000000222e+00 0.000000000000000000 +1.694000000000000020e-02 9.999999999999995559e-01 0.000000000000000000 +1.793499999999999955e-02 7.302544119277273316e-01 0.000000000000000000 +1.892999999999999891e-02 2.552815931521527082e-01 0.000000000000000000 +1.992500000000000174e-02 1.500207458923263903e-01 0.000000000000000000 +2.092000000000000109e-02 9.997793399278399884e-02 0.000000000000000000 +2.191500000000000045e-02 7.123912062170954795e-02 0.000000000000000000 +2.290999999999999981e-02 5.301614647186881496e-02 0.000000000000000000 +2.390500000000000264e-02 4.070644982790416755e-02 0.000000000000000000 +2.490000000000000199e-02 3.201044658983939750e-02 0.000000000000000000 +2.589500000000000135e-02 2.565627153557500234e-02 0.000000000000000000 +2.689000000000000071e-02 2.088803389193751026e-02 0.000000000000000000 +2.788500000000000006e-02 1.723156075999391149e-02 0.000000000000000000 +2.887999999999999942e-02 1.437654145720755616e-02 0.000000000000000000 +2.987500000000000225e-02 1.211283187244694554e-02 0.000000000000000000 +3.087000000000000161e-02 1.029403083215324477e-02 0.000000000000000000 +3.186499999999999749e-02 8.815675506561536021e-03 0.000000000000000000 +3.286000000000000032e-02 7.601682608979293439e-03 0.000000000000000000 +3.385499999999999621e-02 6.595641840799377348e-03 0.000000000000000000 +3.484999999999999903e-02 5.755068914451989294e-03 0.000000000000000000 +3.584500000000000186e-02 5.047520223740087873e-03 0.000000000000000000 +3.683999999999999775e-02 4.447910330864589430e-03 0.000000000000000000 +3.783500000000000058e-02 3.936625104166304942e-03 0.000000000000000000 +3.882999999999999646e-02 3.498172265099319146e-03 0.000000000000000000 +3.982499999999999929e-02 3.120201746921682021e-03 0.000000000000000000 +4.081999999999999518e-02 2.792784835982658510e-03 0.000000000000000000 +4.181499999999999800e-02 2.507877168229455909e-03 0.000000000000000000 +4.281000000000000083e-02 2.258914162673223303e-03 0.000000000000000000 +4.380499999999999672e-02 2.040503064564099227e-03 0.000000000000000000 +4.479999999999999954e-02 1.848186284179480438e-03 0.000000000000000000 +4.579499999999999543e-02 1.678257914894290374e-03 0.000000000000000000 +4.678999999999999826e-02 1.527620311455636605e-03 0.000000000000000000 +4.778500000000000109e-02 1.393671123873522957e-03 0.000000000000000000 +4.877999999999999697e-02 1.274213683683264901e-03 0.000000000000000000 +4.977499999999999980e-02 1.167385439427427989e-03 0.000000000000000000 +5.076999999999999569e-02 1.071600447070272973e-03 0.000000000000000000 +5.176499999999999851e-02 9.855028819590074245e-04 0.000000000000000000 +5.275999999999999440e-02 9.079292507786222884e-04 0.000000000000000000 +5.375499999999999723e-02 8.378775137522353079e-04 0.000000000000000000 +5.475000000000000006e-02 7.744817278207360121e-04 0.000000000000000000 +5.574499999999999594e-02 7.169911253934479513e-04 0.000000000000000000 +5.673999999999999877e-02 6.647527754462639578e-04 0.000000000000000000 +5.773499999999999466e-02 6.171971523537961302e-04 0.000000000000000000 +5.872999999999999748e-02 5.738260761141945280e-04 0.000000000000000000 +5.972500000000000031e-02 5.342025953163497161e-04 0.000000000000000000 +6.071999999999999620e-02 4.979424685541384383e-04 0.000000000000000000 +6.171499999999999903e-02 4.647069664291461882e-04 0.000000000000000000 +6.271000000000000185e-02 4.341967688803725391e-04 0.000000000000000000 +6.370499999999999774e-02 4.061467744268355633e-04 0.000000000000000000 +6.470000000000000751e-02 3.803216713614568584e-04 0.000000000000000000 +6.569500000000000339e-02 3.565121477980526233e-04 0.000000000000000000 +6.668999999999999928e-02 3.345316391388566393e-04 0.000000000000000000 +6.768500000000000905e-02 3.142135290765838492e-04 0.000000000000000000 +6.868000000000000493e-02 2.954087345123552772e-04 0.000000000000000000 +6.967500000000000082e-02 2.779836164163030222e-04 0.000000000000000000 +7.067000000000001059e-02 2.618181681981876160e-04 0.000000000000000000 +7.166500000000000647e-02 2.468044409991756983e-04 0.000000000000000000 +7.266000000000000236e-02 2.328451717867457689e-04 0.000000000000000000 +7.365499999999999825e-02 2.198525854904882944e-04 0.000000000000000000 +7.465000000000000802e-02 2.077473468635113445e-04 0.000000000000000000 +7.564500000000000390e-02 1.964576414578978456e-04 0.000000000000000000 +7.663999999999999979e-02 1.859183681963245624e-04 0.000000000000000000 +7.763500000000000956e-02 1.760704286136114403e-04 0.000000000000000000 +7.863000000000000544e-02 1.668601000190766644e-04 0.000000000000000000 +7.962500000000000133e-02 1.582384816641631969e-04 0.000000000000000000 +8.062000000000001110e-02 1.501610045482572255e-04 0.000000000000000000 +8.161500000000000699e-02 1.425869968064864129e-04 0.000000000000000000 +8.261000000000000287e-02 1.354792977357120428e-04 0.000000000000000000 +8.360499999999999876e-02 1.288039144612181271e-04 0.000000000000000000 +8.460000000000000853e-02 1.225297160532930944e-04 0.000000000000000000 +8.559500000000000441e-02 1.166281605923794913e-04 0.000000000000000000 +8.659000000000000030e-02 1.110730512716228780e-04 0.000000000000000000 +8.758500000000001007e-02 1.058403181323294158e-04 0.000000000000000000 +8.858000000000000596e-02 1.009078224632976368e-04 0.000000000000000000 +8.957500000000000184e-02 9.625518127027844306e-05 0.000000000000000000 +9.057000000000001161e-02 9.186360954578184804e-05 0.000000000000000000 +9.156500000000000750e-02 8.771577834949046066e-05 0.000000000000000000 +9.256000000000000338e-02 8.379568695238581060e-05 0.000000000000000000 +9.355499999999999927e-02 8.008854750826035064e-05 0.000000000000000000 +9.455000000000000904e-02 7.658068089951252906e-05 0.000000000000000000 +9.554500000000000492e-02 7.325942256365089748e-05 0.000000000000000000 +9.654000000000000081e-02 7.011303724606809810e-05 0.000000000000000000 +9.753500000000001058e-02 6.713064174628380202e-05 0.000000000000000000 +9.853000000000000647e-02 6.430213483124872734e-05 0.000000000000000000 +9.952500000000000235e-02 6.161813358258931778e-05 0.000000000000000000 +1.005199999999999982e-01 5.906991552652936407e-05 0.000000000000000000 +1.015150000000000080e-01 5.664936596722652709e-05 0.000000000000000000 +1.025100000000000039e-01 5.434893000757861324e-05 0.000000000000000000 +1.035049999999999998e-01 5.216156879745617451e-05 0.000000000000000000 +1.045000000000000095e-01 5.008071959859009475e-05 0.000000000000000000 +1.054950000000000054e-01 4.810025929894232714e-05 0.000000000000000000 +1.064900000000000013e-01 4.621447104794872937e-05 0.000000000000000000 +1.074850000000000111e-01 4.441801371822664884e-05 0.000000000000000000 +1.084800000000000070e-01 4.270589392966370960e-05 0.000000000000000000 +1.094750000000000029e-01 4.107344039873492037e-05 0.000000000000000000 +1.104699999999999988e-01 3.951628039990539470e-05 0.000000000000000000 +1.114650000000000085e-01 3.803031814727148062e-05 0.000000000000000000 +1.124600000000000044e-01 3.661171492366325104e-05 0.000000000000000000 +1.134550000000000003e-01 3.525687080139357449e-05 0.000000000000000000 +1.144500000000000101e-01 3.396240781400948852e-05 0.000000000000000000 +1.154450000000000059e-01 3.272515445200561756e-05 0.000000000000000000 +1.164400000000000018e-01 3.154213136757109493e-05 0.000000000000000000 +1.174350000000000116e-01 3.041053818437549486e-05 0.000000000000000000 +1.184300000000000075e-01 2.932774131814763082e-05 0.000000000000000000 +1.194250000000000034e-01 2.829126272259308120e-05 0.000000000000000000 +1.204199999999999993e-01 2.729876948309178597e-05 0.000000000000000000 +1.214150000000000090e-01 2.634806418770863114e-05 0.000000000000000000 +1.224100000000000049e-01 2.543707601145856189e-05 0.000000000000000000 +1.234050000000000008e-01 2.456385245553760122e-05 0.000000000000000000 +1.244000000000000106e-01 2.372655168842050194e-05 0.000000000000000000 +1.253950000000000065e-01 2.292343544045605906e-05 0.000000000000000000 +1.263900000000000023e-01 2.215286240780996405e-05 0.000000000000000000 +1.273849999999999982e-01 2.141328212547069355e-05 0.000000000000000000 +1.283799999999999941e-01 2.070322927252014994e-05 0.000000000000000000 +1.293749999999999900e-01 2.002131837599849124e-05 0.000000000000000000 +1.303700000000000137e-01 1.936623888259802600e-05 0.000000000000000000 +1.313650000000000095e-01 1.873675056998053514e-05 0.000000000000000000 +1.323600000000000054e-01 1.813167927190132041e-05 0.000000000000000000 +1.333550000000000013e-01 1.754991289344203385e-05 0.000000000000000000 +1.343499999999999972e-01 1.699039769464770946e-05 0.000000000000000000 +1.353449999999999931e-01 1.645213482259845323e-05 0.000000000000000000 +1.363400000000000167e-01 1.593417707359521767e-05 0.000000000000000000 +1.373350000000000126e-01 1.543562586860838427e-05 0.000000000000000000 +1.383300000000000085e-01 1.495562842648808664e-05 0.000000000000000000 +1.393250000000000044e-01 1.449337512065626627e-05 0.000000000000000000 +1.403200000000000003e-01 1.404809700615483821e-05 0.000000000000000000 +1.413149999999999962e-01 1.361906350491213202e-05 0.000000000000000000 +1.423099999999999921e-01 1.320558023807027655e-05 0.000000000000000000 +1.433050000000000157e-01 1.280698699505669096e-05 0.000000000000000000 +1.443000000000000116e-01 1.242265582987766277e-05 0.000000000000000000 +1.452950000000000075e-01 1.205198927583547193e-05 0.000000000000000000 +1.462900000000000034e-01 1.169441867055197280e-05 0.000000000000000000 +1.472849999999999993e-01 1.134940258375420816e-05 0.000000000000000000 +1.482799999999999951e-01 1.101642534088488612e-05 0.000000000000000000 +1.492750000000000188e-01 1.069499563607656409e-05 0.000000000000000000 +1.502700000000000147e-01 1.038464522852731763e-05 0.000000000000000000 +1.512650000000000106e-01 1.008492771673922509e-05 0.000000000000000000 +1.522600000000000064e-01 9.795417385487658167e-06 0.000000000000000000 +1.532550000000000023e-01 9.515708120754915602e-06 0.000000000000000000 +1.542499999999999982e-01 9.245412388214926215e-06 0.000000000000000000 +1.552449999999999941e-01 8.984160271147430192e-06 0.000000000000000000 +1.562400000000000178e-01 8.731598563979155208e-06 0.000000000000000000 +1.572350000000000136e-01 8.487389917891189619e-06 0.000000000000000000 +1.582300000000000095e-01 8.251212035195819211e-06 0.000000000000000000 +1.592250000000000054e-01 8.022756909411819735e-06 0.000000000000000000 +1.602200000000000013e-01 7.801730108172303166e-06 0.000000000000000000 +1.612149999999999972e-01 7.587850096304319501e-06 0.000000000000000000 +1.622099999999999931e-01 7.380847596593427883e-06 0.000000000000000000 +1.632050000000000167e-01 7.180464985919699528e-06 0.000000000000000000 +1.642000000000000126e-01 6.986455724602389345e-06 0.000000000000000000 +1.651950000000000085e-01 6.798583816938923489e-06 0.000000000000000000 +1.661900000000000044e-01 6.616623301054710733e-06 0.000000000000000000 +1.671850000000000003e-01 6.440357766307891073e-06 0.000000000000000000 +1.681799999999999962e-01 6.269579896604869611e-06 0.000000000000000000 +1.691749999999999921e-01 6.104091038089564868e-06 0.000000000000000000 +1.701700000000000157e-01 5.943700789772575947e-06 0.000000000000000000 +1.711650000000000116e-01 5.788226615756587192e-06 0.000000000000000000 +1.721600000000000075e-01 5.637493477799012715e-06 0.000000000000000000 +1.731550000000000034e-01 5.491333487035706967e-06 0.000000000000000000 +1.741499999999999992e-01 5.349585573761062137e-06 0.000000000000000000 +1.751449999999999951e-01 5.212095174233773578e-06 0.000000000000000000 +1.761400000000000188e-01 5.078713933538307867e-06 0.000000000000000000 +1.771350000000000147e-01 4.949299423590993852e-06 0.000000000000000000 +1.781300000000000106e-01 4.823714875442655119e-06 0.000000000000000000 +1.791250000000000064e-01 4.701828925074577255e-06 0.000000000000000000 +1.801200000000000023e-01 4.583515371940636223e-06 0.000000000000000000 +1.811149999999999982e-01 4.468652949545531132e-06 0.000000000000000000 +1.821099999999999941e-01 4.357125107399881593e-06 0.000000000000000000 +1.831050000000000177e-01 4.248819803728705652e-06 0.000000000000000000 +1.841000000000000136e-01 4.143629308349770852e-06 0.000000000000000000 +1.850950000000000095e-01 4.041450015165261868e-06 0.000000000000000000 +1.860900000000000054e-01 3.942182263758992194e-06 0.000000000000000000 +1.870850000000000013e-01 3.845730169599192739e-06 0.000000000000000000 +1.880799999999999972e-01 3.752001462399423300e-06 0.000000000000000000 +1.890749999999999931e-01 3.660907332198875170e-06 0.000000000000000000 +1.900700000000000167e-01 3.572362282757150113e-06 0.000000000000000000 +1.910650000000000126e-01 3.486283991877368194e-06 0.000000000000000000 +1.920600000000000085e-01 3.402593178302982697e-06 0.000000000000000000 +1.930550000000000044e-01 3.321213474835895762e-06 0.000000000000000000 +1.940500000000000003e-01 3.242071307366984273e-06 0.000000000000000000 +1.950449999999999962e-01 3.165095779504616941e-06 0.000000000000000000 +1.960399999999999920e-01 3.090218562523206605e-06 0.000000000000000000 +1.970350000000000157e-01 3.017373790355003906e-06 0.000000000000000000 +1.980300000000000116e-01 2.946497959373940888e-06 0.000000000000000000 +1.990250000000000075e-01 2.877529832728726358e-06 0.000000000000000000 +2.000200000000000033e-01 2.810410348997253469e-06 0.000000000000000000 +2.010149999999999992e-01 2.745082534945871258e-06 0.000000000000000000 +2.020099999999999951e-01 2.681491422194076088e-06 0.000000000000000000 +2.030050000000000188e-01 2.619583967585816721e-06 0.000000000000000000 +2.040000000000000147e-01 2.559308977088196519e-06 0.000000000000000000 +2.049950000000000105e-01 2.500617033048890839e-06 0.000000000000000000 +2.059900000000000064e-01 2.443460424640982012e-06 0.000000000000000000 +2.069850000000000023e-01 2.387793081346400505e-06 0.000000000000000000 +2.079799999999999982e-01 2.333570509331725681e-06 0.000000000000000000 +2.089749999999999941e-01 2.280749730574460933e-06 0.000000000000000000 +2.099700000000000177e-01 2.229289224610072797e-06 0.000000000000000000 +2.109650000000000136e-01 2.179148872777007317e-06 0.000000000000000000 +2.119600000000000095e-01 2.130289904837552500e-06 0.000000000000000000 +2.129550000000000054e-01 2.082674847866944899e-06 0.000000000000000000 +2.139500000000000013e-01 2.036267477302419947e-06 0.000000000000000000 +2.149449999999999972e-01 1.991032770050237681e-06 0.000000000000000000 +2.159399999999999931e-01 1.946936859557188785e-06 0.000000000000000000 +2.169350000000000167e-01 1.903946992756716464e-06 0.000000000000000000 +2.179300000000000126e-01 1.862031488799201211e-06 0.000000000000000000 +2.189250000000000085e-01 1.821159699489077939e-06 0.000000000000000000 +2.199200000000000044e-01 1.781301971348607896e-06 0.000000000000000000 +2.209150000000000003e-01 1.742429609236075048e-06 0.000000000000000000 +2.219099999999999961e-01 1.704514841445228144e-06 0.000000000000000000 +2.229050000000000198e-01 1.667530786223389054e-06 0.000000000000000000 +2.239000000000000157e-01 1.631451419641829289e-06 0.000000000000000000 +2.248950000000000116e-01 1.596251544758542627e-06 0.000000000000000000 +2.258900000000000075e-01 1.561906762016576218e-06 0.000000000000000000 +2.268850000000000033e-01 1.528393440823871229e-06 0.000000000000000000 +2.278799999999999992e-01 1.495688692261441789e-06 0.000000000000000000 +2.288749999999999951e-01 1.463770342870089032e-06 0.000000000000000000 +2.298700000000000188e-01 1.432616909471420088e-06 0.000000000000000000 +2.308650000000000146e-01 1.402207574973502849e-06 0.000000000000000000 +2.318600000000000105e-01 1.372522165124398464e-06 0.000000000000000000 +2.328550000000000064e-01 1.343541126166518876e-06 0.000000000000000000 +2.338500000000000023e-01 1.315245503359037064e-06 0.000000000000000000 +2.348449999999999982e-01 1.287616920326394123e-06 0.000000000000000000 +2.358399999999999941e-01 1.260637559201489898e-06 0.000000000000000000 +2.368350000000000177e-01 1.234290141526865827e-06 0.000000000000000000 +2.378300000000000136e-01 1.208557909884525645e-06 0.000000000000000000 +2.388250000000000095e-01 1.183424610222043002e-06 0.000000000000000000 +2.398200000000000054e-01 1.158874474846250690e-06 0.000000000000000000 +2.408150000000000013e-01 1.134892206056985017e-06 0.000000000000000000 +2.418099999999999972e-01 1.111462960394385494e-06 0.000000000000000000 +2.428049999999999931e-01 1.088572333473516146e-06 0.000000000000000000 +2.438000000000000167e-01 1.066206345383700941e-06 0.000000000000000000 +2.447950000000000126e-01 1.044351426627338742e-06 0.000000000000000000 +2.457900000000000085e-01 1.022994404578400489e-06 0.000000000000000000 +2.467850000000000044e-01 1.002122490437704232e-06 0.000000000000000000 +2.477800000000000002e-01 9.817232666657718879e-07 0.000000000000000000 +2.487749999999999961e-01 9.617846748736519515e-07 0.000000000000000000 +2.497700000000000198e-01 9.422950041539083708e-07 0.000000000000000000 +2.507650000000000157e-01 9.232428798323453051e-07 0.000000000000000000 +2.517599999999999838e-01 9.046172526266390979e-07 0.000000000000000000 +2.527550000000000074e-01 8.864073881929345266e-07 0.000000000000000000 +2.537499999999999756e-01 8.686028570467542300e-07 0.000000000000000000 +2.547449999999999992e-01 8.511935248416559944e-07 0.000000000000000000 +2.557400000000000229e-01 8.341695429956798617e-07 0.000000000000000000 +2.567349999999999910e-01 8.175213396454100065e-07 0.000000000000000000 +2.577300000000000146e-01 8.012396109212888927e-07 0.000000000000000000 +2.587249999999999828e-01 7.853153125282533498e-07 0.000000000000000000 +2.597200000000000064e-01 7.697396516203173399e-07 0.000000000000000000 +2.607150000000000301e-01 7.545040789584628936e-07 0.000000000000000000 +2.617099999999999982e-01 7.396002813402122049e-07 0.000000000000000000 +2.627050000000000218e-01 7.250201742916859191e-07 0.000000000000000000 +2.636999999999999900e-01 7.107558950102262601e-07 0.000000000000000000 +2.646950000000000136e-01 6.967997955505304836e-07 0.000000000000000000 +2.656899999999999817e-01 6.831444362421918255e-07 0.000000000000000000 +2.666850000000000054e-01 6.697825793328290410e-07 0.000000000000000000 +2.676800000000000290e-01 6.567071828464906383e-07 0.000000000000000000 +2.686749999999999972e-01 6.439113946490282237e-07 0.000000000000000000 +2.696700000000000208e-01 6.313885467153174819e-07 0.000000000000000000 +2.706649999999999889e-01 6.191321495868240811e-07 0.000000000000000000 +2.716600000000000126e-01 6.071358870161023394e-07 0.000000000000000000 +2.726549999999999807e-01 5.953936107895076103e-07 0.000000000000000000 +2.736500000000000044e-01 5.838993357212978451e-07 0.000000000000000000 +2.746450000000000280e-01 5.726472348147212419e-07 0.000000000000000000 +2.756399999999999961e-01 5.616316345813571775e-07 0.000000000000000000 +2.766350000000000198e-01 5.508470105157720654e-07 0.000000000000000000 +2.776299999999999879e-01 5.402879827167730058e-07 0.000000000000000000 +2.786250000000000115e-01 5.299493116534244488e-07 0.000000000000000000 +2.796199999999999797e-01 5.198258940675015360e-07 0.000000000000000000 +2.806150000000000033e-01 5.099127590094127535e-07 0.000000000000000000 +2.816100000000000270e-01 5.002050640022411882e-07 0.000000000000000000 +2.826049999999999951e-01 4.906980913288911179e-07 0.000000000000000000 +2.836000000000000187e-01 4.813872444391793366e-07 0.000000000000000000 +2.845949999999999869e-01 4.722680444710293888e-07 0.000000000000000000 +2.855900000000000105e-01 4.633361268832067542e-07 0.000000000000000000 +2.865850000000000342e-01 4.545872381946849999e-07 0.000000000000000000 +2.875800000000000023e-01 4.460172328274867991e-07 0.000000000000000000 +2.885750000000000259e-01 4.376220700492397344e-07 0.000000000000000000 +2.895699999999999941e-01 4.293978110113955783e-07 0.000000000000000000 +2.905650000000000177e-01 4.213406158812215202e-07 0.000000000000000000 +2.915599999999999858e-01 4.134467410625320186e-07 0.000000000000000000 +2.925550000000000095e-01 4.057125365037572669e-07 0.000000000000000000 +2.935500000000000331e-01 3.981344430887845665e-07 0.000000000000000000 +2.945450000000000013e-01 3.907089901094955503e-07 0.000000000000000000 +2.955400000000000249e-01 3.834327928155199364e-07 0.000000000000000000 +2.965349999999999930e-01 3.763025500396661164e-07 0.000000000000000000 +2.975300000000000167e-01 3.693150418962285531e-07 0.000000000000000000 +2.985249999999999848e-01 3.624671275491292328e-07 0.000000000000000000 +2.995200000000000085e-01 3.557557430487765712e-07 0.000000000000000000 +3.005150000000000321e-01 3.491778992339947667e-07 0.000000000000000000 +3.015100000000000002e-01 3.427306796976922247e-07 0.000000000000000000 +3.025050000000000239e-01 3.364112388139378583e-07 0.000000000000000000 +3.034999999999999920e-01 3.302167998242062930e-07 0.000000000000000000 +3.044950000000000156e-01 3.241446529812717644e-07 0.000000000000000000 +3.054899999999999838e-01 3.181921537481003399e-07 0.000000000000000000 +3.064850000000000074e-01 3.123567210511762908e-07 0.000000000000000000 +3.074800000000000311e-01 3.066358355846650517e-07 0.000000000000000000 +3.084749999999999992e-01 3.010270381660337490e-07 0.000000000000000000 +3.094700000000000228e-01 2.955279281388950346e-07 0.000000000000000000 +3.104649999999999910e-01 2.901361618240254941e-07 0.000000000000000000 +3.114600000000000146e-01 2.848494510149534469e-07 0.000000000000000000 +3.124549999999999828e-01 2.796655615181440895e-07 0.000000000000000000 +3.134500000000000064e-01 2.745823117354215134e-07 0.000000000000000000 +3.144450000000000300e-01 2.695975712878325508e-07 0.000000000000000000 +3.154399999999999982e-01 2.647092596790410133e-07 0.000000000000000000 +3.164350000000000218e-01 2.599153449978837568e-07 0.000000000000000000 +3.174299999999999899e-01 2.552138426577992562e-07 0.000000000000000000 +3.184250000000000136e-01 2.506028141727277769e-07 0.000000000000000000 +3.194199999999999817e-01 2.460803659680998870e-07 0.000000000000000000 +3.204150000000000054e-01 2.416446482256505412e-07 0.000000000000000000 +3.214100000000000290e-01 2.372938537613893963e-07 0.000000000000000000 +3.224049999999999971e-01 2.330262169348859350e-07 0.000000000000000000 +3.234000000000000208e-01 2.288400125900244041e-07 0.000000000000000000 +3.243949999999999889e-01 2.247335550253473878e-07 0.000000000000000000 +3.253900000000000126e-01 2.207051969933976064e-07 0.000000000000000000 +3.263849999999999807e-01 2.167533287283641152e-07 0.000000000000000000 +3.273800000000000043e-01 2.128763770004190671e-07 0.000000000000000000 +3.283750000000000280e-01 2.090728041971626540e-07 0.000000000000000000 +3.293699999999999961e-01 2.053411074299329102e-07 0.000000000000000000 +3.303650000000000198e-01 2.016798176654320889e-07 0.000000000000000000 +3.313599999999999879e-01 1.980874988810449717e-07 0.000000000000000000 +3.323550000000000115e-01 1.945627472435601437e-07 0.000000000000000000 +3.333499999999999797e-01 1.911041903105379646e-07 0.000000000000000000 +3.343450000000000033e-01 1.877104862536845619e-07 0.000000000000000000 +3.353400000000000269e-01 1.843803231029639430e-07 0.000000000000000000 +3.363349999999999951e-01 1.811124180120913374e-07 0.000000000000000000 +3.373300000000000187e-01 1.779055165433834375e-07 0.000000000000000000 +3.383249999999999869e-01 1.747583919723379171e-07 0.000000000000000000 +3.393200000000000105e-01 1.716698446108473038e-07 0.000000000000000000 +3.403150000000000341e-01 1.686387011487514324e-07 0.000000000000000000 +3.413100000000000023e-01 1.656638140131796811e-07 0.000000000000000000 +3.423050000000000259e-01 1.627440607449233080e-07 0.000000000000000000 +3.432999999999999940e-01 1.598783433915807615e-07 0.000000000000000000 +3.442950000000000177e-01 1.570655879169011439e-07 0.000000000000000000 +3.452899999999999858e-01 1.543047436258950896e-07 0.000000000000000000 +3.462850000000000095e-01 1.515947826050264808e-07 0.000000000000000000 +3.472800000000000331e-01 1.489346991773542697e-07 0.000000000000000000 +3.482750000000000012e-01 1.463235093721429985e-07 0.000000000000000000 +3.492700000000000249e-01 1.437602504082063715e-07 0.000000000000000000 +3.502649999999999930e-01 1.412439801910185004e-07 0.000000000000000000 +3.512600000000000167e-01 1.387737768228775831e-07 0.000000000000000000 +3.522549999999999848e-01 1.363487381259259015e-07 0.000000000000000000 +3.532500000000000084e-01 1.339679811775864490e-07 0.000000000000000000 +3.542450000000000321e-01 1.316306418580024381e-07 0.000000000000000000 +3.552400000000000002e-01 1.293358744093316699e-07 0.000000000000000000 +3.562350000000000239e-01 1.270828510063341282e-07 0.000000000000000000 +3.572299999999999920e-01 1.248707613379087200e-07 0.000000000000000000 +3.582250000000000156e-01 1.226988121998597123e-07 0.000000000000000000 +3.592199999999999838e-01 1.205662270974316575e-07 0.000000000000000000 +3.602150000000000074e-01 1.184722458585421587e-07 0.000000000000000000 +3.612100000000000311e-01 1.164161242567355819e-07 0.000000000000000000 +3.622049999999999992e-01 1.143971336435086992e-07 0.000000000000000000 +3.632000000000000228e-01 1.124145605904174832e-07 0.000000000000000000 +3.641949999999999910e-01 1.104677065397677744e-07 0.000000000000000000 +3.651900000000000146e-01 1.085558874643744278e-07 0.000000000000000000 +3.661849999999999827e-01 1.066784335360411807e-07 0.000000000000000000 +3.671800000000000064e-01 1.048346888019738436e-07 0.000000000000000000 +3.681750000000000300e-01 1.030240108696256120e-07 0.000000000000000000 +3.691699999999999982e-01 1.012457705992769268e-07 0.000000000000000000 +3.701650000000000218e-01 9.949935180445753679e-08 0.000000000000000000 +3.711599999999999899e-01 9.778415095948028884e-08 0.000000000000000000 +3.721550000000000136e-01 9.609957691461342208e-08 0.000000000000000000 +3.731499999999999817e-01 9.444505061804599980e-08 0.000000000000000000 +3.741450000000000053e-01 9.282000484481748754e-08 0.000000000000000000 +3.751400000000000290e-01 9.122388393244832792e-08 0.000000000000000000 +3.761349999999999971e-01 8.965614352301605240e-08 0.000000000000000000 +3.771300000000000208e-01 8.811625031155657185e-08 0.000000000000000000 +3.781249999999999889e-01 8.660368180062064381e-08 0.000000000000000000 +3.791200000000000125e-01 8.511792606090979959e-08 0.000000000000000000 +3.801149999999999807e-01 8.365848149753766865e-08 0.000000000000000000 +3.811100000000000043e-01 8.222485662219406386e-08 0.000000000000000000 +3.821050000000000280e-01 8.081656983069726827e-08 0.000000000000000000 +3.830999999999999961e-01 7.943314918590569788e-08 0.000000000000000000 +3.840950000000000197e-01 7.807413220591217810e-08 0.000000000000000000 +3.850899999999999879e-01 7.673906565739948301e-08 0.000000000000000000 +3.860850000000000115e-01 7.542750535373204618e-08 0.000000000000000000 +3.870799999999999796e-01 7.413901595817632364e-08 0.000000000000000000 +3.880750000000000033e-01 7.287317079158164557e-08 0.000000000000000000 +3.890700000000000269e-01 7.162955164475418635e-08 0.000000000000000000 +3.900649999999999951e-01 7.040774859527686503e-08 0.000000000000000000 +3.910600000000000187e-01 6.920735982860711948e-08 0.000000000000000000 +3.920549999999999868e-01 6.802799146356765812e-08 0.000000000000000000 +3.930500000000000105e-01 6.686925738177639130e-08 0.000000000000000000 +3.940450000000000341e-01 6.573077906118054173e-08 0.000000000000000000 +3.950400000000000023e-01 6.461218541347500975e-08 0.000000000000000000 +3.960350000000000259e-01 6.351311262541379473e-08 0.000000000000000000 +3.970299999999999940e-01 6.243320400370203637e-08 0.000000000000000000 +3.980250000000000177e-01 6.137210982358970926e-08 0.000000000000000000 +3.990199999999999858e-01 6.032948718098469951e-08 0.000000000000000000 +4.000150000000000095e-01 5.930499984799508768e-08 0.000000000000000000 +4.010100000000000331e-01 5.829831813179890142e-08 0.000000000000000000 +4.020050000000000012e-01 5.730911873679025764e-08 0.000000000000000000 +4.030000000000000249e-01 5.633708462991893812e-08 0.000000000000000000 +4.039949999999999930e-01 5.538190490915735624e-08 0.000000000000000000 +4.049900000000000166e-01 5.444327467487663858e-08 0.000000000000000000 +4.059849999999999848e-01 5.352089490429422662e-08 0.000000000000000000 +4.069800000000000084e-01 5.261447232878746078e-08 0.000000000000000000 +4.079750000000000321e-01 5.172371931388542301e-08 0.000000000000000000 +4.089700000000000002e-01 5.084835374211253429e-08 0.000000000000000000 +4.099650000000000238e-01 4.998809889844755150e-08 0.000000000000000000 +4.109599999999999920e-01 4.914268335846344356e-08 0.000000000000000000 +4.119550000000000156e-01 4.831184087875673132e-08 0.000000000000000000 +4.129499999999999837e-01 4.749531029020172877e-08 0.000000000000000000 +4.139450000000000074e-01 4.669283539330103853e-08 0.000000000000000000 +4.149400000000000310e-01 4.590416485605566593e-08 0.000000000000000000 +4.159349999999999992e-01 4.512905211408358873e-08 0.000000000000000000 +4.169300000000000228e-01 4.436725527296136481e-08 0.000000000000000000 +4.179249999999999909e-01 4.361853701276109034e-08 0.000000000000000000 +4.189200000000000146e-01 4.288266449474032394e-08 0.000000000000000000 +4.199149999999999827e-01 4.215940926999557206e-08 0.000000000000000000 +4.209100000000000064e-01 4.144854719035587216e-08 0.000000000000000000 +4.219050000000000300e-01 4.074985832100385988e-08 0.000000000000000000 +4.228999999999999981e-01 4.006312685518982154e-08 0.000000000000000000 +4.238950000000000218e-01 3.938814103081402333e-08 0.000000000000000000 +4.248899999999999899e-01 3.872469304875328655e-08 0.000000000000000000 +4.258850000000000136e-01 3.807257899308821213e-08 0.000000000000000000 +4.268799999999999817e-01 3.743159875300075409e-08 0.000000000000000000 +4.278750000000000053e-01 3.680155594641652206e-08 0.000000000000000000 +4.288700000000000290e-01 3.618225784535955942e-08 0.000000000000000000 +4.298649999999999971e-01 3.557351530280438460e-08 0.000000000000000000 +4.308600000000000207e-01 3.497514268124120271e-08 0.000000000000000000 +4.318549999999999889e-01 3.438695778272888431e-08 0.000000000000000000 +4.328500000000000125e-01 3.380878178052697901e-08 0.000000000000000000 +4.338449999999999807e-01 3.324043915208500011e-08 0.000000000000000000 +4.348400000000000043e-01 3.268175761362234442e-08 0.000000000000000000 +4.358350000000000279e-01 3.213256805597840426e-08 0.000000000000000000 +4.368299999999999961e-01 3.159270448196308571e-08 0.000000000000000000 +4.378250000000000197e-01 3.106200394495490724e-08 0.000000000000000000 +4.388199999999999878e-01 3.054030648889349978e-08 0.000000000000000000 +4.398150000000000115e-01 3.002745508947083052e-08 0.000000000000000000 +4.408100000000000351e-01 2.952329559662719818e-08 0.000000000000000000 +4.418050000000000033e-01 2.902767667829952025e-08 0.000000000000000000 +4.428000000000000269e-01 2.854044976526795720e-08 0.000000000000000000 +4.437949999999999950e-01 2.806146899727338396e-08 0.000000000000000000 +4.447900000000000187e-01 2.759059117018932799e-08 0.000000000000000000 +4.457849999999999868e-01 2.712767568439074514e-08 0.000000000000000000 +4.467800000000000105e-01 2.667258449415284049e-08 0.000000000000000000 +4.477750000000000341e-01 2.622518205811867270e-08 0.000000000000000000 +4.487700000000000022e-01 2.578533529082613517e-08 0.000000000000000000 +4.497650000000000259e-01 2.535291351522951938e-08 0.000000000000000000 +4.507599999999999940e-01 2.492778841627287470e-08 0.000000000000000000 +4.517550000000000177e-01 2.450983399531671096e-08 0.000000000000000000 +4.527499999999999858e-01 2.409892652562846511e-08 0.000000000000000000 +4.537450000000000094e-01 2.369494450875368376e-08 0.000000000000000000 +4.547400000000000331e-01 2.329776863176683936e-08 0.000000000000000000 +4.557350000000000012e-01 2.290728172544141217e-08 0.000000000000000000 +4.567300000000000249e-01 2.252336872328070319e-08 0.000000000000000000 +4.577249999999999930e-01 2.214591662139746355e-08 0.000000000000000000 +4.587200000000000166e-01 2.177481443920168254e-08 0.000000000000000000 +4.597149999999999848e-01 2.140995318088074199e-08 0.000000000000000000 +4.607100000000000084e-01 2.105122579775599487e-08 0.000000000000000000 +4.617050000000000320e-01 2.069852715129059986e-08 0.000000000000000000 +4.627000000000000002e-01 2.035175397696612041e-08 0.000000000000000000 +4.636950000000000238e-01 2.001080484878018436e-08 0.000000000000000000 +4.646899999999999920e-01 1.967558014460917590e-08 0.000000000000000000 +4.656850000000000156e-01 1.934598201213554117e-08 0.000000000000000000 +4.666799999999999837e-01 1.902191433555517809e-08 0.000000000000000000 +4.676750000000000074e-01 1.870328270293666115e-08 0.000000000000000000 +4.686700000000000310e-01 1.838999437423243993e-08 0.000000000000000000 +4.696649999999999991e-01 1.808195824993965897e-08 0.000000000000000000 +4.706600000000000228e-01 1.777908484038484727e-08 0.000000000000000000 +4.716549999999999909e-01 1.748128623567682730e-08 0.000000000000000000 +4.726500000000000146e-01 1.718847607616211987e-08 0.000000000000000000 +4.736449999999999827e-01 1.690056952359754085e-08 0.000000000000000000 +4.746400000000000063e-01 1.661748323278907984e-08 0.000000000000000000 +4.756350000000000300e-01 1.633913532386936203e-08 0.000000000000000000 +4.766299999999999981e-01 1.606544535509242241e-08 0.000000000000000000 +4.776250000000000218e-01 1.579633429619561801e-08 0.000000000000000000 +4.786199999999999899e-01 1.553172450226774170e-08 0.000000000000000000 +4.796150000000000135e-01 1.527153968812958752e-08 0.000000000000000000 +4.806099999999999817e-01 1.501570490329198411e-08 0.000000000000000000 +4.816050000000000053e-01 1.476414650728518093e-08 0.000000000000000000 +4.826000000000000290e-01 1.451679214561021136e-08 0.000000000000000000 +4.835949999999999971e-01 1.427357072605299284e-08 0.000000000000000000 +4.845900000000000207e-01 1.403441239554192092e-08 0.000000000000000000 +4.855849999999999889e-01 1.379924851741501211e-08 0.000000000000000000 +4.865800000000000125e-01 1.356801164916471703e-08 0.000000000000000000 +4.875749999999999806e-01 1.334063552058006977e-08 0.000000000000000000 +4.885700000000000043e-01 1.311705501236100186e-08 0.000000000000000000 +4.895650000000000279e-01 1.289720613511240166e-08 0.000000000000000000 +4.905599999999999961e-01 1.268102600878624253e-08 0.000000000000000000 +4.915550000000000197e-01 1.246845284246573869e-08 0.000000000000000000 +4.925499999999999878e-01 1.225942591461487445e-08 0.000000000000000000 +4.935450000000000115e-01 1.205388555364954470e-08 0.000000000000000000 +4.945400000000000351e-01 1.185177311892213667e-08 0.000000000000000000 +4.955350000000000033e-01 1.165303098206406425e-08 0.000000000000000000 +4.965300000000000269e-01 1.145760250866327575e-08 0.000000000000000000 +4.975249999999999950e-01 1.126543204035432285e-08 0.000000000000000000 +4.985200000000000187e-01 1.107646487718022137e-08 0.000000000000000000 +4.995149999999999868e-01 1.089064726035936574e-08 0.000000000000000000 +5.005100000000000104e-01 1.070792635533893917e-08 0.000000000000000000 +5.015049999999999786e-01 1.052825023518430476e-08 0.000000000000000000 +5.024999999999999467e-01 1.035156786429983128e-08 0.000000000000000000 +5.034950000000000259e-01 1.017782908245194928e-08 0.000000000000000000 +5.044899999999999940e-01 1.000698458908213401e-08 0.000000000000000000 +5.054849999999999621e-01 9.838985927942606211e-09 0.000000000000000000 +5.064800000000000413e-01 9.673785472016118153e-09 0.000000000000000000 +5.074750000000000094e-01 9.511336408707597594e-09 0.000000000000000000 +5.084699999999999775e-01 9.351592725336316339e-09 0.000000000000000000 +5.094650000000000567e-01 9.194509194901617369e-09 0.000000000000000000 +5.104600000000000248e-01 9.040041362103622041e-09 0.000000000000000000 +5.114549999999999930e-01 8.888145529627538254e-09 0.000000000000000000 +5.124499999999999611e-01 8.738778744717595970e-09 0.000000000000000000 +5.134450000000000403e-01 8.591898785946051782e-09 0.000000000000000000 +5.144400000000000084e-01 8.447464150305248862e-09 0.000000000000000000 +5.154349999999999765e-01 8.305434040478789650e-09 0.000000000000000000 +5.164300000000000557e-01 8.165768352358212425e-09 0.000000000000000000 +5.174250000000000238e-01 8.028427662851563377e-09 0.000000000000000000 +5.184199999999999919e-01 7.893373217842216118e-09 0.000000000000000000 +5.194149999999999601e-01 7.760566920435978511e-09 0.000000000000000000 +5.204100000000000392e-01 7.629971319358478376e-09 0.000000000000000000 +5.214050000000000074e-01 7.501549597652244998e-09 0.000000000000000000 +5.223999999999999755e-01 7.375265561526750397e-09 0.000000000000000000 +5.233950000000000546e-01 7.251083629405264984e-09 0.000000000000000000 +5.243900000000000228e-01 7.128968821243475963e-09 0.000000000000000000 +5.253849999999999909e-01 7.008886747960125850e-09 0.000000000000000000 +5.263799999999999590e-01 6.890803601115932548e-09 0.000000000000000000 +5.273750000000000382e-01 6.774686142796504578e-09 0.000000000000000000 +5.283700000000000063e-01 6.660501695615936994e-09 0.000000000000000000 +5.293649999999999745e-01 6.548218132964528978e-09 0.000000000000000000 +5.303600000000000536e-01 6.437803869424564685e-09 0.000000000000000000 +5.313550000000000217e-01 6.329227851337567396e-09 0.000000000000000000 +5.323499999999999899e-01 6.222459547568204285e-09 0.000000000000000000 +5.333449999999999580e-01 6.117468940427315924e-09 0.000000000000000000 +5.343400000000000372e-01 6.014226516756166591e-09 0.000000000000000000 +5.353350000000000053e-01 5.912703259200147065e-09 0.000000000000000000 +5.363299999999999734e-01 5.812870637596286722e-09 0.000000000000000000 +5.373250000000000526e-01 5.714700600562036045e-09 0.000000000000000000 +5.383200000000000207e-01 5.618165567214210133e-09 0.000000000000000000 +5.393149999999999888e-01 5.523238419030037714e-09 0.000000000000000000 +5.403099999999999570e-01 5.429892491889169139e-09 0.000000000000000000 +5.413050000000000361e-01 5.338101568217842023e-09 0.000000000000000000 +5.423000000000000043e-01 5.247839869312100044e-09 0.000000000000000000 +5.432949999999999724e-01 5.159082047782700767e-09 0.000000000000000000 +5.442900000000000515e-01 5.071803180117107580e-09 0.000000000000000000 +5.452850000000000197e-01 4.985978759425942900e-09 0.000000000000000000 +5.462799999999999878e-01 4.901584688272952708e-09 0.000000000000000000 +5.472749999999999559e-01 4.818597271653313524e-09 0.000000000000000000 +5.482700000000000351e-01 4.736993210097703913e-09 0.000000000000000000 +5.492650000000000032e-01 4.656749592899734273e-09 0.000000000000000000 +5.502599999999999714e-01 4.577843891457445651e-09 0.000000000000000000 +5.512550000000000505e-01 4.500253952754923854e-09 0.000000000000000000 +5.522500000000000187e-01 4.423957992928620999e-09 0.000000000000000000 +5.532449999999999868e-01 4.348934590969638247e-09 0.000000000000000000 +5.542399999999999549e-01 4.275162682547729828e-09 0.000000000000000000 +5.552350000000000341e-01 4.202621553908566314e-09 0.000000000000000000 +5.562300000000000022e-01 4.131290835932150873e-09 0.000000000000000000 +5.572249999999999703e-01 4.061150498237967917e-09 0.000000000000000000 +5.582200000000000495e-01 3.992180843446344811e-09 0.000000000000000000 +5.592150000000000176e-01 3.924362501509357965e-09 0.000000000000000000 +5.602099999999999858e-01 3.857676424154716910e-09 0.000000000000000000 +5.612049999999999539e-01 3.792103879430714948e-09 0.000000000000000000 +5.622000000000000330e-01 3.727626446332447825e-09 0.000000000000000000 +5.631950000000000012e-01 3.664226009549415779e-09 0.000000000000000000 +5.641899999999999693e-01 3.601884754267642989e-09 0.000000000000000000 +5.651850000000000485e-01 3.540585161106631196e-09 0.000000000000000000 +5.661800000000000166e-01 3.480310001116348841e-09 0.000000000000000000 +5.671749999999999847e-01 3.421042330867932332e-09 0.000000000000000000 +5.681700000000000639e-01 3.362765487628045872e-09 0.000000000000000000 +5.691650000000000320e-01 3.305463084633811144e-09 0.000000000000000000 +5.701600000000000001e-01 3.249119006439248004e-09 0.000000000000000000 +5.711549999999999683e-01 3.193717404330445612e-09 0.000000000000000000 +5.721500000000000474e-01 3.139242691846669754e-09 0.000000000000000000 +5.731450000000000156e-01 3.085679540359040699e-09 0.000000000000000000 +5.741399999999999837e-01 3.033012874741313056e-09 0.000000000000000000 +5.751350000000000628e-01 2.981227869103609884e-09 0.000000000000000000 +5.761300000000000310e-01 2.930309942605486299e-09 0.000000000000000000 +5.771249999999999991e-01 2.880244755344017550e-09 0.000000000000000000 +5.781199999999999672e-01 2.831018204320024633e-09 0.000000000000000000 +5.791150000000000464e-01 2.782616419444479799e-09 0.000000000000000000 +5.801100000000000145e-01 2.735025759662029664e-09 0.000000000000000000 +5.811049999999999827e-01 2.688232809096205337e-09 0.000000000000000000 +5.821000000000000618e-01 2.642224373286249017e-09 0.000000000000000000 +5.830950000000000299e-01 2.596987475486436551e-09 0.000000000000000000 +5.840899999999999981e-01 2.552509353022799725e-09 0.000000000000000000 +5.850849999999999662e-01 2.508777453719068253e-09 0.000000000000000000 +5.860800000000000454e-01 2.465779432375947976e-09 0.000000000000000000 +5.870750000000000135e-01 2.423503147329195027e-09 0.000000000000000000 +5.880699999999999816e-01 2.381936657034776456e-09 0.000000000000000000 +5.890650000000000608e-01 2.341068216750600869e-09 0.000000000000000000 +5.900600000000000289e-01 2.300886275249319634e-09 0.000000000000000000 +5.910549999999999971e-01 2.261379471589899679e-09 0.000000000000000000 +5.920499999999999652e-01 2.222536631965092181e-09 0.000000000000000000 +5.930450000000000443e-01 2.184346766572887835e-09 0.000000000000000000 +5.940400000000000125e-01 2.146799066563923027e-09 0.000000000000000000 +5.950349999999999806e-01 2.109882901029975367e-09 0.000000000000000000 +5.960300000000000598e-01 2.073587814052807845e-09 0.000000000000000000 +5.970250000000000279e-01 2.037903521796197191e-09 0.000000000000000000 +5.980199999999999960e-01 2.002819909644348453e-09 0.000000000000000000 +5.990149999999999642e-01 1.968327029405863638e-09 0.000000000000000000 +6.000100000000000433e-01 1.934415096543460493e-09 0.000000000000000000 +6.010050000000000114e-01 1.901074487462710610e-09 0.000000000000000000 +6.019999999999999796e-01 1.868295736852988358e-09 0.000000000000000000 +6.029950000000000587e-01 1.836069535059167139e-09 0.000000000000000000 +6.039900000000000269e-01 1.804386725507524731e-09 0.000000000000000000 +6.049849999999999950e-01 1.773238302172079969e-09 0.000000000000000000 +6.059799999999999631e-01 1.742615407085404039e-09 0.000000000000000000 +6.069750000000000423e-01 1.712509327890016968e-09 0.000000000000000000 +6.079700000000000104e-01 1.682911495434136928e-09 0.000000000000000000 +6.089649999999999785e-01 1.653813481399450726e-09 0.000000000000000000 +6.099600000000000577e-01 1.625206995987396573e-09 0.000000000000000000 +6.109550000000000258e-01 1.597083885620513122e-09 0.000000000000000000 +6.119499999999999940e-01 1.569436130702139067e-09 0.000000000000000000 +6.129449999999999621e-01 1.542255843404127068e-09 0.000000000000000000 +6.139400000000000412e-01 1.515535265493257126e-09 0.000000000000000000 +6.149350000000000094e-01 1.489266766199405405e-09 0.000000000000000000 +6.159299999999999775e-01 1.463442840109179879e-09 0.000000000000000000 +6.169250000000000567e-01 1.438056105105303416e-09 0.000000000000000000 +6.179200000000000248e-01 1.413099300335438690e-09 0.000000000000000000 +6.189149999999999929e-01 1.388565284219914378e-09 0.000000000000000000 +6.199099999999999611e-01 1.364447032482016621e-09 0.000000000000000000 +6.209050000000000402e-01 1.340737636223382316e-09 0.000000000000000000 +6.219000000000000083e-01 1.317430300025572456e-09 0.000000000000000000 +6.228949999999999765e-01 1.294518340085705259e-09 0.000000000000000000 +6.238900000000000556e-01 1.271995182379897042e-09 0.000000000000000000 +6.248850000000000238e-01 1.249854360861907686e-09 0.000000000000000000 +6.258799999999999919e-01 1.228089515688482748e-09 0.000000000000000000 +6.268749999999999600e-01 1.206694391477565856e-09 0.000000000000000000 +6.278700000000000392e-01 1.185662835590238378e-09 0.000000000000000000 +6.288650000000000073e-01 1.164988796445623888e-09 0.000000000000000000 +6.298599999999999755e-01 1.144666321867794175e-09 0.000000000000000000 +6.308550000000000546e-01 1.124689557446997487e-09 0.000000000000000000 +6.318500000000000227e-01 1.105052744945311523e-09 0.000000000000000000 +6.328449999999999909e-01 1.085750220710908845e-09 0.000000000000000000 +6.338399999999999590e-01 1.066776414137267750e-09 0.000000000000000000 +6.348350000000000382e-01 1.048125846132423263e-09 0.000000000000000000 +6.358300000000000063e-01 1.029793127619577583e-09 0.000000000000000000 +6.368249999999999744e-01 1.011772958067064884e-09 0.000000000000000000 +6.378200000000000536e-01 9.940601240353204801e-10 0.000000000000000000 +6.388150000000000217e-01 9.766494977525064135e-10 0.000000000000000000 +6.398099999999999898e-01 9.595360357101928669e-10 0.000000000000000000 +6.408049999999999580e-01 9.427147772883389336e-10 0.000000000000000000 +6.418000000000000371e-01 9.261808433944503319e-10 0.000000000000000000 +6.427950000000000053e-01 9.099294351329261107e-10 0.000000000000000000 +6.437899999999999734e-01 8.939558324953548407e-10 0.000000000000000000 +6.447850000000000525e-01 8.782553930644280603e-10 0.000000000000000000 +6.457800000000000207e-01 8.628235507521241244e-10 0.000000000000000000 +6.467749999999999888e-01 8.476558145459802247e-10 0.000000000000000000 +6.477699999999999569e-01 8.327477672877727265e-10 0.000000000000000000 +6.487650000000000361e-01 8.180950644622847663e-10 0.000000000000000000 +6.497600000000000042e-01 8.036934330121838051e-10 0.000000000000000000 +6.507549999999999724e-01 7.895386701715532421e-10 0.000000000000000000 +6.517500000000000515e-01 7.756266423150475058e-10 0.000000000000000000 +6.527450000000000196e-01 7.619532838310401384e-10 0.000000000000000000 +6.537399999999999878e-01 7.485145960110557591e-10 0.000000000000000000 +6.547349999999999559e-01 7.353066459561349298e-10 0.000000000000000000 +6.557300000000000351e-01 7.223255655019091240e-10 0.000000000000000000 +6.567250000000000032e-01 7.095675501633230957e-10 0.000000000000000000 +6.577199999999999713e-01 6.970288580952831633e-10 0.000000000000000000 +6.587150000000000505e-01 6.847058090697376434e-10 0.000000000000000000 +6.597100000000000186e-01 6.725947834695765550e-10 0.000000000000000000 +6.607049999999999867e-01 6.606922213008890459e-10 0.000000000000000000 +6.616999999999999549e-01 6.489946212177306857e-10 0.000000000000000000 +6.626950000000000340e-01 6.374985395695149751e-10 0.000000000000000000 +6.636900000000000022e-01 6.262005894555813714e-10 0.000000000000000000 +6.646849999999999703e-01 6.150974398006807465e-10 0.000000000000000000 +6.656800000000000495e-01 6.041858144460597144e-10 0.000000000000000000 +6.666750000000000176e-01 5.934624912519768004e-10 0.000000000000000000 +6.676699999999999857e-01 5.829243012166442471e-10 0.000000000000000000 +6.686650000000000649e-01 5.725681276106499875e-10 0.000000000000000000 +6.696600000000000330e-01 5.623909051228168385e-10 0.000000000000000000 +6.706550000000000011e-01 5.523896190237439203e-10 0.000000000000000000 +6.716499999999999693e-01 5.425613043398145989e-10 0.000000000000000000 +6.726450000000000484e-01 5.329030450417581546e-10 0.000000000000000000 +6.736400000000000166e-01 5.234119732464745679e-10 0.000000000000000000 +6.746349999999999847e-01 5.140852684323522755e-10 0.000000000000000000 +6.756300000000000638e-01 5.049201566664096458e-10 0.000000000000000000 +6.766250000000000320e-01 4.959139098454811543e-10 0.000000000000000000 +6.776200000000000001e-01 4.870638449487790499e-10 0.000000000000000000 +6.786149999999999682e-01 4.783673233012896401e-10 0.000000000000000000 +6.796100000000000474e-01 4.698217498523995215e-10 0.000000000000000000 +6.806050000000000155e-01 4.614245724643800463e-10 0.000000000000000000 +6.815999999999999837e-01 4.531732812111723066e-10 0.000000000000000000 +6.825950000000000628e-01 4.450654076920853576e-10 0.000000000000000000 +6.835900000000000309e-01 4.370985243527584836e-10 0.000000000000000000 +6.845849999999999991e-01 4.292702438197627921e-10 0.000000000000000000 +6.855799999999999672e-01 4.215782182455686226e-10 0.000000000000000000 +6.865750000000000464e-01 4.140201386645318280e-10 0.000000000000000000 +6.875700000000000145e-01 4.065937343561940905e-10 0.000000000000000000 +6.885649999999999826e-01 3.992967722240903926e-10 0.000000000000000000 +6.895600000000000618e-01 3.921270561814422491e-10 0.000000000000000000 +6.905550000000000299e-01 3.850824265461304586e-10 0.000000000000000000 +6.915499999999999980e-01 3.781607594477758664e-10 0.000000000000000000 +6.925449999999999662e-01 3.713599662443719948e-10 0.000000000000000000 +6.935400000000000453e-01 3.646779929451460856e-10 0.000000000000000000 +6.945350000000000135e-01 3.581128196474731658e-10 0.000000000000000000 +6.955299999999999816e-01 3.516624599789905450e-10 0.000000000000000000 +6.965250000000000608e-01 3.453249605512386629e-10 0.000000000000000000 +6.975200000000000289e-01 3.390984004204496542e-10 0.000000000000000000 +6.985149999999999970e-01 3.329808905590815081e-10 0.000000000000000000 +6.995099999999999651e-01 3.269705733336090213e-10 0.000000000000000000 +7.005050000000000443e-01 3.210656219930606029e-10 0.000000000000000000 +7.015000000000000124e-01 3.152642401639120136e-10 0.000000000000000000 +7.024949999999999806e-01 3.095646613535301542e-10 0.000000000000000000 +7.034900000000000597e-01 3.039651484643836440e-10 0.000000000000000000 +7.044850000000000279e-01 2.984639933103836991e-10 0.000000000000000000 +7.054799999999999960e-01 2.930595161482421644e-10 0.000000000000000000 +7.064749999999999641e-01 2.877500652096199171e-10 0.000000000000000000 +7.074700000000000433e-01 2.825340162463892363e-10 0.000000000000000000 +7.084650000000000114e-01 2.774097720789625829e-10 0.000000000000000000 +7.094599999999999795e-01 2.723757621550416838e-10 0.000000000000000000 +7.104550000000000587e-01 2.674304421138305059e-10 0.000000000000000000 +7.114500000000000268e-01 2.625722933581207666e-10 0.000000000000000000 +7.124449999999999950e-01 2.577998226317362304e-10 0.000000000000000000 +7.134399999999999631e-01 2.531115616069366224e-10 0.000000000000000000 +7.144350000000000422e-01 2.485060664753810539e-10 0.000000000000000000 +7.154300000000000104e-01 2.439819175467779222e-10 0.000000000000000000 +7.164249999999999785e-01 2.395377188552389620e-10 0.000000000000000000 +7.174200000000000577e-01 2.351720977695691270e-10 0.000000000000000000 +7.184150000000000258e-01 2.308837046132094100e-10 0.000000000000000000 +7.194099999999999939e-01 2.266712122853988755e-10 0.000000000000000000 +7.204049999999999621e-01 2.225333158951815671e-10 0.000000000000000000 +7.214000000000000412e-01 2.184687323937923984e-10 0.000000000000000000 +7.223950000000000093e-01 2.144762002199834842e-10 0.000000000000000000 +7.233899999999999775e-01 2.105544789457397629e-10 0.000000000000000000 +7.243850000000000566e-01 2.067023489314449509e-10 0.000000000000000000 +7.253800000000000248e-01 2.029186109836347890e-10 0.000000000000000000 +7.263749999999999929e-01 1.992020860208143683e-10 0.000000000000000000 +7.273699999999999610e-01 1.955516147432110017e-10 0.000000000000000000 +7.283650000000000402e-01 1.919660573080928565e-10 0.000000000000000000 +7.293600000000000083e-01 1.884442930107386533e-10 0.000000000000000000 +7.303549999999999764e-01 1.849852199707302973e-10 0.000000000000000000 +7.313500000000000556e-01 1.815877548214458977e-10 0.000000000000000000 +7.323450000000000237e-01 1.782508324083276738e-10 0.000000000000000000 +7.333399999999999919e-01 1.749734054871994406e-10 0.000000000000000000 +7.343349999999999600e-01 1.717544444327696856e-10 0.000000000000000000 +7.353300000000000392e-01 1.685929369464436664e-10 0.000000000000000000 +7.363250000000000073e-01 1.654878877736655847e-10 0.000000000000000000 +7.373199999999999754e-01 1.624383184224845999e-10 0.000000000000000000 +7.383150000000000546e-01 1.594432668877642051e-10 0.000000000000000000 +7.393100000000000227e-01 1.565017873814703209e-10 0.000000000000000000 +7.403049999999999908e-01 1.536129500638754654e-10 0.000000000000000000 +7.412999999999999590e-01 1.507758407823909257e-10 0.000000000000000000 +7.422950000000000381e-01 1.479895608131337696e-10 0.000000000000000000 +7.432900000000000063e-01 1.452532266062458961e-10 0.000000000000000000 +7.442849999999999744e-01 1.425659695365616108e-10 0.000000000000000000 +7.452800000000000535e-01 1.399269356573926378e-10 0.000000000000000000 +7.462750000000000217e-01 1.373352854587497921e-10 0.000000000000000000 +7.472699999999999898e-01 1.347901936294661017e-10 0.000000000000000000 +7.482649999999999579e-01 1.322908488223341237e-10 0.000000000000000000 +7.492600000000000371e-01 1.298364534248632290e-10 0.000000000000000000 +7.502550000000000052e-01 1.274262233316630721e-10 0.000000000000000000 +7.512499999999999734e-01 1.250593877217680957e-10 0.000000000000000000 +7.522450000000000525e-01 1.227351888398047800e-10 0.000000000000000000 +7.532400000000000206e-01 1.204528817793964409e-10 0.000000000000000000 +7.542349999999999888e-01 1.182117342713846246e-10 0.000000000000000000 +7.552299999999999569e-01 1.160110264747073532e-10 0.000000000000000000 +7.562250000000000361e-01 1.138500507714065408e-10 0.000000000000000000 +7.572200000000000042e-01 1.117281115635054185e-10 0.000000000000000000 +7.582149999999999723e-01 1.096445250754567631e-10 0.000000000000000000 +7.592100000000000515e-01 1.075986191572987652e-10 0.000000000000000000 +7.602050000000000196e-01 1.055897330930012879e-10 0.000000000000000000 +7.611999999999999877e-01 1.036172174105339540e-10 0.000000000000000000 +7.621949999999999559e-01 1.016804336962519086e-10 0.000000000000000000 +7.631900000000000350e-01 9.977875441096356335e-11 0.000000000000000000 +7.641850000000000032e-01 9.791156271008344962e-11 0.000000000000000000 +7.651799999999999713e-01 9.607825226625470990e-11 0.000000000000000000 +7.661750000000000504e-01 9.427822709455359464e-11 0.000000000000000000 +7.671700000000000186e-01 9.251090138124984059e-11 0.000000000000000000 +7.681649999999999867e-01 9.077569931482582088e-11 0.000000000000000000 +7.691599999999999548e-01 8.907205491965810509e-11 0.000000000000000000 +7.701550000000000340e-01 8.739941189288420762e-11 0.000000000000000000 +7.711500000000000021e-01 8.575722344352985258e-11 0.000000000000000000 +7.721449999999999703e-01 8.414495213434765917e-11 0.000000000000000000 +7.731400000000000494e-01 8.256206972622971592e-11 0.000000000000000000 +7.741350000000000176e-01 8.100805702532533275e-11 0.000000000000000000 +7.751299999999999857e-01 7.948240373228508669e-11 0.000000000000000000 +7.761250000000000648e-01 7.798460829422891543e-11 0.000000000000000000 +7.771200000000000330e-01 7.651417775903194526e-11 0.000000000000000000 +7.781150000000000011e-01 7.507062763206356851e-11 0.000000000000000000 +7.791099999999999692e-01 7.365348173517222601e-11 0.000000000000000000 +7.801050000000000484e-01 7.226227206788986404e-11 0.000000000000000000 +7.811000000000000165e-01 7.089653867113503250e-11 0.000000000000000000 +7.820949999999999847e-01 6.955582949297110040e-11 0.000000000000000000 +7.830900000000000638e-01 6.823970025633168779e-11 0.000000000000000000 +7.840850000000000319e-01 6.694771432965168588e-11 0.000000000000000000 +7.850800000000000001e-01 6.567944259862998955e-11 0.000000000000000000 +7.860749999999999682e-01 6.443446334061711945e-11 0.000000000000000000 +7.870700000000000474e-01 6.321236210132198715e-11 0.000000000000000000 +7.880650000000000155e-01 6.201273157282145684e-11 0.000000000000000000 +7.890599999999999836e-01 6.083517147412531346e-11 0.000000000000000000 +7.900550000000000628e-01 5.967928843341275616e-11 0.000000000000000000 +7.910500000000000309e-01 5.854469587245565986e-11 0.000000000000000000 +7.920449999999999990e-01 5.743101389234423935e-11 0.000000000000000000 +7.930399999999999672e-01 5.633786916210906675e-11 0.000000000000000000 +7.940350000000000463e-01 5.526489480788727048e-11 0.000000000000000000 +7.950300000000000145e-01 5.421173030509729357e-11 0.000000000000000000 +7.960249999999999826e-01 5.317802137138497194e-11 0.000000000000000000 +7.970200000000000617e-01 5.216341986217019749e-11 0.000000000000000000 +7.980150000000000299e-01 5.116758366718568742e-11 0.000000000000000000 +7.990099999999999980e-01 5.019017660923670763e-11 0.000000000000000000 +8.000049999999999661e-01 4.923086834421724464e-11 0.000000000000000000 +8.010000000000000453e-01 4.828933426320927044e-11 0.000000000000000000 +8.019950000000000134e-01 4.736525539558188763e-11 0.000000000000000000 +8.029899999999999816e-01 4.645831831438245641e-11 0.000000000000000000 +8.039850000000000607e-01 4.556821504268652730e-11 0.000000000000000000 +8.049800000000000288e-01 4.469464296170416256e-11 0.000000000000000000 +8.059749999999999970e-01 4.383730472068802512e-11 0.000000000000000000 +8.069699999999999651e-01 4.299590814766838308e-11 0.000000000000000000 +8.079650000000000443e-01 4.217016616230079168e-11 0.000000000000000000 +8.089600000000000124e-01 4.135979668960845514e-11 0.000000000000000000 +8.099549999999999805e-01 4.056452257571198034e-11 0.000000000000000000 +8.109500000000000597e-01 3.978407150433260260e-11 0.000000000000000000 +8.119450000000000278e-01 3.901817591526678961e-11 0.000000000000000000 +8.129399999999999959e-01 3.826657292356815587e-11 0.000000000000000000 +8.139349999999999641e-01 3.752900424059828834e-11 0.000000000000000000 +8.149300000000000432e-01 3.680521609627443136e-11 0.000000000000000000 +8.159250000000000114e-01 3.609495916209530939e-11 0.000000000000000000 +8.169199999999999795e-01 3.539798847631480826e-11 0.000000000000000000 +8.179150000000000587e-01 3.471406336951419588e-11 0.000000000000000000 +8.189100000000000268e-01 3.404294739185910951e-11 0.000000000000000000 +8.199049999999999949e-01 3.338440824150709322e-11 0.000000000000000000 +8.208999999999999631e-01 3.273821769404085850e-11 0.000000000000000000 +8.218950000000000422e-01 3.210415153329436856e-11 0.000000000000000000 +8.228900000000000103e-01 3.148198948294768353e-11 0.000000000000000000 +8.238849999999999785e-01 3.087151513973246205e-11 0.000000000000000000 +8.248800000000000576e-01 3.027251590737155331e-11 0.000000000000000000 +8.258750000000000258e-01 2.968478293185995294e-11 0.000000000000000000 +8.268699999999999939e-01 2.910811103743564697e-11 0.000000000000000000 +8.278649999999999620e-01 2.854229866422437845e-11 0.000000000000000000 +8.288600000000000412e-01 2.798714780617325204e-11 0.000000000000000000 +8.298550000000000093e-01 2.744246395074316365e-11 0.000000000000000000 +8.308499999999999774e-01 2.690805601903921905e-11 0.000000000000000000 +8.318450000000000566e-01 2.638373630713539760e-11 0.000000000000000000 +8.328400000000000247e-01 2.586932042855219276e-11 0.000000000000000000 +8.338349999999999929e-01 2.536462725737758588e-11 0.000000000000000000 +8.348299999999999610e-01 2.486947887248887770e-11 0.000000000000000000 +8.358250000000000401e-01 2.438370050272607173e-11 0.000000000000000000 +8.368200000000000083e-01 2.390712047288832168e-11 0.000000000000000000 +8.378149999999999764e-01 2.343957015071224223e-11 0.000000000000000000 +8.388100000000000556e-01 2.298088389467405944e-11 0.000000000000000000 +8.398050000000000237e-01 2.253089900258152798e-11 0.000000000000000000 +8.407999999999999918e-01 2.208945566131302509e-11 0.000000000000000000 +8.417949999999999600e-01 2.165639689701962011e-11 0.000000000000000000 +8.427900000000000391e-01 2.123156852639565456e-11 0.000000000000000000 +8.437850000000000072e-01 2.081481910870578539e-11 0.000000000000000000 +8.447799999999999754e-01 2.040599989851381981e-11 0.000000000000000000 +8.457750000000000545e-01 2.000496479944291845e-11 0.000000000000000000 +8.467700000000000227e-01 1.961157031843802305e-11 0.000000000000000000 +8.477649999999999908e-01 1.922567552086915531e-11 0.000000000000000000 +8.487599999999999589e-01 1.884714198652079419e-11 0.000000000000000000 +8.497550000000000381e-01 1.847583376615353297e-11 0.000000000000000000 +8.507500000000000062e-01 1.811161733888242197e-11 0.000000000000000000 +8.517449999999999743e-01 1.775436157018041761e-11 0.000000000000000000 +8.527400000000000535e-01 1.740393767069240377e-11 0.000000000000000000 +8.537350000000000216e-01 1.706021915565210826e-11 0.000000000000000000 +8.547299999999999898e-01 1.672308180502099934e-11 0.000000000000000000 +8.557249999999999579e-01 1.639240362433276411e-11 0.000000000000000000 +8.567200000000000371e-01 1.606806480605511399e-11 0.000000000000000000 +8.577150000000000052e-01 1.574994769175799766e-11 0.000000000000000000 +8.587099999999999733e-01 1.543793673481743599e-11 0.000000000000000000 +8.597050000000000525e-01 1.513191846380246931e-11 0.000000000000000000 +8.607000000000000206e-01 1.483178144642076169e-11 0.000000000000000000 +8.616949999999999887e-01 1.453741625408964590e-11 0.000000000000000000 +8.626899999999999569e-01 1.424871542717199542e-11 0.000000000000000000 +8.636850000000000360e-01 1.396557344067323184e-11 0.000000000000000000 +8.646800000000000042e-01 1.368788667062002115e-11 0.000000000000000000 +8.656749999999999723e-01 1.341555336091990615e-11 0.000000000000000000 +8.666700000000000514e-01 1.314847359090981869e-11 0.000000000000000000 +8.676650000000000196e-01 1.288654924319432812e-11 0.000000000000000000 +8.686599999999999877e-01 1.262968397242288672e-11 0.000000000000000000 +8.696549999999999558e-01 1.237778317413847121e-11 0.000000000000000000 +8.706500000000000350e-01 1.213075395458402982e-11 0.000000000000000000 +8.716450000000000031e-01 1.188850510063939789e-11 0.000000000000000000 +8.726399999999999713e-01 1.165094705056480650e-11 0.000000000000000000 +8.736350000000000504e-01 1.141799186504683717e-11 0.000000000000000000 +8.746300000000000185e-01 1.118955319883575737e-11 0.000000000000000000 +8.756249999999999867e-01 1.096554627279212947e-11 0.000000000000000000 +8.766200000000000658e-01 1.074588784648897165e-11 0.000000000000000000 +8.776150000000000340e-01 1.053049619119633637e-11 0.000000000000000000 +8.786100000000000021e-01 1.031929106337711392e-11 0.000000000000000000 +8.796049999999999702e-01 1.011219367860600992e-11 0.000000000000000000 +8.806000000000000494e-01 9.909126685931416669e-12 0.000000000000000000 +8.815950000000000175e-01 9.710014142709092467e-12 0.000000000000000000 +8.825899999999999856e-01 9.514781489789963117e-12 0.000000000000000000 +8.835850000000000648e-01 9.323355527214140165e-12 0.000000000000000000 +8.845800000000000329e-01 9.135664390280521159e-12 0.000000000000000000 +8.855750000000000011e-01 8.951637525956803811e-12 0.000000000000000000 +8.865699999999999692e-01 8.771205669848477140e-12 0.000000000000000000 +8.875650000000000484e-01 8.594300823370846695e-12 0.000000000000000000 +8.885600000000000165e-01 8.420856231485389200e-12 0.000000000000000000 +8.895549999999999846e-01 8.250806360685502162e-12 0.000000000000000000 +8.905500000000000638e-01 8.084086877442745888e-12 0.000000000000000000 +8.915450000000000319e-01 7.920634626948725029e-12 0.000000000000000000 +8.925400000000000000e-01 7.760387612281252380e-12 0.000000000000000000 +8.935349999999999682e-01 7.603284973905482060e-12 0.000000000000000000 +8.945300000000000473e-01 7.449266969506496546e-12 0.000000000000000000 +8.955250000000000155e-01 7.298274954195714714e-12 0.000000000000000000 +8.965199999999999836e-01 7.150251361045872353e-12 0.000000000000000000 +8.975150000000000627e-01 7.005139681932871316e-12 0.000000000000000000 +8.985100000000000309e-01 6.862884448759745745e-12 0.000000000000000000 +8.995049999999999990e-01 6.723431214957391286e-12 0.000000000000000000 +9.004999999999999671e-01 6.586726537320808128e-12 0.000000000000000000 +9.014950000000000463e-01 6.452717958148575220e-12 0.000000000000000000 +9.024900000000000144e-01 6.321353987697752509e-12 0.000000000000000000 +9.034849999999999826e-01 6.192584086955323570e-12 0.000000000000000000 +9.044800000000000617e-01 6.066358650650915654e-12 0.000000000000000000 +9.054750000000000298e-01 5.942628990640109593e-12 0.000000000000000000 +9.064699999999999980e-01 5.821347319489051845e-12 0.000000000000000000 +9.074649999999999661e-01 5.702466734432494170e-12 0.000000000000000000 +9.084600000000000453e-01 5.585941201518969179e-12 0.000000000000000000 +9.094550000000000134e-01 5.471725540095875727e-12 0.000000000000000000 +9.104499999999999815e-01 5.359775407532663075e-12 0.000000000000000000 +9.114450000000000607e-01 5.250047284201808633e-12 0.000000000000000000 +9.124400000000000288e-01 5.142498458759478234e-12 0.000000000000000000 +9.134349999999999969e-01 5.037087013620237808e-12 0.000000000000000000 +9.144299999999999651e-01 4.933771810723792127e-12 0.000000000000000000 +9.154250000000000442e-01 4.832512477559490473e-12 0.000000000000000000 +9.164200000000000124e-01 4.733269393382690548e-12 0.000000000000000000 +9.174149999999999805e-01 4.636003675708210934e-12 0.000000000000000000 +9.184100000000000597e-01 4.540677167043161048e-12 0.000000000000000000 +9.194050000000000278e-01 4.447252421825848935e-12 0.000000000000000000 +9.203999999999999959e-01 4.355692693609114473e-12 0.000000000000000000 +9.213949999999999640e-01 4.265961922438394138e-12 0.000000000000000000 +9.223900000000000432e-01 4.178024722488739340e-12 0.000000000000000000 +9.233850000000000113e-01 4.091846369909820615e-12 0.000000000000000000 +9.243799999999999795e-01 4.007392790829750474e-12 0.000000000000000000 +9.253750000000000586e-01 3.924630549657840782e-12 0.000000000000000000 +9.263700000000000268e-01 3.843526837507154298e-12 0.000000000000000000 +9.273649999999999949e-01 3.764049460866051308e-12 0.000000000000000000 +9.283599999999999630e-01 3.686166830456769560e-12 0.000000000000000000 +9.293550000000000422e-01 3.609847950283756110e-12 0.000000000000000000 +9.303500000000000103e-01 3.535062406887417040e-12 0.000000000000000000 +9.313449999999999784e-01 3.461780358757763444e-12 0.000000000000000000 +9.323400000000000576e-01 3.389972525956962532e-12 0.000000000000000000 +9.333350000000000257e-01 3.319610179935919121e-12 0.000000000000000000 +9.343299999999999939e-01 3.250665133472402609e-12 0.000000000000000000 +9.353249999999999620e-01 3.183109730872174957e-12 0.000000000000000000 +9.363200000000000411e-01 3.116916838239753724e-12 0.000000000000000000 +9.373150000000000093e-01 3.052059834024750229e-12 0.000000000000000000 +9.383099999999999774e-01 2.988512599643348278e-12 0.000000000000000000 +9.393050000000000566e-01 2.926249510337346485e-12 0.000000000000000000 +9.403000000000000247e-01 2.865245426127051678e-12 0.000000000000000000 +9.412949999999999928e-01 2.805475682992718501e-12 0.000000000000000000 +9.422899999999999610e-01 2.746916084139481357e-12 0.000000000000000000 +9.432850000000000401e-01 2.689542891490299806e-12 0.000000000000000000 +9.442800000000000082e-01 2.633332817262948029e-12 0.000000000000000000 +9.452749999999999764e-01 2.578263015732237005e-12 0.000000000000000000 +9.462700000000000555e-01 2.524311075133569463e-12 0.000000000000000000 +9.472650000000000237e-01 2.471455009705816204e-12 0.000000000000000000 +9.482599999999999918e-01 2.419673251862030195e-12 0.000000000000000000 +9.492549999999999599e-01 2.368944644531134214e-12 0.000000000000000000 +9.502500000000000391e-01 2.319248433593288717e-12 0.000000000000000000 +9.512450000000000072e-01 2.270564260484504975e-12 0.000000000000000000 +9.522399999999999753e-01 2.222872154916162812e-12 0.000000000000000000 +9.532350000000000545e-01 2.176152527732621461e-12 0.000000000000000000 +9.542300000000000226e-01 2.130386163866658255e-12 0.000000000000000000 +9.552249999999999908e-01 2.085554215469351149e-12 0.000000000000000000 +9.562199999999999589e-01 2.041638195121339581e-12 0.000000000000000000 +9.572150000000000380e-01 1.998619969182224490e-12 0.000000000000000000 +9.582100000000000062e-01 1.956481751250051619e-12 0.000000000000000000 +9.592049999999999743e-01 1.915206095750555943e-12 0.000000000000000000 +9.602000000000000535e-01 1.874775891624738814e-12 0.000000000000000000 +9.611950000000000216e-01 1.835174356137109269e-12 0.000000000000000000 +9.621899999999999897e-01 1.796385028799102358e-12 0.000000000000000000 +9.631849999999999579e-01 1.758391765391040215e-12 0.000000000000000000 +9.641800000000000370e-01 1.721178732095956176e-12 0.000000000000000000 +9.651750000000000052e-01 1.684730399735976772e-12 0.000000000000000000 +9.661699999999999733e-01 1.649031538118635951e-12 0.000000000000000000 +9.671650000000000524e-01 1.614067210475218385e-12 0.000000000000000000 +9.681600000000000206e-01 1.579822768003402259e-12 0.000000000000000000 +9.691549999999999887e-01 1.546283844509766956e-12 0.000000000000000000 +9.701499999999999568e-01 1.513436351142013283e-12 0.000000000000000000 +9.711450000000000360e-01 1.481266471218146186e-12 0.000000000000000000 +9.721400000000000041e-01 1.449760655162423748e-12 0.000000000000000000 +9.731349999999999723e-01 1.418905615502230981e-12 0.000000000000000000 +9.741300000000000514e-01 1.388688321986862196e-12 0.000000000000000000 +9.751250000000000195e-01 1.359095996768790642e-12 0.000000000000000000 +9.761199999999999877e-01 1.330116109690863912e-12 0.000000000000000000 +9.771150000000000668e-01 1.301736373650612545e-12 0.000000000000000000 +9.781100000000000350e-01 1.273944740041217820e-12 0.000000000000000000 +9.791050000000000031e-01 1.246729394289011297e-12 0.000000000000000000 +9.800999999999999712e-01 1.220078751455892882e-12 0.000000000000000000 +9.810950000000000504e-01 1.193981451939975580e-12 0.000000000000000000 +9.820900000000000185e-01 1.168426357233797262e-12 0.000000000000000000 +9.830849999999999866e-01 1.143402545775898413e-12 0.000000000000000000 +9.840800000000000658e-01 1.118899308866149742e-12 0.000000000000000000 +9.850750000000000339e-01 1.094906146664561621e-12 0.000000000000000000 +9.860700000000000021e-01 1.071412764247475544e-12 0.000000000000000000 +9.870649999999999702e-01 1.048409067760837229e-12 0.000000000000000000 +9.880600000000000493e-01 1.025885160616447765e-12 0.000000000000000000 +9.890550000000000175e-01 1.003831339770924548e-12 0.000000000000000000 +9.900499999999999856e-01 9.822380920748707792e-13 0.000000000000000000 +9.910450000000000648e-01 9.610960906801041221e-13 0.000000000000000000 +9.920400000000000329e-01 9.403961915179023274e-13 0.000000000000000000 +9.930350000000000010e-01 9.201294298374636062e-13 0.000000000000000000 +9.940299999999999692e-01 9.002870168152242337e-13 0.000000000000000000 +9.950250000000000483e-01 8.808603362145260253e-13 0.000000000000000000 +9.960200000000000164e-01 8.618409411153087119e-13 0.000000000000000000 +9.970149999999999846e-01 8.432205507020908809e-13 0.000000000000000000 +9.980100000000000637e-01 8.249910471071539138e-13 0.000000000000000000 +9.990050000000000319e-01 8.071444723139599604e-13 0.000000000000000000 +1.000000000000000000e+00 7.896730251172689431e-13 0.000000000000000000 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_4.dat b/tests/test_data/ORSO/test_4.dat new file mode 100644 index 00000000..7b99cb86 --- /dev/null +++ b/tests/test_data/ORSO/test_4.dat @@ -0,0 +1,101 @@ +4.999999999999999237e-03 9.660499468321636085e-01 0.000000000000000000e+00 1.061652250360023761e-04 +5.208965929570049704e-03 9.646283312283907563e-01 0.000000000000000000e+00 1.106022080235347408e-04 +5.426665211084315613e-03 9.631435299315659337e-01 0.000000000000000000e+00 1.152246266659623608e-04 +5.653462839144248603e-03 9.615923806647335148e-01 0.000000000000000000e+00 1.200402309100852380e-04 +5.889739062638551202e-03 9.599715341545977942e-01 0.000000000000000000e+00 1.250570945976711191e-04 +6.135890022268412555e-03 9.582774463689063271e-01 0.000000000000000000e+00 1.302836290020575514e-04 +6.392328414716996060e-03 9.565063736552937845e-01 0.000000000000000000e+00 1.357285969304924749e-04 +6.659484184576673627e-03 9.546543728325473932e-01 0.000000000000000000e+00 1.414011274158563051e-04 +6.937805245194089872e-03 9.527173094019888433e-01 0.000000000000000000e+00 1.473107310223976691e-04 +7.227758229641680597e-03 9.506908787954021500e-01 0.000000000000000000e+00 1.534673157911454707e-04 +7.529829273074612438e-03 9.485706483542604150e-01 0.000000000000000000e+00 1.598812038517289096e-04 +7.844524827784976270e-03 9.463521322252024248e-01 0.000000000000000000e+00 1.665631487284599923e-04 +8.172372512319661317e-03 9.440309187595408158e-01 0.000000000000000000e+00 1.735243533696914056e-04 +8.513921996085575816e-03 9.416028824956215182e-01 0.000000000000000000e+00 1.807764889306791788e-04 +8.869745920925360336e-03 9.390645344556776131e-01 0.000000000000000000e+00 1.883317143414410305e-04 +9.240440861208627787e-03 9.364136032254166686e-01 0.000000000000000000e+00 1.962026966924171388e-04 +9.626628324048536189e-03 9.336500112051923095e-01 0.000000000000000000e+00 2.044026324721134858e-04 +1.002895579132056722e-02 9.307775499924635376e-01 0.000000000000000000e+00 2.129452696923334900e-04 +1.044809780523061650e-02 9.278068446083937992e-01 0.000000000000000000e+00 2.218449309380942302e-04 +1.088475709925237553e-02 9.247608214119300563e-01 0.000000000000000000e+00 2.311165373808706110e-04 +1.133966577633027141e-02 9.216853828676729865e-01 0.000000000000000000e+00 2.407756337954316216e-04 +1.181358653632318123e-02 9.186719597214783040e-01 0.000000000000000000e+00 2.508384146222077419e-04 +1.230731395474697620e-02 9.159110487636203946e-01 0.000000000000000000e+00 2.613217511188890515e-04 +1.282167581495980910e-02 9.138467828784078151e-01 0.000000000000000000e+00 2.722432196467755149e-04 +1.335753449602358582e-02 9.108355606753477662e-01 0.000000000000000000e+00 2.836211311393017432e-04 +1.391578841856870238e-02 7.335981045780506360e-01 0.000000000000000000e+00 2.954745618021484190e-04 +1.449737355108597463e-02 2.213862971885717790e-01 0.000000000000000000e+00 3.078233850964063527e-04 +1.510326497917135677e-02 5.065074610089120161e-02 0.000000000000000000e+00 3.206883050584202191e-04 +1.573447854035441712e-02 1.590368472895162949e-02 0.000000000000000000e+00 3.340908910121754400e-04 +1.639207252725145142e-02 4.800075501038165819e-03 0.000000000000000000e+00 3.480536137324245511e-04 +1.707714946189881067e-02 1.223948799745163416e-03 0.000000000000000000e+00 3.625998831191868982e-04 +1.779085794424128605e-02 5.046568494808504907e-04 0.000000000000000000e+00 3.777540874467854378e-04 +1.853439457787469519e-02 8.404754652332931120e-04 0.000000000000000000e+00 3.935416342532259133e-04 +1.930900597627142543e-02 1.458717108645946623e-03 0.000000000000000000e+00 4.099889929384741916e-04 +2.011599085285246946e-02 2.022184226696178543e-03 0.000000000000000000e+00 4.271237391430496191e-04 +2.095670219841026111e-02 2.397327154528816270e-03 0.000000000000000000e+00 4.449746009813422727e-04 +2.183254954953296745e-02 2.551634050707026792e-03 0.000000000000000000e+00 4.635715072071680543e-04 +2.274500135183342431e-02 2.503723878205208874e-03 0.000000000000000000e+00 4.829456373923148504e-04 +2.369558742194500037e-02 2.297014419596041072e-03 0.000000000000000000e+00 5.031294742022117319e-04 +2.468590151241202915e-02 1.984702877815211226e-03 0.000000000000000000e+00 5.241568578563629999e-04 +2.571760398377520920e-02 1.620535097096735370e-03 0.000000000000000000e+00 5.460630428648573405e-04 +2.679242458833201376e-02 1.252789959601383627e-03 0.000000000000000000e+00 5.688847571360784120e-04 +2.791216537023925512e-02 9.202954264280633354e-04 0.000000000000000000e+00 5.926602635547127294e-04 +2.907870368682024739e-02 6.499790081461440973e-04 0.000000000000000000e+00 6.174294241333008141e-04 +3.029399535614193950e-02 4.557902347035073598e-04 0.000000000000000000e+00 6.432337668448841412e-04 +3.156007793613933854e-02 3.389679007057118062e-04 0.000000000000000000e+00 6.701165552488013702e-04 +3.287907414078505841e-02 2.896305199626667578e-04 0.000000000000000000e+00 6.981228610263705585e-04 +3.425319539903139837e-02 2.895827802138814912e-04 0.000000000000000000e+00 7.272996395480660261e-04 +3.568474556249201513e-02 3.160833603894238047e-04 0.000000000000000000e+00 7.576958085988904973e-04 +3.717612476807939659e-02 3.461421601729252370e-04 0.000000000000000000e+00 7.893623303939302548e-04 +3.872983346207417577e-02 3.607471650414172397e-04 0.000000000000000000e+00 8.223522970216000675e-04 +4.034847659237329048e-02 3.483107825318375100e-04 0.000000000000000000e+00 8.567210194578371010e-04 +4.203476797594541542e-02 3.066260485666312411e-04 0.000000000000000000e+00 8.925261203004783862e-04 +4.379153484881635749e-02 2.427846473412773824e-04 0.000000000000000000e+00 9.298276303793059786e-04 +4.562172260621279868e-02 1.708603072276521735e-04 0.000000000000000000e+00 9.686880894037319147e-04 +4.752839974081164709e-02 1.076850793981012493e-04 0.000000000000000000e+00 1.009172650816869167e-03 +4.951476298737475523e-02 6.765012337432836328e-05 0.000000000000000000e+00 1.051349191031792632e-03 +5.158414268239425865e-02 5.796797455235872996e-05 0.000000000000000000e+00 1.095288423233128482e-03 +5.374000834773436097e-02 7.600076548404877867e-05 0.000000000000000000e+00 1.141064015934773043e-03 +5.598597450763168060e-02 1.098724565425083957e-04 0.000000000000000000e+00 1.188752716492522165e-03 +5.832580674880616378e-02 1.425800498622337880e-04 0.000000000000000000e+00 1.238434479778678654e-03 +6.076342803384361668e-02 1.584158826364232800e-04 0.000000000000000000e+00 1.290192602234388778e-03 +6.330292527843461858e-02 1.492439980337561915e-04 0.000000000000000000e+00 1.344113861524451250e-03 +6.594855620349690528e-02 1.177519033425392445e-04 0.000000000000000000e+00 1.400288662028740172e-03 +6.870475647367019212e-02 7.577842573871102763e-05 0.000000000000000000e+00 1.458811186414187651e-03 +7.157614713415108576e-02 3.813747620286129380e-05 0.000000000000000000e+00 1.519779553541433575e-03 +7.456754235833716604e-02 1.502718568743208691e-05 0.000000000000000000e+00 1.583295982970901261e-03 +7.768395751926998605e-02 7.432986794932621371e-06 0.000000000000000000e+00 1.649466966344109589e-03 +8.093061759840886049e-02 8.479436602724126006e-06 0.000000000000000000e+00 1.718403445927546482e-03 +8.431296594583481685e-02 9.720659036587660457e-06 0.000000000000000000e+00 1.790221000618471897e-03 +8.783667340657071165e-02 7.475971384271801476e-06 0.000000000000000000e+00 1.865040039724485304e-03 +9.150764782831966038e-02 4.045160813957839975e-06 0.000000000000000000e+00 1.942986004841762470e-03 +9.533204396656239088e-02 3.178505467676818043e-06 0.000000000000000000e+00 2.024189580170434287e-03 +9.931627380361947310e-02 4.953666565173862248e-06 0.000000000000000000e+00 2.108786911619698213e-03 +1.034670172989808762e-01 5.966968494098515925e-06 0.000000000000000000e+00 2.196919835070051605e-03 +1.077912335889252976e-01 4.395731401080907728e-06 0.000000000000000000e+00 2.288736114175310681e-03 +1.122961726542076877e-01 2.838663311476676714e-06 0.000000000000000000e+00 2.384389688103147591e-03 +1.169893874753767798e-01 4.376365975608713520e-06 0.000000000000000000e+00 2.484040929629491301e-03 +1.218787466961013116e-01 7.365431957590666160e-06 0.000000000000000000e+00 2.587856914019505839e-03 +1.269724478157380210e-01 7.444758004751446953e-06 0.000000000000000000e+00 2.696011699145979719e-03 +1.322790309332581016e-01 4.174506384415917617e-06 0.000000000000000000e+00 2.808686617314733527e-03 +1.378073930655767942e-01 1.378897368540984724e-06 0.000000000000000000e+00 2.926070579286359132e-03 +1.435668030642915372e-01 8.179962055944333663e-07 0.000000000000000000e+00 3.048360391003989995e-03 +1.495669171558374755e-01 7.196203711450000268e-07 0.000000000000000000e+00 3.175761083558122696e-03 +1.558177951311167375e-01 4.074965533304633985e-07 0.000000000000000000e+00 3.308486256941745463e-03 +1.623299172117425582e-01 5.697106402976437542e-07 0.000000000000000000e+00 3.446758438172057518e-03 +1.691142016211787946e-01 6.318259741325602534e-07 0.000000000000000000e+00 3.590809454379265478e-03 +1.761820228902321317e-01 5.884226632043859758e-07 0.000000000000000000e+00 3.740880821487923939e-03 +1.835452309275898974e-01 1.086074476142989135e-06 0.000000000000000000e+00 3.897224149142521597e-03 +1.912161708873765797e-01 1.080905569118702644e-06 0.000000000000000000e+00 4.060101562556204732e-03 +1.992077038670377609e-01 4.319349827800466143e-07 0.000000000000000000e+00 4.229786141989877457e-03 +2.075332284702559316e-01 1.748578430054353337e-07 0.000000000000000000e+00 4.406562380598564102e-03 +2.162067032710481007e-01 1.052279192866519288e-07 0.000000000000000000e+00 4.590726661412603340e-03 +2.252426702167101280e-01 1.207279972283447134e-07 0.000000000000000000e+00 4.782587754253420607e-03 +2.346562790088451700e-01 1.538042650955484403e-07 0.000000000000000000e+00 4.982467333417002313e-03 +2.444633125033515431e-01 2.521547835091313121e-07 0.000000000000000000e+00 5.190700516992979158e-03 +2.546802131719588802e-01 2.588416113893713325e-07 0.000000000000000000e+00 5.407636428723615156e-03 +2.653241106696743179e-01 9.730928539681922884e-08 0.000000000000000000e+00 5.633638783344635526e-03 +2.764128505543612668e-01 3.779049549799957986e-08 0.000000000000000000e+00 5.869086496389332337e-03 +2.879650242066011945e-01 3.707321909920906896e-08 0.000000000000000000e+00 6.114374319478338426e-03 +2.999999999999999334e-01 6.224636414855785008e-08 0.000000000000000000e+00 6.369913502160142078e-03 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_5.dat b/tests/test_data/ORSO/test_5.dat new file mode 100644 index 00000000..66e943fc --- /dev/null +++ b/tests/test_data/ORSO/test_5.dat @@ -0,0 +1,101 @@ +4.999999999999999237e-03 9.995347418414392004e-01 0.000000000000000000e+00 1.061652250360023761e-04 +5.208965929570049704e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.106022080235347408e-04 +5.426665211084315613e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.152246266659623608e-04 +5.653462839144248603e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.200402309100852380e-04 +5.889739062638551202e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.250570945976711191e-04 +6.135890022268412555e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.302836290020575514e-04 +6.392328414716996060e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.357285969304924749e-04 +6.659484184576673627e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.414011274158563051e-04 +6.937805245194089872e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.473107310223976691e-04 +7.227758229641680597e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.534673157911454707e-04 +7.529829273074612438e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.598812038517289096e-04 +7.844524827784976270e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.665631487284599923e-04 +8.172372512319661317e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.735243533696914056e-04 +8.513921996085575816e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.807764889306791788e-04 +8.869745920925360336e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.883317143414410305e-04 +9.240440861208627787e-03 9.995347418414394225e-01 0.000000000000000000e+00 1.962026966924171388e-04 +9.626628324048536189e-03 9.995347409441184272e-01 0.000000000000000000e+00 2.044026324721134858e-04 +1.002895579132056722e-02 9.995345972239910726e-01 0.000000000000000000e+00 2.129452696923334900e-04 +1.044809780523061650e-02 9.995335809338743438e-01 0.000000000000000000e+00 2.218449309380942302e-04 +1.088475709925237553e-02 9.995319376173226189e-01 0.000000000000000000e+00 2.311165373808706110e-04 +1.133966577633027141e-02 9.995294782765237196e-01 0.000000000000000000e+00 2.407756337954316216e-04 +1.181358653632318123e-02 9.995252951907817041e-01 0.000000000000000000e+00 2.508384146222077419e-04 +1.230731395474697620e-02 9.995177248225737276e-01 0.000000000000000000e+00 2.613217511188890515e-04 +1.282167581495980910e-02 9.995032338579179498e-01 0.000000000000000000e+00 2.722432196467755149e-04 +1.335753449602358582e-02 9.994736896749567556e-01 0.000000000000000000e+00 2.836211311393017432e-04 +1.391578841856870238e-02 9.994086786140352618e-01 0.000000000000000000e+00 2.954745618021484190e-04 +1.449737355108597463e-02 9.992511445455712904e-01 0.000000000000000000e+00 3.078233850964063527e-04 +1.510326497917135677e-02 9.988174516917052159e-01 0.000000000000000000e+00 3.206883050584202191e-04 +1.573447854035441712e-02 9.973868504651979272e-01 0.000000000000000000e+00 3.340908910121754400e-04 +1.639207252725145142e-02 9.910958762816924894e-01 0.000000000000000000e+00 3.480536137324245511e-04 +1.707714946189881067e-02 9.456679331164480340e-01 0.000000000000000000e+00 3.625998831191868982e-04 +1.779085794424128605e-02 6.239075595183121159e-01 0.000000000000000000e+00 3.777540874467854378e-04 +1.853439457787469519e-02 2.220532757094483278e-01 0.000000000000000000e+00 3.935416342532259133e-04 +1.930900597627142543e-02 3.395812773155912900e-01 0.000000000000000000e+00 4.099889929384741916e-04 +2.011599085285246946e-02 2.639596573194147311e-01 0.000000000000000000e+00 4.271237391430496191e-04 +2.095670219841026111e-02 7.370336814121217217e-02 0.000000000000000000e+00 4.449746009813422727e-04 +2.183254954953296745e-02 5.762829676915928734e-02 0.000000000000000000e+00 4.635715072071680543e-04 +2.274500135183342431e-02 1.289775859050606155e-01 0.000000000000000000e+00 4.829456373923148504e-04 +2.369558742194500037e-02 1.161359991837665612e-01 0.000000000000000000e+00 5.031294742022117319e-04 +2.468590151241202915e-02 4.324968283846475359e-02 0.000000000000000000e+00 5.241568578563629999e-04 +2.571760398377520920e-02 1.474300569008134970e-02 0.000000000000000000e+00 5.460630428648573405e-04 +2.679242458833201376e-02 4.585137031529725599e-02 0.000000000000000000e+00 5.688847571360784120e-04 +2.791216537023925512e-02 6.062808398501595697e-02 0.000000000000000000e+00 5.926602635547127294e-04 +2.907870368682024739e-02 3.224250745146049757e-02 0.000000000000000000e+00 6.174294241333008141e-04 +3.029399535614193950e-02 7.770236822814377206e-03 0.000000000000000000e+00 6.432337668448841412e-04 +3.156007793613933854e-02 1.995369062054090648e-02 0.000000000000000000e+00 6.701165552488013702e-04 +3.287907414078505841e-02 3.387854049698348080e-02 0.000000000000000000e+00 6.981228610263705585e-04 +3.425319539903139837e-02 1.989645066231699594e-02 0.000000000000000000e+00 7.272996395480660261e-04 +3.568474556249201513e-02 5.320064115781057701e-03 0.000000000000000000e+00 7.576958085988904973e-04 +3.717612476807939659e-02 1.517416261117541035e-02 0.000000000000000000e+00 7.893623303939302548e-04 +3.872983346207417577e-02 2.188266883156762474e-02 0.000000000000000000e+00 8.223522970216000675e-04 +4.034847659237329048e-02 9.035769538976985357e-03 0.000000000000000000e+00 8.567210194578371010e-04 +4.203476797594541542e-02 6.566239737102203683e-03 0.000000000000000000e+00 8.925261203004783862e-04 +4.379153484881635749e-02 1.737568809464553818e-02 0.000000000000000000e+00 9.298276303793059786e-04 +4.562172260621279868e-02 1.142390005087293506e-02 0.000000000000000000e+00 9.686880894037319147e-04 +4.752839974081164709e-02 5.661994425118474332e-03 0.000000000000000000e+00 1.009172650816869167e-03 +4.951476298737475523e-02 1.686894590267987853e-02 0.000000000000000000e+00 1.051349191031792632e-03 +5.158414268239425865e-02 1.193631975965038332e-02 0.000000000000000000e+00 1.095288423233128482e-03 +5.374000834773436097e-02 1.010241440505187972e-02 0.000000000000000000e+00 1.141064015934773043e-03 +5.598597450763168060e-02 2.645723338110145262e-02 0.000000000000000000e+00 1.188752716492522165e-03 +5.832580674880616378e-02 1.765555837309498721e-02 0.000000000000000000e+00 1.238434479778678654e-03 +6.076342803384361668e-02 8.395246909668385715e-02 0.000000000000000000e+00 1.290192602234388778e-03 +6.330292527843461858e-02 2.249088167590238829e-01 0.000000000000000000e+00 1.344113861524451250e-03 +6.594855620349690528e-02 2.273568286412138151e-01 0.000000000000000000e+00 1.400288662028740172e-03 +6.870475647367019212e-02 9.055756469547908416e-02 0.000000000000000000e+00 1.458811186414187651e-03 +7.157614713415108576e-02 1.074761298874900468e-02 0.000000000000000000e+00 1.519779553541433575e-03 +7.456754235833716604e-02 4.016535135742961907e-03 0.000000000000000000e+00 1.583295982970901261e-03 +7.768395751926998605e-02 1.055027197335543137e-03 0.000000000000000000e+00 1.649466966344109589e-03 +8.093061759840886049e-02 6.351678920636424225e-04 0.000000000000000000e+00 1.718403445927546482e-03 +8.431296594583481685e-02 1.882122845669426483e-04 0.000000000000000000e+00 1.790221000618471897e-03 +8.783667340657071165e-02 1.160349347707180187e-04 0.000000000000000000e+00 1.865040039724485304e-03 +9.150764782831966038e-02 4.994818959850997096e-05 0.000000000000000000e+00 1.942986004841762470e-03 +9.533204396656239088e-02 4.092940564544614144e-05 0.000000000000000000e+00 2.024189580170434287e-03 +9.931627380361947310e-02 5.922116090374987904e-05 0.000000000000000000e+00 2.108786911619698213e-03 +1.034670172989808762e-01 1.013197459580711347e-04 0.000000000000000000e+00 2.196919835070051605e-03 +1.077912335889252976e-01 1.540584654263765243e-04 0.000000000000000000e+00 2.288736114175310681e-03 +1.122961726542076877e-01 3.080120592576946490e-04 0.000000000000000000e+00 2.384389688103147591e-03 +1.169893874753767798e-01 8.442185366483938953e-04 0.000000000000000000e+00 2.484040929629491301e-03 +1.218787466961013116e-01 6.748312225586391815e-03 0.000000000000000000e+00 2.587856914019505839e-03 +1.269724478157380210e-01 1.821808508949064598e-02 0.000000000000000000e+00 2.696011699145979719e-03 +1.322790309332581016e-01 5.612466816999907814e-03 0.000000000000000000e+00 2.808686617314733527e-03 +1.378073930655767942e-01 5.615203002698456944e-04 0.000000000000000000e+00 2.926070579286359132e-03 +1.435668030642915372e-01 1.589729787112498021e-04 0.000000000000000000e+00 3.048360391003989995e-03 +1.495669171558374755e-01 6.609542839334061389e-05 0.000000000000000000e+00 3.175761083558122696e-03 +1.558177951311167375e-01 3.043696661106251805e-05 0.000000000000000000e+00 3.308486256941745463e-03 +1.623299172117425582e-01 1.391404828241209817e-05 0.000000000000000000e+00 3.446758438172057518e-03 +1.691142016211787946e-01 5.479625762064427952e-06 0.000000000000000000e+00 3.590809454379265478e-03 +1.761820228902321317e-01 3.690195637097416411e-06 0.000000000000000000e+00 3.740880821487923939e-03 +1.835452309275898974e-01 1.038156605558009023e-04 0.000000000000000000e+00 3.897224149142521597e-03 +1.912161708873765797e-01 2.663393318270543177e-04 0.000000000000000000e+00 4.060101562556204732e-03 +1.992077038670377609e-01 5.698905429184937657e-05 0.000000000000000000e+00 4.229786141989877457e-03 +2.075332284702559316e-01 1.442605642935067086e-05 0.000000000000000000e+00 4.406562380598564102e-03 +2.162067032710481007e-01 1.014307934844652567e-05 0.000000000000000000e+00 4.590726661412603340e-03 +2.252426702167101280e-01 1.027225286682177676e-05 0.000000000000000000e+00 4.782587754253420607e-03 +2.346562790088451700e-01 1.773114047801788005e-05 0.000000000000000000e+00 4.982467333417002313e-03 +2.444633125033515431e-01 1.466511552515621512e-04 0.000000000000000000e+00 5.190700516992979158e-03 +2.546802131719588802e-01 2.479837294688417367e-04 0.000000000000000000e+00 5.407636428723615156e-03 +2.653241106696743179e-01 2.307614876591286497e-05 0.000000000000000000e+00 5.633638783344635526e-03 +2.764128505543612668e-01 8.700467345332319597e-07 0.000000000000000000e+00 5.869086496389332337e-03 +2.879650242066011945e-01 2.489103699592064588e-06 0.000000000000000000e+00 6.114374319478338426e-03 +2.999999999999999334e-01 3.536911877545927558e-05 0.000000000000000000e+00 6.369913502160142078e-03 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_6.dat b/tests/test_data/ORSO/test_6.dat new file mode 100644 index 00000000..8833a071 --- /dev/null +++ b/tests/test_data/ORSO/test_6.dat @@ -0,0 +1,201 @@ +4.999999999999999237e-03 9.939755665005451934e-01 0.000000000000000000 +5.103413528987262200e-03 9.938206872422250537e-01 0.000000000000000000 +5.208965929570049704e-03 9.936601836202287874e-01 0.000000000000000000 +5.316701439400301800e-03 9.934937175049458613e-01 0.000000000000000000 +5.426665211084315613e-03 9.933209194694191391e-01 0.000000000000000000 +5.538903331106443881e-03 9.931413848834969027e-01 0.000000000000000000 +5.653462839144248603e-03 9.929546693938089419e-01 0.000000000000000000 +5.770391747783105117e-03 9.927602836719287005e-01 0.000000000000000000 +5.889739062638551202e-03 9.925576872863686173e-01 0.000000000000000000 +6.011554802894874400e-03 9.923462815200732035e-01 0.000000000000000000 +6.135890022268412555e-03 9.921254009119249151e-01 0.000000000000000000 +6.262796830404514410e-03 9.918943032452941511e-01 0.000000000000000000 +6.392328414716996060e-03 9.916521576349313083e-01 0.000000000000000000 +6.524539062679283845e-03 9.913980302700486913e-01 0.000000000000000000 +6.659484184576673627e-03 9.911308672485296123e-01 0.000000000000000000 +6.797220336729060952e-03 9.908494737742563618e-01 0.000000000000000000 +6.937805245194089872e-03 9.905524887713003102e-01 0.000000000000000000 +7.081297829960469560e-03 9.902383536735351877e-01 0.000000000000000000 +7.227758229641680597e-03 9.899052737445386274e-01 0.000000000000000000 +7.377247826680483588e-03 9.895511697240637616e-01 0.000000000000000000 +7.529829273074612438e-03 9.891736168147553521e-01 0.000000000000000000 +7.685566516634660846e-03 9.887697669113257870e-01 0.000000000000000000 +7.844524827784976270e-03 9.883362483726991776e-01 0.000000000000000000 +8.006770826918864839e-03 9.878690352926330354e-01 0.000000000000000000 +8.172372512319661317e-03 9.873632747316588576e-01 0.000000000000000000 +8.341399288659158417e-03 9.868130550727606254e-01 0.000000000000000000 +8.513921996085575816e-03 9.862110904529330924e-01 0.000000000000000000 +8.690012939913081824e-03 9.855482832160168405e-01 0.000000000000000000 +8.869745920925360336e-03 9.848131052091352311e-01 0.000000000000000000 +9.053196266306023574e-03 9.839907034851622658e-01 0.000000000000000000 +9.240440861208627787e-03 9.830615752848420597e-01 0.000000000000000000 +9.431558180979763770e-03 9.819995490664760185e-01 0.000000000000000000 +9.626628324048536189e-03 9.807686081705797587e-01 0.000000000000000000 +9.825733045496255758e-03 9.793177063178200026e-01 0.000000000000000000 +1.002895579132056722e-02 9.775719355257010967e-01 0.000000000000000000 +1.023638173340811301e-02 9.754167044741799408e-01 0.000000000000000000 +1.044809780523061650e-02 9.726676468677111220e-01 0.000000000000000000 +1.066419273827921670e-02 9.690090864274675253e-01 0.000000000000000000 +1.088475709925237553e-02 9.638564236097431071e-01 0.000000000000000000 +1.110988332801295109e-02 9.560115404729649935e-01 0.000000000000000000 +1.133966577633027141e-02 9.426635155412600442e-01 0.000000000000000000 +1.157420074742355857e-02 9.158694970930539858e-01 0.000000000000000000 +1.181358653632318123e-02 8.467900563613481868e-01 0.000000000000000000 +1.205792347106669944e-02 6.216619932274364269e-01 0.000000000000000000 +1.230731395474697620e-02 5.821661115181411272e-01 0.000000000000000000 +1.256186250842989717e-02 8.435669905097354926e-01 0.000000000000000000 +1.282167581495980910e-02 9.092019434673695999e-01 0.000000000000000000 +1.308686276367094191e-02 9.210246389137153322e-01 0.000000000000000000 +1.335753449602358582e-02 9.120296586690502805e-01 0.000000000000000000 +1.363380445218417142e-02 8.849952669956724360e-01 0.000000000000000000 +1.391578841856870238e-02 8.385719278172414359e-01 0.000000000000000000 +1.420360457636956480e-02 8.139242773937437336e-01 0.000000000000000000 +1.449737355108597463e-02 8.715859644793091388e-01 0.000000000000000000 +1.479721846307885565e-02 4.985317241021904322e-01 0.000000000000000000 +1.510326497917135677e-02 3.401588009082476827e-01 0.000000000000000000 +1.541564136531653299e-02 2.676396693660294535e-01 0.000000000000000000 +1.573447854035441712e-02 2.020861609409263238e-01 0.000000000000000000 +1.605991013088091390e-02 1.367692338742153568e-01 0.000000000000000000 +1.639207252725145142e-02 7.721829415316711076e-02 0.000000000000000000 +1.673110494074310506e-02 3.187863256060462225e-02 0.000000000000000000 +1.707714946189881067e-02 6.543490785276955338e-03 0.000000000000000000 +1.743035112007838838e-02 9.464603379006008253e-04 0.000000000000000000 +1.779085794424128605e-02 9.227302773341827802e-03 0.000000000000000000 +1.815882102498629982e-02 2.327806831978219623e-02 0.000000000000000000 +1.853439457787469519e-02 3.604680504919670347e-02 0.000000000000000000 +1.891773600806278752e-02 4.314013305232745898e-02 0.000000000000000000 +1.930900597627142543e-02 4.297620226362990764e-02 0.000000000000000000 +1.970836846611992085e-02 3.630749034796362101e-02 0.000000000000000000 +2.011599085285246946e-02 2.556614766648357753e-02 0.000000000000000000 +2.053204397348627405e-02 1.406805422420995960e-02 0.000000000000000000 +2.095670219841026111e-02 5.020570085276109332e-03 0.000000000000000000 +2.139014350446480708e-02 4.957100751866040222e-04 0.000000000000000000 +2.183254954953296745e-02 7.833324323053738724e-04 0.000000000000000000 +2.228410574867426344e-02 4.477448759505670353e-03 0.000000000000000000 +2.274500135183342431e-02 9.237083924984949845e-03 0.000000000000000000 +2.321542952315606978e-02 1.278728511049758571e-02 0.000000000000000000 +2.369558742194500037e-02 1.370821722795012056e-02 0.000000000000000000 +2.418567628529092947e-02 1.179361709630874847e-02 0.000000000000000000 +2.468590151241202915e-02 7.964736427749346398e-03 0.000000000000000000 +2.519647275073814627e-02 3.812717426040292644e-03 0.000000000000000000 +2.571760398377520920e-02 9.082649390462809369e-04 0.000000000000000000 +2.624951362078702458e-02 1.285814593773583719e-04 0.000000000000000000 +2.679242458833201376e-02 1.313935667385258185e-03 0.000000000000000000 +2.734656442369291784e-02 3.436198959545269313e-03 0.000000000000000000 +2.791216537023925512e-02 5.175377989595004134e-03 0.000000000000000000 +2.848946447476177410e-02 5.581400584745706966e-03 0.000000000000000000 +2.907870368682024739e-02 4.495289227962314359e-03 0.000000000000000000 +2.968012996014608024e-02 2.554920873457094867e-03 0.000000000000000000 +3.029399535614193950e-02 7.994946887251992533e-04 0.000000000000000000 +3.092055714952243392e-02 7.093544504298202448e-05 0.000000000000000000 +3.156007793613933854e-02 5.421551181067894333e-04 0.000000000000000000 +3.221282574303718088e-02 1.662317796867772250e-03 0.000000000000000000 +3.287907414078505841e-02 2.552755307668288284e-03 0.000000000000000000 +3.355910235813154563e-02 2.585832748415986884e-03 0.000000000000000000 +3.425319539903139837e-02 1.768419442519352132e-03 0.000000000000000000 +3.496164416209223552e-02 6.893617187153074175e-04 0.000000000000000000 +3.568474556249201513e-02 7.049139753030966848e-05 0.000000000000000000 +3.642280265641802822e-02 2.342246593656592936e-04 0.000000000000000000 +3.717612476807939659e-02 8.868197312386969346e-04 0.000000000000000000 +3.794502761934698959e-02 1.390076202093149579e-03 0.000000000000000000 +3.872983346207417577e-02 1.297163603890422309e-03 0.000000000000000000 +3.953087121315458641e-02 7.071349944080154541e-04 0.000000000000000000 +4.034847659237329048e-02 1.424891080096753789e-04 0.000000000000000000 +4.118299226310875166e-02 5.705736586050726735e-05 0.000000000000000000 +4.203476797594541542e-02 4.213120510591815892e-04 0.000000000000000000 +4.290416071525609415e-02 7.827561206945531048e-04 0.000000000000000000 +4.379153484881635749e-02 7.412107776810452795e-04 0.000000000000000000 +4.469726228051336403e-02 3.520808896368878699e-04 0.000000000000000000 +4.562172260621279868e-02 3.660740338258279948e-05 0.000000000000000000 +4.656530327285011289e-02 9.711622317495926301e-05 0.000000000000000000 +4.752839974081164709e-02 3.825865652663160404e-04 0.000000000000000000 +4.851141564967457326e-02 4.966031497793727987e-04 0.000000000000000000 +4.951476298737475523e-02 2.935501171426769130e-04 0.000000000000000000 +5.053886226287324784e-02 4.237175408983848341e-05 0.000000000000000000 +5.158414268239425865e-02 4.952981199695478867e-05 0.000000000000000000 +5.265104232930806205e-02 2.462259720310629348e-04 0.000000000000000000 +5.374000834773436097e-02 3.106968633529766832e-04 0.000000000000000000 +5.485149712994322191e-02 1.461716150577979667e-04 0.000000000000000000 +5.598597450763168060e-02 6.347578354762725267e-06 0.000000000000000000 +5.714391594715673844e-02 8.205889274364191641e-05 0.000000000000000000 +5.832580674880616378e-02 2.055995142952439460e-04 0.000000000000000000 +5.953214225019079486e-02 1.515240343105891138e-04 0.000000000000000000 +6.076342803384361668e-02 1.904906210358529525e-05 0.000000000000000000 +6.202018013911232003e-02 3.352624828268177824e-05 0.000000000000000000 +6.330292527843461858e-02 1.335557340988029228e-04 0.000000000000000000 +6.461220105808664071e-02 1.086065805714583096e-04 0.000000000000000000 +6.594855620349690528e-02 1.129765048451848730e-05 0.000000000000000000 +6.731255078922063206e-02 3.063271737054765669e-05 0.000000000000000000 +6.870475647367019212e-02 9.887963123718823862e-05 0.000000000000000000 +7.012575673870077853e-02 5.632428773601654340e-05 0.000000000000000000 +7.157614713415108576e-02 6.527192722904570643e-07 0.000000000000000000 +7.305653552744191537e-02 4.669954817250492789e-05 0.000000000000000000 +7.456754235833716604e-02 6.576102432063088660e-05 0.000000000000000000 +7.610980089897377565e-02 9.673449514336654342e-06 0.000000000000000000 +7.768395751926998605e-02 1.635250774153107923e-05 0.000000000000000000 +7.929067195782288358e-02 5.193080616559815041e-05 0.000000000000000000 +8.093061759840886049e-02 1.572768833490181356e-05 0.000000000000000000 +8.260448175220293232e-02 6.592686908564736290e-06 0.000000000000000000 +8.431296594583481685e-02 3.795770900446226656e-05 0.000000000000000000 +8.605678621540320539e-02 1.285534691168955851e-05 0.000000000000000000 +8.783667340657071165e-02 5.453573693841068081e-06 0.000000000000000000 +8.965337348086573066e-02 2.854475199787521469e-05 0.000000000000000000 +9.150764782831966038e-02 5.814273755634897092e-06 0.000000000000000000 +9.340027358656974310e-02 8.553461155381284414e-06 0.000000000000000000 +9.533204396656239088e-02 1.978747016317828280e-05 0.000000000000000000 +9.730376858499266424e-02 3.305163845243520234e-07 0.000000000000000000 +9.931627380361947310e-02 1.335288284533154904e-05 0.000000000000000000 +1.013704030755990387e-01 8.197906491429931731e-06 0.000000000000000000 +1.034670172989808762e-01 2.616697893983120813e-06 0.000000000000000000 +1.056069951775156918e-01 1.210564653035881141e-05 0.000000000000000000 +1.077912335889252976e-01 1.113740938148492638e-07 0.000000000000000000 +1.100206479607895166e-01 9.123620766428273762e-06 0.000000000000000000 +1.122961726542076877e-01 2.170099724991137433e-06 0.000000000000000000 +1.146187613553946577e-01 4.931285843051425179e-06 0.000000000000000000 +1.169893874753767798e-01 3.897989970791964400e-06 0.000000000000000000 +1.194090445579542303e-01 2.362495177690372946e-06 0.000000000000000000 +1.218787466961013116e-01 4.200394525796327005e-06 0.000000000000000000 +1.243995289569790746e-01 1.292890626519598200e-06 0.000000000000000000 +1.269724478157380210e-01 3.643319459387689401e-06 0.000000000000000000 +1.295985815982934053e-01 1.026372630834993919e-06 0.000000000000000000 +1.322790309332581016e-01 2.739316080758487579e-06 0.000000000000000000 +1.350149192132228115e-01 1.182556523530242899e-06 0.000000000000000000 +1.378073930655767942e-01 1.688025655137954109e-06 0.000000000000000000 +1.406576228330660983e-01 1.578071958865053895e-06 0.000000000000000000 +1.435668030642915372e-01 6.759350727749671926e-07 0.000000000000000000 +1.465361530143510782e-01 1.876217032650562472e-06 0.000000000000000000 +1.495669171558374755e-01 1.558990616278469146e-07 0.000000000000000000 +1.526603657004036996e-01 1.523982276870081789e-06 0.000000000000000000 +1.558177951311167375e-01 5.241653454576845813e-07 0.000000000000000000 +1.590405287458214467e-01 5.401553921646178897e-07 0.000000000000000000 +1.623299172117425582e-01 1.067243554196275687e-06 0.000000000000000000 +1.656873391315579480e-01 1.921193577418163403e-07 0.000000000000000000 +1.691142016211787946e-01 5.611117239272481087e-07 0.000000000000000000 +1.726119408994808146e-01 7.059848770917984486e-07 0.000000000000000000 +1.761820228902321317e-01 1.757294548959623123e-07 0.000000000000000000 +1.798259438364708529e-01 3.292609637211258647e-07 0.000000000000000000 +1.835452309275898974e-01 5.279863247368908290e-07 0.000000000000000000 +1.873414429393908121e-01 2.618484755811921919e-07 0.000000000000000000 +1.912161708873765797e-01 1.300425120922733325e-07 0.000000000000000000 +1.951710386935557040e-01 2.683096600888571270e-07 0.000000000000000000 +1.992077038670377609e-01 3.186616700930325326e-07 0.000000000000000000 +2.033278581987058575e-01 2.080135430240364746e-07 0.000000000000000000 +2.075332284702559316e-01 1.119633461183070299e-07 0.000000000000000000 +2.118255771779018470e-01 1.094045752498844995e-07 0.000000000000000000 +2.162067032710481007e-01 1.462972910961180958e-07 0.000000000000000000 +2.206784429062403075e-01 1.628556908938313585e-07 0.000000000000000000 +2.252426702167101280e-01 1.488243833534163936e-07 0.000000000000000000 +2.299012980978350773e-01 1.212740015851626348e-07 0.000000000000000000 +2.346562790088451700e-01 9.571660091437348363e-08 0.000000000000000000 +2.395096057911101639e-01 7.762407045815986633e-08 0.000000000000000000 +2.444633125033515431e-01 6.607709715055563083e-08 0.000000000000000000 +2.495194752741292099e-01 5.852562871393658698e-08 0.000000000000000000 +2.546802131719588802e-01 5.303544318316800654e-08 0.000000000000000000 +2.599476890934271367e-01 4.864011236713956217e-08 0.000000000000000000 +2.653241106696743179e-01 4.500328267909314749e-08 0.000000000000000000 +2.708117311916259373e-01 4.201132773919712298e-08 0.000000000000000000 +2.764128505543612668e-01 3.946234683388756240e-08 0.000000000000000000 +2.821298162210124638e-01 3.690136829563254986e-08 0.000000000000000000 +2.879650242066011945e-01 3.371552854537424394e-08 0.000000000000000000 +2.939209200822227586e-01 2.959122548394927572e-08 0.000000000000000000 +2.999999999999999334e-01 2.508280697994873666e-08 0.000000000000000000 \ No newline at end of file diff --git a/tests/test_data/ORSO/test_7.dat b/tests/test_data/ORSO/test_7.dat new file mode 100644 index 00000000..00653f97 --- /dev/null +++ b/tests/test_data/ORSO/test_7.dat @@ -0,0 +1,1001 @@ +1.000000000000000021e-02 9.940562200389422287e-01 0.000000000000000000 +1.001610733752729410e-02 9.940395345738044508e-01 0.000000000000000000 +1.003224061968681011e-02 9.940227619654243840e-01 0.000000000000000000 +1.004839988826844270e-02 9.940059014156407136e-01 0.000000000000000000 +1.006458518512939361e-02 9.939889521157246888e-01 0.000000000000000000 +1.008079655219430194e-02 9.939719132462083717e-01 0.000000000000000000 +1.009703403145532051e-02 9.939547839766955661e-01 0.000000000000000000 +1.011329766497224246e-02 9.939375634656733016e-01 0.000000000000000000 +1.012958749487261403e-02 9.939202508603199870e-01 0.000000000000000000 +1.014590356335182998e-02 9.939028452963043492e-01 0.000000000000000000 +1.016224591267325325e-02 9.938853458975890343e-01 0.000000000000000000 +1.017861458516833295e-02 9.938677517762217750e-01 0.000000000000000000 +1.019500962323668762e-02 9.938500620321253365e-01 0.000000000000000000 +1.021143106934623707e-02 9.938322757528823548e-01 0.000000000000000000 +1.022787896603330297e-02 9.938143920135202869e-01 0.000000000000000000 +1.024435335590272340e-02 9.937964098762798182e-01 0.000000000000000000 +1.026085428162796208e-02 9.937783283903908194e-01 0.000000000000000000 +1.027738178595121420e-02 9.937601465918353139e-01 0.000000000000000000 +1.029393591168353134e-02 9.937418635031123326e-01 0.000000000000000000 +1.031051670170491340e-02 9.937234781329882249e-01 0.000000000000000000 +1.032712419896443003e-02 9.937049894762497448e-01 0.000000000000000000 +1.034375844648033164e-02 9.936863965134431487e-01 0.000000000000000000 +1.036041948734015700e-02 9.936676982106222855e-01 0.000000000000000000 +1.037710736470085111e-02 9.936488935190717076e-01 0.000000000000000000 +1.039382212178886766e-02 9.936299813750372190e-01 0.000000000000000000 +1.041056380190029905e-02 9.936109606994465437e-01 0.000000000000000000 +1.042733244840096142e-02 9.935918303976211119e-01 0.000000000000000000 +1.044412810472653171e-02 9.935725893589855140e-01 0.000000000000000000 +1.046095081438264476e-02 9.935532364567674080e-01 0.000000000000000000 +1.047780062094501308e-02 9.935337705476903203e-01 0.000000000000000000 +1.049467756805953431e-02 9.935141904716596750e-01 0.000000000000000000 +1.051158169944241966e-02 9.934944950514436046e-01 0.000000000000000000 +1.052851305888028409e-02 9.934746830923445460e-01 0.000000000000000000 +1.054547169023027468e-02 9.934547533818615106e-01 0.000000000000000000 +1.056245763742018166e-02 9.934347046893479138e-01 0.000000000000000000 +1.057947094444854942e-02 9.934145357656579689e-01 0.000000000000000000 +1.059651165538479274e-02 9.933942453427851982e-01 0.000000000000000000 +1.061357981436930609e-02 9.933738321334981691e-01 0.000000000000000000 +1.063067546561359891e-02 9.933532948309543587e-01 0.000000000000000000 +1.064779865340037372e-02 9.933326321083211230e-01 0.000000000000000000 +1.066494942208367352e-02 9.933118426183724647e-01 0.000000000000000000 +1.068212781608897551e-02 9.932909249930864659e-01 0.000000000000000000 +1.069933387991331940e-02 9.932698778432285103e-01 0.000000000000000000 +1.071656765812541157e-02 9.932486997579240695e-01 0.000000000000000000 +1.073382919536576378e-02 9.932273893042214974e-01 0.000000000000000000 +1.075111853634677130e-02 9.932059450266431666e-01 0.000000000000000000 +1.076843572585286027e-02 9.931843654467296112e-01 0.000000000000000000 +1.078578080874058841e-02 9.931626490625664605e-01 0.000000000000000000 +1.080315382993876812e-02 9.931407943483010481e-01 0.000000000000000000 +1.082055483444857927e-02 9.931187997536521372e-01 0.000000000000000000 +1.083798386734367847e-02 9.930966637033983302e-01 0.000000000000000000 +1.085544097377034653e-02 9.930743845968578176e-01 0.000000000000000000 +1.087292619894755959e-02 9.930519608073600235e-01 0.000000000000000000 +1.089043958816714175e-02 9.930293906816929361e-01 0.000000000000000000 +1.090798118679386225e-02 9.930066725395447769e-01 0.000000000000000000 +1.092555104026556902e-02 9.929838046729281276e-01 0.000000000000000000 +1.094314919409329276e-02 9.929607853455858502e-01 0.000000000000000000 +1.096077569386136666e-02 9.929376127923890127e-01 0.000000000000000000 +1.097843058522756515e-02 9.929142852187116119e-01 0.000000000000000000 +1.099611391392318893e-02 9.928908007997947482e-01 0.000000000000000000 +1.101382572575320198e-02 9.928671576800842669e-01 0.000000000000000000 +1.103156606659635303e-02 9.928433539725654011e-01 0.000000000000000000 +1.104933498240528479e-02 9.928193877580659965e-01 0.000000000000000000 +1.106713251920665199e-02 9.927952570845456348e-01 0.000000000000000000 +1.108495872310126876e-02 9.927709599663725459e-01 0.000000000000000000 +1.110281364026417979e-02 9.927464943835678790e-01 0.000000000000000000 +1.112069731694481818e-02 9.927218582810352077e-01 0.000000000000000000 +1.113860979946710780e-02 9.926970495677762685e-01 0.000000000000000000 +1.115655113422959165e-02 9.926720661160719494e-01 0.000000000000000000 +1.117452136770554806e-02 9.926469057606484014e-01 0.000000000000000000 +1.119252054644310178e-02 9.926215662978187249e-01 0.000000000000000000 +1.121054871706537483e-02 9.925960454845983438e-01 0.000000000000000000 +1.122860592627056980e-02 9.925703410377985092e-01 0.000000000000000000 +1.124669222083211038e-02 9.925444506330931560e-01 0.000000000000000000 +1.126480764759876449e-02 9.925183719040542307e-01 0.000000000000000000 +1.128295225349475704e-02 9.924921024411711423e-01 0.000000000000000000 +1.130112608551988966e-02 9.924656397908254712e-01 0.000000000000000000 +1.131932919074968638e-02 9.924389814542511346e-01 0.000000000000000000 +1.133756161633548386e-02 9.924121248864569145e-01 0.000000000000000000 +1.135582340950456494e-02 9.923850674951175677e-01 0.000000000000000000 +1.137411461756028877e-02 9.923578066394341812e-01 0.000000000000000000 +1.139243528788220529e-02 9.923303396289574474e-01 0.000000000000000000 +1.141078546792618359e-02 9.923026637223821833e-01 0.000000000000000000 +1.142916520522451948e-02 9.922747761262996624e-01 0.000000000000000000 +1.144757454738609681e-02 9.922466739939164171e-01 0.000000000000000000 +1.146601354209645686e-02 9.922183544237299646e-01 0.000000000000000000 +1.148448223711796487e-02 9.921898144581696721e-01 0.000000000000000000 +1.150298068028991240e-02 9.921610510821921025e-01 0.000000000000000000 +1.152150891952864915e-02 9.921320612218342827e-01 0.000000000000000000 +1.154006700282770616e-02 9.921028417427231183e-01 0.000000000000000000 +1.155865497825791545e-02 9.920733894485386228e-01 0.000000000000000000 +1.157727289396754886e-02 9.920437010794264099e-01 0.000000000000000000 +1.159592079818242208e-02 9.920137733103626676e-01 0.000000000000000000 +1.161459873920603174e-02 9.919836027494693953e-01 0.000000000000000000 +1.163330676541967854e-02 9.919531859362682447e-01 0.000000000000000000 +1.165204492528259562e-02 9.919225193398918394e-01 0.000000000000000000 +1.167081326733206137e-02 9.918915993572234857e-01 0.000000000000000000 +1.168961184018355547e-02 9.918604223109845908e-01 0.000000000000000000 +1.170844069253084568e-02 9.918289844477596873e-01 0.000000000000000000 +1.172729987314613531e-02 9.917972819359520686e-01 0.000000000000000000 +1.174618943088019153e-02 9.917653108636832471e-01 0.000000000000000000 +1.176510941466246338e-02 9.917330672366044819e-01 0.000000000000000000 +1.178405987350120837e-02 9.917005469756552394e-01 0.000000000000000000 +1.180304085648364171e-02 9.916677459147331675e-01 0.000000000000000000 +1.182205241277602473e-02 9.916346597982891309e-01 0.000000000000000000 +1.184109459162381930e-02 9.916012842788453074e-01 0.000000000000000000 +1.186016744235180928e-02 9.915676149144203588e-01 0.000000000000000000 +1.187927101436422710e-02 9.915336471658759976e-01 0.000000000000000000 +1.189840535714488390e-02 9.914993763941623017e-01 0.000000000000000000 +1.191757052025728750e-02 9.914647978574719911e-01 0.000000000000000000 +1.193676655334480023e-02 9.914299067082980033e-01 0.000000000000000000 +1.195599350613072397e-02 9.913946979903821566e-01 0.000000000000000000 +1.197525142841846142e-02 9.913591666355597853e-01 0.000000000000000000 +1.199454037009163761e-02 9.913233074604886896e-01 0.000000000000000000 +1.201386038111421951e-02 9.912871151632653977e-01 0.000000000000000000 +1.203321151153065836e-02 9.912505843199136413e-01 0.000000000000000000 +1.205259381146600757e-02 9.912137093807517063e-01 0.000000000000000000 +1.207200733112607366e-02 9.911764846666198947e-01 0.000000000000000000 +1.209145212079751515e-02 9.911389043649765362e-01 0.000000000000000000 +1.211092823084799520e-02 9.911009625258472289e-01 0.000000000000000000 +1.213043571172630480e-02 9.910626530576176485e-01 0.000000000000000000 +1.214997461396249805e-02 9.910239697226763678e-01 0.000000000000000000 +1.216954498816801185e-02 9.909849061328882547e-01 0.000000000000000000 +1.218914688503580819e-02 9.909454557449002277e-01 0.000000000000000000 +1.220878035534051116e-02 9.909056118552631576e-01 0.000000000000000000 +1.222844544993851798e-02 9.908653675953659201e-01 0.000000000000000000 +1.224814221976814471e-02 9.908247159261790449e-01 0.000000000000000000 +1.226787071584975464e-02 9.907836496327814269e-01 0.000000000000000000 +1.228763098928589530e-02 9.907421613186899734e-01 0.000000000000000000 +1.230742309126141645e-02 9.907002433999422264e-01 0.000000000000000000 +1.232724707304363142e-02 9.906578880989652669e-01 0.000000000000000000 +1.234710298598241766e-02 9.906150874381811633e-01 0.000000000000000000 +1.236699088151036602e-02 9.905718332333633969e-01 0.000000000000000000 +1.238691081114291249e-02 9.905281170867218377e-01 0.000000000000000000 +1.240686282647846840e-02 9.904839303797009498e-01 0.000000000000000000 +1.242684697919855565e-02 9.904392642654831214e-01 0.000000000000000000 +1.244686332106795419e-02 9.903941096611775796e-01 0.000000000000000000 +1.246691190393480787e-02 9.903484572396897834e-01 0.000000000000000000 +1.248699277973078052e-02 9.903022974212324359e-01 0.000000000000000000 +1.250710600047118086e-02 9.902556203644956589e-01 0.000000000000000000 +1.252725161825510476e-02 9.902084159574188194e-01 0.000000000000000000 +1.254742968526556188e-02 9.901606738075762193e-01 0.000000000000000000 +1.256764025376961268e-02 9.901123832321491181e-01 0.000000000000000000 +1.258788337611851937e-02 9.900635332474392314e-01 0.000000000000000000 +1.260815910474785521e-02 9.900141125579408063e-01 0.000000000000000000 +1.262846749217765539e-02 9.899641095449109862e-01 0.000000000000000000 +1.264880859101255237e-02 9.899135122544390208e-01 0.000000000000000000 +1.266918245394190942e-02 9.898623083849681370e-01 0.000000000000000000 +1.268958913373996120e-02 9.898104852742516391e-01 0.000000000000000000 +1.271002868326593857e-02 9.897580298857154846e-01 0.000000000000000000 +1.273050115546423347e-02 9.897049287941798168e-01 0.000000000000000000 +1.275100660336450122e-02 9.896511681709231345e-01 0.000000000000000000 +1.277154508008181664e-02 9.895967337680466880e-01 0.000000000000000000 +1.279211663881680942e-02 9.895416109020814810e-01 0.000000000000000000 +1.281272133285580282e-02 9.894857844368361022e-01 0.000000000000000000 +1.283335921557094382e-02 9.894292387653959020e-01 0.000000000000000000 +1.285403034042036444e-02 9.893719577912655216e-01 0.000000000000000000 +1.287473476094828755e-02 9.893139249085726172e-01 0.000000000000000000 +1.289547253078518647e-02 9.892551229813063562e-01 0.000000000000000000 +1.291624370364791684e-02 9.891955343215191876e-01 0.000000000000000000 +1.293704833333986226e-02 9.891351406664223855e-01 0.000000000000000000 +1.295788647375106448e-02 9.890739231543371757e-01 0.000000000000000000 +1.297875817885836384e-02 9.890118622994078512e-01 0.000000000000000000 +1.299966350272556415e-02 9.889489379650142631e-01 0.000000000000000000 +1.302060249950352973e-02 9.888851293357946437e-01 0.000000000000000000 +1.304157522343035204e-02 9.888204148882162592e-01 0.000000000000000000 +1.306258172883149188e-02 9.887547723595674354e-01 0.000000000000000000 +1.308362207011990776e-02 9.886881787153132262e-01 0.000000000000000000 +1.310469630179619815e-02 9.886206101146768344e-01 0.000000000000000000 +1.312580447844876978e-02 9.885520418743571902e-01 0.000000000000000000 +1.314694665475393473e-02 9.884824484302527914e-01 0.000000000000000000 +1.316812288547607873e-02 9.884118032970653500e-01 0.000000000000000000 +1.318933322546780515e-02 9.883400790256389179e-01 0.000000000000000000 +1.321057772967006161e-02 9.882672471579044826e-01 0.000000000000000000 +1.323185645311229612e-02 9.881932781792416298e-01 0.000000000000000000 +1.325316945091258719e-02 9.881181414681080577e-01 0.000000000000000000 +1.327451677827781555e-02 9.880418052427444309e-01 0.000000000000000000 +1.329589849050375958e-02 9.879642365047466290e-01 0.000000000000000000 +1.331731464297527916e-02 9.878854009793036628e-01 0.000000000000000000 +1.333876529116643714e-02 9.878052630518532329e-01 0.000000000000000000 +1.336025049064065370e-02 9.877237857009182331e-01 0.000000000000000000 +1.338177029705084863e-02 9.876409304268343181e-01 0.000000000000000000 +1.340332476613957310e-02 9.875566571760970858e-01 0.000000000000000000 +1.342491395373918844e-02 9.874709242609889248e-01 0.000000000000000000 +1.344653791577196493e-02 9.873836882741484633e-01 0.000000000000000000 +1.346819670825025531e-02 9.872949039977172436e-01 0.000000000000000000 +1.348989038727663181e-02 9.872045243066398523e-01 0.000000000000000000 +1.351161900904403884e-02 9.871125000656898463e-01 0.000000000000000000 +1.353338262983592652e-02 9.870187800197430805e-01 0.000000000000000000 +1.355518130602639815e-02 9.869233106767653085e-01 0.000000000000000000 +1.357701509408038194e-02 9.868260361829577221e-01 0.000000000000000000 +1.359888405055373513e-02 9.867268981894414814e-01 0.000000000000000000 +1.362078823209341566e-02 9.866258357097974496e-01 0.000000000000000000 +1.364272769543762795e-02 9.865227849677363769e-01 0.000000000000000000 +1.366470249741595817e-02 9.864176792340966227e-01 0.000000000000000000 +1.368671269494955295e-02 9.863104486522745740e-01 0.000000000000000000 +1.370875834505121821e-02 9.862010200511452940e-01 0.000000000000000000 +1.373083950482560309e-02 9.860893167444084728e-01 0.000000000000000000 +1.375295623146933523e-02 9.859752583152083805e-01 0.000000000000000000 +1.377510858227117344e-02 9.858587603847521752e-01 0.000000000000000000 +1.379729661461214993e-02 9.857397343635446729e-01 0.000000000000000000 +1.381952038596571952e-02 9.856180871836965895e-01 0.000000000000000000 +1.384177995389792616e-02 9.854937210106154977e-01 0.000000000000000000 +1.386407537606752262e-02 9.853665329322347510e-01 0.000000000000000000 +1.388640671022614050e-02 9.852364146237021503e-01 0.000000000000000000 +1.390877401421842900e-02 9.851032519852750413e-01 0.000000000000000000 +1.393117734598221628e-02 9.849669247509126313e-01 0.000000000000000000 +1.395361676354864994e-02 9.848273060647725341e-01 0.000000000000000000 +1.397609232504234099e-02 9.846842620225366716e-01 0.000000000000000000 +1.399860408868154951e-02 9.845376511741443792e-01 0.000000000000000000 +1.402115211277828524e-02 9.843873239841305356e-01 0.000000000000000000 +1.404373645573848972e-02 9.842331222453256645e-01 0.000000000000000000 +1.406635717606218548e-02 9.840748784412020056e-01 0.000000000000000000 +1.408901433234361657e-02 9.839124150516095346e-01 0.000000000000000000 +1.411170798327140985e-02 9.837455437959955473e-01 0.000000000000000000 +1.413443818762871902e-02 9.835740648075378401e-01 0.000000000000000000 +1.415720500429340153e-02 9.833977657308051734e-01 0.000000000000000000 +1.418000849223812615e-02 9.832164207346368867e-01 0.000000000000000000 +1.420284871053056376e-02 9.830297894309598661e-01 0.000000000000000000 +1.422572571833352444e-02 9.828376156890185067e-01 0.000000000000000000 +1.424863957490511528e-02 9.826396263332052294e-01 0.000000000000000000 +1.427159033959889134e-02 9.824355297111144747e-01 0.000000000000000000 +1.429457807186400309e-02 9.822250141166994908e-01 0.000000000000000000 +1.431760283124538027e-02 9.820077460513872980e-01 0.000000000000000000 +1.434066467738384122e-02 9.817833683036709669e-01 0.000000000000000000 +1.436376367001627845e-02 9.815514978250393652e-01 0.000000000000000000 +1.438689986897580264e-02 9.813117233769892422e-01 0.000000000000000000 +1.441007333419189358e-02 9.810636029202710606e-01 0.000000000000000000 +1.443328412569058229e-02 9.808066607133852921e-01 0.000000000000000000 +1.445653230359456552e-02 9.805403840824730155e-01 0.000000000000000000 +1.447981792812338790e-02 9.802642198191179324e-01 0.000000000000000000 +1.450314105959359286e-02 9.799775701559806373e-01 0.000000000000000000 +1.452650175841887700e-02 9.796797882624440623e-01 0.000000000000000000 +1.454990008511024453e-02 9.793701731934139065e-01 0.000000000000000000 +1.457333610027616508e-02 9.790479642136863392e-01 0.000000000000000000 +1.459680986462275065e-02 9.787123344077491849e-01 0.000000000000000000 +1.462032143895387187e-02 9.783623834698973454e-01 0.000000000000000000 +1.464387088417134879e-02 9.779971295518856689e-01 0.000000000000000000 +1.466745826127509485e-02 9.776155000242174875e-01 0.000000000000000000 +1.469108363136327998e-02 9.772163209820038388e-01 0.000000000000000000 +1.471474705563248844e-02 9.767983052961586310e-01 0.000000000000000000 +1.473844859537786454e-02 9.763600389744541141e-01 0.000000000000000000 +1.476218831199330693e-02 9.758999655532609729e-01 0.000000000000000000 +1.478596626697158134e-02 9.754163681879172154e-01 0.000000000000000000 +1.480978252190451143e-02 9.749073490454851498e-01 0.000000000000000000 +1.483363713848312448e-02 9.743708055254284295e-01 0.000000000000000000 +1.485753017849782143e-02 9.738044027380358125e-01 0.000000000000000000 +1.488146170383852253e-02 9.732055415529085041e-01 0.000000000000000000 +1.490543177649483915e-02 9.725713213848794503e-01 0.000000000000000000 +1.492944045855624374e-02 9.718984967052771706e-01 0.000000000000000000 +1.495348781221220516e-02 9.711834260432190558e-01 0.000000000000000000 +1.497757389975236386e-02 9.704220119626489893e-01 0.000000000000000000 +1.500169878356669324e-02 9.696096301507247661e-01 0.000000000000000000 +1.502586252614566444e-02 9.687410453113436404e-01 0.000000000000000000 +1.505006519008039202e-02 9.678103109975366714e-01 0.000000000000000000 +1.507430683806283180e-02 9.668106498024383599e-01 0.000000000000000000 +1.509858753288590046e-02 9.657343094136718875e-01 0.000000000000000000 +1.512290733744365949e-02 9.645723888566992699e-01 0.000000000000000000 +1.514726631473147823e-02 9.633146277241746436e-01 0.000000000000000000 +1.517166452784619868e-02 9.619491491949030415e-01 0.000000000000000000 +1.519610203998627944e-02 9.604621450303264529e-01 0.000000000000000000 +1.522057891445200567e-02 9.588374872824635409e-01 0.000000000000000000 +1.524509521464559487e-02 9.570562468565224634e-01 0.000000000000000000 +1.526965100407139814e-02 9.550960929296685720e-01 0.000000000000000000 +1.529424634633605451e-02 9.529305389558853090e-01 0.000000000000000000 +1.531888130514865755e-02 9.505279897729324023e-01 0.000000000000000000 +1.534355594432091664e-02 9.478505290258955052e-01 0.000000000000000000 +1.536827032776731834e-02 9.448523651135493084e-01 0.000000000000000000 +1.539302451950532238e-02 9.414778248587880594e-01 0.000000000000000000 +1.541781858365548138e-02 9.376587438728278823e-01 0.000000000000000000 +1.544265258444163513e-02 9.333110466073071265e-01 0.000000000000000000 +1.546752658619106845e-02 9.283302311648128358e-01 0.000000000000000000 +1.549244065333468638e-02 9.225853658482517927e-01 0.000000000000000000 +1.551739485040717036e-02 9.159110560735300721e-01 0.000000000000000000 +1.554238924204714295e-02 9.080966413106291713e-01 0.000000000000000000 +1.556742389299736566e-02 8.988716274248305105e-01 0.000000000000000000 +1.559249886810486381e-02 8.878860677540538759e-01 0.000000000000000000 +1.561761423232111562e-02 8.746843601801463919e-01 0.000000000000000000 +1.564277005070222396e-02 8.586709865800404851e-01 0.000000000000000000 +1.566796638840907419e-02 8.390677845138969637e-01 0.000000000000000000 +1.569320331070751459e-02 8.148661622090488388e-01 0.000000000000000000 +1.571848088296850729e-02 7.847883936518198489e-01 0.000000000000000000 +1.574379917066833640e-02 7.472988432733710384e-01 0.000000000000000000 +1.576915823938872599e-02 7.007658386828663488e-01 0.000000000000000000 +1.579455815481704134e-02 6.439892781247459341e-01 0.000000000000000000 +1.581999898274645197e-02 5.774576900379768674e-01 0.000000000000000000 +1.584548078907610860e-02 5.056427377844019411e-01 0.000000000000000000 +1.587100363981128887e-02 4.396235641851662379e-01 0.000000000000000000 +1.589656760106362629e-02 3.966991097101011943e-01 0.000000000000000000 +1.592217273905120398e-02 3.925698079642124250e-01 0.000000000000000000 +1.594781912009878011e-02 4.296123793399831414e-01 0.000000000000000000 +1.597350681063794756e-02 4.945868106718255275e-01 0.000000000000000000 +1.599923587720729692e-02 5.690160140720793569e-01 0.000000000000000000 +1.602500638645258310e-02 6.394431378073742733e-01 0.000000000000000000 +1.605081840512694730e-02 6.997695626570558103e-01 0.000000000000000000 +1.607667200009101766e-02 7.488763884389497694e-01 0.000000000000000000 +1.610256723831312436e-02 7.879150245504279448e-01 0.000000000000000000 +1.612850418686946966e-02 8.186887252991870145e-01 0.000000000000000000 +1.615448291294429781e-02 8.429423881623353543e-01 0.000000000000000000 +1.618050348383006862e-02 8.621339303238243490e-01 0.000000000000000000 +1.620656596692762047e-02 8.774088049729275030e-01 0.000000000000000000 +1.623267042974638544e-02 8.896430768743078810e-01 0.000000000000000000 +1.625881693990451071e-02 8.994999793796369936e-01 0.000000000000000000 +1.628500556512906330e-02 9.074808656390431771e-01 0.000000000000000000 +1.631123637325620351e-02 9.139658992415667926e-01 0.000000000000000000 +1.633750943223135493e-02 9.192449249978390524e-01 0.000000000000000000 +1.636382481010938486e-02 9.235403579677438080e-01 0.000000000000000000 +1.639018257505477083e-02 9.270240005266869865e-01 0.000000000000000000 +1.641658279534181225e-02 9.298293767208087868e-01 0.000000000000000000 +1.644302553935474490e-02 9.320607995604727192e-01 0.000000000000000000 +1.646951087558797683e-02 9.338000661774862321e-01 0.000000000000000000 +1.649603887264623064e-02 9.351114280525631983e-01 0.000000000000000000 +1.652260959924473777e-02 9.360453010045299838e-01 0.000000000000000000 +1.654922312420941191e-02 9.366410481315422532e-01 0.000000000000000000 +1.657587951647701910e-02 9.369290750758679787e-01 0.000000000000000000 +1.660257884509538234e-02 9.369324102437187607e-01 0.000000000000000000 +1.662932117922353084e-02 9.366678950852094232e-01 0.000000000000000000 +1.665610658813188386e-02 9.361470755902192575e-01 0.000000000000000000 +1.668293514120244500e-02 9.353768618183803119e-01 0.000000000000000000 +1.670980690792896878e-02 9.343600047986874158e-01 0.000000000000000000 +1.673672195791716180e-02 9.330954276116429913e-01 0.000000000000000000 +1.676368036088482505e-02 9.315784386282468521e-01 0.000000000000000000 +1.679068218666206896e-02 9.298008489039230051e-01 0.000000000000000000 +1.681772750519147999e-02 9.277510121416029376e-01 0.000000000000000000 +1.684481638652829752e-02 9.254138042728138336e-01 0.000000000000000000 +1.687194890084060817e-02 9.227705606634446500e-01 0.000000000000000000 +1.689912511840950884e-02 9.197989926316789688e-01 0.000000000000000000 +1.692634510962932881e-02 9.164731121102367428e-01 0.000000000000000000 +1.695360894500775456e-02 9.127632050476167658e-01 0.000000000000000000 +1.698091669516605534e-02 9.086359121772977776e-01 0.000000000000000000 +1.700826843083924622e-02 9.040545023158205185e-01 0.000000000000000000 +1.703566422287627891e-02 8.989794611700537841e-01 0.000000000000000000 +1.706310414224023256e-02 8.933695708676211433e-01 0.000000000000000000 +1.709058826000846645e-02 8.871837248187680602e-01 0.000000000000000000 +1.711811664737286284e-02 8.803838097438310140e-01 0.000000000000000000 +1.714568937563994491e-02 8.729390868741854215e-01 0.000000000000000000 +1.717330651623110230e-02 8.648326005897848390e-01 0.000000000000000000 +1.720096814068276456e-02 8.560701955960102749e-01 0.000000000000000000 +1.722867432064658505e-02 8.466926558178456963e-01 0.000000000000000000 +1.725642512788963523e-02 8.367911578899470681e-01 0.000000000000000000 +1.728422063429456423e-02 8.265254687226619712e-01 0.000000000000000000 +1.731206091185984522e-02 8.161428972821311856e-01 0.000000000000000000 +1.733994603269988638e-02 8.059938308258028927e-01 0.000000000000000000 +1.736787606904526340e-02 7.965370230300987675e-01 0.000000000000000000 +1.739585109324289641e-02 7.883256966392956366e-01 0.000000000000000000 +1.742387117775623731e-02 7.819659866141922544e-01 0.000000000000000000 +1.745193639516545714e-02 7.780446799691850268e-01 0.000000000000000000 +1.748004681816762995e-02 7.770344752131898014e-01 0.000000000000000000 +1.750820251957694099e-02 7.791988262097384599e-01 0.000000000000000000 +1.753640357232484626e-02 7.845269120091042936e-01 0.000000000000000000 +1.756465004946027378e-02 7.927242038190153162e-01 0.000000000000000000 +1.759294202414982133e-02 8.032647439348401530e-01 0.000000000000000000 +1.762127956967792300e-02 8.154875284989805406e-01 0.000000000000000000 +1.764966275944708507e-02 8.287051441358848081e-01 0.000000000000000000 +1.767809166697801790e-02 8.422947864143098817e-01 0.000000000000000000 +1.770656636590986141e-02 8.557555424504237340e-01 0.000000000000000000 +1.773508693000037592e-02 8.687315613459980490e-01 0.000000000000000000 +1.776365343312611908e-02 8.810115946331938952e-01 0.000000000000000000 +1.779226594928264363e-02 8.925213279664037103e-01 0.000000000000000000 +1.782092455258468128e-02 9.033352912671933632e-01 0.000000000000000000 +1.784962931726637517e-02 9.138047506597195557e-01 0.000000000000000000 +1.787838031768140476e-02 9.266153715817254666e-01 0.000000000000000000 +1.790717762830322871e-02 6.775176493896506447e-01 0.000000000000000000 +1.793602132372525484e-02 6.018475785521723020e-01 0.000000000000000000 +1.796491147866105531e-02 5.554174544314203210e-01 0.000000000000000000 +1.799384816794452960e-02 5.226572367654968021e-01 0.000000000000000000 +1.802283146653011967e-02 4.977945722840035336e-01 0.000000000000000000 +1.805186144949301116e-02 4.779850261475416806e-01 0.000000000000000000 +1.808093819202930691e-02 4.616079513347511876e-01 0.000000000000000000 +1.811006176945622118e-02 4.476531530688140359e-01 0.000000000000000000 +1.813923225721229826e-02 4.354510387369498470e-01 0.000000000000000000 +1.816844973085758944e-02 4.245374818760679902e-01 0.000000000000000000 +1.819771426607385070e-02 4.145796768998394888e-01 0.000000000000000000 +1.822702593866473014e-02 4.053325875157672287e-01 0.000000000000000000 +1.825638482455601425e-02 3.966119749957613405e-01 0.000000000000000000 +1.828579099979574241e-02 3.882769730393704211e-01 0.000000000000000000 +1.831524454055447060e-02 3.802184347972591416e-01 0.000000000000000000 +1.834474552312543444e-02 3.723509133738286958e-01 0.000000000000000000 +1.837429402392475389e-02 3.646070081598016821e-01 0.000000000000000000 +1.840389011949167264e-02 3.569332965399628077e-01 0.000000000000000000 +1.843353388648865179e-02 3.492873545951443170e-01 0.000000000000000000 +1.846322540170170293e-02 3.416355420678682253e-01 0.000000000000000000 +1.849296474204047483e-02 3.339513338367857687e-01 0.000000000000000000 +1.852275198453851371e-02 3.262140486419027319e-01 0.000000000000000000 +1.855258720635344707e-02 3.184078707210553638e-01 0.000000000000000000 +1.858247048476716415e-02 3.105210901048606198e-01 0.000000000000000000 +1.861240189718608648e-02 3.025455078550745025e-01 0.000000000000000000 +1.864238152114124081e-02 2.944759667913020018e-01 0.000000000000000000 +1.867240943428860253e-02 2.863099783054011138e-01 0.000000000000000000 +1.870248571440919286e-02 2.780474230530058932e-01 0.000000000000000000 +1.873261043940933207e-02 2.696903085198437688e-01 0.000000000000000000 +1.876278368732081994e-02 2.612425702804748728e-01 0.000000000000000000 +1.879300553630114043e-02 2.527099066019058426e-01 0.000000000000000000 +1.882327606463369066e-02 2.440996381741200039e-01 0.000000000000000000 +1.885359535072794052e-02 2.354205863699268542e-01 0.000000000000000000 +1.888396347311966164e-02 2.266829646870217874e-01 0.000000000000000000 +1.891438051047112517e-02 2.178982790064369623e-01 0.000000000000000000 +1.894484654157130646e-02 2.090792330863608106e-01 0.000000000000000000 +1.897536164533609668e-02 2.002396363525043299e-01 0.000000000000000000 +1.900592590080847633e-02 1.913943115851661769e-01 0.000000000000000000 +1.903653938715878235e-02 1.825590005682446726e-01 0.000000000000000000 +1.906720218368484002e-02 1.737502661783084101e-01 0.000000000000000000 +1.909791436981221960e-02 1.649853897677093784e-01 0.000000000000000000 +1.912867602509440990e-02 1.562822630460526385e-01 0.000000000000000000 +1.915948722921305761e-02 1.476592739958036415e-01 0.000000000000000000 +1.919034806197813733e-02 1.391351866750305533e-01 0.000000000000000000 +1.922125860332818403e-02 1.307290150644814797e-01 0.000000000000000000 +1.925221893333050466e-02 1.224598914073051215e-01 0.000000000000000000 +1.928322913218135509e-02 1.143469297653379735e-01 0.000000000000000000 +1.931428928020617608e-02 1.064090857726608108e-01 0.000000000000000000 +1.934539945785978404e-02 9.866501380072824345e-02 0.000000000000000000 +1.937655974572658271e-02 9.113292295463991388e-02 0.000000000000000000 +1.940777022452081294e-02 8.383043349198707195e-02 0.000000000000000000 +1.943903097508665329e-02 7.677443538909384246e-02 0.000000000000000000 +1.947034207839858089e-02 6.998095086964359335e-02 0.000000000000000000 +1.950170361556144427e-02 6.346500275453788309e-02 0.000000000000000000 +1.953311566781075481e-02 5.724049048605062140e-02 0.000000000000000000 +1.956457831651286366e-02 5.132007562378638338e-02 0.000000000000000000 +1.959609164316518035e-02 4.571507850443509713e-02 0.000000000000000000 +1.962765572939640518e-02 4.043538760450624686e-02 0.000000000000000000 +1.965927065696669584e-02 3.548938294890888190e-02 0.000000000000000000 +1.969093650776791715e-02 3.088387467390504154e-02 0.000000000000000000 +1.972265336382382842e-02 2.662405758771792252e-02 0.000000000000000000 +1.975442130729032283e-02 2.271348228381557879e-02 0.000000000000000000 +1.978624042045561485e-02 1.915404305970301591e-02 0.000000000000000000 +1.981811078574045176e-02 1.594598258715149500e-02 0.000000000000000000 +1.985003248569837397e-02 1.308791297764429727e-02 0.000000000000000000 +1.988200560301586414e-02 1.057685259840362643e-02 0.000000000000000000 +1.991403022051259700e-02 8.408277727886423469e-03 0.000000000000000000 +1.994610642114165097e-02 6.576187902432598965e-03 0.000000000000000000 +1.997823428798971637e-02 5.073183603543953736e-03 0.000000000000000000 +2.001041390427731742e-02 3.890554772492665816e-03 0.000000000000000000 +2.004264535335901348e-02 3.018378518327578287e-03 0.000000000000000000 +2.007492871872365234e-02 2.445624307944856655e-03 0.000000000000000000 +2.010726408399453671e-02 2.160264892285386918e-03 0.000000000000000000 +2.013965153292967061e-02 2.149391228991257442e-03 0.000000000000000000 +2.017209114942197096e-02 2.399329705904938628e-03 0.000000000000000000 +2.020458301749947921e-02 2.895760047461747467e-03 0.000000000000000000 +2.023712722132559039e-02 3.623832392453384035e-03 0.000000000000000000 +2.026972384519924730e-02 4.568282161456970088e-03 0.000000000000000000 +2.030237297355521470e-02 5.713541479852985404e-03 0.000000000000000000 +2.033507469096422146e-02 7.043846082215088344e-03 0.000000000000000000 +2.036782908213323126e-02 8.543336790629647154e-03 0.000000000000000000 +2.040063623190564723e-02 1.019615482819375384e-02 0.000000000000000000 +2.043349622526152015e-02 1.198653039517281506e-02 0.000000000000000000 +2.046640914731782945e-02 1.389886409523213850e-02 0.000000000000000000 +2.049937508332857344e-02 1.591780094964790129e-02 0.000000000000000000 +2.053239411868515094e-02 1.802829687606424813e-02 0.000000000000000000 +2.056546633891646186e-02 2.021567763327374728e-02 0.000000000000000000 +2.059859182968917443e-02 2.246569034370637236e-02 0.000000000000000000 +2.063177067680795063e-02 2.476454780005069023e-02 0.000000000000000000 +2.066500296621564745e-02 2.709896584176091708e-02 0.000000000000000000 +2.069828878399358404e-02 2.945619415144215200e-02 0.000000000000000000 +2.073162821636170480e-02 3.182404087092162437e-02 0.000000000000000000 +2.076502134967883606e-02 3.419089147326195843e-02 0.000000000000000000 +2.079846827044291163e-02 3.654572235110705586e-02 0.000000000000000000 +2.083196906529118445e-02 3.887810959495084651e-02 0.000000000000000000 +2.086552382100046593e-02 4.117823343847951123e-02 0.000000000000000000 +2.089913262448732031e-02 4.343687884343003236e-02 0.000000000000000000 +2.093279556280834910e-02 4.564543268478633842e-02 0.000000000000000000 +2.096651272316035070e-02 4.779587797982252223e-02 0.000000000000000000 +2.100028419288057363e-02 4.988078558275625685e-02 0.000000000000000000 +2.103411005944695600e-02 5.189330374160541076e-02 0.000000000000000000 +2.106799041047833360e-02 5.382714588625758106e-02 0.000000000000000000 +2.110192533373467239e-02 5.567657698763359836e-02 0.000000000000000000 +2.113591491711728360e-02 5.743639879783765667e-02 0.000000000000000000 +2.116995924866910128e-02 5.910193425102180237e-02 0.000000000000000000 +2.120405841657483845e-02 6.066901127480865685e-02 0.000000000000000000 +2.123821250916126113e-02 6.213394623300408370e-02 0.000000000000000000 +2.127242161489740699e-02 6.349352719222720043e-02 0.000000000000000000 +2.130668582239481426e-02 6.474499717832669921e-02 0.000000000000000000 +2.134100522040774731e-02 6.588603756315698778e-02 0.000000000000000000 +2.137537989783342210e-02 6.691475169860013061e-02 0.000000000000000000 +2.140980994371227686e-02 6.782964889270751141e-02 0.000000000000000000 +2.144429544722813510e-02 6.862962880251272102e-02 0.000000000000000000 +2.147883649770848669e-02 6.931396629945783816e-02 0.000000000000000000 +2.151343318462470289e-02 6.988229684640079320e-02 0.000000000000000000 +2.154808559759225500e-02 7.033460240983729905e-02 0.000000000000000000 +2.158279382637101271e-02 7.067119791716562627e-02 0.000000000000000000 +2.161755796086533774e-02 7.089271825649855197e-02 0.000000000000000000 +2.165237809112448633e-02 7.100010580560729700e-02 0.000000000000000000 +2.168725430734272028e-02 7.099459846696178078e-02 0.000000000000000000 +2.172218669985958445e-02 7.087771817747723357e-02 0.000000000000000000 +2.175717535916013579e-02 7.065125985436224165e-02 0.000000000000000000 +2.179222037587517924e-02 7.031728073236519216e-02 0.000000000000000000 +2.182732184078151755e-02 6.987809004263391410e-02 0.000000000000000000 +2.186247984480215248e-02 6.933623897930769886e-02 0.000000000000000000 +2.189769447900654156e-02 6.869451089677766631e-02 0.000000000000000000 +2.193296583461083402e-02 6.795591167825965062e-02 0.000000000000000000 +2.196829400297810320e-02 6.712366021486611267e-02 0.000000000000000000 +2.200367907561858252e-02 6.620117893372223783e-02 0.000000000000000000 +2.203912114418989793e-02 6.519208431381658120e-02 0.000000000000000000 +2.207462030049733848e-02 6.410017732918144029e-02 0.000000000000000000 +2.211017663649403331e-02 6.292943376065886218e-02 0.000000000000000000 +2.214579024428124307e-02 6.168399431988198095e-02 0.000000000000000000 +2.218146121610857502e-02 6.036815453221046346e-02 0.000000000000000000 +2.221718964437421895e-02 5.898635432914560439e-02 0.000000000000000000 +2.225297562162520393e-02 5.754316730522892470e-02 0.000000000000000000 +2.228881924055760647e-02 5.604328959956503958e-02 0.000000000000000000 +2.232472059401685929e-02 5.449152836786089193e-02 0.000000000000000000 +2.236067977499789708e-02 5.289278981726330126e-02 0.000000000000000000 +2.239669687664545827e-02 5.125206678316865383e-02 0.000000000000000000 +2.243277199225432103e-02 4.957442583464641284e-02 0.000000000000000000 +2.246890521526951831e-02 4.786499390299898959e-02 0.000000000000000000 +2.250509663928663973e-02 4.612894443626860963e-02 0.000000000000000000 +2.254134635805196685e-02 4.437148309111829669e-02 0.000000000000000000 +2.257765446546284444e-02 4.259783298232392573e-02 0.000000000000000000 +2.261402105556782616e-02 4.081321951911906498e-02 0.000000000000000000 +2.265044622256696602e-02 3.902285486660649755e-02 0.000000000000000000 +2.268693006081203695e-02 3.723192207939168830e-02 0.000000000000000000 +2.272347266480678404e-02 3.544555896330729705e-02 0.000000000000000000 +2.276007412920722645e-02 3.366884172949598242e-02 0.000000000000000000 +2.279673454882175099e-02 3.190676851307557016e-02 0.000000000000000000 +2.283345401861155283e-02 3.016424283593699060e-02 0.000000000000000000 +2.287023263369072565e-02 2.844605709993438050e-02 0.000000000000000000 +2.290707048932658432e-02 2.675687620248052082e-02 0.000000000000000000 +2.294396768093989389e-02 2.510122137147208221e-02 0.000000000000000000 +2.298092430410510548e-02 2.348345432024575435e-02 0.000000000000000000 +2.301794045455064774e-02 2.190776182592023280e-02 0.000000000000000000 +2.305501622815910728e-02 2.037814083589424216e-02 0.000000000000000000 +2.309215172096753046e-02 1.889838420736438332e-02 0.000000000000000000 +2.312934702916763854e-02 1.747206718351152627e-02 0.000000000000000000 +2.316660224910611215e-02 1.610253470739056447e-02 0.000000000000000000 +2.320391747728480294e-02 1.479288967061029823e-02 0.000000000000000000 +2.324129281036100420e-02 1.354598218858274992e-02 0.000000000000000000 +2.327872834514771797e-02 1.236439998754786107e-02 0.000000000000000000 +2.331622417861386673e-02 1.125045998077988871e-02 0.000000000000000000 +2.335378040788456747e-02 1.020620110247278008e-02 0.000000000000000000 +2.339139713024137798e-02 9.233378457899649172e-03 0.000000000000000000 +2.342907444312255713e-02 8.333458837681028894e-03 0.000000000000000000 +2.346681244412330419e-02 7.507617632532500619e-03 0.000000000000000000 +2.350461123099601216e-02 6.756737172869813589e-03 0.000000000000000000 +2.354247090165055914e-02 6.081406505298862786e-03 0.000000000000000000 +2.358039155415449922e-02 5.481922605507743955e-03 0.000000000000000000 +2.361837328673335040e-02 4.958293014574076223e-03 0.000000000000000000 +2.365641619777085480e-02 4.510239873419991802e-03 0.000000000000000000 +2.369452038580920766e-02 4.137205318237484677e-03 0.000000000000000000 +2.373268594954937652e-02 3.838358188365355046e-03 0.000000000000000000 +2.377091298785123305e-02 3.612601987469502875e-03 0.000000000000000000 +2.380920159973395900e-02 3.458584029102660610e-03 0.000000000000000000 +2.384755188437618842e-02 3.374705688937303018e-03 0.000000000000000000 +2.388596394111631993e-02 3.359133678252480913e-03 0.000000000000000000 +2.392443786945275264e-02 3.409812246719241737e-03 0.000000000000000000 +2.396297376904414633e-02 3.524476217206966733e-03 0.000000000000000000 +2.400157173970972682e-02 3.700664751270946705e-03 0.000000000000000000 +2.404023188142942469e-02 3.935735741180448714e-03 0.000000000000000000 +2.407895429434428469e-02 4.226880722805153104e-03 0.000000000000000000 +2.411773907875661149e-02 4.571140203347527631e-03 0.000000000000000000 +2.415658633513028883e-02 4.965419298756387247e-03 0.000000000000000000 +2.419549616409100504e-02 5.406503577591974252e-03 0.000000000000000000 +2.423446866642652714e-02 5.891075011067794208e-03 0.000000000000000000 +2.427350394308700615e-02 6.415727932861009335e-03 0.000000000000000000 +2.431260209518514709e-02 6.976984916956278579e-03 0.000000000000000000 +2.435176322399653856e-02 7.571312487165676036e-03 0.000000000000000000 +2.439098743095990604e-02 8.195136577908518349e-03 0.000000000000000000 +2.443027481767735126e-02 8.844857672246077621e-03 0.000000000000000000 +2.446962548591464018e-02 9.516865549912247035e-03 0.000000000000000000 +2.450903953760143889e-02 1.020755358505242433e-02 0.000000000000000000 +2.454851707483163281e-02 1.091333254046931989e-02 0.000000000000000000 +2.458805819986352101e-02 1.163064381227017600e-02 0.000000000000000000 +2.462766301512011452e-02 1.235597208582463365e-02 0.000000000000000000 +2.466733162318941394e-02 1.308585737078308414e-02 0.000000000000000000 +2.470706412682465575e-02 1.381690638949594450e-02 0.000000000000000000 +2.474686062894458291e-02 1.454580329945831356e-02 0.000000000000000000 +2.478672123263370164e-02 1.526931973631066169e-02 0.000000000000000000 +2.482664604114260057e-02 1.598432416942360129e-02 0.000000000000000000 +2.486663515788813464e-02 1.668779056713417738e-02 0.000000000000000000 +2.490668868645375122e-02 1.737680637327905162e-02 0.000000000000000000 +2.494680673058974688e-02 1.804857980074217605e-02 0.000000000000000000 +2.498698939421351364e-02 1.870044645131787794e-02 0.000000000000000000 +2.502723678140987909e-02 1.932987527428086175e-02 0.000000000000000000 +2.506754899643123466e-02 1.993447387864179937e-02 0.000000000000000000 +2.510792614369798323e-02 2.051199321620550062e-02 0.000000000000000000 +2.514836832779867443e-02 2.106033165420233277e-02 0.000000000000000000 +2.518887565349033075e-02 2.157753845751880784e-02 0.000000000000000000 +2.522944822569871473e-02 2.206181670138525688e-02 0.000000000000000000 +2.527008614951857177e-02 2.251152563585242031e-02 0.000000000000000000 +2.531078953021399444e-02 2.292518252352535729e-02 0.000000000000000000 +2.535155847321853007e-02 2.330146397185289472e-02 0.000000000000000000 +2.539239308413563517e-02 2.363920678085301361e-02 0.000000000000000000 +2.543329346873882471e-02 2.393740832648488109e-02 0.000000000000000000 +2.547425973297199470e-02 2.419522649904511449e-02 0.000000000000000000 +2.551529198294968936e-02 2.441197921495901618e-02 0.000000000000000000 +2.555639032495736138e-02 2.458714351922370450e-02 0.000000000000000000 +2.559755486545169795e-02 2.472035429455992500e-02 0.000000000000000000 +2.563878571106082208e-02 2.481140259207790383e-02 0.000000000000000000 +2.568008296858462561e-02 2.486023359699795002e-02 0.000000000000000000 +2.572144674499501557e-02 2.486694424171001505e-02 0.000000000000000000 +2.576287714743621254e-02 2.483178047724211510e-02 0.000000000000000000 +2.580437428322500740e-02 2.475513421306101483e-02 0.000000000000000000 +2.584593825985104926e-02 2.463753993407323192e-02 0.000000000000000000 +2.588756918497715082e-02 2.447967100275066921e-02 0.000000000000000000 +2.592926716643951385e-02 2.428233565349808762e-02 0.000000000000000000 +2.597103231224803452e-02 2.404647268571842578e-02 0.000000000000000000 +2.601286473058659829e-02 2.377314686154139919e-02 0.000000000000000000 +2.605476452981334012e-02 2.346354401386457900e-02 0.000000000000000000 +2.609673181846092899e-02 2.311896587022915089e-02 0.000000000000000000 +2.613876670523683846e-02 2.274082459812173940e-02 0.000000000000000000 +2.618086929902368326e-02 2.233063707756040989e-02 0.000000000000000000 +2.622303970887941704e-02 2.189001890729603758e-02 0.000000000000000000 +2.626527804403767236e-02 2.142067815162520053e-02 0.000000000000000000 +2.630758441390802782e-02 2.092440883568306639e-02 0.000000000000000000 +2.634995892807627527e-02 2.040308419813899321e-02 0.000000000000000000 +2.639240169630477362e-02 1.985864971145204910e-02 0.000000000000000000 +2.643491282853259114e-02 1.929311588125566870e-02 0.000000000000000000 +2.647749243487597035e-02 1.870855083798069959e-02 0.000000000000000000 +2.652014062562845984e-02 1.810707273553530811e-02 0.000000000000000000 +2.656285751126129246e-02 1.749084197364038709e-02 0.000000000000000000 +2.660564320242362127e-02 1.686205326232371668e-02 0.000000000000000000 +2.664849780994282824e-02 1.622292754901808950e-02 0.000000000000000000 +2.669142144482484005e-02 1.557570383069803790e-02 0.000000000000000000 +2.673441421825434663e-02 1.492263087548128392e-02 0.000000000000000000 +2.677747624159513770e-02 1.426595888007766051e-02 0.000000000000000000 +2.682060762639038379e-02 1.360793109137827320e-02 0.000000000000000000 +2.686380848436292421e-02 1.295077542228293722e-02 0.000000000000000000 +2.690707892741554461e-02 1.229669609355025887e-02 0.000000000000000000 +2.695041906763127534e-02 1.164786533497862327e-02 0.000000000000000000 +2.699382901727371067e-02 1.100641518055823359e-02 0.000000000000000000 +2.703730888878724120e-02 1.037442939335044521e-02 0.000000000000000000 +2.708085879479738001e-02 9.753935556703254711e-03 0.000000000000000000 +2.712447884811106102e-02 9.146897369002577813e-03 0.000000000000000000 +2.716816916171690618e-02 8.555207179437770634e-03 0.000000000000000000 +2.721192984878554808e-02 7.980678802223421103e-03 0.000000000000000000 +2.725576102266987627e-02 7.425040646350414102e-03 0.000000000000000000 +2.729966279690541897e-02 6.889929197215264450e-03 0.000000000000000000 +2.734363528521052689e-02 6.376882885414298686e-03 0.000000000000000000 +2.738767860148673752e-02 5.887336376554217453e-03 0.000000000000000000 +2.743179285981905968e-02 5.422615314166004397e-03 0.000000000000000000 +2.747597817447625101e-02 4.983931545688307513e-03 0.000000000000000000 +2.752023465991113721e-02 4.572378859048091548e-03 0.000000000000000000 +2.756456243076087567e-02 4.188929254620730840e-03 0.000000000000000000 +2.760896160184731982e-02 3.834429774322565578e-03 0.000000000000000000 +2.765343228817722376e-02 3.509599906313364600e-03 0.000000000000000000 +2.769797460494261010e-02 3.215029580283281386e-03 0.000000000000000000 +2.774258866752103356e-02 2.951177764626358030e-03 0.000000000000000000 +2.778727459147588286e-02 2.718371672977558905e-03 0.000000000000000000 +2.783203249255674847e-02 2.516806583675111619e-03 0.000000000000000000 +2.787686248669955791e-02 2.346546271736095566e-03 0.000000000000000000 +2.792176469002708231e-02 2.207524048947260512e-03 0.000000000000000000 +2.796673921884907515e-02 2.099544403730324409e-03 0.000000000000000000 +2.801178618966265743e-02 2.022285228567139576e-03 0.000000000000000000 +2.805690571915258821e-02 1.975300619026921448e-03 0.000000000000000000 +2.810209792419155958e-02 1.958024224853248483e-03 0.000000000000000000 +2.814736292184056091e-02 1.969773130184807996e-03 0.000000000000000000 +2.819270082934909397e-02 2.009752236836478013e-03 0.000000000000000000 +2.823811176415553029e-02 2.077059121683625439e-03 0.000000000000000000 +2.828359584388740258e-02 2.170689336600787993e-03 0.000000000000000000 +2.832915318636170660e-02 2.289542117126247816e-03 0.000000000000000000 +2.837478390958522376e-02 2.432426464072867927e-03 0.000000000000000000 +2.842048813175478139e-02 2.598067560693938672e-03 0.000000000000000000 +2.846626597125764477e-02 2.785113486748134505e-03 0.000000000000000000 +2.851211754667172180e-02 2.992142189886877642e-03 0.000000000000000000 +2.855804297676593426e-02 3.217668674214346162e-03 0.000000000000000000 +2.860404238050050924e-02 3.460152365626669325e-03 0.000000000000000000 +2.865011587702728443e-02 3.718004613618798148e-03 0.000000000000000000 +2.869626358569002042e-02 3.989596289633929455e-03 0.000000000000000000 +2.874248562602469553e-02 4.273265442701628010e-03 0.000000000000000000 +2.878878211775987364e-02 4.567324974046876353e-03 0.000000000000000000 +2.883515318081692272e-02 4.870070293523640938e-03 0.000000000000000000 +2.888159893531038955e-02 5.179786922113726981e-03 0.000000000000000000 +2.892811950154828768e-02 5.494758006296680819e-03 0.000000000000000000 +2.897471500003240621e-02 5.813271711820962480e-03 0.000000000000000000 +2.902138555145868798e-02 6.133628466254326290e-03 0.000000000000000000 +2.906813127671738217e-02 6.454148021635246375e-03 0.000000000000000000 +2.911495229689356132e-02 6.773176310568311195e-03 0.000000000000000000 +2.916184873326727392e-02 7.089092071156097470e-03 0.000000000000000000 +2.920882070731393651e-02 7.400313218246456874e-03 0.000000000000000000 +2.925586834070462855e-02 7.705302940538501059e-03 0.000000000000000000 +2.930299175530639774e-02 8.002575505141476878e-03 0.000000000000000000 +2.935019107318263473e-02 8.290701753180421824e-03 0.000000000000000000 +2.939746641659325352e-02 8.568314271982700736e-03 0.000000000000000000 +2.944481790799519105e-02 8.834112231251250655e-03 0.000000000000000000 +2.949224567004257030e-02 9.086865872404106814e-03 0.000000000000000000 +2.953974982558709578e-02 9.325420641957472487e-03 0.000000000000000000 +2.958733049767835188e-02 9.548700961411060381e-03 0.000000000000000000 +2.963498780956410478e-02 9.755713627585196543e-03 0.000000000000000000 +2.968272188469069789e-02 9.945550838740968222e-03 0.000000000000000000 +2.973053284670324620e-02 1.011739284309340348e-02 0.000000000000000000 +2.977842081944606298e-02 1.027051020751274663e-02 0.000000000000000000 +2.982638592696292695e-02 1.040426570529215909e-02 0.000000000000000000 +2.987442829349741882e-02 1.051811582286316452e-02 0.000000000000000000 +2.992254804349325087e-02 1.061161188625930202e-02 0.000000000000000000 +2.997074530159455491e-02 1.068440080898054069e-02 0.000000000000000000 +3.001902019264629171e-02 1.073622546370132241e-02 0.000000000000000000 +3.006737284169445218e-02 1.076692468100773174e-02 0.000000000000000000 +3.011580337398647028e-02 1.077643287905432658e-02 0.000000000000000000 +3.016431191497151096e-02 1.076477932870881747e-02 0.000000000000000000 +3.021289859030081362e-02 1.073208705941724322e-02 0.000000000000000000 +3.026156352582800441e-02 1.067857141168151655e-02 0.000000000000000000 +3.031030684760940494e-02 1.060453824270854960e-02 0.000000000000000000 +3.035912868190443481e-02 1.051038179247282094e-02 0.000000000000000000 +3.040802915517583360e-02 1.039658221814425930e-02 0.000000000000000000 +3.045700839409005642e-02 1.026370280557406707e-02 0.000000000000000000 +3.050606652551757919e-02 1.011238686731416592e-02 0.000000000000000000 +3.055520367653322480e-02 9.943354337472381371e-03 0.000000000000000000 +3.060441997441655515e-02 9.757398074579919089e-03 0.000000000000000000 +3.065371554665203765e-02 9.555379884573729499e-03 0.000000000000000000 +3.070309052092959692e-02 9.338226276968484424e-03 0.000000000000000000 +3.075254502514476393e-02 9.106923968319503848e-03 0.000000000000000000 +3.080207918739909581e-02 8.862515148140714602e-03 0.000000000000000000 +3.085169313600048466e-02 8.606092523549607395e-03 0.000000000000000000 +3.090138699946347670e-02 8.338794160046323484e-03 0.000000000000000000 +3.095116090650968169e-02 8.061798136991822628e-03 0.000000000000000000 +3.100101498606793946e-02 7.776317037519342272e-03 0.000000000000000000 +3.105094936727487154e-02 7.483592293775536732e-03 0.000000000000000000 +3.110096417947503383e-02 7.184888409543249525e-03 0.000000000000000000 +3.115105955222133988e-02 6.881487083408898212e-03 0.000000000000000000 +3.120123561527538697e-02 6.574681256710715807e-03 0.000000000000000000 +3.125149249860775802e-02 6.265769111506288604e-03 0.000000000000000000 +3.130183033239843787e-02 5.956048044717139958e-03 0.000000000000000000 +3.135224924703704230e-02 5.646808645428477713e-03 0.000000000000000000 +3.140274937312322739e-02 5.339328703018546111e-03 0.000000000000000000 +3.145333084146702263e-02 5.034867274356671224e-03 0.000000000000000000 +3.150399378308913617e-02 4.734658838716398511e-03 0.000000000000000000 +3.155473832922133653e-02 4.439907569288346380e-03 0.000000000000000000 +3.160556461130674399e-02 4.151781750234635922e-03 0.000000000000000000 +3.165647276100026081e-02 3.871408368083425512e-03 0.000000000000000000 +3.170746291016874469e-02 3.599867905918751124e-03 0.000000000000000000 +3.175853519089157084e-02 3.338189368252815047e-03 0.000000000000000000 +3.180968973546078465e-02 3.087345563694490844e-03 0.000000000000000000 +3.186092667638152492e-02 2.848248671514397312e-03 0.000000000000000000 +3.191224614637242635e-02 2.621746116986055711e-03 0.000000000000000000 +3.196364827836578604e-02 2.408616778934434023e-03 0.000000000000000000 +3.201513320550811864e-02 2.209567551261618339e-03 0.000000000000000000 +3.206670106116035757e-02 2.025230278361591849e-03 0.000000000000000000 +3.211835197889825744e-02 1.856159082278215295e-03 0.000000000000000000 +3.217008609251270634e-02 1.702828097234771213e-03 0.000000000000000000 +3.222190353601011442e-02 1.565629624775653544e-03 0.000000000000000000 +3.227380444361277467e-02 1.444872720239199050e-03 0.000000000000000000 +3.232578894975907113e-02 1.340782218643237628e-03 0.000000000000000000 +3.237785718910405480e-02 1.253498205337536279e-03 0.000000000000000000 +3.243000929651960323e-02 1.183075933990474383e-03 0.000000000000000000 +3.248224540709483688e-02 1.129486191647330025e-03 0.000000000000000000 +3.253456565613647988e-02 1.092616107765679656e-03 0.000000000000000000 +3.258697017916919320e-02 1.072270401315302771e-03 0.000000000000000000 +3.263945911193598393e-02 1.068173057261730249e-03 0.000000000000000000 +3.269203259039839965e-02 1.079969421055653085e-03 0.000000000000000000 +3.274469075073708352e-02 1.107228697153142538e-03 0.000000000000000000 +3.279743372935198242e-02 1.149446835117847636e-03 0.000000000000000000 +3.285026166286275640e-02 1.206049784526501542e-03 0.000000000000000000 +3.290317468810911861e-02 1.276397097735791760e-03 0.000000000000000000 +3.295617294215119619e-02 1.359785857586975249e-03 0.000000000000000000 +3.300925656226991883e-02 1.455454905341176282e-03 0.000000000000000000 +3.306242568596725467e-02 1.562589342563321104e-03 0.000000000000000000 +3.311568045096675156e-02 1.680325279317966417e-03 0.000000000000000000 +3.316902099521372438e-02 1.807754799906571928e-03 0.000000000000000000 +3.322244745687569223e-02 1.943931116474035582e-03 0.000000000000000000 +3.327595997434278086e-02 2.087873880133959709e-03 0.000000000000000000 +3.332955868622791001e-02 2.238574618810595766e-03 0.000000000000000000 +3.338324373136741102e-02 2.395002270765942028e-03 0.000000000000000000 +3.343701524882109616e-02 2.556108782756344629e-03 0.000000000000000000 +3.349087337787290397e-02 2.720834741952422343e-03 0.000000000000000000 +3.354481825803103112e-02 2.888115011123676759e-03 0.000000000000000000 +3.359885002902839729e-02 3.056884337148164151e-03 0.000000000000000000 +3.365296883082306151e-02 3.226082903620016394e-03 0.000000000000000000 +3.370717480359840257e-02 3.394661799195068403e-03 0.000000000000000000 +3.376146808776370883e-02 3.561588374316403474e-03 0.000000000000000000 +3.381584882395437253e-02 3.725851460074903164e-03 0.000000000000000000 +3.387031715303230606e-02 3.886466424183882343e-03 0.000000000000000000 +3.392487321608634449e-02 4.042480040350544292e-03 0.000000000000000000 +3.397951715443254389e-02 4.192975148706035160e-03 0.000000000000000000 +3.403424910961465322e-02 4.337075086393132363e-03 0.000000000000000000 +3.408906922340429468e-02 4.473947868890285062e-03 0.000000000000000000 +3.414397763780156053e-02 4.602810104168631768e-03 0.000000000000000000 +3.419897449503520731e-02 4.722930623312474735e-03 0.000000000000000000 +3.425405993756309303e-02 4.833633812788707372e-03 0.000000000000000000 +3.430923410807254492e-02 4.934302635106132401e-03 0.000000000000000000 +3.436449714948069251e-02 5.024381326163254897e-03 0.000000000000000000 +3.441984920493495331e-02 5.103377759135651996e-03 0.000000000000000000 +3.447529041781318554e-02 5.170865466296200620e-03 0.000000000000000000 +3.453082093172430561e-02 5.226485311695578534e-03 0.000000000000000000 +3.458644089050848941e-02 5.269946809148253787e-03 0.000000000000000000 +3.464215043823760942e-02 5.301029081478725313e-03 0.000000000000000000 +3.469794971921560944e-02 5.319581458477841071e-03 0.000000000000000000 +3.475383887797883764e-02 5.325523712504671124e-03 0.000000000000000000 +3.480981805929653922e-02 5.318845932146545712e-03 0.000000000000000000 +3.486588740817100213e-02 5.299608035820135843e-03 0.000000000000000000 +3.492204706983820239e-02 5.267938928662235440e-03 0.000000000000000000 +3.497829718976799840e-02 5.224035307522393971e-03 0.000000000000000000 +3.503463791366454028e-02 5.168160120332280366e-03 0.000000000000000000 +3.509106938746674870e-02 5.100640687588859148e-03 0.000000000000000000 +3.514759175734849528e-02 5.021866495152886405e-03 0.000000000000000000 +3.520420516971921321e-02 4.932286669026311049e-03 0.000000000000000000 +3.526090977122409154e-02 4.832407144236078311e-03 0.000000000000000000 +3.531770570874454701e-02 4.722787541408321813e-03 0.000000000000000000 +3.537459312939858491e-02 4.604037766067938311e-03 0.000000000000000000 +3.543157218054115987e-02 4.476814347135110554e-03 0.000000000000000000 +3.548864300976464770e-02 4.341816532507068900e-03 0.000000000000000000 +3.554580576489901889e-02 4.199782161003831789e-03 0.000000000000000000 +3.560306059401250472e-02 4.051483331305676290e-03 0.000000000000000000 +3.566040764541175689e-02 3.897721889819424565e-03 0.000000000000000000 +3.571784706764231238e-02 3.739324760651190939e-03 0.000000000000000000 +3.577537900948898897e-02 3.577139142038494261e-03 0.000000000000000000 +3.583300361997623917e-02 3.412027594683166628e-03 0.000000000000000000 +3.589072104836862898e-02 3.244863048411390522e-03 0.000000000000000000 +3.594853144417101826e-02 3.076523754464603050e-03 0.000000000000000000 +3.600643495712919917e-02 2.907888211464095332e-03 0.000000000000000000 +3.606443173723010431e-02 2.739830093699082737e-03 0.000000000000000000 +3.612252193470226469e-02 2.573213210824921732e-03 0.000000000000000000 +3.618070570001619829e-02 2.408886528333467961e-03 0.000000000000000000 +3.623898318388476397e-02 2.247679278244637223e-03 0.000000000000000000 +3.629735453726366107e-02 2.090396189360209812e-03 0.000000000000000000 +3.635581991135159591e-02 1.937812866113860447e-03 0.000000000000000000 +3.641437945759096878e-02 1.790671344524867375e-03 0.000000000000000000 +3.647303332766800577e-02 1.649675853030999973e-03 0.000000000000000000 +3.653178167351330691e-02 1.515488805012835203e-03 0.000000000000000000 +3.659062464730217235e-02 1.388727048650275622e-03 0.000000000000000000 +3.664956240145501865e-02 1.269958398355912343e-03 0.000000000000000000 +3.670859508863782289e-02 1.159698470426518725e-03 0.000000000000000000 +3.676772286176235166e-02 1.058407843747266423e-03 0.000000000000000000 +3.682694587398679248e-02 9.664895643812686709e-04 0.000000000000000000 +3.688626427871596197e-02 8.842870107033496503e-04 0.000000000000000000 +3.694567822960177078e-02 8.120821333941030500e-04 0.000000000000000000 +3.700518788054368846e-02 7.500940821306905726e-04 0.000000000000000000 +3.706479338568895165e-02 6.984782282068638772e-04 0.000000000000000000 +3.712449489943322328e-02 6.573255896112733783e-04 0.000000000000000000 +3.718429257642077296e-02 6.266626623188324263e-04 0.000000000000000000 +3.724418657154498352e-02 6.064516587231715342e-04 0.000000000000000000 +3.730417703994871881e-02 5.965911512924706788e-04 0.000000000000000000 +3.736426413702473998e-02 5.969171166893548789e-04 0.000000000000000000 +3.742444801841616348e-02 6.072043727858239884e-04 0.000000000000000000 +3.748472884001667615e-02 6.271683982529537233e-04 0.000000000000000000 +3.754510675797120139e-02 6.564675217384336944e-04 0.000000000000000000 +3.760558192867609340e-02 6.947054650865297238e-04 0.000000000000000000 +3.766615450877964372e-02 7.414342226283800489e-04 0.000000000000000000 +3.772682465518245598e-02 7.961572562961228075e-04 0.000000000000000000 +3.778759252503784138e-02 8.583329842113257818e-04 0.000000000000000000 +3.784845827575232524e-02 9.273785384833851302e-04 0.000000000000000000 +3.790942206498583433e-02 1.002673766239268799e-03 0.000000000000000000 +3.797048405065236998e-02 1.083565446406913697e-03 0.000000000000000000 +3.803164439092023008e-02 1.169371693493731620e-03 0.000000000000000000 +3.809290324421248791e-02 1.259386518551686976e-03 0.000000000000000000 +3.815426076920739457e-02 1.352884516697892316e-03 0.000000000000000000 +3.821571712483878142e-02 1.449125649969686472e-03 0.000000000000000000 +3.827727247029653890e-02 1.547360093931796814e-03 0.000000000000000000 +3.833892696502684549e-02 1.646833116315851589e-03 0.000000000000000000 +3.840068076873284081e-02 1.746789956056304114e-03 0.000000000000000000 +3.846253404137482679e-02 1.846480671377013832e-03 0.000000000000000000 +3.852448694317075345e-02 1.945164926079466028e-03 0.000000000000000000 +3.858653963459672542e-02 2.042116683866339495e-03 0.000000000000000000 +3.864869227638717541e-02 2.136628781397737972e-03 0.000000000000000000 +3.871094502953562749e-02 2.228017351808918040e-03 0.000000000000000000 +3.877329805529473178e-02 2.315626071598732034e-03 0.000000000000000000 +3.883575151517703467e-02 2.398830205126633794e-03 0.000000000000000000 +3.889830557095514535e-02 2.477040422404233784e-03 0.000000000000000000 +3.896096038466224237e-02 2.549706367438597451e-03 0.000000000000000000 +3.902371611859259404e-02 2.616319956053624052e-03 0.000000000000000000 +3.908657293530172494e-02 2.676418383878331753e-03 0.000000000000000000 +3.914953099760713068e-02 2.729586827035892452e-03 0.000000000000000000 +3.921259046858850683e-02 2.775460819978815743e-03 0.000000000000000000 +3.927575151158821387e-02 2.813728296892390596e-03 0.000000000000000000 +3.933901429021174206e-02 2.844131285115007735e-03 0.000000000000000000 +3.940237896832807230e-02 2.866467241095592422e-03 0.000000000000000000 +3.946584571007021730e-02 2.880590021517362258e-03 0.000000000000000000 +3.952941467983541596e-02 2.886410484355637039e-03 0.000000000000000000 +3.959308604228586881e-02 2.883896716799728022e-03 0.000000000000000000 +3.965685996234889765e-02 2.873073889148603996e-03 0.000000000000000000 +3.972073660521751454e-02 2.854023735980815591e-03 0.000000000000000000 +3.978471613635081727e-02 2.826883668094466121e-03 0.000000000000000000 +3.984879872147437108e-02 2.791845520907082923e-03 0.000000000000000000 +3.991298452658079143e-02 2.749153947189869347e-03 0.000000000000000000 +3.997727371792990370e-02 2.699104464179946129e-03 0.000000000000000000 +4.004166646204947860e-02 2.642041167257557985e-03 0.000000000000000000 +4.010616292573543351e-02 2.578354124486210985e-03 0.000000000000000000 +4.017076327605238056e-02 2.508476468379393799e-03 0.000000000000000000 +4.023546768033402221e-02 2.432881203269236965e-03 0.000000000000000000 +4.030027630618356754e-02 2.352077748596845264e-03 0.000000000000000000 +4.036518932147428046e-02 2.266608240308456545e-03 0.000000000000000000 +4.043020689434967396e-02 2.177043614311887851e-03 0.000000000000000000 +4.049532919322423180e-02 2.083979497608674444e-03 0.000000000000000000 +4.056055638678365133e-02 1.988031934255511841e-03 0.000000000000000000 +4.062588864398530841e-02 1.889832974704139376e-03 0.000000000000000000 +4.069132613405881949e-02 1.790026158309202453e-03 0.000000000000000000 +4.075686902650624971e-02 1.689261919861657609e-03 0.000000000000000000 +4.082251749110283462e-02 1.588192951880986782e-03 0.000000000000000000 +4.088827169789711891e-02 1.487469555076492093e-03 0.000000000000000000 +4.095413181721169193e-02 1.387735009838586726e-03 0.000000000000000000 +4.102009801964340979e-02 1.289621001847101591e-03 0.000000000000000000 +4.108617047606389489e-02 1.193743134859370130e-03 0.000000000000000000 +4.115234935762010493e-02 1.100696563466432984e-03 0.000000000000000000 +4.121863483573452031e-02 1.011051778070516443e-03 0.000000000000000000 +4.128502708210586569e-02 9.253505735321177622e-04 0.000000000000000000 +4.135152626870935988e-02 8.441022318676846695e-04 0.000000000000000000 +4.141813256779725005e-02 7.677799480388445945e-04 0.000000000000000000 +4.148484615189922120e-02 6.968175262758248599e-04 0.000000000000000000 +4.155166719382284712e-02 6.316063725207356639e-04 0.000000000000000000 +4.161859586665413863e-02 5.724928064772778291e-04 0.000000000000000000 +4.168563234375774473e-02 5.197757144227579213e-04 0.000000000000000000 +4.175277679877770209e-02 4.737045613948068657e-04 0.000000000000000000 +4.182002940563767091e-02 4.344777786309194051e-04 0.000000000000000000 +4.188739033854146920e-02 4.022415392339047206e-04 0.000000000000000000 +4.195485977197351002e-02 3.770889319900375862e-04 0.000000000000000000 +4.202243788069923852e-02 3.590595401058738765e-04 0.000000000000000000 +4.209012483976568020e-02 3.481394283832682252e-04 0.000000000000000000 +4.215792082450166289e-02 3.442615390548187972e-04 0.000000000000000000 +4.222582601051858009e-02 3.473064931824063973e-04 0.000000000000000000 +4.229384057371059907e-02 3.571037912159646531e-04 0.000000000000000000 +4.236196469025523687e-02 3.734334030484301350e-04 0.000000000000000000 +4.243019853661376267e-02 3.960277347200352131e-04 0.000000000000000000 +4.249854228953167667e-02 4.245739558508711937e-04 0.000000000000000000 +4.256699612603924432e-02 4.587166689456494877e-04 0.000000000000000000 +4.263556022345173224e-02 4.980608989457250809e-04 0.000000000000000000 +4.270423475937017849e-02 5.421753788281151367e-04 0.000000000000000000 +4.277301991168157291e-02 5.905961046897250776e-04 0.000000000000000000 +4.284191585855946782e-02 6.428301316314747596e-04 0.000000000000000000 +4.291092277846446368e-02 6.983595798844536738e-04 0.000000000000000000 +4.298004085014447972e-02 7.566458190160214696e-04 0.000000000000000000 +4.304927025263551726e-02 8.171337967279896242e-04 0.000000000000000000 +4.311861116526178456e-02 8.792564777167911731e-04 0.000000000000000000 +4.318806376763648786e-02 9.424393573171931885e-04 0.000000000000000000 +4.325762823966205345e-02 1.006105014190203676e-03 0.000000000000000000 +4.332730476153067584e-02 1.069677666149407552e-03 0.000000000000000000 +4.339709351372488672e-02 1.132587693337406588e-03 0.000000000000000000 +4.346699467701777703e-02 1.194276093361901518e-03 0.000000000000000000 +4.353700843247376023e-02 1.254198833672293947e-03 0.000000000000000000 +4.360713496144880824e-02 1.311831067386976055e-03 0.000000000000000000 +4.367737444559104121e-02 1.366671179963341830e-03 0.000000000000000000 +4.374772706684115775e-02 1.418244635518045669e-03 0.000000000000000000 +4.381819300743289292e-02 1.466107593243553588e-03 0.000000000000000000 +4.388877244989360105e-02 1.509850266211925631e-03 0.000000000000000000 +4.395946557704447782e-02 1.549099996892497550e-03 0.000000000000000000 +4.403027257200137212e-02 1.583524025922241349e-03 0.000000000000000000 +4.410119361817497335e-02 1.612831933036395224e-03 0.000000000000000000 +4.417222889927142210e-02 1.636777731581298863e-03 0.000000000000000000 +4.424337859929276806e-02 1.655161600669515908e-03 0.000000000000000000 +4.431464290253741417e-02 1.667831241786872035e-03 0.000000000000000000 +4.438602199360070638e-02 1.674682849503645416e-03 0.000000000000000000 +4.445751605737516265e-02 1.675661688861882197e-03 0.000000000000000000 +4.452912527905129175e-02 1.670762274991136748e-03 0.000000000000000000 +4.460084984411777365e-02 1.660028153529445692e-03 0.000000000000000000 +4.467268993836211177e-02 1.643551283476948986e-03 0.000000000000000000 +4.474464574787104937e-02 1.621471027170770388e-03 0.000000000000000000 +4.481671745903104132e-02 1.593972755121191411e-03 0.000000000000000000 +4.488890525852886476e-02 1.561286076474832814e-03 0.000000000000000000 +4.496120933335182729e-02 1.523682708849639304e-03 0.000000000000000000 +4.503362987078858570e-02 1.481474004198986630e-03 0.000000000000000000 +4.510616705842938889e-02 1.435008150190131586e-03 0.000000000000000000 +4.517882108416663295e-02 1.384667069299975279e-03 0.000000000000000000 +4.525159213619544402e-02 1.330863040420994514e-03 0.000000000000000000 +4.532448040301393505e-02 1.274035070207542222e-03 0.000000000000000000 +4.539748607342401765e-02 1.214645043653967468e-03 0.000000000000000000 +4.547060933653152004e-02 1.153173685462312954e-03 0.000000000000000000 +4.554385038174704747e-02 1.090116365598868152e-03 0.000000000000000000 +4.561720939878618347e-02 1.025978784042460602e-03 0.000000000000000000 +4.569068657767011432e-02 9.612725710615330167e-04 0.000000000000000000 +4.576428210872617031e-02 8.965108404104832774e-04 0.000000000000000000 +4.583799618258810327e-02 8.322037335833511835e-04 0.000000000000000000 +4.591182899019688457e-02 7.688539936901050325e-04 0.000000000000000000 +4.598578072280093409e-02 7.069526076156769064e-04 0.000000000000000000 +4.605985157195675861e-02 6.469745548676157513e-04 0.000000000000000000 +4.613404172952941668e-02 5.893747009124998461e-04 0.000000000000000000 +4.620835138769297662e-02 5.345838718359871263e-04 0.000000000000000000 +4.628278073893114103e-02 4.830051458367050723e-04 0.000000000000000000 +4.635732997603748962e-02 4.350103953857861207e-04 0.000000000000000000 +4.643199929211630494e-02 3.909371118560530669e-04 0.000000000000000000 +4.650678888058282223e-02 3.510855420662196600e-04 0.000000000000000000 +4.658169893516383997e-02 3.157161635057313177e-04 0.000000000000000000 +4.665672964989819177e-02 2.850475220347417930e-04 0.000000000000000000 +4.673188121913722515e-02 2.592544526107154489e-04 0.000000000000000000 +4.680715383754546072e-02 2.384667001127284826e-04 0.000000000000000000 +4.688254770010076566e-02 2.227679536487619182e-04 0.000000000000000000 +4.695806300209526968e-02 2.121953038767527644e-04 0.000000000000000000 +4.703369993913553843e-02 2.067391288897609523e-04 0.000000000000000000 +4.710945870714324663e-02 2.063434101469426127e-04 0.000000000000000000 +4.718533950235565683e-02 2.109064758238981489e-04 0.000000000000000000 +4.726134252132607738e-02 2.202821648488739476e-04 0.000000000000000000 +4.733746796092450776e-02 2.342814008327644701e-04 0.000000000000000000 +4.741371601833788835e-02 2.526741611345303474e-04 0.000000000000000000 +4.749008689107095393e-02 2.751918224728520197e-04 0.000000000000000000 +4.756658077694645576e-02 3.015298608413290258e-04 0.000000000000000000 +4.764319787410578599e-02 3.313508800481517608e-04 0.000000000000000000 +4.771993838100960228e-02 3.642879400174973037e-04 0.000000000000000000 +4.779680249643803586e-02 3.999481530926096750e-04 0.000000000000000000 +4.787379041949159364e-02 4.379165139995928879e-04 0.000000000000000000 +4.795090234959135944e-02 4.777599268896272431e-04 0.000000000000000000 +4.802813848647968092e-02 5.190313909999198175e-04 0.000000000000000000 +4.810549903022061369e-02 5.612743049735653428e-04 0.000000000000000000 +4.818298418120046250e-02 6.040268487704387188e-04 0.000000000000000000 +4.826059414012837112e-02 6.468264013917196433e-04 0.000000000000000000 +4.833832910803662758e-02 6.892139523334332935e-04 0.000000000000000000 +4.841618928628148300e-02 7.307384647800957943e-04 0.000000000000000000 +4.849417487654343606e-02 7.709611490409045299e-04 0.000000000000000000 +4.857228608082784366e-02 8.094596056137555451e-04 0.000000000000000000 +4.865052310146546211e-02 8.458317985214627247e-04 0.000000000000000000 +4.872888614111291206e-02 8.796998211878513966e-04 0.000000000000000000 +4.880737540275333769e-02 9.107134190908514927e-04 0.000000000000000000 +4.888599108969666346e-02 9.385532357254891067e-04 0.000000000000000000 +4.896473340558046838e-02 9.629337510110858034e-04 0.000000000000000000 +4.904360255437023586e-02 9.836058841584027681e-04 0.000000000000000000 +4.912259874036000590e-02 1.000359236151715948e-03 0.000000000000000000 +4.920172216817288863e-02 1.013023950368015019e-03 0.000000000000000000 +4.928097304276155000e-02 1.021472173425439856e-03 0.000000000000000000 +4.936035156940889873e-02 1.025619102095132445e-03 0.000000000000000000 +4.943985795372831532e-02 1.025423605995544893e-03 0.000000000000000000 +4.951949240166453325e-02 1.020888419784884548e-03 0.000000000000000000 +4.959925511949392352e-02 1.012059902643778131e-03 0.000000000000000000 +4.967914631382512602e-02 9.990273669634817250e-04 0.000000000000000000 +4.975916619159959087e-02 9.819219822922449058e-04 0.000000000000000000 +4.983931496009204321e-02 9.609152647082178133e-04 0.000000000000000000 +4.991959282691120492e-02 9.362171658475176156e-04 0.000000000000000000 +4.999999999999999584e-02 9.080737797844798441e-04 0.000000000000000000 \ No newline at end of file diff --git a/tests/test_data/R1DoubleBilayerVolumeModel.mat b/tests/test_data/R1DoubleBilayerVolumeModel.mat new file mode 100644 index 00000000..c65b170a Binary files /dev/null and b/tests/test_data/R1DoubleBilayerVolumeModel.mat differ diff --git a/tests/test_data/R1Monolayer_8_contrasts.mat b/tests/test_data/R1Monolayer_8_contrasts.mat new file mode 100644 index 00000000..da9de417 Binary files /dev/null and b/tests/test_data/R1Monolayer_8_contrasts.mat differ diff --git a/tests/test_data/R1motofitBenchMark.mat b/tests/test_data/R1motofitBenchMark.mat new file mode 100644 index 00000000..449362a5 Binary files /dev/null and b/tests/test_data/R1motofitBenchMark.mat differ diff --git a/tests/test_data/R1orsoPolymerExample.mat b/tests/test_data/R1orsoPolymerExample.mat new file mode 100644 index 00000000..48bc10f6 Binary files /dev/null and b/tests/test_data/R1orsoPolymerExample.mat differ diff --git a/tests/test_data/bare_substrate.json b/tests/test_data/bare_substrate.json new file mode 100644 index 00000000..65e405c2 --- /dev/null +++ b/tests/test_data/bare_substrate.json @@ -0,0 +1 @@ +{"name": "substrate", "calculation": "normal", "model": "standard layers", "geometry": "air/substrate", "absorption": false, "parameters": [{"name": "Substrate Roughness", "min": 1.0, "value": 3.0, "max": 5.0, "fit": true, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "bulk_in": [{"name": "air SLD", "min": 4.42927130586151e-09, "value": 4.42927130586151e-09, "max": 4.42927130586151e-09, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "bulk_out": [{"name": "D2O SLD", "min": 6.360408603667384e-06, "value": 6.360408603667384e-06, "max": 6.360408603667384e-06, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "scalefactors": [{"name": "Scalefactor 1", "min": 0.02, "value": 0.23, "max": 0.25, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "domain_ratios": [], "background_parameters": [{"name": "Background Param 1", "min": 1e-07, "value": 1e-06, "max": 1e-05, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "backgrounds": [{"name": "Background 1", "type": "constant", "source": "Background Param 1", "value_1": "", "value_2": "", "value_3": "", "value_4": "", "value_5": ""}], "resolution_parameters": [{"name": "Resolution Param 1", "min": 0.01, "value": 0.03, "max": 0.05, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "resolutions": [{"name": "Resolution 1", "type": "constant", "source": "Resolution Param 1", "value_1": "", "value_2": "", "value_3": "", "value_4": "", "value_5": ""}], "custom_files": [], "data": [{"name": "Simulation", "data": [], "data_range": [], "simulation_range": [0.005, 0.7]}, {"name": "D2O substrate", "data": [[0.048866, 0.00012343, 1.3213e-06, 0.03], [0.051309, 0.00010063, 1.0803e-06, 0.03], [0.053874, 8.2165e-05, 8.8779e-07, 0.03], [0.056568, 6.4993e-05, 7.2018e-07, 0.03], [0.059396, 5.3958e-05, 6.0015e-07, 0.03], [0.062366, 4.359e-05, 5.0129e-07, 0.03], [0.065485, 3.578e-05, 4.1957e-07, 0.03], [0.068759, 2.913e-05, 3.5171e-07, 0.03], [0.072197, 2.3481e-05, 3.0586e-07, 0.03], [0.075807, 1.8906e-05, 2.6344e-07, 0.03], [0.079597, 1.4642e-05, 2.2314e-07, 0.03], [0.083577, 1.1589e-05, 1.8938e-07, 0.03], [0.087756, 9.5418e-06, 1.622e-07, 0.03], [0.092143, 7.5694e-06, 1.3809e-07, 0.03], [0.096751, 6.3831e-06, 1.2097e-07, 0.03], [0.10159, 5.0708e-06, 1.0333e-07, 0.03], [0.10667, 4.1041e-06, 8.9548e-08, 0.03], [0.112, 3.4253e-06, 7.983e-08, 0.03], [0.1176, 2.8116e-06, 7.1554e-08, 0.03], [0.12348, 2.3767e-06, 6.3738e-08, 0.03], [0.12966, 1.9241e-06, 5.6586e-08, 0.03], [0.13614, 1.5642e-06, 5.2778e-08, 0.03], [0.14294, 1.2922e-06, 4.973e-08, 0.03], [0.15009, 1.1694e-06, 5.1175e-08, 0.03], [0.1576, 9.7837e-07, 5.0755e-08, 0.03], [0.16548, 8.9138e-07, 5.3542e-08, 0.03], [0.17375, 7.942e-07, 5.4857e-08, 0.03], [0.18244, 7.9131e-07, 5.8067e-08, 0.03], [0.19156, 6.5358e-07, 5.7717e-08, 0.03], [0.20114, 6.297e-07, 5.7951e-08, 0.03], [0.21119, 5.013e-07, 5.5262e-08, 0.03], [0.22175, 5.0218e-07, 5.6461e-08, 0.03], [0.23284, 3.9299e-07, 5.0685e-08, 0.03], [0.24448, 3.5324e-07, 5.0194e-08, 0.03], [0.25671, 4.4475e-07, 5.6485e-08, 0.03], [0.26954, 5.1338e-07, 6.2247e-08, 0.03], [0.28302, 3.4918e-07, 4.9745e-08, 0.03], [0.29717, 4.3037e-07, 5.5488e-08, 0.03], [0.31203, 4.0099e-07, 5.3591e-08, 0.03], [0.32763, 3.8397e-07, 5.1303e-08, 0.03], [0.34401, 3.0995e-07, 4.5965e-08, 0.03], [0.36121, 3.9357e-07, 5.0135e-08, 0.03], [0.37927, 3.0997e-07, 4.368e-08, 0.03], [0.39824, 2.9656e-07, 4.2432e-08, 0.03], [0.41815, 2.1909e-07, 3.6117e-08, 0.03], [0.43906, 2.3153e-07, 3.6307e-08, 0.03], [0.46101, 3.3428e-07, 4.3874e-08, 0.03], [0.48406, 2.3441e-07, 3.7488e-08, 0.03], [0.50826, 1.5496e-07, 3.0585e-08, 0.03], [0.53368, 2.4708e-07, 3.9376e-08, 0.03], [0.56036, 2.2157e-07, 3.8258e-08, 0.03], [0.58838, 2.2798e-07, 4.6976e-08, 0.03], [0.61169, 6.0272e-07, 2.3239e-07, 0.03]], "data_range": [0.048866, 0.61169], "simulation_range": [0.048866, 0.61169]}], "layers": [], "domain_contrasts": [], "contrasts": []} \ No newline at end of file diff --git a/tests/test_data/bare_substrate.ort b/tests/test_data/bare_substrate.ort new file mode 100644 index 00000000..7e4ffb52 --- /dev/null +++ b/tests/test_data/bare_substrate.ort @@ -0,0 +1,83 @@ +# # ORSO reflectivity data file | 1.1 standard | YAML encoding | https://www.reflectometry.org/ +# # handwritten test file header created to test RAT orsopy integration! +# data_source: +# owner: +# name: null +# affiliation: null +# measurement: +# instrument_settings: null +# data_files: null +# experiment: +# title: Bare D2O substrate +# probe: neutron +# instrument: None +# start_date: 1970-01-01T00:00:00 +# sample: +# name: D2O substrate +# model: +# stack: air | D2O +# reduction: +# software: null +# timestamp: null +# data_set: 0 +# columns: +# - {name: Qz, unit: 1/angstrom, physical_quantity: normal momentum transfer} +# - {name: R, unit: '', physical_quantity: specular reflectivity} +# - {error_of: R, error_type: uncertainty, value_is: sigma} +# - {error_of: Qz, error_type: resolution, value_is: sigma} +# # Qz (1/angstrom) R () sR sQz +4.8866e-02 1.2343e-04 1.3213e-06 0.03 +5.1309e-02 1.0063e-04 1.0803e-06 0.03 +5.3874e-02 8.2165e-05 8.8779e-07 0.03 +5.6568e-02 6.4993e-05 7.2018e-07 0.03 +5.9396e-02 5.3958e-05 6.0015e-07 0.03 +6.2366e-02 4.3590e-05 5.0129e-07 0.03 +6.5485e-02 3.5780e-05 4.1957e-07 0.03 +6.8759e-02 2.9130e-05 3.5171e-07 0.03 +7.2197e-02 2.3481e-05 3.0586e-07 0.03 +7.5807e-02 1.8906e-05 2.6344e-07 0.03 +7.9597e-02 1.4642e-05 2.2314e-07 0.03 +8.3577e-02 1.1589e-05 1.8938e-07 0.03 +8.7756e-02 9.5418e-06 1.6220e-07 0.03 +9.2143e-02 7.5694e-06 1.3809e-07 0.03 +9.6751e-02 6.3831e-06 1.2097e-07 0.03 +1.0159e-01 5.0708e-06 1.0333e-07 0.03 +1.0667e-01 4.1041e-06 8.9548e-08 0.03 +1.1200e-01 3.4253e-06 7.9830e-08 0.03 +1.1760e-01 2.8116e-06 7.1554e-08 0.03 +1.2348e-01 2.3767e-06 6.3738e-08 0.03 +1.2966e-01 1.9241e-06 5.6586e-08 0.03 +1.3614e-01 1.5642e-06 5.2778e-08 0.03 +1.4294e-01 1.2922e-06 4.9730e-08 0.03 +1.5009e-01 1.1694e-06 5.1175e-08 0.03 +1.5760e-01 9.7837e-07 5.0755e-08 0.03 +1.6548e-01 8.9138e-07 5.3542e-08 0.03 +1.7375e-01 7.9420e-07 5.4857e-08 0.03 +1.8244e-01 7.9131e-07 5.8067e-08 0.03 +1.9156e-01 6.5358e-07 5.7717e-08 0.03 +2.0114e-01 6.2970e-07 5.7951e-08 0.03 +2.1119e-01 5.0130e-07 5.5262e-08 0.03 +2.2175e-01 5.0218e-07 5.6461e-08 0.03 +2.3284e-01 3.9299e-07 5.0685e-08 0.03 +2.4448e-01 3.5324e-07 5.0194e-08 0.03 +2.5671e-01 4.4475e-07 5.6485e-08 0.03 +2.6954e-01 5.1338e-07 6.2247e-08 0.03 +2.8302e-01 3.4918e-07 4.9745e-08 0.03 +2.9717e-01 4.3037e-07 5.5488e-08 0.03 +3.1203e-01 4.0099e-07 5.3591e-08 0.03 +3.2763e-01 3.8397e-07 5.1303e-08 0.03 +3.4401e-01 3.0995e-07 4.5965e-08 0.03 +3.6121e-01 3.9357e-07 5.0135e-08 0.03 +3.7927e-01 3.0997e-07 4.3680e-08 0.03 +3.9824e-01 2.9656e-07 4.2432e-08 0.03 +4.1815e-01 2.1909e-07 3.6117e-08 0.03 +4.3906e-01 2.3153e-07 3.6307e-08 0.03 +4.6101e-01 3.3428e-07 4.3874e-08 0.03 +4.8406e-01 2.3441e-07 3.7488e-08 0.03 +5.0826e-01 1.5496e-07 3.0585e-08 0.03 +5.3368e-01 2.4708e-07 3.9376e-08 0.03 +5.6036e-01 2.2157e-07 3.8258e-08 0.03 +5.8838e-01 2.2798e-07 4.6976e-08 0.03 +6.1169e-01 6.0272e-07 2.3239e-07 0.03 + + diff --git a/tests/test_data/moto.dat b/tests/test_data/moto.dat new file mode 100644 index 00000000..bacdb1ea --- /dev/null +++ b/tests/test_data/moto.dat @@ -0,0 +1,400 @@ +2.000000000000000042e-02 9.999599999999999600e-01 9.999800000000000041e-05 +2.143300000000000066e-02 1.000199999999999978e+00 1.000099999999999996e-04 +2.286699999999999844e-02 9.998500000000000165e-01 9.999200000000000080e-05 +2.429999999999999868e-02 9.999400000000000510e-01 9.999699999999999821e-05 +2.573299999999999893e-02 1.000099999999999989e+00 1.000000000000000048e-04 +2.716599999999999918e-02 9.998799999999999910e-01 9.999400000000000519e-05 +2.860000000000000042e-02 9.999900000000000455e-01 9.999900000000000260e-05 +3.003300000000000067e-02 9.999299999999999855e-01 9.999599999999999602e-05 +3.146600000000000091e-02 9.998899999999999455e-01 9.999400000000000519e-05 +3.289999999999999869e-02 3.114100000000000201e-01 5.580400000000000307e-05 +3.433300000000000241e-02 1.969499999999999862e-01 4.437900000000000319e-05 +3.576599999999999918e-02 1.030900000000000011e-01 3.210700000000000278e-05 +3.719999999999999696e-02 3.366899999999999754e-02 1.834899999999999999e-05 +3.863300000000000067e-02 5.127699999999999793e-03 7.160800000000000117e-06 +4.006599999999999745e-02 8.905400000000000815e-03 9.436899999999999382e-06 +4.149900000000000116e-02 2.294799999999999965e-02 1.514900000000000014e-05 +4.293299999999999894e-02 3.121600000000000069e-02 1.766800000000000092e-05 +4.436600000000000266e-02 2.888500000000000095e-02 1.699600000000000126e-05 +4.579899999999999943e-02 1.918999999999999873e-02 1.385299999999999933e-05 +4.723299999999999721e-02 8.333600000000000035e-03 9.128899999999999959e-06 +4.866600000000000092e-02 1.518000000000000035e-03 3.896200000000000067e-06 +5.009899999999999770e-02 4.664700000000000248e-04 2.159800000000000057e-06 +5.153200000000000142e-02 3.377900000000000087e-03 5.811999999999999580e-06 +5.296599999999999919e-02 7.010100000000000012e-03 8.372600000000000102e-06 +5.439900000000000291e-02 8.816299999999999137e-03 9.389500000000000480e-06 +5.583199999999999968e-02 7.962399999999999686e-03 8.923199999999999540e-06 +5.726599999999999746e-02 5.249099999999999600e-03 7.245100000000000310e-06 +5.869900000000000118e-02 2.273400000000000074e-03 4.767999999999999920e-06 +6.013199999999999795e-02 3.864399999999999931e-04 1.965799999999999881e-06 +6.156600000000000267e-02 1.337800000000000100e-04 1.156600000000000073e-06 +6.299899999999999944e-02 1.111199999999999905e-03 3.333400000000000137e-06 +6.443200000000000316e-02 2.436600000000000137e-03 4.936200000000000274e-06 +6.586500000000000687e-02 3.236399999999999954e-03 5.688899999999999861e-06 +6.729899999999999771e-02 3.133500000000000001e-03 5.597699999999999786e-06 +6.873200000000000143e-02 2.268200000000000164e-03 4.762499999999999718e-06 +7.016500000000000514e-02 1.132900000000000053e-03 3.365800000000000030e-06 +7.159899999999999598e-02 2.832499999999999732e-04 1.683000000000000022e-06 +7.303199999999999970e-02 1.961999999999999850e-05 4.429400000000000210e-07 +7.446500000000000341e-02 3.102399999999999841e-04 1.761399999999999983e-06 +7.589899999999999425e-02 8.720800000000000123e-04 2.953100000000000152e-06 +7.733199999999999796e-02 1.345499999999999908e-03 3.668100000000000083e-06 +7.876500000000000168e-02 1.461800000000000078e-03 3.823300000000000308e-06 +8.019800000000000539e-02 1.217100000000000039e-03 3.488700000000000157e-06 +8.163199999999999623e-02 7.391700000000000397e-04 2.718800000000000126e-06 +8.306499999999999995e-02 2.771000000000000134e-04 1.664599999999999910e-06 +8.449800000000000366e-02 2.859499999999999981e-05 5.347000000000000432e-07 +8.593199999999999450e-02 5.878500000000000045e-05 7.666799999999999804e-07 +8.736499999999999821e-02 2.926000000000000107e-04 1.710599999999999978e-06 +8.879800000000000193e-02 5.642299999999999833e-04 2.375400000000000161e-06 +9.023100000000000565e-02 7.333899999999999968e-04 2.708099999999999957e-06 +9.166499999999999648e-02 7.032800000000000292e-04 2.651899999999999970e-06 +9.309800000000000020e-02 5.188299999999999640e-04 2.277800000000000028e-06 +9.453100000000000391e-02 2.686100000000000185e-04 1.638900000000000097e-06 +9.596499999999999475e-02 7.123199999999999834e-05 8.439799999999999645e-07 +9.739799999999999847e-02 4.900099999999999892e-06 2.213599999999999916e-07 +9.883100000000000218e-02 7.526500000000000529e-05 8.675800000000000435e-07 +1.002600000000000019e-01 2.236399999999999933e-04 1.495499999999999912e-06 +1.016999999999999987e-01 3.596000000000000130e-04 1.896299999999999954e-06 +1.031299999999999994e-01 4.167500000000000197e-04 2.041400000000000055e-06 +1.045600000000000002e-01 3.655099999999999886e-04 1.911800000000000059e-06 +1.059999999999999970e-01 2.410900000000000109e-04 1.552699999999999974e-06 +1.074299999999999977e-01 1.041799999999999953e-04 1.020700000000000028e-06 +1.088599999999999984e-01 1.688000000000000101e-05 4.108500000000000030e-07 +1.102999999999999953e-01 9.166900000000000273e-06 3.028200000000000077e-07 +1.117299999999999960e-01 7.323700000000000370e-05 8.558000000000000267e-07 +1.131599999999999967e-01 1.670800000000000063e-04 1.292599999999999915e-06 +1.145999999999999935e-01 2.342599999999999967e-04 1.530600000000000008e-06 +1.160299999999999943e-01 2.498700000000000183e-04 1.580699999999999960e-06 +1.174599999999999950e-01 2.000700000000000004e-04 1.414499999999999967e-06 +1.189000000000000057e-01 1.178000000000000038e-04 1.085400000000000018e-06 +1.203300000000000064e-01 4.043399999999999946e-05 6.358500000000000192e-07 +1.217599999999999932e-01 2.313200000000000146e-06 1.519899999999999998e-07 +1.232000000000000040e-01 1.488200000000000083e-05 3.857500000000000230e-07 +1.246300000000000047e-01 6.628099999999999780e-05 8.141300000000000513e-07 +1.260600000000000054e-01 1.229900000000000134e-04 1.109000000000000097e-06 +1.275000000000000022e-01 1.606099999999999954e-04 1.267299999999999920e-06 +1.289299999999999891e-01 1.550500000000000012e-04 1.245199999999999953e-06 +1.303600000000000037e-01 1.143000000000000000e-04 1.069100000000000064e-06 +1.318000000000000005e-01 5.900299999999999734e-05 7.681099999999999608e-07 +1.332299999999999873e-01 1.461000000000000073e-05 3.822300000000000021e-07 +1.346600000000000019e-01 5.125699999999999900e-07 7.141399999999999348e-08 +1.360999999999999988e-01 1.844700000000000143e-05 4.295300000000000088e-07 +1.375300000000000133e-01 5.764800000000000100e-05 7.592799999999999539e-07 +1.389600000000000002e-01 9.192999999999999566e-05 9.588000000000000358e-07 +1.403999999999999970e-01 1.091400000000000020e-04 1.044699999999999925e-06 +1.418300000000000116e-01 9.775500000000000172e-05 9.887399999999999982e-07 +1.432599999999999985e-01 6.527600000000000318e-05 8.079599999999999901e-07 +1.446999999999999953e-01 2.882299999999999831e-05 5.368400000000000346e-07 +1.461300000000000099e-01 4.040099999999999655e-06 2.010000000000000131e-07 +1.475599999999999967e-01 2.138600000000000158e-06 1.462899999999999951e-07 +1.489999999999999936e-01 2.075500000000000034e-05 4.556300000000000109e-07 +1.504300000000000082e-01 4.759300000000000325e-05 6.898600000000000112e-07 +1.518599999999999950e-01 6.952499999999999587e-05 8.338499999999999658e-07 +1.532999999999999918e-01 7.418100000000000009e-05 8.612799999999999937e-07 +1.547300000000000064e-01 6.195100000000000368e-05 7.870800000000000307e-07 +1.561599999999999933e-01 3.649500000000000210e-05 6.041499999999999670e-07 +1.575999999999999901e-01 1.217000000000000037e-05 3.488600000000000150e-07 +1.590300000000000047e-01 5.659999999999999596e-07 7.549800000000000543e-08 +1.604599999999999915e-01 5.112000000000000353e-06 2.260499999999999893e-07 +1.618999999999999884e-01 2.135600000000000017e-05 4.621700000000000152e-07 +1.633300000000000030e-01 4.103899999999999790e-05 6.406199999999999753e-07 +1.647599999999999898e-01 5.290800000000000234e-05 7.273899999999999509e-07 +1.661999999999999866e-01 4.904200000000000242e-05 7.002900000000000325e-07 +1.676300000000000012e-01 3.763099999999999936e-05 6.134300000000000077e-07 +1.690599999999999881e-01 1.891899999999999962e-05 4.349699999999999834e-07 +1.705000000000000127e-01 4.593799999999999961e-06 2.142399999999999914e-07 +1.719299999999999995e-01 2.185900000000000006e-07 4.690400000000000098e-08 +1.733599999999999863e-01 6.528100000000000229e-06 2.555400000000000237e-07 +1.748000000000000109e-01 1.911799999999999890e-05 4.372599999999999860e-07 +1.762299999999999978e-01 3.301699999999999915e-05 5.746299999999999515e-07 +1.776600000000000124e-01 3.653399999999999953e-05 6.043999999999999858e-07 +1.791000000000000092e-01 3.191599999999999732e-05 5.649799999999999676e-07 +1.805299999999999960e-01 2.190000000000000039e-05 4.679699999999999745e-07 +1.819600000000000106e-01 9.374399999999999557e-06 3.061000000000000212e-07 +1.834000000000000075e-01 1.398600000000000043e-06 1.183200000000000033e-07 +1.848299999999999943e-01 9.713900000000000711e-07 9.848900000000000266e-08 +1.862600000000000089e-01 7.569100000000000087e-06 2.751400000000000140e-07 +1.877000000000000057e-01 1.738800000000000022e-05 4.170099999999999999e-07 +1.891299999999999926e-01 2.432699999999999934e-05 4.932499999999999996e-07 +1.905600000000000072e-01 2.685400000000000073e-05 5.181699999999999872e-07 +1.920000000000000040e-01 2.062299999999999889e-05 4.540900000000000116e-07 +1.934299999999999908e-01 1.225100000000000010e-05 3.499999999999999842e-07 +1.948600000000000054e-01 4.253799999999999828e-06 2.061599999999999879e-07 +1.963000000000000023e-01 2.845600000000000017e-07 5.291500000000000101e-08 +1.977299999999999891e-01 1.850300000000000098e-06 1.360100000000000115e-07 +1.991600000000000037e-01 7.572300000000000328e-06 2.751400000000000140e-07 +2.006000000000000005e-01 1.419299999999999947e-05 3.766999999999999784e-07 +2.020299999999999874e-01 1.730800000000000098e-05 4.160500000000000230e-07 +2.034600000000000020e-01 1.686900000000000061e-05 4.107300000000000257e-07 +2.048999999999999988e-01 1.341799999999999926e-05 3.663300000000000252e-07 +2.063300000000000134e-01 6.591800000000000144e-06 2.567099999999999740e-07 +2.077600000000000002e-01 1.779100000000000042e-06 1.334200000000000128e-07 +2.091899999999999871e-01 2.154999999999999908e-07 4.690400000000000098e-08 +2.106300000000000117e-01 2.475000000000000020e-06 1.571600000000000123e-07 +2.120599999999999985e-01 6.593400000000000264e-06 2.567099999999999740e-07 +2.134900000000000131e-01 1.094300000000000009e-05 3.307599999999999786e-07 +2.149300000000000099e-01 1.274899999999999940e-05 3.570700000000000071e-07 +2.163599999999999968e-01 1.167999999999999998e-05 3.417600000000000110e-07 +2.177900000000000114e-01 7.430800000000000073e-06 2.725800000000000228e-07 +2.192300000000000082e-01 3.389800000000000139e-06 1.841200000000000102e-07 +2.206599999999999950e-01 6.721299999999999709e-07 8.185399999999999961e-08 +2.220900000000000096e-01 3.908300000000000129e-07 6.244999999999999342e-08 +2.235300000000000065e-01 2.378500000000000182e-06 1.542699999999999911e-07 +2.249599999999999933e-01 5.754199999999999897e-06 2.397900000000000051e-07 +2.263900000000000079e-01 8.293100000000000271e-06 2.879200000000000000e-07 +2.278300000000000047e-01 8.377099999999999805e-06 2.894800000000000219e-07 +2.292599999999999916e-01 7.302399999999999744e-06 2.701900000000000126e-07 +2.306900000000000062e-01 4.315199999999999783e-06 2.078499999999999984e-07 +2.321300000000000030e-01 1.769699999999999971e-06 1.330400000000000055e-07 +2.335599999999999898e-01 2.779000000000000201e-07 5.291500000000000101e-08 +2.349900000000000044e-01 5.284499999999999972e-07 7.280100000000000451e-08 +2.364300000000000013e-01 2.592399999999999947e-06 1.609299999999999991e-07 +2.378599999999999881e-01 4.344199999999999844e-06 2.083299999999999868e-07 +2.392900000000000027e-01 6.215399999999999818e-06 2.493999999999999965e-07 +2.407299999999999995e-01 6.025100000000000132e-06 2.455599999999999833e-07 +2.421599999999999864e-01 4.653500000000000423e-06 2.156399999999999907e-07 +2.435900000000000010e-01 2.756399999999999986e-06 1.661299999999999927e-07 +2.450299999999999978e-01 9.029900000000000145e-07 9.486799999999999955e-08 +2.464600000000000124e-01 2.107899999999999969e-07 4.582600000000000285e-08 +2.478899999999999992e-01 8.002999999999999863e-07 8.944300000000000226e-08 +2.493299999999999961e-01 2.008800000000000147e-06 1.417700000000000049e-07 +2.507599999999999829e-01 3.498199999999999812e-06 1.870800000000000050e-07 +2.521900000000000253e-01 4.081499999999999801e-06 2.019899999999999975e-07 +2.536300000000000221e-01 3.672999999999999816e-06 1.915699999999999876e-07 +2.550600000000000089e-01 3.029000000000000137e-06 1.740699999999999963e-07 +2.564899999999999958e-01 1.488600000000000029e-06 1.220700000000000071e-07 +2.579299999999999926e-01 5.013900000000000183e-07 7.071100000000000366e-08 +2.593599999999999794e-01 2.381100000000000060e-07 4.898999999999999730e-08 +2.607900000000000218e-01 8.394400000000000046e-07 9.165200000000000569e-08 +2.622300000000000186e-01 1.744599999999999992e-06 1.319099999999999947e-07 +2.636600000000000055e-01 2.846500000000000190e-06 1.688199999999999989e-07 +2.650899999999999923e-01 3.200399999999999885e-06 1.788900000000000090e-07 +2.665299999999999891e-01 2.711499999999999789e-06 1.646200000000000010e-07 +2.679599999999999760e-01 2.075699999999999879e-06 1.442200000000000037e-07 +2.693900000000000183e-01 9.190299999999999914e-07 9.591699999999999789e-08 +2.708300000000000152e-01 3.300500000000000206e-07 5.744599999999999705e-08 +2.722600000000000020e-01 2.427800000000000074e-07 4.898999999999999730e-08 +2.736899999999999888e-01 7.507300000000000527e-07 8.660299999999999800e-08 +2.751299999999999857e-01 1.289799999999999916e-06 1.135800000000000019e-07 +2.765599999999999725e-01 2.175799999999999988e-06 1.476500000000000019e-07 +2.779900000000000149e-01 2.173500000000000027e-06 1.473099999999999870e-07 +2.794300000000000117e-01 1.704299999999999928e-06 1.303800000000000068e-07 +2.808599999999999985e-01 1.293399999999999975e-06 1.135800000000000019e-07 +2.822899999999999854e-01 6.768399999999999648e-07 8.246200000000000082e-08 +2.837299999999999822e-01 2.092100000000000053e-07 4.582600000000000285e-08 +2.851600000000000246e-01 2.089899999999999940e-07 4.582600000000000285e-08 +2.865900000000000114e-01 7.006000000000000134e-07 8.366600000000000287e-08 +2.880300000000000082e-01 1.200699999999999998e-06 1.095400000000000002e-07 +2.894599999999999951e-01 1.598700000000000042e-06 1.264899999999999898e-07 +2.908899999999999819e-01 1.713499999999999984e-06 1.307699999999999990e-07 +2.923299999999999788e-01 1.479199999999999958e-06 1.216599999999999922e-07 +2.937600000000000211e-01 8.770699999999999518e-07 9.380800000000000197e-08 +2.951900000000000079e-01 5.017900000000000483e-07 7.071100000000000366e-08 +2.966300000000000048e-01 1.249400000000000057e-07 3.464099999999999897e-08 +2.980599999999999916e-01 3.192899999999999957e-07 5.656900000000000183e-08 +2.994899999999999785e-01 5.400099999999999763e-07 7.348499999999999925e-08 +3.009299999999999753e-01 9.167800000000000341e-07 9.591699999999999789e-08 +3.023600000000000176e-01 1.091600000000000060e-06 1.043999999999999952e-07 +3.037900000000000045e-01 1.114899999999999905e-06 1.053599999999999985e-07 +3.052300000000000013e-01 9.849099999999999434e-07 9.899499999999999409e-08 +3.066599999999999882e-01 5.490900000000000020e-07 7.416199999999999929e-08 +3.080899999999999750e-01 3.416999999999999959e-07 5.830999999999999737e-08 +3.095300000000000273e-01 1.432499999999999890e-07 3.741699999999999683e-08 +3.109600000000000142e-01 2.503500000000000150e-07 4.999999999999999774e-08 +3.123900000000000010e-01 4.171299999999999771e-07 6.480700000000000585e-08 +3.138299999999999979e-01 9.677600000000000313e-07 9.848900000000000266e-08 +3.152599999999999847e-01 1.076900000000000015e-06 1.039199999999999935e-07 +3.166900000000000270e-01 1.102100000000000002e-06 1.048799999999999968e-07 +3.181300000000000239e-01 7.944699999999999930e-07 8.888200000000000140e-08 +3.195600000000000107e-01 6.477999999999999641e-07 8.062299999999999342e-08 +3.209899999999999975e-01 3.333600000000000152e-07 5.744599999999999705e-08 +3.224299999999999944e-01 1.998799999999999872e-07 4.472100000000000056e-08 +3.238599999999999812e-01 1.082500000000000065e-07 3.316600000000000065e-08 +3.252900000000000236e-01 4.829499999999999670e-07 6.928199999999999795e-08 +3.267300000000000204e-01 4.738000000000000207e-07 6.855699999999999642e-08 +3.281600000000000072e-01 7.670899999999999689e-07 8.775000000000000159e-08 +3.295899999999999941e-01 8.786399999999999851e-07 9.380800000000000197e-08 +3.310299999999999909e-01 5.818999999999999894e-07 7.615799999999999943e-08 +3.324599999999999778e-01 3.664899999999999948e-07 6.082799999999999385e-08 +3.338900000000000201e-01 1.812200000000000041e-07 4.242599999999999887e-08 +3.353200000000000069e-01 2.487500000000000007e-07 4.999999999999999774e-08 +3.367600000000000038e-01 1.971099999999999962e-07 4.472100000000000056e-08 +3.381899999999999906e-01 4.357900000000000132e-07 6.633200000000000131e-08 +3.396199999999999775e-01 4.189199999999999951e-07 6.480700000000000585e-08 +3.410599999999999743e-01 6.466600000000000479e-07 8.062299999999999342e-08 +3.424900000000000166e-01 6.991799999999999914e-07 8.366600000000000287e-08 +3.439200000000000035e-01 5.755199999999999548e-07 7.615799999999999943e-08 +3.453600000000000003e-01 3.603500000000000206e-07 5.999999999999999464e-08 +3.467899999999999872e-01 1.908699999999999879e-07 4.358900000000000075e-08 +3.482199999999999740e-01 1.215699999999999961e-07 3.464099999999999897e-08 +3.496600000000000263e-01 2.594900000000000029e-07 5.099000000000000197e-08 +3.510900000000000132e-01 4.234200000000000156e-07 6.480700000000000585e-08 +3.525200000000000000e-01 5.051399999999999824e-07 7.141399999999999348e-08 +3.539599999999999969e-01 5.445300000000000194e-07 7.348499999999999925e-08 +3.553899999999999837e-01 5.015700000000000106e-07 7.071100000000000366e-08 +3.568200000000000260e-01 3.772199999999999857e-07 6.164400000000000592e-08 +3.582600000000000229e-01 2.957999999999999885e-07 5.477200000000000235e-08 +3.596900000000000097e-01 2.358000000000000071e-07 4.898999999999999730e-08 +3.611199999999999966e-01 2.356400000000000110e-07 4.898999999999999730e-08 +3.625599999999999934e-01 3.554699999999999928e-07 5.999999999999999464e-08 +3.639899999999999802e-01 3.051100000000000103e-07 5.567799999999999736e-08 +3.654200000000000226e-01 5.067300000000000383e-07 7.141399999999999348e-08 +3.668600000000000194e-01 4.637399999999999955e-07 6.782299999999999792e-08 +3.682900000000000063e-01 4.123100000000000174e-07 6.403099999999999943e-08 +3.697199999999999931e-01 3.372199999999999981e-07 5.830999999999999737e-08 +3.711599999999999899e-01 1.999900000000000061e-07 4.472100000000000056e-08 +3.725899999999999768e-01 1.626799999999999982e-07 4.000000000000000084e-08 +3.740200000000000191e-01 2.533499999999999757e-07 4.999999999999999774e-08 +3.754600000000000160e-01 2.250499999999999936e-07 4.795799999999999838e-08 +3.768900000000000028e-01 2.792699999999999854e-07 5.291500000000000101e-08 +3.783199999999999896e-01 5.591900000000000197e-07 7.483300000000000576e-08 +3.797599999999999865e-01 2.937700000000000160e-07 5.385199999999999808e-08 +3.811899999999999733e-01 2.764299999999999944e-07 5.291500000000000101e-08 +3.826200000000000156e-01 1.937699999999999941e-07 4.358900000000000075e-08 +3.840600000000000125e-01 1.970000000000000038e-07 4.472100000000000056e-08 +3.854899999999999993e-01 1.628899999999999981e-07 4.000000000000000084e-08 +3.869199999999999862e-01 2.141100000000000028e-07 4.582600000000000285e-08 +3.883599999999999830e-01 2.244199999999999939e-07 4.690400000000000098e-08 +3.897900000000000253e-01 2.390900000000000055e-07 4.898999999999999730e-08 +3.912200000000000122e-01 3.728600000000000181e-07 6.082799999999999385e-08 +3.926600000000000090e-01 2.364599999999999879e-07 4.898999999999999730e-08 +3.940899999999999959e-01 2.442599999999999916e-07 4.898999999999999730e-08 +3.955199999999999827e-01 1.591200000000000113e-07 4.000000000000000084e-08 +3.969599999999999795e-01 1.592899999999999924e-07 4.000000000000000084e-08 +3.983900000000000219e-01 1.133700000000000020e-07 3.316600000000000065e-08 +3.998200000000000087e-01 1.962300000000000042e-07 4.472100000000000056e-08 +4.012600000000000056e-01 1.410599999999999939e-07 3.741699999999999683e-08 +4.026899999999999924e-01 2.510299999999999920e-07 4.999999999999999774e-08 +4.041199999999999792e-01 2.820400000000000029e-07 5.291500000000000101e-08 +4.055599999999999761e-01 3.117400000000000108e-07 5.567799999999999736e-08 +4.069900000000000184e-01 1.021300000000000020e-07 3.162299999999999802e-08 +4.084200000000000053e-01 1.329700000000000055e-07 3.605600000000000205e-08 +4.098600000000000021e-01 1.103000000000000017e-07 3.316600000000000065e-08 +4.112899999999999889e-01 1.326200000000000057e-07 3.605600000000000205e-08 +4.127199999999999758e-01 1.460700000000000103e-07 3.872999999999999674e-08 +4.141599999999999726e-01 1.917399999999999951e-07 4.358900000000000075e-08 +4.155900000000000150e-01 2.328800000000000048e-07 4.795799999999999838e-08 +4.170200000000000018e-01 2.353300000000000036e-07 4.898999999999999730e-08 +4.184599999999999986e-01 2.429300000000000187e-07 4.898999999999999730e-08 +4.198899999999999855e-01 1.760600000000000029e-07 4.242599999999999887e-08 +4.213199999999999723e-01 1.400799999999999944e-07 3.741699999999999683e-08 +4.227600000000000247e-01 2.440299999999999954e-07 4.898999999999999730e-08 +4.241900000000000115e-01 1.158800000000000027e-07 3.464099999999999897e-08 +4.256199999999999983e-01 1.759999999999999878e-07 4.242599999999999887e-08 +4.270599999999999952e-01 7.706599999999999671e-08 2.828400000000000035e-08 +4.284899999999999820e-01 2.745499999999999802e-07 5.196199999999999903e-08 +4.299200000000000244e-01 1.284000000000000116e-07 3.605600000000000205e-08 +4.313600000000000212e-01 1.833299999999999879e-07 4.242599999999999887e-08 +4.327900000000000080e-01 1.847599999999999948e-07 4.242599999999999887e-08 +4.342199999999999949e-01 1.731500000000000119e-07 4.123100000000000041e-08 +4.356599999999999917e-01 9.118400000000000441e-08 2.999999999999999732e-08 +4.370899999999999785e-01 1.957499999999999893e-07 4.472100000000000056e-08 +4.385200000000000209e-01 1.920399999999999911e-07 4.358900000000000075e-08 +4.399600000000000177e-01 1.945599999999999899e-07 4.358900000000000075e-08 +4.413900000000000046e-01 1.568700000000000011e-07 4.000000000000000084e-08 +4.428199999999999914e-01 1.953500000000000122e-07 4.472100000000000056e-08 +4.442599999999999882e-01 1.654200000000000082e-07 4.123100000000000041e-08 +4.456899999999999751e-01 1.368599999999999960e-07 3.741699999999999683e-08 +4.471200000000000174e-01 2.139000000000000029e-07 4.582600000000000285e-08 +4.485600000000000143e-01 1.256499999999999902e-07 3.605600000000000205e-08 +4.499900000000000011e-01 8.671100000000000135e-08 2.999999999999999732e-08 +4.514199999999999879e-01 2.137699999999999879e-07 4.582600000000000285e-08 +4.528599999999999848e-01 1.410599999999999939e-07 3.741699999999999683e-08 +4.542900000000000271e-01 1.612900000000000103e-07 4.000000000000000084e-08 +4.557200000000000140e-01 1.604000000000000069e-07 4.000000000000000084e-08 +4.571600000000000108e-01 1.167399999999999985e-07 3.464099999999999897e-08 +4.585899999999999976e-01 1.624699999999999983e-07 4.000000000000000084e-08 +4.600199999999999845e-01 1.695099999999999873e-07 4.123100000000000041e-08 +4.614500000000000268e-01 1.064199999999999961e-07 3.316600000000000065e-08 +4.628900000000000237e-01 9.822699999999999674e-08 3.162299999999999802e-08 +4.643200000000000105e-01 1.886799999999999928e-07 4.358900000000000075e-08 +4.657499999999999973e-01 1.214299999999999961e-07 3.464099999999999897e-08 +4.671899999999999942e-01 1.188599999999999936e-07 3.464099999999999897e-08 +4.686199999999999810e-01 1.647799999999999972e-07 4.000000000000000084e-08 +4.700500000000000234e-01 1.168099999999999984e-07 3.464099999999999897e-08 +4.714900000000000202e-01 1.719899999999999936e-07 4.123100000000000041e-08 +4.729200000000000070e-01 9.757199999999999517e-08 3.162299999999999802e-08 +4.743499999999999939e-01 1.612600000000000027e-07 4.000000000000000084e-08 +4.757899999999999907e-01 2.017200000000000090e-07 4.472100000000000056e-08 +4.772199999999999775e-01 1.734099999999999891e-07 4.123100000000000041e-08 +4.786500000000000199e-01 1.175899999999999962e-07 3.464099999999999897e-08 +4.800900000000000167e-01 1.819299999999999886e-07 4.242599999999999887e-08 +4.815200000000000036e-01 1.103700000000000016e-07 3.316600000000000065e-08 +4.829499999999999904e-01 1.772899999999999947e-07 4.242599999999999887e-08 +4.843899999999999872e-01 1.506200000000000080e-07 3.872999999999999674e-08 +4.858199999999999741e-01 1.333799999999999939e-07 3.605600000000000205e-08 +4.872500000000000164e-01 1.528600000000000069e-07 3.872999999999999674e-08 +4.886900000000000133e-01 1.639799999999999900e-07 4.000000000000000084e-08 +4.901200000000000001e-01 1.014599999999999966e-07 3.162299999999999802e-08 +4.915499999999999869e-01 2.166400000000000129e-07 4.690400000000000098e-08 +4.929899999999999838e-01 1.104300000000000035e-07 3.316600000000000065e-08 +4.944200000000000261e-01 1.644900000000000125e-07 4.000000000000000084e-08 +4.958500000000000130e-01 2.125700000000000036e-07 4.582600000000000285e-08 +4.972900000000000098e-01 1.332899999999999978e-07 3.605600000000000205e-08 +4.987199999999999966e-01 1.907200000000000031e-07 4.358900000000000075e-08 +5.001499999999999835e-01 1.103899999999999979e-07 3.316600000000000065e-08 +5.015899999999999803e-01 1.628099999999999868e-07 4.000000000000000084e-08 +5.030200000000000227e-01 1.564699999999999975e-07 4.000000000000000084e-08 +5.044499999999999540e-01 2.116999999999999965e-07 4.582600000000000285e-08 +5.058899999999999508e-01 1.125200000000000044e-07 3.316600000000000065e-08 +5.073199999999999932e-01 1.239199999999999873e-07 3.464099999999999897e-08 +5.087500000000000355e-01 1.728600000000000007e-07 4.123100000000000041e-08 +5.101900000000000324e-01 1.738400000000000002e-07 4.123100000000000041e-08 +5.116199999999999637e-01 1.037300000000000031e-07 3.162299999999999802e-08 +5.130500000000000060e-01 1.545200000000000099e-07 3.872999999999999674e-08 +5.144900000000000029e-01 2.247199999999999900e-07 4.690400000000000098e-08 +5.159200000000000452e-01 1.780599999999999943e-07 4.242599999999999887e-08 +5.173499999999999766e-01 8.477199999999999967e-08 2.828400000000000035e-08 +5.187899999999999734e-01 1.513000000000000115e-07 3.872999999999999674e-08 +5.202200000000000157e-01 1.958499999999999968e-07 4.472100000000000056e-08 +5.216499999999999471e-01 9.982499999999999556e-08 3.162299999999999802e-08 +5.230900000000000549e-01 1.309099999999999990e-07 3.605600000000000205e-08 +5.245199999999999863e-01 1.317600000000000099e-07 3.605600000000000205e-08 +5.259500000000000286e-01 1.400799999999999944e-07 3.741699999999999683e-08 +5.273900000000000254e-01 1.935900000000000017e-07 4.358900000000000075e-08 +5.288199999999999568e-01 1.446999999999999921e-07 3.741699999999999683e-08 +5.302499999999999991e-01 1.913599999999999877e-07 4.358900000000000075e-08 +5.316899999999999959e-01 1.878800000000000121e-07 4.358900000000000075e-08 +5.331200000000000383e-01 8.692899999999999708e-08 2.999999999999999732e-08 +5.345499999999999696e-01 1.305200000000000067e-07 3.605600000000000205e-08 +5.359899999999999665e-01 1.802600000000000008e-07 4.242599999999999887e-08 +5.374200000000000088e-01 1.069199999999999939e-07 3.316600000000000065e-08 +5.388500000000000512e-01 1.900799999999999921e-07 4.358900000000000075e-08 +5.402900000000000480e-01 1.831199999999999880e-07 4.242599999999999887e-08 +5.417199999999999793e-01 1.681099999999999880e-07 4.123100000000000041e-08 +5.431500000000000217e-01 1.333900000000000053e-07 3.605600000000000205e-08 +5.445900000000000185e-01 1.158100000000000027e-07 3.464099999999999897e-08 +5.460199999999999498e-01 1.890099999999999964e-07 4.358900000000000075e-08 +5.474499999999999922e-01 5.076999999999999735e-08 2.236100000000000085e-08 +5.488899999999999890e-01 1.515800000000000113e-07 3.872999999999999674e-08 +5.503200000000000314e-01 1.764199999999999876e-07 4.242599999999999887e-08 +5.517499999999999627e-01 1.254399999999999903e-07 3.605600000000000205e-08 +5.531899999999999595e-01 7.189599999999999740e-08 2.645800000000000107e-08 +5.546200000000000019e-01 1.533399999999999953e-07 3.872999999999999674e-08 +5.560500000000000442e-01 2.005300000000000096e-07 4.472100000000000056e-08 +5.574900000000000411e-01 1.467200000000000062e-07 3.872999999999999674e-08 +5.589199999999999724e-01 1.129899999999999947e-07 3.316600000000000065e-08 +5.603500000000000147e-01 1.063900000000000017e-07 3.316600000000000065e-08 +5.617900000000000116e-01 7.993799999999999755e-08 2.828400000000000035e-08 +5.632200000000000539e-01 1.288999999999999962e-07 3.605600000000000205e-08 +5.646499999999999853e-01 1.651499999999999932e-07 4.123100000000000041e-08 +5.660899999999999821e-01 1.030900000000000053e-07 3.162299999999999802e-08 +5.675200000000000244e-01 1.426699999999999931e-07 3.741699999999999683e-08 +5.689499999999999558e-01 1.464099999999999988e-07 3.872999999999999674e-08 +5.703899999999999526e-01 1.396900000000000021e-07 3.741699999999999683e-08 +5.718199999999999950e-01 1.245999999999999908e-07 3.464099999999999897e-08 +5.732500000000000373e-01 1.078500000000000029e-07 3.316600000000000065e-08 +5.746900000000000341e-01 1.481999999999999903e-07 3.872999999999999674e-08 +5.761199999999999655e-01 1.322200000000000021e-07 3.605600000000000205e-08 +5.775500000000000078e-01 1.317399999999999872e-07 3.605600000000000205e-08 +5.789900000000000047e-01 8.568300000000000035e-08 2.999999999999999732e-08 +5.804200000000000470e-01 4.987799999999999837e-08 2.236100000000000085e-08 +5.818499999999999783e-01 1.980500000000000033e-07 4.472100000000000056e-08 +5.832899999999999752e-01 1.649700000000000009e-07 4.000000000000000084e-08 +5.847200000000000175e-01 1.235900000000000102e-07 3.464099999999999897e-08 +5.861499999999999488e-01 1.132400000000000002e-07 3.316600000000000065e-08 +5.875799999999999912e-01 1.552400000000000057e-07 4.000000000000000084e-08 +5.890199999999999880e-01 1.425600000000000007e-07 3.741699999999999683e-08 +5.904500000000000304e-01 1.441899999999999961e-07 3.741699999999999683e-08 +5.918799999999999617e-01 2.349600000000000075e-07 4.795799999999999838e-08 diff --git a/tests/test_data/nonUniqueContrast.mat b/tests/test_data/nonUniqueContrast.mat new file mode 100644 index 00000000..41375134 Binary files /dev/null and b/tests/test_data/nonUniqueContrast.mat differ diff --git a/tests/test_data/orso_poly.dat b/tests/test_data/orso_poly.dat new file mode 100644 index 00000000..4187f29a --- /dev/null +++ b/tests/test_data/orso_poly.dat @@ -0,0 +1,408 @@ +8.060200000000000004e-03 7.095799999999999885e-01 8.506800000000000472e-02 +8.136600000000000776e-03 8.622800000000000464e-01 1.123699999999999977e-01 +8.263799999999999965e-03 9.086499999999999577e-01 7.900500000000000578e-02 +8.370700000000000016e-03 7.732900000000000329e-01 7.927299999999999625e-02 +8.450300000000000866e-03 1.058000000000000052e+00 1.259599999999999886e-01 +8.530799999999999841e-03 1.015700000000000047e+00 1.132999999999999979e-01 +8.612200000000000411e-03 7.347200000000000397e-01 6.115700000000000303e-02 +8.694399999999999698e-03 7.692200000000000149e-01 6.170599999999999696e-02 +8.777399999999999439e-03 1.115699999999999914e+00 1.127299999999999969e-01 +8.861400000000000179e-03 9.723000000000000531e-01 8.971600000000000408e-02 +8.946199999999999639e-03 7.512100000000000444e-01 5.493900000000000172e-02 +9.031799999999999551e-03 7.976499999999999702e-01 5.671199999999999852e-02 +9.118400000000000463e-03 9.221899999999999542e-01 6.858400000000000607e-02 +9.205899999999999500e-03 9.757599999999999607e-01 7.294000000000000483e-02 +9.294300000000000131e-03 8.195000000000000062e-01 5.216200000000000003e-02 +9.383600000000000621e-03 7.883200000000000207e-01 4.794699999999999657e-02 +9.473900000000000376e-03 7.946999999999999620e-01 4.602200000000000041e-02 +9.565099999999999991e-03 8.743999999999999551e-01 5.151599999999999929e-02 +9.657199999999999465e-03 8.396599999999999620e-01 4.742799999999999794e-02 +9.750299999999999939e-03 8.008699999999999708e-01 4.399600000000000039e-02 +9.844399999999999679e-03 1.117099999999999982e+00 7.373300000000000687e-02 +9.939399999999999277e-03 8.884100000000000330e-01 4.954100000000000170e-02 +1.003500000000000052e-02 7.791299999999999892e-01 3.898700000000000082e-02 +1.013200000000000038e-02 7.999699999999999589e-01 3.899699999999999694e-02 +1.022999999999999951e-02 8.431199999999999806e-01 4.159800000000000303e-02 +1.032899999999999964e-02 9.613300000000000178e-01 4.925399999999999917e-02 +1.048699999999999979e-02 8.805399999999999894e-01 2.990800000000000056e-02 +1.063300000000000009e-02 7.557399999999999674e-01 3.208500000000000241e-02 +1.073600000000000075e-02 9.712300000000000377e-01 4.534799999999999942e-02 +1.084000000000000068e-02 8.955499999999999572e-01 3.905399999999999844e-02 +1.094499999999999987e-02 8.625899999999999679e-01 3.580699999999999855e-02 +1.105199999999999932e-02 8.909899999999999487e-01 3.612599999999999839e-02 +1.115900000000000052e-02 9.003499999999999837e-01 3.679199999999999832e-02 +1.126800000000000024e-02 8.459299999999999597e-01 3.218800000000000133e-02 +1.137799999999999923e-02 9.431500000000000439e-01 3.655300000000000216e-02 +1.148799999999999995e-02 9.956300000000000150e-01 3.901199999999999807e-02 +1.159999999999999920e-02 9.695899999999999519e-01 3.636199999999999849e-02 +1.171299999999999945e-02 9.051799999999999846e-01 3.204100000000000004e-02 +1.182799999999999997e-02 8.933799999999999519e-01 3.061200000000000032e-02 +1.194300000000000049e-02 9.195999999999999730e-01 3.146800000000000291e-02 +1.205999999999999954e-02 9.190000000000000391e-01 3.060999999999999832e-02 +1.217799999999999959e-02 7.810599999999999765e-01 2.355399999999999855e-02 +1.229700000000000064e-02 8.649099999999999566e-01 2.720300000000000148e-02 +1.241699999999999922e-02 8.435200000000000475e-01 2.550099999999999936e-02 +1.253800000000000053e-02 9.984199999999999742e-01 3.197200000000000042e-02 +1.266100000000000038e-02 8.812600000000000433e-01 2.602700000000000152e-02 +1.278499999999999949e-02 8.835699999999999665e-01 2.558600000000000110e-02 +1.291100000000000060e-02 9.376700000000000035e-01 2.746499999999999983e-02 +1.303699999999999998e-02 1.019200000000000106e+00 3.051099999999999993e-02 +1.316499999999999962e-02 8.455300000000000038e-01 2.262700000000000128e-02 +1.329400000000000026e-02 8.738000000000000211e-01 2.324700000000000030e-02 +1.342400000000000017e-02 8.659499999999999975e-01 2.249100000000000057e-02 +1.355600000000000034e-02 8.779799999999999827e-01 2.244900000000000020e-02 +1.368899999999999978e-02 9.475400000000000489e-01 2.489900000000000099e-02 +1.382399999999999948e-02 8.881499999999999950e-01 2.209600000000000106e-02 +1.395899999999999919e-02 8.913600000000000412e-01 2.181500000000000106e-02 +1.409700000000000016e-02 8.884600000000000275e-01 2.150900000000000034e-02 +1.423499999999999939e-02 9.137199999999999767e-01 2.225900000000000101e-02 +1.437500000000000062e-02 8.103599999999999692e-01 1.882899999999999852e-02 +1.451700000000000039e-02 7.385500000000000398e-01 1.688299999999999870e-02 +1.465999999999999942e-02 6.865099999999999536e-01 1.597399999999999862e-02 +1.480399999999999945e-02 5.822399999999999798e-01 1.350200000000000011e-02 +1.494999999999999975e-02 4.468599999999999794e-01 1.006300000000000076e-02 +1.509699999999999931e-02 3.924599999999999755e-01 9.155500000000000443e-03 +1.524599999999999914e-02 3.205200000000000271e-01 7.319599999999999891e-03 +1.539599999999999996e-02 2.810099999999999820e-01 6.399099999999999580e-03 +1.554799999999999932e-02 2.401000000000000079e-01 5.442400000000000015e-03 +1.570099999999999968e-02 2.208799999999999930e-01 5.024400000000000047e-03 +1.585599999999999857e-02 1.920300000000000062e-01 4.314400000000000353e-03 +1.601299999999999946e-02 1.798500000000000099e-01 4.051599999999999820e-03 +1.617100000000000135e-02 1.600699999999999901e-01 3.562000000000000062e-03 +1.633000000000000076e-02 1.531299999999999883e-01 3.467800000000000049e-03 +1.649199999999999972e-02 1.342200000000000060e-01 3.016000000000000018e-03 +1.665399999999999867e-02 1.283299999999999996e-01 2.888500000000000009e-03 +1.681900000000000062e-02 1.247899999999999981e-01 2.861799999999999847e-03 +1.698500000000000010e-02 1.091300000000000048e-01 2.483099999999999804e-03 +1.715300000000000158e-02 1.044299999999999951e-01 2.353899999999999916e-03 +1.732300000000000159e-02 9.468300000000000327e-02 2.091599999999999883e-03 +1.758799999999999947e-02 8.969100000000000683e-02 1.439399999999999968e-03 +1.784200000000000022e-02 8.091399999999999981e-02 1.872799999999999986e-03 +1.801799999999999929e-02 7.465399999999999814e-02 1.714199999999999925e-03 +1.819700000000000137e-02 7.036599999999999799e-02 1.634199999999999932e-03 +1.837700000000000097e-02 6.904399999999999427e-02 1.605300000000000043e-03 +1.855899999999999911e-02 6.270499999999999685e-02 1.461499999999999909e-03 +1.874299999999999924e-02 5.939099999999999935e-02 1.400100000000000042e-03 +1.892800000000000038e-02 5.754800000000000193e-02 1.361000000000000014e-03 +1.911600000000000105e-02 5.138299999999999812e-02 1.226700000000000056e-03 +1.930499999999999924e-02 4.922699999999999992e-02 1.178199999999999907e-03 +1.949700000000000044e-02 4.521700000000000025e-02 1.079600000000000004e-03 +1.968999999999999917e-02 4.245600000000000068e-02 1.022200000000000018e-03 +1.988499999999999990e-02 4.126099999999999907e-02 9.947800000000000132e-04 +2.008199999999999916e-02 3.523300000000000043e-02 8.777900000000000372e-04 +2.028200000000000142e-02 3.352700000000000125e-02 8.367500000000000372e-04 +2.048300000000000121e-02 3.326799999999999896e-02 8.339600000000000181e-04 +2.068599999999999953e-02 3.166399999999999770e-02 7.898900000000000149e-04 +2.089099999999999985e-02 2.915999999999999842e-02 7.496099999999999465e-04 +2.109799999999999870e-02 2.651999999999999844e-02 7.063800000000000504e-04 +2.130800000000000055e-02 2.518300000000000052e-02 6.713900000000000076e-04 +2.152000000000000093e-02 2.387600000000000139e-02 6.426900000000000147e-04 +2.173299999999999885e-02 2.289300000000000015e-02 6.330700000000000086e-04 +2.194899999999999976e-02 2.086500000000000160e-02 5.931299999999999810e-04 +2.216699999999999920e-02 2.087699999999999972e-02 5.920100000000000189e-04 +2.238700000000000065e-02 1.822299999999999962e-02 5.292100000000000103e-04 +2.261000000000000162e-02 1.773500000000000076e-02 5.251500000000000525e-04 +2.283400000000000013e-02 1.587099999999999969e-02 4.818800000000000145e-04 +2.306100000000000164e-02 1.432499999999999919e-02 4.516200000000000162e-04 +2.329000000000000167e-02 1.427800000000000076e-02 4.522500000000000153e-04 +2.352200000000000124e-02 1.266199999999999964e-02 4.198499999999999867e-04 +2.375499999999999834e-02 1.221299999999999990e-02 4.137899999999999803e-04 +2.399199999999999944e-02 1.046099999999999981e-02 3.745299999999999801e-04 +2.423000000000000154e-02 1.061299999999999917e-02 3.810500000000000193e-04 +2.447099999999999970e-02 9.879000000000000628e-03 3.641299999999999984e-04 +2.471500000000000086e-02 8.371999999999999234e-03 3.313899999999999832e-04 +2.495999999999999955e-02 7.670500000000000235e-03 3.077099999999999931e-04 +2.520899999999999877e-02 7.344899999999999693e-03 3.049799999999999972e-04 +2.545899999999999899e-02 6.798600000000000129e-03 2.898700000000000148e-04 +2.571299999999999975e-02 5.916300000000000205e-03 2.671800000000000000e-04 +2.596800000000000150e-02 5.344999999999999925e-03 2.515400000000000210e-04 +2.622700000000000031e-02 5.122699999999999997e-03 2.474099999999999910e-04 +2.648800000000000113e-02 4.750299999999999835e-03 2.379500000000000105e-04 +2.675200000000000147e-02 4.307199999999999744e-03 2.238499999999999930e-04 +2.701800000000000035e-02 4.018200000000000417e-03 2.200500000000000090e-04 +2.728699999999999876e-02 3.539200000000000158e-03 2.046499999999999871e-04 +2.755799999999999916e-02 3.818199999999999893e-03 2.079399999999999912e-04 +2.783300000000000010e-02 2.864799999999999812e-03 1.819199999999999930e-04 +2.810999999999999957e-02 2.795800000000000195e-03 1.766899999999999905e-04 +2.838999999999999857e-02 2.621500000000000132e-03 1.749999999999999982e-04 +2.867300000000000057e-02 2.484800000000000116e-03 1.694599999999999937e-04 +2.895800000000000110e-02 2.420100000000000116e-03 1.709199999999999966e-04 +2.924699999999999869e-02 2.359299999999999939e-03 1.700600000000000082e-04 +2.953799999999999829e-02 1.978600000000000064e-03 1.600200000000000027e-04 +2.983200000000000088e-02 1.947200000000000059e-03 1.582800000000000092e-04 +3.013000000000000053e-02 1.735900000000000073e-03 1.527300000000000098e-04 +3.042999999999999872e-02 1.894599999999999973e-03 1.602999999999999933e-04 +3.073299999999999990e-02 1.696699999999999988e-03 1.525700000000000114e-04 +3.103900000000000062e-02 1.793700000000000069e-03 1.592400000000000000e-04 +3.134900000000000186e-02 1.786899999999999903e-03 1.552000000000000048e-04 +3.166100000000000164e-02 1.871999999999999966e-03 1.584000000000000013e-04 +3.197699999999999848e-02 1.688199999999999944e-03 1.499799999999999972e-04 +3.229499999999999732e-02 1.732400000000000042e-03 1.543199999999999997e-04 +3.261700000000000016e-02 1.537600000000000078e-03 1.454000000000000106e-04 +3.294199999999999906e-02 1.541300000000000005e-03 1.497600000000000027e-04 +3.327100000000000196e-02 1.700300000000000075e-03 1.572099999999999941e-04 +3.360300000000000092e-02 2.142199999999999920e-03 1.728900000000000066e-04 +3.393800000000000289e-02 1.943999999999999981e-03 1.686900000000000129e-04 +3.422100000000000142e-02 1.913999999999999903e-03 1.077099999999999970e-04 +3.466500000000000137e-02 1.986400000000000145e-03 1.438300000000000104e-04 +3.502199999999999758e-02 1.849699999999999912e-03 1.279700000000000097e-04 +3.538499999999999979e-02 1.932600000000000030e-03 1.227099999999999957e-04 +3.571599999999999775e-02 2.188999999999999974e-03 1.496000000000000042e-04 +3.607699999999999796e-02 2.314300000000000038e-03 1.503400000000000005e-04 +3.646800000000000042e-02 1.831799999999999965e-03 1.041600000000000056e-04 +3.682599999999999763e-02 1.797100000000000043e-03 1.012900000000000009e-04 +3.716200000000000059e-02 2.278699999999999823e-03 1.417300000000000135e-04 +3.754199999999999898e-02 2.183399999999999837e-03 1.294599999999999972e-04 +3.794000000000000150e-02 1.799000000000000035e-03 9.624999999999999496e-05 +3.831299999999999983e-02 1.828100000000000037e-03 9.734599999999999937e-05 +3.868400000000000311e-02 1.949800000000000014e-03 1.082599999999999969e-04 +3.906899999999999956e-02 2.042099999999999818e-03 1.122399999999999960e-04 +3.947300000000000114e-02 1.659499999999999951e-03 8.395500000000000510e-05 +3.986300000000000260e-02 1.620300000000000082e-03 8.073400000000000324e-05 +4.026600000000000318e-02 1.588599999999999908e-03 7.617699999999999927e-05 +4.066100000000000270e-02 1.582499999999999922e-03 7.829099999999999970e-05 +4.107000000000000234e-02 1.429900000000000008e-03 7.034400000000000277e-05 +4.147800000000000098e-02 1.336100000000000005e-03 6.498799999999999510e-05 +4.187400000000000150e-02 1.721899999999999950e-03 9.200100000000000226e-05 +4.230500000000000232e-02 1.404899999999999942e-03 6.788199999999999822e-05 +4.273199999999999915e-02 1.146499999999999950e-03 5.315200000000000203e-05 +4.315499999999999892e-02 1.030099999999999939e-03 4.872799999999999831e-05 +4.358299999999999674e-02 1.018599999999999931e-03 4.851600000000000102e-05 +4.401499999999999857e-02 1.060200000000000075e-03 5.148900000000000118e-05 +4.445500000000000146e-02 9.115599999999999528e-04 4.517699999999999792e-05 +4.489800000000000041e-02 7.795400000000000072e-04 3.746800000000000109e-05 +4.534699999999999842e-02 5.957599999999999745e-04 2.867799999999999885e-05 +4.579500000000000237e-02 6.476399999999999995e-04 3.286700000000000228e-05 +4.625100000000000044e-02 5.268399999999999906e-04 2.666199999999999985e-05 +4.671199999999999658e-02 4.365500000000000131e-04 2.240899999999999839e-05 +4.717799999999999772e-02 3.696099999999999798e-04 1.929699999999999837e-05 +4.764700000000000185e-02 3.315600000000000036e-04 1.808599999999999929e-05 +4.812099999999999711e-02 2.545800000000000190e-04 1.440600000000000065e-05 +4.859900000000000331e-02 2.090799999999999972e-04 1.312400000000000005e-05 +4.908300000000000163e-02 1.929400000000000060e-04 1.261600000000000084e-05 +4.957099999999999701e-02 1.309200000000000001e-04 9.992200000000000656e-06 +5.006399999999999739e-02 1.098200000000000023e-04 9.080500000000000558e-06 +5.056200000000000278e-02 9.565500000000000489e-05 8.370099999999999703e-06 +5.106499999999999928e-02 7.925700000000000366e-05 7.699100000000000537e-06 +5.157300000000000079e-02 7.956000000000000398e-05 6.898600000000000324e-06 +5.208600000000000035e-02 7.224999999999999435e-05 6.102700000000000033e-06 +5.260399999999999798e-02 7.825099999999999330e-05 6.391400000000000335e-06 +5.312800000000000161e-02 8.637100000000000365e-05 6.561899999999999804e-06 +5.365700000000000330e-02 1.331600000000000058e-04 8.789800000000000106e-06 +5.419100000000000306e-02 1.436300000000000055e-04 8.178800000000000366e-06 +5.473000000000000087e-02 1.586799999999999918e-04 8.565300000000000816e-06 +5.527399999999999675e-02 1.900100000000000053e-04 9.755199999999999367e-06 +5.582499999999999962e-02 2.354199999999999923e-04 1.141699999999999928e-05 +5.637999999999999956e-02 2.339300000000000049e-04 1.034500000000000006e-05 +5.694199999999999956e-02 2.433900000000000126e-04 1.059599999999999986e-05 +5.750899999999999762e-02 2.708599999999999918e-04 1.125099999999999951e-05 +5.808100000000000068e-02 3.109699999999999856e-04 1.233600000000000014e-05 +5.865999999999999687e-02 3.483299999999999938e-04 1.357899999999999992e-05 +5.924399999999999805e-02 3.329599999999999834e-04 1.275599999999999950e-05 +5.983399999999999830e-02 3.546600000000000230e-04 1.322400000000000078e-05 +6.042999999999999761e-02 3.544700000000000129e-04 1.306599999999999992e-05 +6.103200000000000292e-02 3.855199999999999816e-04 1.408900000000000012e-05 +6.164000000000000035e-02 3.325099999999999996e-04 1.201800000000000081e-05 +6.225399999999999684e-02 3.330900000000000245e-04 1.197199999999999989e-05 +6.287399999999999933e-02 3.303100000000000003e-04 1.197199999999999989e-05 +6.350100000000000189e-02 3.224699999999999941e-04 1.162899999999999996e-05 +6.413399999999999657e-02 2.744600000000000251e-04 9.948800000000000360e-06 +6.477299999999999724e-02 2.792399999999999895e-04 1.025400000000000042e-05 +6.541800000000000392e-02 2.389400000000000128e-04 8.960899999999999196e-06 +6.607000000000000373e-02 2.330300000000000101e-04 8.726700000000000659e-06 +6.672899999999999665e-02 1.863400000000000082e-04 7.236100000000000057e-06 +6.739399999999999558e-02 1.649499999999999979e-04 6.619499999999999896e-06 +6.806600000000000150e-02 1.332399999999999915e-04 5.541599999999999594e-06 +6.874500000000000055e-02 1.153799999999999965e-04 4.971599999999999969e-06 +6.943000000000000560e-02 8.250300000000000613e-05 3.951200000000000388e-06 +7.012200000000000377e-02 6.719200000000000313e-05 3.570200000000000139e-06 +7.082099999999999507e-02 5.033199999999999854e-05 2.926200000000000037e-06 +7.152799999999999436e-02 3.336100000000000128e-05 2.509699999999999874e-06 +7.224099999999999966e-02 2.290499999999999839e-05 2.116400000000000184e-06 +7.293399999999999883e-02 1.879399999999999997e-05 1.860500000000000017e-06 +7.366799999999999737e-02 1.553400000000000069e-05 1.798199999999999995e-06 +7.440099999999999492e-02 1.824499999999999896e-05 1.951800000000000100e-06 +7.513999999999999846e-02 2.235600000000000076e-05 1.800999999999999994e-06 +7.587199999999999500e-02 2.773600000000000007e-05 1.890099999999999911e-06 +7.663999999999999979e-02 3.931000000000000141e-05 2.300899999999999858e-06 +7.739600000000000646e-02 4.596700000000000222e-05 2.332399999999999895e-06 +7.810599999999999488e-02 5.541299999999999953e-05 2.459299999999999900e-06 +7.886799999999999367e-02 6.726000000000000316e-05 2.729600000000000090e-06 +7.979500000000000481e-02 7.650600000000000239e-05 2.773100000000000182e-06 +8.072899999999999521e-02 7.794700000000000435e-05 2.857399999999999951e-06 +8.153299999999999437e-02 8.505400000000000254e-05 2.990400000000000202e-06 +8.233200000000000240e-02 9.685699999999999778e-05 3.222700000000000078e-06 +8.315999999999999781e-02 9.462399999999999392e-05 3.166199999999999857e-06 +8.402500000000000246e-02 8.585599999999999927e-05 2.824499999999999808e-06 +8.486499999999999599e-02 8.101399999999999379e-05 2.662499999999999919e-06 +8.573400000000000465e-02 7.655899999999999663e-05 2.549800000000000134e-06 +8.655500000000000693e-02 7.385400000000000135e-05 2.485799999999999985e-06 +8.743700000000000083e-02 6.249699999999999472e-05 2.190900000000000064e-06 +8.831600000000000561e-02 5.495400000000000274e-05 2.001299999999999795e-06 +8.911099999999999577e-02 5.694499999999999774e-05 2.081600000000000111e-06 +9.004199999999999704e-02 4.229200000000000098e-05 1.729699999999999931e-06 +9.095499999999999419e-02 3.367499999999999861e-05 1.458899999999999915e-06 +9.185000000000000109e-02 2.545600000000000158e-05 1.249600000000000072e-06 +9.274399999999999311e-02 2.092200000000000060e-05 1.159800000000000102e-06 +9.362900000000000389e-02 1.531099999999999960e-05 1.060100000000000023e-06 +9.455299999999999816e-02 1.265600000000000046e-05 9.577500000000000628e-07 +9.551800000000000568e-02 9.331199999999999700e-06 8.621400000000000160e-07 +9.647699999999999332e-02 8.901499999999999392e-06 7.828999999999999496e-07 +9.741900000000000559e-02 1.079100000000000053e-05 8.938500000000000266e-07 +9.842599999999999960e-02 1.213699999999999916e-05 9.113100000000000255e-07 +9.941999999999999449e-02 1.540799999999999885e-05 9.077799999999999932e-07 +1.004300000000000054e-01 1.938000000000000080e-05 9.602500000000000389e-07 +1.014300000000000063e-01 2.091199999999999900e-05 1.040900000000000063e-06 +1.024999999999999939e-01 2.519199999999999868e-05 1.078399999999999916e-06 +1.034999999999999948e-01 2.818799999999999846e-05 1.132199999999999934e-06 +1.045500000000000040e-01 2.998099999999999976e-05 1.178500000000000024e-06 +1.056099999999999955e-01 3.056299999999999859e-05 1.150500000000000038e-06 +1.066799999999999971e-01 2.818999999999999945e-05 1.099099999999999988e-06 +1.077599999999999947e-01 2.692599999999999936e-05 1.037400000000000012e-06 +1.088299999999999962e-01 2.541899999999999837e-05 1.012600000000000054e-06 +1.099200000000000038e-01 2.282700000000000015e-05 9.367100000000000279e-07 +1.110399999999999998e-01 1.769199999999999934e-05 7.904499999999999875e-07 +1.121199999999999974e-01 1.547500000000000007e-05 7.625400000000000506e-07 +1.132399999999999934e-01 1.172599999999999920e-05 6.687999999999999536e-07 +1.143200000000000049e-01 1.050299999999999922e-05 6.598099999999999770e-07 +1.154599999999999932e-01 8.121500000000000084e-06 5.846999999999999880e-07 +1.166399999999999937e-01 4.988800000000000415e-06 5.267199999999999943e-07 +1.177600000000000036e-01 4.909999999999999577e-06 5.361000000000000426e-07 +1.189299999999999941e-01 5.304300000000000189e-06 5.240799999999999654e-07 +1.201300000000000007e-01 5.689100000000000300e-06 4.912300000000000385e-07 +1.213499999999999995e-01 6.444700000000000316e-06 5.061099999999999705e-07 +1.225900000000000045e-01 7.456199999999999864e-06 5.057999999999999896e-07 +1.238199999999999995e-01 8.248400000000000512e-06 5.025600000000000215e-07 +1.250900000000000067e-01 1.067500000000000028e-05 5.845400000000000184e-07 +1.263600000000000001e-01 1.131599999999999974e-05 5.722299999999999829e-07 +1.276400000000000035e-01 1.104399999999999963e-05 5.762600000000000528e-07 +1.289299999999999891e-01 1.062599999999999957e-05 5.655300000000000090e-07 +1.302099999999999924e-01 9.337700000000000400e-06 5.254700000000000063e-07 +1.315500000000000003e-01 8.922800000000000357e-06 5.000700000000000038e-07 +1.328499999999999959e-01 6.436100000000000093e-06 4.446899999999999936e-07 +1.341600000000000015e-01 6.181099999999999994e-06 4.556199999999999995e-07 +1.355099999999999916e-01 4.685699999999999878e-06 4.034800000000000104e-07 +1.368199999999999972e-01 4.667499999999999781e-06 3.809300000000000103e-07 +1.381999999999999895e-01 4.262500000000000270e-06 3.763000000000000013e-07 +1.395899999999999919e-01 3.884300000000000232e-06 3.571600000000000033e-07 +1.409900000000000042e-01 3.699499999999999901e-06 3.796599999999999996e-07 +1.424300000000000010e-01 3.659899999999999890e-06 3.543399999999999820e-07 +1.438500000000000056e-01 4.559399999999999918e-06 3.665699999999999797e-07 +1.452600000000000002e-01 4.580899999999999627e-06 3.470599999999999856e-07 +1.467499999999999916e-01 4.829299999999999655e-06 3.503900000000000029e-07 +1.482199999999999906e-01 4.930899999999999665e-06 3.533300000000000014e-07 +1.497100000000000097e-01 4.780999999999999626e-06 3.612599999999999937e-07 +1.512199999999999933e-01 4.644799999999999981e-06 3.397100000000000158e-07 +1.527399999999999869e-01 4.365099999999999932e-06 3.324600000000000005e-07 +1.542600000000000082e-01 3.807099999999999938e-06 3.253800000000000191e-07 +1.558199999999999863e-01 3.544199999999999880e-06 3.053900000000000102e-07 +1.573700000000000099e-01 2.632699999999999798e-06 2.773599999999999902e-07 +1.589399999999999979e-01 2.129700000000000125e-06 2.570600000000000003e-07 +1.605100000000000138e-01 2.509099999999999829e-06 2.684200000000000173e-07 +1.621400000000000063e-01 2.606299999999999932e-06 2.683499999999999909e-07 +1.637599999999999889e-01 2.467999999999999918e-06 2.618099999999999866e-07 +1.653999999999999915e-01 2.437699999999999971e-06 2.457099999999999946e-07 +1.670300000000000118e-01 2.818500000000000204e-06 2.626300000000000164e-07 +1.687400000000000011e-01 3.201900000000000210e-06 2.677200000000000177e-07 +1.704100000000000059e-01 3.020999999999999960e-06 2.548700000000000052e-07 +1.721199999999999952e-01 2.398600000000000210e-06 2.324600000000000050e-07 +1.738399999999999945e-01 2.458200000000000029e-06 2.385499999999999755e-07 +1.755700000000000038e-01 2.033700000000000112e-06 2.231999999999999869e-07 +1.773399999999999976e-01 1.684000000000000097e-06 2.048299999999999885e-07 +1.790899999999999992e-01 1.293800000000000005e-06 2.007699999999999906e-07 +1.809099999999999875e-01 1.439699999999999955e-06 1.882099999999999893e-07 +1.827100000000000113e-01 1.540200000000000094e-06 1.999999999999999909e-07 +1.845400000000000096e-01 1.338499999999999975e-06 1.864800000000000128e-07 +1.863799999999999901e-01 1.616000000000000071e-06 1.863699999999999940e-07 +1.882500000000000007e-01 1.493499999999999973e-06 1.883900000000000081e-07 +1.901299999999999935e-01 2.059699999999999948e-06 1.920699999999999987e-07 +1.920399999999999885e-01 1.690199999999999928e-06 1.767699999999999874e-07 +1.939500000000000113e-01 1.488400000000000014e-06 1.792699999999999900e-07 +1.958999999999999908e-01 1.403800000000000010e-06 1.747300000000000036e-07 +1.978600000000000081e-01 1.346899999999999971e-06 1.705699999999999981e-07 +1.998399999999999899e-01 9.477100000000000073e-07 1.617800000000000100e-07 +2.018300000000000094e-01 1.089599999999999910e-06 1.735000000000000117e-07 +2.038600000000000134e-01 1.246300000000000036e-06 1.654700000000000120e-07 +2.058999999999999997e-01 1.227400000000000098e-06 1.644900000000000125e-07 +2.079600000000000060e-01 1.168999999999999946e-06 1.584600000000000041e-07 +2.100400000000000045e-01 1.161700000000000033e-06 1.521999999999999997e-07 +2.121399999999999952e-01 1.216899999999999945e-06 1.588499999999999964e-07 +2.142600000000000060e-01 1.317600000000000099e-06 1.546100000000000060e-07 +2.164000000000000090e-01 1.032800000000000090e-06 1.472899999999999908e-07 +2.185699999999999865e-01 1.030699999999999932e-06 1.514699999999999925e-07 +2.207800000000000040e-01 5.945299999999999642e-07 1.511699999999999964e-07 +2.229899999999999938e-01 7.279999999999999544e-07 1.429299999999999967e-07 +2.252200000000000035e-01 7.806299999999999697e-07 1.485200000000000091e-07 +2.274700000000000055e-01 1.063400000000000059e-06 1.499299999999999932e-07 +2.297399999999999998e-01 6.527000000000000146e-07 1.296699999999999958e-07 +2.320399999999999963e-01 1.074400000000000039e-06 1.484500000000000091e-07 +2.343600000000000128e-01 8.687600000000000051e-07 1.468600000000000061e-07 +2.366999999999999937e-01 9.218700000000000353e-07 1.450799999999999994e-07 +2.390599999999999947e-01 6.471500000000000212e-07 1.368099999999999922e-07 +2.414499999999999980e-01 5.363900000000000008e-07 1.356899999999999928e-07 +2.438700000000000034e-01 6.337199999999999863e-07 1.304000000000000030e-07 +2.462999999999999912e-01 6.292699999999999696e-07 1.365599999999999999e-07 +2.487699999999999911e-01 6.332899999999999751e-07 1.224499999999999881e-07 +2.512499999999999734e-01 1.037099999999999989e-06 1.354099999999999929e-07 +2.537599999999999856e-01 8.252900000000000003e-07 1.431599999999999928e-07 +2.562999999999999723e-01 6.268299999999999557e-07 1.192599999999999972e-07 +2.588599999999999790e-01 5.252600000000000328e-07 1.227399999999999993e-07 +2.614500000000000157e-01 5.218300000000000081e-07 1.309200000000000103e-07 +2.640600000000000169e-01 3.916600000000000012e-07 1.213700000000000075e-07 +2.666999999999999926e-01 4.724400000000000138e-07 1.399700000000000020e-07 +2.693699999999999983e-01 5.595400000000000460e-07 1.391499999999999986e-07 +2.720600000000000240e-01 6.640700000000000430e-07 1.448699999999999996e-07 +2.747800000000000242e-01 4.593799999999999750e-07 1.514699999999999925e-07 +2.775299999999999989e-01 3.669599999999999984e-07 1.435500000000000116e-07 +2.802999999999999936e-01 5.315299999999999957e-07 1.483100000000000092e-07 +2.831000000000000183e-01 4.289099999999999939e-07 1.361500000000000115e-07 +2.859300000000000175e-01 5.520100000000000308e-07 1.419800000000000048e-07 +2.887899999999999912e-01 5.702600000000000255e-07 1.528999999999999993e-07 +2.916799999999999948e-01 5.047299999999999939e-07 1.364300000000000113e-07 +2.945999999999999730e-01 6.619199999999999873e-07 1.407900000000000054e-07 +2.975400000000000267e-01 7.601300000000000177e-07 1.607199999999999992e-07 +3.005200000000000093e-01 4.685299999999999742e-07 1.348900000000000121e-07 +3.035200000000000120e-01 4.428599999999999832e-07 1.471299999999999946e-07 +3.065499999999999892e-01 4.899800000000000504e-07 1.404299999999999942e-07 +3.096200000000000063e-01 3.601600000000000169e-07 1.337299999999999938e-07 +3.127099999999999880e-01 2.905599999999999760e-07 1.480599999999999904e-07 +3.158400000000000096e-01 5.199599999999999523e-07 1.515599999999999887e-07 +3.190000000000000058e-01 4.666699999999999827e-07 1.562599999999999977e-07 +3.221899999999999764e-01 3.888800000000000253e-07 1.570100000000000011e-07 +3.254099999999999770e-01 4.467799999999999812e-07 1.555099999999999942e-07 +3.286600000000000077e-01 3.238800000000000123e-07 1.525899999999999919e-07 +3.319500000000000228e-01 3.787400000000000152e-07 1.581800000000000043e-07 +3.352700000000000125e-01 3.881999999999999954e-07 1.539100000000000064e-07 +3.386199999999999766e-01 4.428800000000000059e-07 1.491000000000000050e-07 +3.420000000000000262e-01 2.477900000000000238e-07 1.463200000000000026e-07 +3.454200000000000048e-01 2.857699999999999973e-07 1.351299999999999931e-07 +3.488800000000000234e-01 4.759599999999999818e-07 1.536599999999999876e-07 +3.523600000000000065e-01 4.496399999999999949e-07 1.539600000000000101e-07 +3.558899999999999841e-01 2.471499999999999863e-07 1.443200000000000112e-07 +3.594499999999999917e-01 2.167599999999999901e-07 1.491799999999999898e-07 +3.630399999999999738e-01 5.205899999999999784e-07 1.573700000000000122e-07 +3.666699999999999959e-01 5.247000000000000331e-07 1.545400000000000061e-07 +3.703400000000000025e-01 3.644000000000000072e-07 1.550199999999999945e-07 +3.740399999999999836e-01 4.597500000000000239e-07 1.653099999999999894e-07 +3.777800000000000047e-01 5.359200000000000502e-07 1.820400000000000075e-07 +3.815500000000000003e-01 4.268099999999999950e-07 1.770000000000000100e-07 +3.853699999999999903e-01 4.036700000000000141e-07 1.811100000000000117e-07 +3.892200000000000104e-01 2.554499999999999746e-07 1.597299999999999884e-07 +3.931100000000000150e-01 9.269699999999999950e-08 1.654000000000000120e-07 +3.970400000000000040e-01 1.106699999999999977e-07 1.808900000000000005e-07 +4.010099999999999776e-01 4.521599999999999937e-07 1.731900000000000043e-07 +4.050199999999999911e-01 3.780699999999999966e-07 1.516000000000000075e-07 +4.090699999999999892e-01 3.091399999999999743e-07 1.571899999999999934e-07 +4.131600000000000272e-01 3.417700000000000223e-07 1.448199999999999958e-07 +4.172899999999999943e-01 3.449199999999999943e-07 1.595800000000000036e-07 +4.214700000000000113e-01 2.518400000000000105e-07 1.597599999999999959e-07 +4.256800000000000028e-01 4.017399999999999962e-07 1.538099999999999989e-07 +4.299399999999999888e-01 3.172799999999999929e-07 1.691300000000000064e-07 +4.342300000000000049e-01 5.506299999999999483e-07 1.611399999999999990e-07 +4.385800000000000254e-01 5.085100000000000450e-07 1.649899999999999971e-07 +4.429600000000000204e-01 6.025899999999999980e-07 1.738299999999999889e-07 +4.473900000000000099e-01 4.384500000000000119e-07 1.653500000000000082e-07 +4.518699999999999939e-01 3.387599999999999973e-07 1.876400000000000047e-07 +4.563800000000000079e-01 4.358499999999999754e-07 1.978299999999999920e-07 +4.609500000000000264e-01 3.855799999999999891e-07 1.761399999999999877e-07 +4.655500000000000194e-01 3.834100000000000166e-07 1.884499999999999967e-07 diff --git a/tests/test_data/prist.json b/tests/test_data/prist.json new file mode 100644 index 00000000..3b36893e --- /dev/null +++ b/tests/test_data/prist.json @@ -0,0 +1 @@ +{"name": "Example Project", "calculation": "normal", "model": "standard layers", "geometry": "air/substrate", "absorption": false, "parameters": [{"name": "Substrate Roughness", "min": 1.0, "value": 3.0, "max": 5.0, "fit": true, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}, {"name": "Al2O3 Thickness", "min": 20.0, "value": 20.0, "max": 20.0, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}, {"name": "Al2O3 Roughness", "min": 3.0, "value": 3.0, "max": 3.0, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}, {"name": "Al2O3 SLD", "min": 5.715275837467511e-06, "value": 5.715275837467511e-06, "max": 5.715275837467511e-06, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}, {"name": "Ti0.27Co0.73 Thickness", "min": 93.0, "value": 93.0, "max": 93.0, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}, {"name": "Ti0.27Co0.73 Roughness", "min": 3.0, "value": 3.0, "max": 3.0, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}, {"name": "Ti0.27Co0.73 SLD", "min": 6.720584953375607e-07, "value": 6.720584953375607e-07, "max": 6.720584953375607e-07, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "bulk_in": [{"name": "vacuum SLD", "min": 0.0, "value": 0.0, "max": 0.0, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "bulk_out": [{"name": "Si SLD", "min": 2.07370547828562e-06, "value": 2.07370547828562e-06, "max": 2.07370547828562e-06, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "scalefactors": [{"name": "Scalefactor", "min": 0.0, "value": 1.0, "max": 1.5, "fit": true, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "domain_ratios": [], "background_parameters": [{"name": "Background Parameter", "min": 0.0, "value": 0.025, "max": 1.0, "fit": true, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "backgrounds": [{"name": "Background", "type": "constant", "source": "Background Parameter", "value_1": "", "value_2": "", "value_3": "", "value_4": "", "value_5": ""}], "resolution_parameters": [{"name": "Resolution Param 1", "min": 0.01, "value": 0.03, "max": 0.05, "fit": false, "prior_type": "uniform", "mu": 0.0, "sigma": Infinity, "show_priors": false}], "resolutions": [{"name": "Data Resolution", "type": "data", "source": "", "value_1": "", "value_2": "", "value_3": "", "value_4": "", "value_5": ""}], "custom_files": [], "data": [{"name": "Simulation", "data": [], "data_range": [], "simulation_range": [0.005, 0.7]}, {"name": "prist4", "data": [[0.0021999999999999997, 0.004724119389721505, 0.004724119389721505, 0.00019999999999999987], [0.0026, 0.0, 0.0, 0.0002000000000000001], [0.003, 0.0049441079014990305, 0.0028632759811688313, 0.0002000000000000001], [0.0034000000000000002, 0.00539571466421478, 0.0027033018099334193, 0.00019999999999999987], [0.0038, 0.011948517768746966, 0.0037903477990210636, 0.0002000000000000001], [0.004200000000000001, 0.016302332669940297, 0.003972317564845323, 0.0002000000000000001], [0.0046, 0.02265216487165058, 0.0045763672802481776, 0.0002000000000000001], [0.005, 0.023020814468949415, 0.00425372711337262, 0.00019999999999999966], [0.0054, 0.027305557750665344, 0.004428700971127359, 0.0002000000000000001], [0.0058, 0.019457945835850306, 0.0037817426451169783, 0.0002000000000000001], [0.006200000000000001, 0.027645506109865266, 0.004267993991409073, 0.0002000000000000001], [0.0066, 0.024223034347324195, 0.0037655052701117517, 0.0002000000000000001], [0.007, 0.028408308819418325, 0.0037377941755602716, 0.00019999999999999966], [0.0074, 0.057460495308053604, 0.0052154049057105455, 0.0002000000000000001], [0.0078, 0.1489883351950982, 0.00754789840356179, 0.0002000000000000001], [0.008199999999999999, 0.3520480929443021, 0.011146891694516669, 0.00019999999999999966], [0.0086, 0.5317657760789548, 0.01351725179531962, 0.00019999999999999966], [0.009, 0.7914500646501588, 0.016276277463585134, 0.00020000000000000052], [0.009399999999999999, 0.9680331047846104, 0.01782748799306378, 0.00019999999999999966], [0.0098, 1.0324643310179094, 0.018104900945963596, 0.00020000000000000052], [0.010204081632653062, 0.6287661683321234, 0.013873373556929145, 0.00020408163265306107], [0.010620574760516453, 0.3506955915110479, 0.010136613757789808, 0.00021241149521033023], [0.011054067607884473, 0.23477751708069897, 0.008109962639928676, 0.000221081352157689], [0.011505254040859348, 0.18964302712880826, 0.007180573014831645, 0.00023010508081718756], [0.011974856246608712, 0.14285208497806512, 0.006016224926747713, 0.00023949712493217482], [0.012463625889327434, 0.12188457497836602, 0.005435279585343197, 0.00024927251778654805], [0.012972345313381616, 0.10530945504618572, 0.005027517945960155, 0.00025944690626763297], [0.013501828795560456, 0.08038795087657985, 0.004197556276825506, 0.0002700365759112089], [0.014052923848440476, 0.07313672279549625, 0.003958200398418697, 0.00028105847696880976], [0.01462651257694825, 0.06129841978151465, 0.0034783001152817426, 0.0002925302515389659], [0.01522351309029308, 0.06240905936586468, 0.003479800062460076, 0.000304470261805862], [0.015844880971529533, 0.05651280096554304, 0.0032223775371921573, 0.00031689761943059103], [0.016491610807102167, 0.05044073793552524, 0.00290210672478378, 0.0003298322161420439], [0.017164737778820625, 0.0502775250441711, 0.002825286449304508, 0.00034329475557641313], [0.0178653393208133, 0.05168970509722787, 0.002811814341605395, 0.0003573067864162654], [0.018594536844111803, 0.0530076187705834, 0.0027685413804410695, 0.00037189073688223724], [0.019353497531626573, 0.0490707566771454, 0.0025677593751218504, 0.00038706995063253133], [0.020143436206386842, 0.04687883170966378, 0.0024119133732668076, 0.0004028687241277376], [0.020965617276035284, 0.04919955377214455, 0.0024276503561561644, 0.0004193123455207056], [0.021821356756689787, 0.05204111270310913, 0.00245561515567379, 0.00043642713513379616], [0.022712024379411822, 0.04925178172610669, 0.0023335505076022252, 0.00045424048758823873], [0.02363904578265312, 0.04317260894774357, 0.00211385396560445, 0.0004727809156530611], [0.024603904794189984, 0.0383043276355005, 0.0019158755178575817, 0.0004920780958838009], [0.02560814580619774, 0.04444220010645997, 0.002018641932709427, 0.0005121629161239545], [0.026653376247267036, 0.039587001147536376, 0.0018488058581743547, 0.0005330675249453423], [0.027741269155318757, 0.036677858215866437, 0.0017473224966445143, 0.0005548253831063766], [0.028873565855535847, 0.037663512267048754, 0.0017682821318945074, 0.0005774713171107174], [0.030052078747598535, 0.036755569252809664, 0.0017350440273063527, 0.0006010415749519698], [0.03127869420668419, 0.03854639441776167, 0.0017965558626918197, 0.0006255738841336837], [0.032555375602875386, 0.032866785139061716, 0.0016217721152892931, 0.000651107512057509], [0.03388416644380907, 0.0315131968037535, 0.0016061232808323794, 0.0006776833288761816], [0.0352671936455972, 0.030280345918169513, 0.0015885947028228238, 0.0007053438729119448], [0.03670667093725423, 0.025036982048446406, 0.0014176844815086535, 0.0007341334187450851], [0.038204902404080934, 0.02083180456328542, 0.001280336546816776, 0.0007640980480816198], [0.03976428617567608, 0.019376976329704945, 0.0012712203272554497, 0.0007952857235135231], [0.04138731826447918, 0.016729675515039004, 0.0011715497338181137, 0.000827746365289584], [0.04307659656098854, 0.013996303090353096, 0.0010654383375290077, 0.0008615319312197701], [0.0448348249920493, 0.010621480384334052, 0.0009246807782300395, 0.0008966964998409904], [0.04666481784886764, 0.007820332463525126, 0.0008093102454836752, 0.000933296356977354], [0.04856950429167857, 0.0060428022894521575, 0.0007183835413384203, 0.0009713900858335685], [0.050551933038277694, 0.004095892971484393, 0.0005841670446995313, 0.0010110386607655557], [0.05261527724392169, 0.005111525161941947, 0.0006658003030884043, 0.0010523055448784409], [0.05476283958040829, 0.0020207116612746484, 0.0004143866059231477, 0.0010952567916081637], [0.05699805752246577, 0.001711568931414378, 0.00038529038925611664, 0.0011399611504493146], [0.05932450884991336, 0.0008496305883131249, 0.00027095330976641694, 0.001186490176998272], [0.06174591737439962, 0.0008142116035177235, 0.00027251395576638693, 0.0012349183474879948], [0.06426615889988532, 8.92042382623096e-05, 8.920423826322552e-05, 0.0012853231779977048], [0.06688926742641126, 9.339736346561163e-05, 9.339736346489978e-05, 0.0013377853485282282], [0.06961944160708111, 0.00040599169078880156, 0.0002030320824188672, 0.0013923888321416208], [0.07246105146859462, 0.0002183257352075823, 0.00015439324988622013, 0.0014492210293718943], [0.07541864540608828, 0.00012684339163879, 0.00012684339163797725, 0.001508372908121773], [0.07849695746347965, 0.0, 0.0, 0.001569939149269589], [0.08170091491096862, 0.0, 0.0, 0.0016340182982193738], [0.08503564613182449, 0.0004165748322677754, 0.00024090333523406435, 0.001700712922636495], [0.08850648883108263, 0.0, 0.0, 0.0017701297766216512], [0.09211899857929008, 0.0, 0.0, 0.001842379971585803], [0.0958789577049754, 0.0, 0.0, 0.0019175791540995135], [0.09979238455007644, 0.0, 0.0, 0.001995847691001529], [0.10386554310314079, 0.0, 0.0, 0.0020773108620628228]], "data_range": [0.0021999999999999997, 0.10386554310314079], "simulation_range": [0.0021999999999999997, 0.10386554310314079]}], "layers": [{"name": "Al2O3", "thickness": "Al2O3 Thickness", "SLD": "Al2O3 SLD", "roughness": "Al2O3 Roughness", "hydration": "", "hydrate_with": "bulk out"}, {"name": "Ti0.27Co0.73", "thickness": "Ti0.27Co0.73 Thickness", "SLD": "Ti0.27Co0.73 SLD", "roughness": "Ti0.27Co0.73 Roughness", "hydration": "", "hydrate_with": "bulk out"}], "domain_contrasts": [], "contrasts": [{"name": "prist4", "data": "prist4", "background": "Background", "background_action": "add", "bulk_in": "vacuum SLD", "bulk_out": "Si SLD", "scalefactor": "Scalefactor", "resolution": "Data Resolution", "resample": false, "model": ["Al2O3", "Ti0.27Co0.73"]}]} \ No newline at end of file diff --git a/tests/test_data/prist5_10K_m_025.Rqz.ort b/tests/test_data/prist5_10K_m_025.Rqz.ort new file mode 100644 index 00000000..5b60b8fc --- /dev/null +++ b/tests/test_data/prist5_10K_m_025.Rqz.ort @@ -0,0 +1,124 @@ +# # ORSO reflectivity data file | 1.0 standard | YAML encoding | https://www.reflectometry.org/ +# data_source: +# owner: +# name: Artur Glavic +# affiliation: null +# contact: b'' +# experiment: +# title: Structural evolution of the CO2/Water interface +# instrument: Amor +# start_date: 2023-11-29T10:12:45 +# probe: neutron +# facility: SINQ@PSI +# proposalID: '20230368' +# sample: +# name: prist4 +# sample_parameters: +# tempMean: {magnitude: -9999.0} +# model: +# stack: vacuum | Al2O3 2 | Ti0.27Co0.73 9.3 | Si +# measurement: +# instrument_settings: +# incident_angle: {min: 0.0950000000000002, max: 1.495, unit: deg} +# wavelength: {min: 3.0, max: 12.0, unit: angstrom} +# mu: {magnitude: 0.25, unit: deg, comment: sample angle to referece direction} +# nu: {magnitude: 1.0450000000000002, unit: deg, comment: detector angle to referece +# direction} +# data_files: +# - file: raw/amor2023n000848.hdf +# timestamp: 2023-11-29T10:12:45 +# amor_monitor: 1792.443302905 +# scheme: angle- and energy-dispersive +# references: [] +# amor_monitor: 1792.443302905 +# reduction: +# software: {name: eos, version: '2.0'} +# timestamp: 2023-11-29T10:57:48.480339 +# computer: amor.psi.ch +# call: eos.py -a 0.04 -F 0.0093,0.0101 -n 848 prist5_10K_m_025 +# data_set: 0 +# columns: +# - {name: Qz, unit: 1/angstrom, physical_quantity: normal momentum transfer} +# - {name: R, unit: '', physical_quantity: specular reflectivity} +# - {error_of: R, error_type: uncertainty, value_is: sigma} +# - {error_of: Qz, error_type: resolution, value_is: sigma} +# # Qz (1/angstrom) R () sR sQz +2.1999999999999997e-03 4.7241193897215048e-03 4.7241193897215048e-03 1.9999999999999987e-04 +2.5999999999999999e-03 0.0000000000000000e+00 0.0000000000000000e+00 2.0000000000000009e-04 +3.0000000000000001e-03 4.9441079014990305e-03 2.8632759811688313e-03 2.0000000000000009e-04 +3.4000000000000002e-03 5.3957146642147798e-03 2.7033018099334193e-03 1.9999999999999987e-04 +3.8000000000000000e-03 1.1948517768746966e-02 3.7903477990210636e-03 2.0000000000000009e-04 +4.2000000000000006e-03 1.6302332669940297e-02 3.9723175648453228e-03 2.0000000000000009e-04 +4.5999999999999999e-03 2.2652164871650581e-02 4.5763672802481776e-03 2.0000000000000009e-04 +5.0000000000000001e-03 2.3020814468949415e-02 4.2537271133726200e-03 1.9999999999999966e-04 +5.4000000000000003e-03 2.7305557750665344e-02 4.4287009711273589e-03 2.0000000000000009e-04 +5.7999999999999996e-03 1.9457945835850306e-02 3.7817426451169783e-03 2.0000000000000009e-04 +6.2000000000000006e-03 2.7645506109865266e-02 4.2679939914090732e-03 2.0000000000000009e-04 +6.6000000000000000e-03 2.4223034347324195e-02 3.7655052701117517e-03 2.0000000000000009e-04 +7.0000000000000001e-03 2.8408308819418325e-02 3.7377941755602716e-03 1.9999999999999966e-04 +7.4000000000000003e-03 5.7460495308053604e-02 5.2154049057105455e-03 2.0000000000000009e-04 +7.7999999999999996e-03 1.4898833519509819e-01 7.5478984035617898e-03 2.0000000000000009e-04 +8.1999999999999990e-03 3.5204809294430212e-01 1.1146891694516669e-02 1.9999999999999966e-04 +8.6000000000000000e-03 5.3176577607895481e-01 1.3517251795319620e-02 1.9999999999999966e-04 +8.9999999999999993e-03 7.9145006465015877e-01 1.6276277463585134e-02 2.0000000000000052e-04 +9.3999999999999986e-03 9.6803310478461035e-01 1.7827487993063780e-02 1.9999999999999966e-04 +9.7999999999999997e-03 1.0324643310179094e+00 1.8104900945963596e-02 2.0000000000000052e-04 +1.0204081632653062e-02 6.2876616833212340e-01 1.3873373556929145e-02 2.0408163265306107e-04 +1.0620574760516453e-02 3.5069559151104790e-01 1.0136613757789808e-02 2.1241149521033023e-04 +1.1054067607884473e-02 2.3477751708069897e-01 8.1099626399286761e-03 2.2108135215768900e-04 +1.1505254040859348e-02 1.8964302712880826e-01 7.1805730148316446e-03 2.3010508081718756e-04 +1.1974856246608712e-02 1.4285208497806512e-01 6.0162249267477130e-03 2.3949712493217482e-04 +1.2463625889327434e-02 1.2188457497836602e-01 5.4352795853431970e-03 2.4927251778654805e-04 +1.2972345313381616e-02 1.0530945504618572e-01 5.0275179459601553e-03 2.5944690626763297e-04 +1.3501828795560456e-02 8.0387950876579850e-02 4.1975562768255060e-03 2.7003657591120889e-04 +1.4052923848440476e-02 7.3136722795496253e-02 3.9582003984186967e-03 2.8105847696880976e-04 +1.4626512576948251e-02 6.1298419781514651e-02 3.4783001152817426e-03 2.9253025153896592e-04 +1.5223513090293080e-02 6.2409059365864682e-02 3.4798000624600761e-03 3.0447026180586197e-04 +1.5844880971529533e-02 5.6512800965543043e-02 3.2223775371921573e-03 3.1689761943059103e-04 +1.6491610807102167e-02 5.0440737935525240e-02 2.9021067247837801e-03 3.2983221614204389e-04 +1.7164737778820625e-02 5.0277525044171101e-02 2.8252864493045079e-03 3.4329475557641313e-04 +1.7865339320813300e-02 5.1689705097227867e-02 2.8118143416053952e-03 3.5730678641626538e-04 +1.8594536844111803e-02 5.3007618770583402e-02 2.7685413804410695e-03 3.7189073688223724e-04 +1.9353497531626573e-02 4.9070756677145402e-02 2.5677593751218504e-03 3.8706995063253133e-04 +2.0143436206386842e-02 4.6878831709663782e-02 2.4119133732668076e-03 4.0286872412773761e-04 +2.0965617276035284e-02 4.9199553772144550e-02 2.4276503561561644e-03 4.1931234552070561e-04 +2.1821356756689787e-02 5.2041112703109127e-02 2.4556151556737898e-03 4.3642713513379616e-04 +2.2712024379411822e-02 4.9251781726106690e-02 2.3335505076022252e-03 4.5424048758823873e-04 +2.3639045782653120e-02 4.3172608947743572e-02 2.1138539656044499e-03 4.7278091565306109e-04 +2.4603904794189984e-02 3.8304327635500499e-02 1.9158755178575817e-03 4.9207809588380086e-04 +2.5608145806197739e-02 4.4442200106459967e-02 2.0186419327094269e-03 5.1216291612395451e-04 +2.6653376247267036e-02 3.9587001147536376e-02 1.8488058581743547e-03 5.3306752494534232e-04 +2.7741269155318757e-02 3.6677858215866437e-02 1.7473224966445143e-03 5.5482538310637659e-04 +2.8873565855535847e-02 3.7663512267048754e-02 1.7682821318945074e-03 5.7747131711071743e-04 +3.0052078747598535e-02 3.6755569252809664e-02 1.7350440273063527e-03 6.0104157495196979e-04 +3.1278694206684193e-02 3.8546394417761670e-02 1.7965558626918197e-03 6.2557388413368373e-04 +3.2555375602875386e-02 3.2866785139061716e-02 1.6217721152892931e-03 6.5110751205750897e-04 +3.3884166443809073e-02 3.1513196803753502e-02 1.6061232808323794e-03 6.7768332887618160e-04 +3.5267193645597203e-02 3.0280345918169513e-02 1.5885947028228238e-03 7.0534387291194475e-04 +3.6706670937254229e-02 2.5036982048446406e-02 1.4176844815086535e-03 7.3413341874508514e-04 +3.8204902404080934e-02 2.0831804563285421e-02 1.2803365468167761e-03 7.6409804808161980e-04 +3.9764286175676081e-02 1.9376976329704945e-02 1.2712203272554497e-03 7.9528572351352314e-04 +4.1387318264479181e-02 1.6729675515039004e-02 1.1715497338181137e-03 8.2774636528958404e-04 +4.3076596560988542e-02 1.3996303090353096e-02 1.0654383375290077e-03 8.6153193121977015e-04 +4.4834824992049299e-02 1.0621480384334052e-02 9.2468077823003954e-04 8.9669649984099042e-04 +4.6664817848867640e-02 7.8203324635251256e-03 8.0931024548367521e-04 9.3329635697735405e-04 +4.8569504291678570e-02 6.0428022894521575e-03 7.1838354133842033e-04 9.7139008583356848e-04 +5.0551933038277694e-02 4.0958929714843932e-03 5.8416704469953131e-04 1.0110386607655557e-03 +5.2615277243921690e-02 5.1115251619419473e-03 6.6580030308840434e-04 1.0523055448784409e-03 +5.4762839580408292e-02 2.0207116612746484e-03 4.1438660592314769e-04 1.0952567916081637e-03 +5.6998057522465770e-02 1.7115689314143780e-03 3.8529038925611664e-04 1.1399611504493146e-03 +5.9324508849913360e-02 8.4963058831312487e-04 2.7095330976641694e-04 1.1864901769982721e-03 +6.1745917374399620e-02 8.1421160351772355e-04 2.7251395576638693e-04 1.2349183474879948e-03 +6.4266158899885323e-02 8.9204238262309603e-05 8.9204238263225523e-05 1.2853231779977048e-03 +6.6889267426411256e-02 9.3397363465611626e-05 9.3397363464899779e-05 1.3377853485282282e-03 +6.9619441607081112e-02 4.0599169078880156e-04 2.0303208241886721e-04 1.3923888321416208e-03 +7.2461051468594620e-02 2.1832573520758229e-04 1.5439324988622013e-04 1.4492210293718943e-03 +7.5418645406088280e-02 1.2684339163878999e-04 1.2684339163797725e-04 1.5083729081217731e-03 +7.8496957463479650e-02 0.0000000000000000e+00 0.0000000000000000e+00 1.5699391492695891e-03 +8.1700914910968619e-02 0.0000000000000000e+00 0.0000000000000000e+00 1.6340182982193738e-03 +8.5035646131824488e-02 4.1657483226777538e-04 2.4090333523406435e-04 1.7007129226364950e-03 +8.8506488831082628e-02 0.0000000000000000e+00 0.0000000000000000e+00 1.7701297766216512e-03 +9.2118998579290082e-02 0.0000000000000000e+00 0.0000000000000000e+00 1.8423799715858030e-03 +9.5878957704975398e-02 0.0000000000000000e+00 0.0000000000000000e+00 1.9175791540995135e-03 +9.9792384550076441e-02 0.0000000000000000e+00 0.0000000000000000e+00 1.9958476910015288e-03 +1.0386554310314079e-01 0.0000000000000000e+00 0.0000000000000000e+00 2.0773108620628228e-03 diff --git a/tests/test_enums.py b/tests/test_enums.py index 0b3911ae..3d07c308 100644 --- a/tests/test_enums.py +++ b/tests/test_enums.py @@ -1,10 +1,10 @@ """Tests the enums module.""" -from typing import Callable +from collections.abc import Callable import pytest -from RATapi.utils.enums import ( +from ratapi.utils.enums import ( BackgroundActions, BoundHandling, Calculations, @@ -17,6 +17,7 @@ Priors, Procedures, RATEnum, + Strategies, TypeOptions, ) @@ -48,12 +49,11 @@ (Languages, "cpp", Languages.Cpp), (Languages, "python", Languages.Python), (Languages, "matlab", Languages.Matlab), - (Hydration, "none", Hydration.None_), (Hydration, "bulk in", Hydration.BulkIn), (Hydration, "bulk out", Hydration.BulkOut), (Priors, "uniform", Priors.Uniform), (Priors, "gaussian", Priors.Gaussian), - (Calculations, "non polarised", Calculations.NonPolarised), + (Calculations, "normal", Calculations.Normal), (Calculations, "domains", Calculations.Domains), (LayerModels, "custom layers", LayerModels.CustomLayers), (LayerModels, "custom xy", LayerModels.CustomXY), @@ -74,7 +74,7 @@ def test_case_insensitivity(test_enum: Callable, test_str: str, expected_value: [ (Hydration, "bulk in", Hydration.BulkIn), (Hydration, "bulk out", Hydration.BulkOut), - (Calculations, "non polarised", Calculations.NonPolarised), + (Calculations, "normal", Calculations.Normal), (LayerModels, "custom layers", LayerModels.CustomLayers), (LayerModels, "custom xy", LayerModels.CustomXY), (LayerModels, "standard layers", LayerModels.StandardLayers), @@ -90,7 +90,6 @@ def test_dash_underscore(test_enum: Callable, test_str: str, expected_value: RAT ["test_enum", "test_str", "expected_value"], [ (Languages, "c++", Languages.Cpp), - (Calculations, "non polarized", Calculations.NonPolarised), ], ) def test_alternative_spellings(test_enum: Callable, test_str: str, expected_value: RATEnum) -> None: @@ -98,3 +97,8 @@ def test_alternative_spellings(test_enum: Callable, test_str: str, expected_valu assert test_enum(test_str) == expected_value assert test_enum(test_str.upper()) == expected_value assert test_enum(test_str.title()) == expected_value + + +def test_integer_strategies(): + """Test that strategies can be input as integers.""" + assert [Strategies(i) for i in range(1, len(Strategies) + 1)] == list(Strategies) diff --git a/tests/test_events.py b/tests/test_events.py index 185f7800..06b43c39 100644 --- a/tests/test_events.py +++ b/tests/test_events.py @@ -1,8 +1,10 @@ +import pickle from unittest import mock +import numpy as np import pytest -import RATapi.events +import ratapi.events def test_event_register() -> None: @@ -10,57 +12,88 @@ def test_event_register() -> None: second_callback = mock.Mock() with pytest.raises(ValueError): - RATapi.events.register("Message", first_callback) + ratapi.events.register("Message", first_callback) - RATapi.events.register(RATapi.events.EventTypes.Message, first_callback) - result = RATapi.events.get_event_callback(RATapi.events.EventTypes.Message) + ratapi.events.register(ratapi.events.EventTypes.Message, first_callback) + result = ratapi.events.get_event_callback(ratapi.events.EventTypes.Message) assert result == [first_callback] - RATapi.events.register(RATapi.events.EventTypes.Plot, second_callback) - assert RATapi.events.get_event_callback(RATapi.events.EventTypes.Plot) == [second_callback] + ratapi.events.register(ratapi.events.EventTypes.Plot, second_callback) + assert ratapi.events.get_event_callback(ratapi.events.EventTypes.Plot) == [second_callback] - RATapi.events.register(RATapi.events.EventTypes.Message, second_callback) + ratapi.events.register(ratapi.events.EventTypes.Message, second_callback) # the list is not guaranteed to be in the same order as inputted hence the set - assert set(RATapi.events.get_event_callback(RATapi.events.EventTypes.Message)) == set( - [first_callback, second_callback] - ) + assert set(ratapi.events.get_event_callback(ratapi.events.EventTypes.Message)) == {first_callback, second_callback} - RATapi.events.clear(RATapi.events.EventTypes.Message, second_callback) - result = RATapi.events.get_event_callback(RATapi.events.EventTypes.Message) + ratapi.events.clear(ratapi.events.EventTypes.Message, second_callback) + result = ratapi.events.get_event_callback(ratapi.events.EventTypes.Message) assert result == [first_callback] - result = RATapi.events.get_event_callback(RATapi.events.EventTypes.Plot) + result = ratapi.events.get_event_callback(ratapi.events.EventTypes.Plot) assert result == [second_callback] - RATapi.events.clear() - assert RATapi.events.get_event_callback(RATapi.events.EventTypes.Plot) == [] - assert RATapi.events.get_event_callback(RATapi.events.EventTypes.Message) == [] + ratapi.events.clear() + assert ratapi.events.get_event_callback(ratapi.events.EventTypes.Plot) == [] + assert ratapi.events.get_event_callback(ratapi.events.EventTypes.Message) == [] def test_event_notify() -> None: first_callback = mock.Mock() second_callback = mock.Mock() third_callback = mock.Mock() - RATapi.events.register(RATapi.events.EventTypes.Message, first_callback) - RATapi.events.register(RATapi.events.EventTypes.Plot, second_callback) - RATapi.events.register(RATapi.events.EventTypes.Progress, third_callback) + ratapi.events.register(ratapi.events.EventTypes.Message, first_callback) + ratapi.events.register(ratapi.events.EventTypes.Plot, second_callback) + ratapi.events.register(ratapi.events.EventTypes.Progress, third_callback) - RATapi.events.notify(RATapi.events.EventTypes.Message, "Hello World") + ratapi.events.notify(ratapi.events.EventTypes.Message, "Hello World") first_callback.assert_called_once_with("Hello World") second_callback.assert_not_called() - data = RATapi.events.PlotEventData() - RATapi.events.notify(RATapi.events.EventTypes.Plot, data) + data = ratapi.events.PlotEventData() + ratapi.events.notify(ratapi.events.EventTypes.Plot, data) first_callback.assert_called_once() second_callback.assert_called_once_with(data) - data = RATapi.events.ProgressEventData() - RATapi.events.notify(RATapi.events.EventTypes.Progress, data) + data = ratapi.events.ProgressEventData() + ratapi.events.notify(ratapi.events.EventTypes.Progress, data) first_callback.assert_called_once() second_callback.assert_called_once() third_callback.assert_called_once_with(data) - RATapi.events.clear() - RATapi.events.notify(RATapi.events.EventTypes.Message, "Hello World") - RATapi.events.notify(RATapi.events.EventTypes.Plot, data) + ratapi.events.clear() + ratapi.events.notify(ratapi.events.EventTypes.Message, "Hello World") + ratapi.events.notify(ratapi.events.EventTypes.Plot, data) assert first_callback.call_count == 1 assert second_callback.call_count == 1 assert third_callback.call_count == 1 + + +def test_event_data_pickle(): + data = ratapi.events.ProgressEventData() + data.message = "Hello" + data.percent = 0.5 + pickled_data = pickle.loads(pickle.dumps(data)) + assert pickled_data.message == data.message + assert pickled_data.percent == data.percent + + data = ratapi.events.PlotEventData() + data.modelType = "custom layers" + data.dataPresent = np.ones(2) + data.subRoughs = np.ones((20, 2)) + data.resample = np.ones(2) + data.resampledLayers = [np.ones((20, 2)), np.ones((20, 2))] + data.reflectivity = [np.ones((20, 2)), np.ones((20, 2))] + data.shiftedData = [np.ones((20, 2)), np.ones((20, 2))] + data.sldProfiles = [np.ones((20, 2)), np.ones((20, 2))] + data.contrastNames = ["D2O", "SMW"] + + pickled_data = pickle.loads(pickle.dumps(data)) + + assert pickled_data.modelType == data.modelType + assert (pickled_data.dataPresent == data.dataPresent).all() + assert (pickled_data.subRoughs == data.subRoughs).all() + assert (pickled_data.resample == data.resample).all() + for i in range(2): + assert (pickled_data.resampledLayers[i] == data.resampledLayers[i]).all() + assert (pickled_data.reflectivity[i] == data.reflectivity[i]).all() + assert (pickled_data.shiftedData[i] == data.shiftedData[i]).all() + assert (pickled_data.sldProfiles[i] == data.sldProfiles[i]).all() + assert pickled_data.contrastNames == data.contrastNames diff --git a/tests/test_examples.py b/tests/test_examples.py new file mode 100644 index 00000000..532a5854 --- /dev/null +++ b/tests/test_examples.py @@ -0,0 +1,56 @@ +"""Test the RAT examples.""" + +import importlib +from pathlib import Path + +import pytest + +import ratapi.examples as examples + + +@pytest.mark.parametrize( + "example_name", + [ + "absorption", + "domains_custom_layers", + "domains_custom_XY", + "domains_standard_layers", + "DSPC_custom_layers", + "DSPC_custom_XY", + "DSPC_standard_layers", + "DSPC_data_background", + ], +) +def test_rat_examples(example_name): + """Test that the RAT example projects run successfully.""" + p, r = getattr(examples, example_name)() + assert p is not None + assert r is not None + + +@pytest.mark.parametrize( + "example_name", + [ + "DSPC_function_background", + ], +) +@pytest.mark.skipif(importlib.util.find_spec("matlab") is None, reason="Matlab not installed") +def test_function_background(example_name): + """Test examples which rely on MATLAB engine being installed.""" + p, r = getattr(examples, example_name)() + assert p is not None + assert r is not None + + +@pytest.mark.parametrize( + "example_name", + [ + "convert_rascal", + ], +) +@pytest.mark.skipif(importlib.util.find_spec("matlab") is None, reason="Matlab not installed") +def test_matlab_examples(example_name, temp_dir): + """Test convert_rascal example, directing the output to a temporary directory.""" + p, r = examples.convert_rascal(Path(temp_dir, "lipid_bilayer.mat")) + assert p is not None + assert r is not None diff --git a/tests/test_inputs.py b/tests/test_inputs.py index a3ae2b7e..242d7480 100644 --- a/tests/test_inputs.py +++ b/tests/test_inputs.py @@ -1,17 +1,19 @@ """Test the inputs module.""" import pathlib -from itertools import chain -from unittest import mock +import pickle +import tempfile +from unittest.mock import patch import numpy as np import pytest -import RATapi -import RATapi.wrappers -from RATapi.inputs import check_indices, make_cells, make_controls, make_input, make_problem -from RATapi.rat_core import Cells, Checks, Control, Limits, Priors, ProblemDefinition -from RATapi.utils.enums import ( +import ratapi +import ratapi.wrappers +from ratapi.inputs import FileHandles, check_indices, make_controls, make_input, make_problem +from ratapi.rat_core import Checks, Control, NameStore, ProblemDefinition +from ratapi.utils.enums import ( + BackgroundActions, BoundHandling, Calculations, Display, @@ -19,16 +21,15 @@ 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 = RATapi.Project( - data=RATapi.ClassList([RATapi.models.Data(name="Test Data", data=np.array([[1.0, 1.0, 1.0]]))]), + """Add parameters to the default project for a normal calculation.""" + test_project = ratapi.Project( + data=ratapi.ClassList([ratapi.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") @@ -61,9 +62,9 @@ def standard_layers_project(): @pytest.fixture def domains_project(): """Add parameters to the default project for a domains calculation.""" - test_project = RATapi.Project( + test_project = ratapi.Project( calculation=Calculations.Domains, - data=RATapi.ClassList([RATapi.models.Data(name="Test Data", data=np.array([[1.0, 1.0, 1.0]]))]), + data=ratapi.ClassList([ratapi.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") @@ -93,8 +94,8 @@ def domains_project(): @pytest.fixture def custom_xy_project(): - """Add parameters to the default project for a non polarised calculation and use the custom xy model.""" - test_project = RATapi.Project(model=LayerModels.CustomXY) + """Add parameters to the default project for a normal calculation and use the custom xy model.""" + test_project = ratapi.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") @@ -113,330 +114,215 @@ def custom_xy_project(): @pytest.fixture -def standard_layers_problem(): +def test_names(): + """The expected NameStore object from "standard_layers_project", "domains_project" and "custom_xy_project".""" + names = NameStore() + names.params = ["Substrate Roughness", "Test Thickness", "Test SLD", "Test Roughness"] + names.backgroundParams = ["Background Param 1"] + names.scalefactors = ["Scalefactor 1"] + names.bulkIns = ["SLD Air"] + names.bulkOuts = ["SLD D2O"] + names.resolutionParams = ["Resolution Param 1"] + names.domainRatios = [] + names.contrasts = ["Test Contrast"] + + return names + + +@pytest.fixture +def test_checks(): + """The expected checks object from "standard_layers_project", "domains_project" and "custom_xy_project".""" + checks = Checks() + checks.params = np.array([1, 0, 0, 0]) + checks.backgroundParams = np.array([0]) + checks.scalefactors = np.array([0]) + checks.bulkIns = np.array([0]) + checks.bulkOuts = np.array([0]) + checks.resolutionParams = np.array([0]) + checks.domainRatios = np.array([]) + + return checks + + +@pytest.fixture +def standard_layers_problem(test_names, test_checks): """The expected problem object from "standard_layers_project".""" problem = ProblemDefinition() - problem.TF = Calculations.NonPolarised + problem.TF = Calculations.Normal problem.modelType = LayerModels.StandardLayers problem.geometry = Geometries.AirSubstrate problem.useImaginary = False problem.params = [3.0, 0.0, 0.0, 0.0] - problem.bulkIn = [0.0] - problem.bulkOut = [6.35e-06] - problem.qzshifts = [] + problem.bulkIns = [0.0] + problem.bulkOuts = [6.35e-06] problem.scalefactors = [0.23] - problem.domainRatio = [] + problem.domainRatios = [] problem.backgroundParams = [1e-06] problem.resolutionParams = [0.03] problem.contrastBulkIns = [1] problem.contrastBulkOuts = [1] - problem.contrastQzshifts = [] problem.contrastScalefactors = [1] - problem.contrastBackgroundParams = [1] - problem.contrastBackgroundActions = [1] - problem.contrastResolutionParams = [1] + problem.contrastBackgroundParams = [[1]] + problem.contrastBackgroundActions = [BackgroundActions.Add] + problem.contrastBackgroundTypes = ["constant"] + problem.contrastResolutionParams = [[1]] + problem.contrastResolutionTypes = ["constant"] problem.contrastCustomFiles = [float("NaN")] problem.contrastDomainRatios = [0] problem.resample = [False] problem.dataPresent = [1] - problem.oilChiDataPresent = [0] + problem.data = [np.array([[1.0, 1.0, 1.0, 0.0, 0.0, 0.0]])] + problem.dataLimits = [[1.0, 1.0]] + problem.simulationLimits = [[1.0, 1.0]] problem.numberOfContrasts = 1 problem.numberOfLayers = 1 + problem.repeatLayers = [1] + problem.layersDetails = [[2, 3, 4, float("NaN"), 1]] + problem.contrastLayers = [[1]] problem.numberOfDomainContrasts = 0 + problem.domainContrastLayers = [] 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.priorNames = [ + "Substrate Roughness", + "Test Thickness", + "Test SLD", + "Test Roughness", + "Background Param 1", + "Scalefactor 1", + "SLD Air", + "SLD D2O", + "Resolution Param 1", ] + problem.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], + ] + problem.customFiles = FileHandles([]) + problem.names = test_names + problem.checks = test_checks return problem @pytest.fixture -def domains_problem(): - """The expected problem object from "standard_layers_project".""" +def domains_problem(test_names, test_checks): + """The expected problem object from "domains_project".""" problem = ProblemDefinition() problem.TF = Calculations.Domains problem.modelType = LayerModels.StandardLayers problem.geometry = Geometries.AirSubstrate problem.useImaginary = False problem.params = [3.0, 0.0, 0.0, 0.0] - problem.bulkIn = [0.0] - problem.bulkOut = [6.35e-06] - problem.qzshifts = [] + problem.bulkIns = [0.0] + problem.bulkOuts = [6.35e-06] problem.scalefactors = [0.23] - problem.domainRatio = [0.5] + problem.domainRatios = [0.5] problem.backgroundParams = [1e-06] problem.resolutionParams = [0.03] problem.contrastBulkIns = [1] problem.contrastBulkOuts = [1] - problem.contrastQzshifts = [] problem.contrastScalefactors = [1] - problem.contrastBackgroundParams = [1] - problem.contrastBackgroundActions = [1] - problem.contrastResolutionParams = [1] + problem.contrastBackgroundParams = [[1]] + problem.contrastBackgroundActions = [BackgroundActions.Add] + problem.contrastBackgroundTypes = ["constant"] + problem.contrastResolutionParams = [[1]] + problem.contrastResolutionTypes = ["constant"] problem.contrastCustomFiles = [float("NaN")] problem.contrastDomainRatios = [1] problem.resample = [False] problem.dataPresent = [1] - problem.oilChiDataPresent = [0] + problem.data = [np.array([[1.0, 1.0, 1.0, 0.0, 0.0, 0.0]])] + problem.dataLimits = [[1.0, 1.0]] + problem.simulationLimits = [[1.0, 1.0]] problem.numberOfContrasts = 1 problem.numberOfLayers = 1 + problem.repeatLayers = [1] + problem.layersDetails = [[2, 3, 4, float("NaN"), 1]] + problem.contrastLayers = [[2, 1]] problem.numberOfDomainContrasts = 2 + problem.domainContrastLayers = [[1], [1]] 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.priorNames = [ + "Substrate Roughness", + "Test Thickness", + "Test SLD", + "Test Roughness", + "Background Param 1", + "Scalefactor 1", + "SLD Air", + "SLD D2O", + "Resolution Param 1", + "Domain Ratio 1", + ] + problem.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], ] + problem.customFiles = FileHandles([]) + problem.names = test_names + problem.names.domainRatios = ["Domain Ratio 1"] + problem.checks = test_checks return problem @pytest.fixture -def custom_xy_problem(): +def custom_xy_problem(test_names, test_checks): """The expected problem object from "custom_xy_project".""" problem = ProblemDefinition() - problem.TF = Calculations.NonPolarised + problem.TF = Calculations.Normal problem.modelType = LayerModels.CustomXY problem.geometry = Geometries.AirSubstrate problem.useImaginary = False problem.params = [3.0, 0.0, 0.0, 0.0] - problem.bulkIn = [0.0] - problem.bulkOut = [6.35e-06] - problem.qzshifts = [] + problem.bulkIns = [0.0] + problem.bulkOuts = [6.35e-06] problem.scalefactors = [0.23] - problem.domainRatio = [] + problem.domainRatios = [] problem.backgroundParams = [1e-06] problem.resolutionParams = [0.03] problem.contrastBulkIns = [1] problem.contrastBulkOuts = [1] - problem.contrastQzshifts = [] problem.contrastScalefactors = [1] - problem.contrastBackgroundParams = [1] - problem.contrastBackgroundActions = [1] - problem.contrastResolutionParams = [1] + problem.contrastBackgroundParams = [[1]] + problem.contrastBackgroundActions = [BackgroundActions.Add] + problem.contrastBackgroundTypes = ["constant"] + problem.contrastResolutionParams = [[1]] + problem.contrastResolutionTypes = ["constant"] problem.contrastCustomFiles = [1] problem.contrastDomainRatios = [0] - problem.resample = [False] + problem.resample = [True] problem.dataPresent = [0] - problem.oilChiDataPresent = [0] + problem.data = [np.empty([0, 6])] + problem.dataLimits = [[0.0, 0.0]] + problem.simulationLimits = [[0.005, 0.7]] + problem.repeatLayers = [1] + problem.layersDetails = [] + problem.contrastLayers = [[]] problem.numberOfContrasts = 1 problem.numberOfLayers = 0 problem.numberOfDomainContrasts = 0 + problem.domainContrastLayers = [] 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], - ] - - return problem - - -@pytest.fixture -def standard_layers_cells(): - """The expected cells object from "standard_layers_project".""" - cells = Cells() - cells.f1 = [[0, 1]] - cells.f2 = [np.array([[1.0, 1.0, 1.0]])] - 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.f10 = [] - 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 = [] - cells.f19 = [] - cells.f20 = [] - cells.f21 = ["D2O"] - - return cells - - -@pytest.fixture -def domains_cells(): - """The expected cells object from "domains_project".""" - cells = Cells() - cells.f1 = [[0, 1]] - cells.f2 = [np.array([[1.0, 1.0, 1.0]])] - 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.f10 = [] - 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.f21 = ["D2O"] - - return cells - - -@pytest.fixture -def custom_xy_cells(): - """The expected cells object from "custom_xy_project".""" - cells = Cells() - cells.f1 = [[0, 1]] - cells.f2 = [np.empty([0, 3])] - cells.f3 = [[0.0, 0.0]] - 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.f10 = [] - 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 = [] - cells.f19 = [] - cells.f20 = [] - cells.f21 = ["D2O"] - - return cells - - -@pytest.fixture -def non_polarised_limits(): - """The expected limits object from "standard_layers_project" and "custom_xy_project".""" - limits = Limits() - limits.param = [[1.0, 5.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] - limits.backgroundParam = [[1e-7, 1e-5]] - limits.qzshift = [] - limits.scalefactor = [[0.02, 0.25]] - limits.bulkIn = [[0.0, 0.0]] - limits.bulkOut = [[6.2e-6, 6.35e-6]] - limits.resolutionParam = [[0.01, 0.05]] - limits.domainRatio = [] - - return limits - - -@pytest.fixture -def domains_limits(): - """The expected limits object from "domains_project".""" - limits = Limits() - limits.param = [[1.0, 5.0], [0.0, 0.0], [0.0, 0.0], [0.0, 0.0]] - limits.backgroundParam = [[1e-7, 1e-5]] - limits.qzshift = [] - limits.scalefactor = [[0.02, 0.25]] - limits.bulkIn = [[0.0, 0.0]] - limits.bulkOut = [[6.2e-6, 6.35e-6]] - limits.resolutionParam = [[0.01, 0.05]] - limits.domainRatio = [[0.4, 0.6]] - - return limits - - -@pytest.fixture -def non_polarised_priors(): - """The expected priors object from "standard_layers_project" and "custom_xy_project".""" - priors = Priors() - priors.param = [ - ["Substrate Roughness", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ["Test Thickness", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ["Test SLD", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ["Test Roughness", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ] - priors.backgroundParam = [["Background Param 1", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.qzshift = [] - priors.scalefactor = [["Scalefactor 1", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkIn = [["SLD Air", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkOut = [["SLD D2O", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.resolutionParam = [["Resolution Param 1", RATapi.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], - ] - - return priors - - -@pytest.fixture -def domains_priors(): - """The expected priors object from "domains_project".""" - priors = Priors() - priors.param = [ - ["Substrate Roughness", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ["Test Thickness", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ["Test SLD", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ["Test Roughness", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf], - ] - priors.backgroundParam = [["Background Param 1", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.qzshift = [] - priors.scalefactor = [["Scalefactor 1", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkIn = [["SLD Air", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.bulkOut = [["SLD D2O", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.resolutionParam = [["Resolution Param 1", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.domainRatio = [["Domain Ratio 1", RATapi.utils.enums.Priors.Uniform, 0.0, np.inf]] - priors.priorNames = [ + problem.priorNames = [ "Substrate Roughness", "Test Thickness", "Test SLD", @@ -446,10 +332,8 @@ def domains_priors(): "SLD Air", "SLD D2O", "Resolution Param 1", - "Domain Ratio 1", ] - priors.priorValues = [ - [1, 0.0, np.inf], + problem.priorValues = [ [1, 0.0, np.inf], [1, 0.0, np.inf], [1, 0.0, np.inf], @@ -460,8 +344,13 @@ def domains_priors(): [1, 0.0, np.inf], [1, 0.0, np.inf], ] + problem.customFiles = FileHandles( + [ratapi.models.CustomFile(name="Test Custom File", filename="cpp_test.dll", language="cpp")] + ) + problem.names = test_names + problem.checks = test_checks - return priors + return problem @pytest.fixture @@ -472,8 +361,9 @@ def standard_layers_controls(): controls = Control() controls.procedure = Procedures.Calculate controls.parallel = Parallel.Single - controls.calcSldDuringFit = False - controls.resampleParams = [0.9, 50.0] + controls.numSimulationPoints = 500 + controls.resampleMinAngle = 0.9 + controls.resampleNPoints = 50 controls.display = Display.Iter controls.xTolerance = 1.0e-6 controls.funcTolerance = 1.0e-6 @@ -497,14 +387,6 @@ def standard_layers_controls(): controls.pUnitGamma = 0.2 controls.boundHandling = BoundHandling.Reflect controls.adaptPCR = True - controls.checks.fitParam = [1, 0, 0, 0] - controls.checks.fitBackgroundParam = [0] - controls.checks.fitQzshift = [] - controls.checks.fitScalefactor = [0] - controls.checks.fitBulkIn = [0] - controls.checks.fitBulkOut = [0] - controls.checks.fitResolutionParam = [0] - controls.checks.fitDomainRatio = [] return controls @@ -517,8 +399,9 @@ def custom_xy_controls(): controls = Control() controls.procedure = Procedures.Calculate controls.parallel = Parallel.Single - controls.calcSldDuringFit = True - controls.resampleParams = [0.9, 50.0] + controls.numSimulationPoints = 500 + controls.resampleMinAngle = 0.9 + controls.resampleNPoints = 50.0 controls.display = Display.Iter controls.xTolerance = 1.0e-6 controls.funcTolerance = 1.0e-6 @@ -542,116 +425,44 @@ def custom_xy_controls(): controls.pUnitGamma = 0.2 controls.boundHandling = BoundHandling.Reflect controls.adaptPCR = True - controls.checks.fitParam = [1, 0, 0, 0] - controls.checks.fitBackgroundParam = [0] - controls.checks.fitQzshift = [] - controls.checks.fitScalefactor = [0] - controls.checks.fitBulkIn = [0] - controls.checks.fitBulkOut = [0] - controls.checks.fitResolutionParam = [0] - controls.checks.fitDomainRatio = [] return controls -@pytest.fixture -def test_checks(): - """The expected checks object from "standard_layers_project", "domains_project" and "custom_xy_project".""" - checks = Checks() - checks.fitParam = [1, 0, 0, 0] - checks.fitBackgroundParam = [0] - checks.fitQzshift = [] - checks.fitScalefactor = [0] - checks.fitBulkIn = [0] - checks.fitBulkOut = [0] - checks.fitResolutionParam = [0] - checks.fitDomainRatio = [] - - return checks - - @pytest.mark.parametrize( - ["test_project", "test_problem", "test_cells", "test_limits", "test_priors", "test_controls"], + ["test_project", "test_problem", "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 +def test_make_input(test_project, test_problem, test_controls, request) -> None: + """When converting the "project" and "controls", we should obtain the two input objects required for the compiled RAT code. """ test_project = request.getfixturevalue(test_project) test_problem = request.getfixturevalue(test_problem) - test_cells = request.getfixturevalue(test_cells) - test_limits = request.getfixturevalue(test_limits) - test_priors = request.getfixturevalue(test_priors) test_controls = request.getfixturevalue(test_controls) - parameter_fields = [ - "param", - "backgroundParam", - "scalefactor", - "qzshift", - "bulkIn", - "bulkOut", - "resolutionParam", - "domainRatio", - ] - - mocked_matlab_future = mock.MagicMock() - mocked_engine = mock.MagicMock() - mocked_matlab_future.result.return_value = mocked_engine - - with mock.patch.object( - RATapi.wrappers.MatlabWrapper, - "loader", - mocked_matlab_future, - ), mock.patch.object(RATapi.rat_core, "DylibEngine", mock.MagicMock()), mock.patch.object( - RATapi.inputs, - "get_python_handle", - mock.MagicMock(return_value=dummy_function), - ), mock.patch.object( - RATapi.wrappers.MatlabWrapper, - "getHandle", - mock.MagicMock(return_value=dummy_function), - ), mock.patch.object(RATapi.wrappers.DylibWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)): - problem, cells, limits, priors, controls = make_input(test_project, RATapi.Controls()) + problem, controls = make_input(test_project, ratapi.Controls()) + problem = pickle.loads(pickle.dumps(problem)) check_problem_equal(problem, test_problem) - check_cells_equal(cells, test_cells) - - for limit_field in parameter_fields: - assert (getattr(limits, limit_field) == getattr(test_limits, limit_field)).all() - - for prior_field in parameter_fields: - assert getattr(priors, prior_field) == getattr(test_priors, prior_field) - - assert priors.priorNames == test_priors.priorNames - assert (priors.priorValues == test_priors.priorValues).all() + controls = pickle.loads(pickle.dumps(controls)) check_controls_equal(controls, test_controls) @@ -672,129 +483,224 @@ 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", - ], -) -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) +@pytest.mark.parametrize("test_problem", ["standard_layers_problem", "custom_xy_problem", "domains_problem"]) +class TestCheckIndices: + """Tests for check_indices over a set of three test problems.""" - check_indices(test_problem) + def test_check_indices(self, test_problem, request) -> None: + """The check_indices routine should not raise errors for a properly defined ProblemDefinition object.""" + test_problem = request.getfixturevalue(test_problem) + 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_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", - } + @pytest.mark.parametrize( + "index_list", + [ + "contrastBulkIns", + "contrastBulkOuts", + "contrastScalefactors", + "contrastDomainRatios", + ], + ) + @pytest.mark.parametrize("bad_value", ([0.0], [2.0])) + def test_check_indices_error(self, 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": "bulkIns", + "contrastBulkOuts": "bulkOuts", + "contrastScalefactors": "scalefactors", + "contrastDomainRatios": "domainRatios", + } + if (test_problem != "domains_problem") and (index_list == "contrastDomainRatios"): + # we expect this to not raise an error for non-domains problems as domainRatios is empty + pytest.xfail() + + 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 lies ' + f'outside of the range of "{param_list[index_list]}"', + ): + check_indices(test_problem) + + @pytest.mark.parametrize("background_type", ["constant", "data", "function"]) + @pytest.mark.parametrize("bad_value", ([[0.0]], [[2.0]])) + def test_background_params_source_indices(self, test_problem, background_type, bad_value, request): + """check_indices should raise an IndexError for bad sources in the nested list contrastBackgroundParams.""" + test_problem = request.getfixturevalue(test_problem) + test_problem.contrastBackgroundParams = bad_value + test_problem.contrastBackgroundTypes = [background_type] + + source_param_lists = { + "constant": "backgroundParams", + "data": "data", + "function": "customFiles", + } + + with pytest.raises( + IndexError, + match=f'Entry 0 of contrastBackgroundParams has type "{background_type}" ' + f"and source index {bad_value[0][0]}, " + f'which is outside the range of "{source_param_lists[background_type]}".', + ): + check_indices(test_problem) + + @pytest.mark.parametrize( + "bad_value", + ( + [[1.0, 0.0]], + [[1.0, 2.0]], + [[1.0, 1.0, 2.0]], + [[1.0], [1.0, 0.0]], + ), + ) + def test_background_params_value_indices(self, test_problem, bad_value, request): + """check_indices should raise an IndexError for bad values in the nested list contrastBackgroundParams.""" + test_problem = request.getfixturevalue(test_problem) + test_problem.contrastBackgroundParams = bad_value + + if len(bad_value) > 1: + test_problem.contrastBackgroundTypes.append("constant") + + with pytest.raises( + IndexError, + match=f"Entry {len(bad_value) - 1} of contrastBackgroundParams contains: {bad_value[-1][-1]}" + f', which lies outside of the range of "backgroundParams"', + ): + check_indices(test_problem) + + +@pytest.mark.parametrize("test_project", ["standard_layers_project", "custom_xy_project", "domains_project"]) +@pytest.mark.parametrize("field", ["data", "background", "bulk_in", "bulk_out", "scalefactor", "resolution"]) +def test_undefined_contrast_fields(test_project, field, request): + """If a field in a contrast is empty, we should raise an error.""" + test_project = request.getfixturevalue(test_project) + setattr(test_project.contrasts[0], field, "") - test_problem = request.getfixturevalue(test_problem) - setattr(test_problem, index_list, bad_value) + with pytest.raises( + ValueError, + match=f'In the input project, the "{field}" field of contrast ' + f'"{test_project.contrasts[0].name}" does not have a value defined. ' + f"A value must be supplied before running the project.", + ): + make_problem(test_project) + + +@pytest.mark.parametrize("test_project", ["standard_layers_project", "custom_xy_project", "domains_project"]) +def test_undefined_background(test_project, request): + """If the source field of a background defined in a contrast is empty, we should raise an error.""" + test_project = request.getfixturevalue(test_project) + background = test_project.backgrounds[test_project.contrasts[0].background] + background.source = "" 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]}"', + ValueError, + match=f"All backgrounds must have a source defined. For a {background.type} type " + f"background, the source must be defined in " + f'"{ratapi.project.values_defined_in[f"backgrounds.{background.type}.source"]}"', ): - check_indices(test_problem) + make_problem(test_project) -@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.""" +@pytest.mark.parametrize("test_project", ["standard_layers_project", "custom_xy_project", "domains_project"]) +def test_undefined_resolution(test_project, request): + """If the source field of a resolution defined in a contrast is empty, we should raise an error.""" + test_project = request.getfixturevalue(test_project) + resolution = test_project.resolutions[test_project.contrasts[0].resolution] + resolution.source = "" + + with pytest.raises( + ValueError, + match=f"Constant resolutions must have a source defined. The source must be defined in " + f'"{ratapi.project.values_defined_in[f"resolutions.{resolution.type}.source"]}"', + ): + make_problem(test_project) + + +@pytest.mark.parametrize("test_project", ["standard_layers_project", "domains_project"]) +@pytest.mark.parametrize("field", ["thickness", "SLD", "roughness"]) +def test_undefined_layers(test_project, field, request): + """If the thickness, SLD, or roughness fields of a layer defined in the project are empty, we should raise an + error.""" test_project = request.getfixturevalue(test_project) - test_cells = request.getfixturevalue(test_cells) - - mocked_matlab_future = mock.MagicMock() - mocked_engine = mock.MagicMock() - mocked_matlab_future.result.return_value = mocked_engine - with mock.patch.object( - RATapi.wrappers.MatlabWrapper, - "loader", - mocked_matlab_future, - ), mock.patch.object(RATapi.rat_core, "DylibEngine", mock.MagicMock()), mock.patch.object( - RATapi.inputs, - "get_python_handle", - mock.MagicMock(return_value=dummy_function), - ), mock.patch.object( - RATapi.wrappers.MatlabWrapper, - "getHandle", - mock.MagicMock(return_value=dummy_function), - ), mock.patch.object(RATapi.wrappers.DylibWrapper, "getHandle", mock.MagicMock(return_value=dummy_function)): - cells = make_cells(test_project) - - check_cells_equal(cells, test_cells) + setattr(test_project.layers[0], field, "") + + with pytest.raises( + ValueError, + match=f'In the input project, the "{field}" field of layer {test_project.layers[0].name} ' + f"does not have a value defined. A value must be supplied before running the project.", + ): + make_problem(test_project) + + +def test_append_data_background(): + """Test that background data is correctly added to contrast data.""" + data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + background = np.array([[1, 10, 11], [4, 12, 13], [7, 14, 15]]) + + result = ratapi.inputs.append_data_background(data, background) + np.testing.assert_allclose(result, np.array([[1, 2, 3, 0, 10, 11], [4, 5, 6, 0, 12, 13], [7, 8, 9, 0, 14, 15]])) + + +def test_append_data_background_res(): + """Test that background data is correctly added to contrast data when a resolution is in the data.""" + data = np.array([[1, 2, 3, 4], [4, 5, 6, 6], [7, 8, 9, 72]]) + background = np.array([[1, 10, 11], [4, 12, 13], [7, 14, 15]]) + + result = ratapi.inputs.append_data_background(data, background) + np.testing.assert_allclose(result, np.array([[1, 2, 3, 4, 10, 11], [4, 5, 6, 6, 12, 13], [7, 8, 9, 72, 14, 15]])) + + +def test_append_data_background_error(): + """Test that append_data_background raises an error if the q-values are not equal.""" + data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) + background = np.array([[56, 10, 11], [41, 12, 13], [7, 14, 15]]) + + with pytest.raises(ValueError, match=("The q-values of the data and background must be equal.")): + ratapi.inputs.append_data_background(data, background) def test_get_python_handle(): - path = pathlib.Path(__file__).parent.resolve() - assert RATapi.inputs.get_python_handle("utils.py", "dummy_function", path).__code__ == dummy_function.__code__ + path = pathlib.Path(__file__).parent + assert ratapi.inputs.get_python_handle("utils.py", "dummy_function", path).__code__ == dummy_function.__code__ -def test_make_controls(standard_layers_controls, test_checks) -> None: +def test_make_controls(standard_layers_controls) -> None: """The controls object should contain the full set of controls parameters, with the appropriate set defined by the input controls. """ - controls = make_controls(RATapi.Controls(), test_checks) + controls = make_controls(ratapi.Controls()) check_controls_equal(controls, standard_layers_controls) +@patch("ratapi.wrappers.MatlabWrapper") +def test_file_handles(wrapper): + handle = FileHandles([ratapi.models.CustomFile(name="Test Custom File", filename="cpp_test.dll", language="cpp")]) + + with pytest.raises(FileNotFoundError, match="The custom file \\(Test Custom File\\) does not have a valid path."): + handle.get_handle(0) + + with tempfile.NamedTemporaryFile("w", suffix=".dll") as f: + tmp_file = pathlib.Path(f.name) + handle.files[0]["path"] = tmp_file.parent + handle.files[0]["filename"] = tmp_file.name + handle.files[0]["function_name"] = "" + # No function name should throw exception + with pytest.raises( + ValueError, match="The custom file \\(Test Custom File\\) does not have a valid function name." + ): + handle.get_handle(0) + + # Matlab does not need function name + handle.files[0]["language"] = "matlab" + handle.get_handle(0) + wrapper.assert_called() + + def check_problem_equal(actual_problem, expected_problem) -> None: """Compare two instances of the "problem" object for equality.""" scalar_fields = [ @@ -805,20 +711,19 @@ def check_problem_equal(actual_problem, expected_problem) -> None: "numberOfContrasts", "numberOfLayers", "numberOfDomainContrasts", + "priorNames", ] array_fields = [ "params", "backgroundParams", - "qzshifts", "scalefactors", - "bulkIn", - "bulkOut", + "bulkIns", + "bulkOuts", "resolutionParams", - "domainRatio", + "domainRatios", "contrastBackgroundParams", "contrastBackgroundActions", - "contrastQzshifts", "contrastScalefactors", "contrastBulkIns", "contrastBulkOuts", @@ -826,48 +731,60 @@ def check_problem_equal(actual_problem, expected_problem) -> None: "contrastDomainRatios", "resample", "dataPresent", - "oilChiDataPresent", + "dataLimits", + "simulationLimits", + "repeatLayers", + "contrastLayers", + "domainContrastLayers", "fitParams", - "otherParams", "fitLimits", - "otherLimits", + "priorValues", + ] + checks_fields = [ + "params", + "backgroundParams", + "scalefactors", + "bulkIns", + "bulkOuts", + "resolutionParams", + "domainRatios", ] + names_fields = [*checks_fields, "contrasts"] for scalar_field in scalar_fields: assert getattr(actual_problem, scalar_field) == getattr(expected_problem, scalar_field) for array_field in array_fields: - assert (getattr(actual_problem, array_field) == getattr(expected_problem, array_field)).all() + assert np.all(getattr(actual_problem, array_field) == getattr(expected_problem, array_field)) + for field in names_fields: + assert getattr(actual_problem.names, field) == getattr(expected_problem.names, field) + for field in checks_fields: + assert (getattr(actual_problem.checks, field) == getattr(expected_problem.checks, field)).all() + + # Data field is a numpy array + assert [ + actual_data == expected_data + for (actual_data, expected_data) in zip(actual_problem.data, expected_problem.data, strict=False) + ] + + # Need to account for "NaN" entries in layersDetails and contrastCustomFiles field + for actual_layer, expected_layer in zip(actual_problem.layersDetails, expected_problem.layersDetails, strict=False): + assert (actual_layer == expected_layer) or ["NaN" if np.isnan(el) else el for el in actual_layer] == [ + "NaN" if np.isnan(el) else el for el in expected_layer + ] - # 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] -def check_cells_equal(actual_cells, expected_cells) -> None: - """Compare two instances of the "cells" object for equality.""" - 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): - 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] - - for index in chain(range(3, 6), range(7, 21)): - field = f"f{index}" - assert getattr(actual_cells, field) == getattr(expected_cells, field) - - 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", + "numSimulationPoints", + "resampleMinAngle", + "resampleNPoints", "display", "xTolerance", "funcTolerance", @@ -892,20 +809,6 @@ def check_controls_equal(actual_controls, expected_controls) -> None: "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() for field in controls_fields: 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() diff --git a/tests/test_models.py b/tests/test_models.py index 1a901af0..4343b442 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,30 +1,30 @@ """Test the pydantic models.""" import re -from typing import Callable +from collections.abc import Callable import numpy as np import pydantic import pytest -import RATapi.models +import ratapi.models @pytest.mark.parametrize( ["model", "model_name", "model_params"], [ - (RATapi.models.Background, "Background", {}), - (RATapi.models.Contrast, "Contrast", {}), - (RATapi.models.CustomFile, "Custom File", {}), - (RATapi.models.Data, "Data", {}), - (RATapi.models.DomainContrast, "Domain Contrast", {}), + (ratapi.models.Background, "Background", {}), + (ratapi.models.Contrast, "Contrast", {}), + (ratapi.models.CustomFile, "Custom File", {}), + (ratapi.models.Data, "Data", {}), + (ratapi.models.DomainContrast, "Domain Contrast", {}), ( - RATapi.models.Layer, + ratapi.models.Layer, "Layer", {"thickness": "Test Thickness", "SLD": "Test SLD", "roughness": "Test Roughness"}, ), - (RATapi.models.Parameter, "Parameter", {}), - (RATapi.models.Resolution, "Resolution", {}), + (ratapi.models.Parameter, "Parameter", {}), + (ratapi.models.Resolution, "Resolution", {}), ], ) def test_default_names(model: Callable, model_name: str, model_params: dict) -> None: @@ -32,28 +32,37 @@ def test_default_names(model: Callable, model_name: str, model_params: dict) -> format: "New ". """ model_1 = model(**model_params) + prefix = f"New {model_name} " + assert model_1.name.startswith(prefix) + index = int(model_1.name[len(prefix) :]) + model_2 = model(**model_params) model_3 = model(name="Given Name", **model_params) model_4 = model(**model_params) - assert model_1.name == f"New {model_name} 1" - assert model_2.name == f"New {model_name} 2" + assert model_1.name == f"New {model_name} {index}" + assert model_2.name == f"New {model_name} {index + 1}" assert model_3.name == "Given Name" - assert model_4.name == f"New {model_name} 3" + assert model_4.name == f"New {model_name} {index + 2}" + + # If user adds name in similar format. The next auto number will take it into account. + model(name=f"{prefix}{index + 20}", **model_params) + model_5 = model(**model_params) + assert model_5.name == f"New {model_name} {index + 21}" @pytest.mark.parametrize( ["model", "model_params"], [ - (RATapi.models.Background, {}), - (RATapi.models.Contrast, {}), - (RATapi.models.ContrastWithRatio, {}), - (RATapi.models.CustomFile, {}), - (RATapi.models.Data, {}), - (RATapi.models.DomainContrast, {}), - (RATapi.models.Layer, {"thickness": "Test Thickness", "SLD": "Test SLD", "roughness": "Test Roughness"}), + (ratapi.models.Background, {}), + (ratapi.models.Contrast, {}), + (ratapi.models.ContrastWithRatio, {}), + (ratapi.models.CustomFile, {}), + (ratapi.models.Data, {}), + (ratapi.models.DomainContrast, {}), + (ratapi.models.Layer, {"thickness": "Test Thickness", "SLD": "Test SLD", "roughness": "Test Roughness"}), ( - RATapi.models.AbsorptionLayer, + ratapi.models.AbsorptionLayer, { "thickness": "Test Thickness", "SLD_real": "Test SLD", @@ -61,8 +70,8 @@ def test_default_names(model: Callable, model_name: str, model_params: dict) -> "roughness": "Test Roughness", }, ), - (RATapi.models.Parameter, {}), - (RATapi.models.Resolution, {}), + (ratapi.models.Parameter, {}), + (ratapi.models.Resolution, {}), ], ) class TestModels: @@ -70,7 +79,7 @@ def test_initialise_with_wrong_type(self, model: Callable, model_params: dict) - """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 " f"Input should be a valid string", + match=f"1 validation error for {model.__name__}\nname\n Input should be a valid string", ): model(name=1, **model_params) @@ -79,7 +88,7 @@ def test_assignment_with_wrong_type(self, model: Callable, model_params: dict) - test_model = model(**model_params) with pytest.raises( pydantic.ValidationError, - match=f"1 validation error for {model.__name__}\nname\n " f"Input should be a valid string", + match=f"1 validation error for {model.__name__}\nname\n Input should be a valid string", ): test_model.name = 1 @@ -87,7 +96,7 @@ def test_initialise_with_zero_length_name(self, model: Callable, model_params: d """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 " f"String should have at least 1 character", + match=f"1 validation error for {model.__name__}\nname\n String should have at least 1 character", ): model(name="", **model_params) @@ -95,7 +104,7 @@ def test_initialise_with_extra_fields(self, model: Callable, model_params: dict) """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 " f"Extra inputs are not permitted", + match=f"1 validation error for {model.__name__}\nnew_field\n Extra inputs are not permitted", ): model(new_field=1, **model_params) @@ -104,7 +113,7 @@ 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 RATapi.models.Data().__eq__("data") == NotImplemented + assert ratapi.models.Data().__eq__("data") == NotImplemented @pytest.mark.parametrize( @@ -117,7 +126,7 @@ 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. """ - test_data = RATapi.models.Data(data=input_data) + test_data = ratapi.models.Data(data=input_data) assert (test_data.data == input_data).all() @@ -134,9 +143,9 @@ def test_data_too_few_dimensions(input_data: np.ndarray[float]) -> None: """ with pytest.raises( pydantic.ValidationError, - match='1 validation error for Data\ndata\n Value error, "data" must ' "have at least two dimensions", + match='1 validation error for Data\ndata\n Value error, "data" must have at least two dimensions', ): - RATapi.models.Data(data=input_data) + ratapi.models.Data(data=input_data) @pytest.mark.parametrize( @@ -153,9 +162,9 @@ def test_data_too_few_values(input_data: np.ndarray[float]) -> None: """ with pytest.raises( pydantic.ValidationError, - match='1 validation error for Data\ndata\n Value error, "data" must ' "have at least three columns", + match='1 validation error for Data\ndata\n Value error, "data" must have at least three columns', ): - RATapi.models.Data(data=input_data) + ratapi.models.Data(data=input_data) @pytest.mark.parametrize( @@ -166,8 +175,8 @@ def test_data_too_few_values(input_data: np.ndarray[float]) -> None: ) 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 RATapi.models.Data(data_range=input_range).data_range == input_range - assert RATapi.models.Data(simulation_range=input_range).simulation_range == input_range + assert ratapi.models.Data(data_range=input_range).data_range == input_range + assert ratapi.models.Data(simulation_range=input_range).simulation_range == input_range @pytest.mark.parametrize( @@ -184,11 +193,11 @@ def test_two_values_in_data_range(input_range: list[float]) -> None: """ 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)}', + 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)}", ): - RATapi.models.Data(data_range=input_range) + ratapi.models.Data(data_range=input_range) @pytest.mark.parametrize( @@ -205,11 +214,11 @@ def test_two_values_in_simulation_range(input_range: list[float]) -> None: """ 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)}', + 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)}", ): - RATapi.models.Data(simulation_range=input_range) + ratapi.models.Data(simulation_range=input_range) @pytest.mark.parametrize( @@ -228,14 +237,14 @@ def test_min_max_in_range(field: str) -> None: match=f"1 validation error for Data\n{field}\n Value error, {field} " f'"min" value is greater than the "max" value', ): - RATapi.models.Data(**{field: [1.0, 0.0]}) + ratapi.models.Data(**{field: [1.0, 0.0]}) def test_default_ranges() -> None: """If "data" is specified but either the "data_range" or "simulation_range" fields are not, we set the ranges to the minimum and maximum values of the first column of the data. """ - test_data = RATapi.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]])) + test_data = ratapi.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]])) assert test_data.data_range == [1.0, 3.0] assert test_data.simulation_range == [1.0, 3.0] @@ -260,7 +269,7 @@ def test_data_range(test_range) -> None: f"the min/max values of the data: [1.0, 3.0]", ), ): - RATapi.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]]), data_range=test_range) + ratapi.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]]), data_range=test_range) @pytest.mark.parametrize( @@ -284,7 +293,7 @@ def test_simulation_range(test_range) -> None: f"[1.0, 3.0]", ), ): - RATapi.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]]), simulation_range=test_range) + ratapi.models.Data(data=np.array([[1.0, 0.0, 0.0], [3.0, 0.0, 0.0]]), simulation_range=test_range) @pytest.mark.parametrize( @@ -305,4 +314,79 @@ def test_parameter_range(minimum: float, value: float, maximum: float) -> None: f"{float(value)} is not within the defined range: " f"{float(minimum)} <= value <= {float(maximum)}", ): - RATapi.models.Parameter(min=minimum, value=value, max=maximum) + ratapi.models.Parameter(min=minimum, value=value, max=maximum) + + +def test_layer_bad_imaginary_SLD(): + """If 'SLD_imaginary' is given to a Layer, it should raise a descriptive ValidationError.""" + with pytest.raises( + pydantic.ValidationError, + match=( + "1 validation error for Layer\n" + " Value error, The Layer class does not support imaginary SLD." + " Use the AbsorptionLayer class instead." + ), + ): + ratapi.models.Layer(name="My Layer", SLD_imaginary="bad sld") + + +def test_contrast_bad_ratio(): + """If 'domain_ratios' is given to a Contrast, it should raise a descriptive ValidationError.""" + with pytest.raises( + pydantic.ValidationError, + match=( + "1 validation error for Contrast\n" + " Value error, The Contrast class does not support domain ratios." + " Use the ContrastWithRatio class instead." + ), + ): + ratapi.models.Contrast(name="My Contrast", domain_ratio="bad ratio") + + +@pytest.mark.parametrize( + ["model", "type", "values"], + [ + (ratapi.models.Background, "function", ["val1", "val2", "val3", "val4", "val5"]), + (ratapi.models.Resolution, "constant", ["", "", "", "", ""]), + ], +) +def test_type_change_clear(model, type, values): + """If the type of a background or resolution is changed, it should wipe the other fields and warn the user.""" + model_instance = model( + name="Test", + type=type, + source="src", + value_1=values[0], + value_2=values[1], + value_3=values[2], + value_4=values[3], + value_5=values[4], + ) + + with pytest.warns(UserWarning, match="Changing the type of Test clears its source and value fields."): + model_instance.type = "data" + for attr in ["source", "value_1", "value_2", "value_3", "value_4", "value_5"]: + assert getattr(model_instance, attr) == "" + + +@pytest.mark.parametrize( + ["model", "signal_type", "values"], + [ + (ratapi.models.Background, "constant", ["value_1", "value_2", "value_3", "value_4", "value_5"]), + (ratapi.models.Background, "data", ["value_2", "value_3", "value_4", "value_5"]), + (ratapi.models.Resolution, "constant", ["value_1", "value_2", "value_3", "value_4", "value_5"]), + (ratapi.models.Resolution, "data", ["value_1", "value_2", "value_3", "value_4", "value_5"]), + ], +) +def test_unsupported_parameters_error(model, signal_type, values): + """If a value is inputted for an unsupported field for a particular type of background or resolution then we should + raise an error.""" + for value in values: + with pytest.raises( + pydantic.ValidationError, + match=( + f"1 validation error for {model.__name__}\n Value error, The following values are not supported" + f' by the "{signal_type}" {model.__name__} type: {value}' + ), + ): + model(**{"type": signal_type, value: "unsupported"}) diff --git a/tests/test_orso_utils.py b/tests/test_orso_utils.py new file mode 100644 index 00000000..60f04494 --- /dev/null +++ b/tests/test_orso_utils.py @@ -0,0 +1,122 @@ +"""Tests for the ratapi.utils.orso module.""" + +import os +from io import StringIO +from pathlib import Path + +import numpy as np +import pytest +from orsopy.fileio.model_language import SampleModel + +from ratapi.examples.bayes_benchmark.bayes_benchmark import get_project +from ratapi.project import Project +from ratapi.utils.orso import ORSOProject, orso_model_to_rat + +TEST_DIR_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data") + + +@pytest.fixture +def bare_subs(): + """The bare substrate project from the Bayes Benchmark example.""" + return get_project() + + +@pytest.fixture +def prist(): + """The project from the model data from prist5_10K_m_025.Rqz.ort""" + return Project.load(Path(TEST_DIR_PATH, "prist.json")) + + +@pytest.mark.parametrize( + "model", + [ + "air | FeO2 0.75 | Fe 10 | Si", + "vacuum | 5 (O3 3 | He2 4) | SiO2 0.75 | Si", + "Si | 5 (O2 2 | 3 (D2O 1 | H2O 1)) | air", + ], +) +@pytest.mark.parametrize("absorption", [True, False]) +@pytest.mark.skip(reason="orsopy database website (https://slddb.esss.dk/slddb/) is not available") +def test_orso_model_to_rat(model, absorption): + """Test that orso_model_to_rat gives the expected parameters, layers and model.""" + + expected = SampleModel(model).resolve_to_layers()[1:-1] + expected_layers = [layer.material.formula for layer in expected] + expected_thicknesses = {layer.material.formula: layer.thickness for layer in expected} + expected_roughnesses = {layer.material.formula: layer.roughness for layer in expected} + actual = orso_model_to_rat(model, absorption=absorption) + + assert actual.model == expected_layers + + for layer in actual.layers: + assert layer.name in expected_layers + for layer in expected_layers: + assert layer in [actual_layer.name for actual_layer in actual.layers] + + expected_parameters = [] + # get set of parameters + for layer in set(expected_layers): + expected_parameters.extend([f"{layer} Thickness", f"{layer} Roughness", f"{layer} SLD"]) + if absorption: + expected_parameters.append(f"{layer} SLD imaginary") + + assert actual.parameters[f"{layer} Thickness"].value == expected_thicknesses[layer].as_unit("angstrom") + assert actual.parameters[f"{layer} Roughness"].value == expected_roughnesses[layer].as_unit("angstrom") + + assert set(p.name for p in actual.parameters) == set(expected_parameters) + + +@pytest.mark.parametrize( + "test_data", + [ + "bare_substrate.ort", + "prist5_10K_m_025.Rqz.ort", + ], +) +@pytest.mark.skip(reason="orsopy database website (https://slddb.esss.dk/slddb/) is not available") +def test_load_ort_data(test_data): + """Test that .ort data is loaded correctly.""" + # manually get the test data for comparison + data_strings = [""] + parsing_data = False + with Path(TEST_DIR_PATH, test_data).open() as file: + for line in file: + if line[0] == "#": + if parsing_data: + parsing_data = False + data_strings.append("") + else: + continue + else: + parsing_data = True + data_strings[-1] += line + + expected_data = list(map(lambda s: np.loadtxt(StringIO(s)), data_strings)) + actual_data = ORSOProject(Path(TEST_DIR_PATH, test_data)).data + + assert len(actual_data) == len(expected_data) + for actual_dataset, expected_dataset in zip(actual_data, expected_data, strict=False): + np.testing.assert_array_equal(actual_dataset.data, expected_dataset) + + +@pytest.mark.parametrize( + "test_data, expected_data", + [ + ["bare_substrate.ort", "bare_substrate.json"], + ["prist5_10K_m_025.Rqz.ort", "prist.json"], + ], +) +@pytest.mark.skip(reason="orsopy database website (https://slddb.esss.dk/slddb/) is not available") +def test_load_ort_project(test_data, expected_data): + """Test that a project with model data is loaded correctly.""" + ort_data = ORSOProject(Path(TEST_DIR_PATH, test_data)) + sample = ort_data.samples[0] + exp_project = Project.load(Path(TEST_DIR_PATH, expected_data)) + + for class_list in ["bulk_in", "bulk_out"]: + assert getattr(sample, class_list) == getattr(exp_project, class_list)[0] + assert sample.parameters == exp_project.parameters[1:] + assert sample.layers == exp_project.layers + + for data, exp_data in zip(ort_data.data, exp_project.data[1:], strict=False): + np.testing.assert_array_equal(data.data, exp_data.data) diff --git a/tests/test_orso_validation.py b/tests/test_orso_validation.py new file mode 100644 index 00000000..a7ed22f5 --- /dev/null +++ b/tests/test_orso_validation.py @@ -0,0 +1,84 @@ +import os +import pathlib +import tempfile + +import numpy as np +import pytest + +import ratapi as RAT + +TEST_FUNC = """import pathlib +import numpy as np + + +def run_func(params, bulk_in, bulk_out, contrast): + layers = np.loadtxt("{layers_file_path}") + + # Change the units to Ã… + layers[:, 1:3] = layers[:, 1:3] * 1e-6 + + # Returns layers only, bulk in and bulk out added to project + return layers[1:-1, :], params[0] +""" + + +@pytest.mark.parametrize( + "layer_index", + [0, 1, 2, 3, 6, 7], +) +def test_orso_validation(layer_index): + data_path = pathlib.Path(__file__).parent / "test_data" / "ORSO" + + problem = RAT.Project(name="test", model="custom layers", absorption=True) + problem.scalefactors.set_fields(0, min=1, value=1, max=1) + problem.background_parameters.set_fields(0, min=0, value=0, max=0) + problem.resolution_parameters.set_fields(0, min=0, value=0, max=0) + + # Write a custom file that reads the ORSO layers. + filename = data_path / f"test{layer_index}.layers" + with tempfile.NamedTemporaryFile("w+", suffix=".py", delete=False) as f: + f.write(TEST_FUNC.format(layers_file_path=filename.as_posix())) + f.flush() + + layers = np.loadtxt(filename) + sub_rough = layers[-1, -1] + + # Change the units to Ã… + bulk_in = layers[0, 1] * 1e-6 + bulk_out = layers[-1, 1] * 1e-6 + + problem.parameters.set_fields(0, min=sub_rough, value=sub_rough, max=sub_rough) + problem.bulk_in.set_fields(0, name="Bulk In", min=bulk_in, value=bulk_in, max=bulk_in, fit=False) + problem.bulk_out.set_fields(0, name="Bulk Out", min=bulk_out, value=bulk_out, max=bulk_out, fit=False) + + data = np.loadtxt(data_path / f"test_{layer_index}.dat") + problem.data.append(name="Data", data=data) + + problem.custom_files.append( + name="Model", + filename=pathlib.Path(f.name).name, + language="python", + path=pathlib.Path(f.name).parent, + function_name="run_func", + ) + + problem.contrasts.append( + name="ORSO Contrast", + background="Background 1", + background_action="add", + resolution="Resolution 1", + scalefactor="Scalefactor 1", + bulk_out="Bulk Out", + bulk_in="Bulk In", + data="Data", + resample=False, + model=["Model"], + ) + + controls = RAT.Controls() + problem, results = RAT.run(problem, controls) + total_error = sum((results.reflectivity[0][:, 1] - results.shiftedData[0][:, 1]) ** 2) + + assert total_error < 1e-10 + f.close() + os.remove(f.name) diff --git a/tests/test_outputs.py b/tests/test_outputs.py index ed4df65d..7d2afff9 100644 --- a/tests/test_outputs.py +++ b/tests/test_outputs.py @@ -3,13 +3,16 @@ We use the example for both a reflectivity calculation, and Bayesian analysis using the Dream algorithm. """ +import tempfile +from pathlib import Path + import numpy as np import pytest -import RATapi -import RATapi.outputs -import RATapi.rat_core -from RATapi.utils.enums import Procedures +import ratapi +import ratapi.outputs +import ratapi.rat_core +from ratapi.utils.enums import Procedures from tests.utils import check_results_equal @@ -22,19 +25,19 @@ def reflectivity_calculation_str(): "reflectivity = [Data array: [21 x 2], Data array: [21 x 2]],\n" "simulation = [Data array: [21 x 2], Data array: [21 x 2]],\n" "shiftedData = [Data array: [21 x 3], Data array: [21 x 3]],\n" - "layerSlds = [[Data array: [8 x 3]], [Data array: [8 x 3]]],\n" + "backgrounds = [Data array: [82 x 3], Data array: [82 x 3]],\n" + "resolutions = [Data array: [82 x 2], Data array: [82 x 2]],\n" "sldProfiles = [[Data array: [25 x 2], Data array: [25 x 2]]],\n" + "layers = [[Data array: [8 x 3]], [Data array: [8 x 3]]],\n" "resampledLayers = [[Data array: [1 x 3]], [Data array: [1 x 3]]],\n" "calculationResults = CalculationResults(\n" "\tchiValues = [ 202.83057377 1641.4024969 ],\n" "\tsumChi = 1844.2330706690975,\n" "),\n" "contrastParams = ContrastParams(\n" - "\tbackgroundParams = [2.23e-06 3.38e-06],\n" "\tscalefactors = [0.1 0.15],\n" "\tbulkIn = [2.073e-06 2.073e-06],\n" "\tbulkOut = [5.98e-06 2.21e-06],\n" - "\tresolutionParams = [0.03 0.03],\n" "\tsubRoughs = [3. 3.],\n" "\tresample = [0. 0.],\n" "),\n" @@ -57,19 +60,19 @@ def dream_str(): "reflectivity = [Data array: [21 x 2], Data array: [21 x 2]],\n" "simulation = [Data array: [21 x 2], Data array: [21 x 2]],\n" "shiftedData = [Data array: [21 x 3], Data array: [21 x 3]],\n" - "layerSlds = [[Data array: [8 x 3]], [Data array: [8 x 3]]],\n" + "backgrounds = [Data array: [82 x 3], Data array: [82 x 3]],\n" + "resolutions = [Data array: [82 x 2], Data array: [82 x 2]],\n" "sldProfiles = [[Data array: [29 x 2], Data array: [29 x 2]]],\n" + "layers = [[Data array: [8 x 3]], [Data array: [8 x 3]]],\n" "resampledLayers = [[Data array: [1 x 3]], [Data array: [1 x 3]]],\n" "calculationResults = CalculationResults(\n" "\tchiValues = [4.6077885 7.00028098],\n" "\tsumChi = 11.608069475997699,\n" "),\n" "contrastParams = ContrastParams(\n" - "\tbackgroundParams = [2.37113128e-06 1.99006694e-06],\n" "\tscalefactors = [0.1 0.15],\n" "\tbulkIn = [2.073e-06 2.073e-06],\n" "\tbulkOut = [6.01489149e-06 1.59371685e-06],\n" - "\tresolutionParams = [0.03 0.03],\n" "\tsubRoughs = [6.19503045 6.19503045],\n" "\tresample = [0. 0.],\n" "),\n" @@ -85,9 +88,7 @@ def dream_str(): "'Background parameter D2O', 'Background parameter SMW', 'D2O', 'SMW'],\n" "predictionIntervals = PredictionIntervals(\n" "\treflectivity = [Data array: [5 x 21], Data array: [5 x 21]],\n" - "\tsld = [[Data array: [5 x 30], Data array: [5 x 30]]],\n" - "\treflectivityXData = [Data array: [1 x 21], Data array: [1 x 21]],\n" - "\tsldXData = [[Data array: [1 x 30], Data array: [1 x 30]]],\n" + "\tsld = [[Data array: [5 x 29], Data array: [5 x 29]]],\n" "\tsampleChi = Data array: [1000],\n" "),\n" "confidenceIntervals = ConfidenceIntervals(\n" @@ -121,13 +122,13 @@ def dream_str(): "\toutlierChains = Data array: [1 x 2],\n" "\truntime = 2.6e-06,\n" "\titeration = 2.0,\n" - "\tmodelOutput = 0.0,\n" "\tAR = Data array: [1 x 2],\n" "\tR_stat = Data array: [1 x 19],\n" "\tCR = Data array: [1 x 4],\n" "),\n" "nestedSamplerOutput = NestedSamplerOutput(\n" "\tlogZ = 0.0,\n" + "\tlogZErr = 0.0,\n" "\tnestSamples = Data array: [1 x 2],\n" "\tpostSamples = Data array: [1 x 2],\n" "),\n" @@ -166,7 +167,7 @@ def test_get_field_string(test_value, array_limit, expected_field_string) -> Non """For the string representation of output classes, we represent multidimensional and large arrays by their shape, with other variables printed normally. """ - field_string = RATapi.outputs.get_field_string("test_field", test_value, array_limit) + field_string = ratapi.outputs.get_field_string("test_field", test_value, array_limit) assert field_string == expected_field_string @@ -185,15 +186,28 @@ def test_make_results(test_procedure, test_output_results, test_bayes, test_resu test_bayes = request.getfixturevalue(test_bayes) test_results = request.getfixturevalue(test_results) - results = RATapi.outputs.make_results(test_procedure, test_output_results, test_bayes) + results = ratapi.outputs.make_results(test_procedure, test_output_results, test_bayes) check_results_equal(test_results, results) +@pytest.mark.parametrize( + ["test_procedure", "test_results"], + [ + (Procedures.NS, "nested_sampler_results"), + (Procedures.DREAM, "dream_results"), + ], +) +def test_results_procedure(test_procedure, test_results, request) -> None: + """Test that bayes results object return correct procedure.""" + test_output_results = request.getfixturevalue(test_results) + assert test_output_results.from_procedure() == test_procedure + + @pytest.mark.parametrize( ["test_output_results", "test_str"], [ - # ("reflectivity_calculation_results", "reflectivity_calculation_str"), + ("reflectivity_calculation_results", "reflectivity_calculation_str"), ("dream_results", "dream_str"), ], ) @@ -205,3 +219,18 @@ def test_results_str(test_output_results, test_str, request) -> None: test_str = request.getfixturevalue(test_str) assert test_output_results.__str__() == test_str + + +@pytest.mark.parametrize("result_class", [ratapi.Results, ratapi.BayesResults]) +@pytest.mark.parametrize("test_results", ["reflectivity_calculation_results", "dream_results"]) +def test_save_load(result_class, test_results, request): + """Test that saving and loading an output object returns the same object.""" + test_results = request.getfixturevalue(test_results) + + with tempfile.TemporaryDirectory() as tmp: + # ignore relative path warnings + path = Path(tmp, "results.json") + test_results.save(path) + loaded_results = result_class.load(path) + + check_results_equal(test_results, loaded_results) diff --git a/tests/test_plotting.py b/tests/test_plotting.py index bd877348..518888fe 100644 --- a/tests/test_plotting.py +++ b/tests/test_plotting.py @@ -1,7 +1,6 @@ import os import pickle from math import ceil, sqrt -from textwrap import fill from unittest.mock import MagicMock, patch import matplotlib.pyplot as plt @@ -10,9 +9,9 @@ from matplotlib.collections import PolyCollection, QuadMesh from matplotlib.patches import Rectangle -import RATapi.utils.plotting as RATplot -from RATapi.events import notify -from RATapi.rat_core import EventTypes, PlotEventData +import ratapi.utils.plotting as RATplot +from ratapi.events import notify +from ratapi.rat_core import EventTypes, PlotEventData TEST_DIR_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test_data") @@ -51,7 +50,8 @@ def fig(request) -> plt.figure: """Creates the fixture for the tests.""" plt.close("all") figure = plt.subplots(1, 2)[0] - return RATplot.plot_ref_sld_helper(fig=figure, data=domains_data() if request.param else data()) + RATplot.plot_ref_sld_helper(fig=figure, data=domains_data() if request.param else data()) + return figure @pytest.fixture @@ -68,15 +68,14 @@ def bayes_fig(request) -> plt.figure: [(curve[:, 1] - curve[:, 1] * 0.1, curve[:, 1] + curve[:, 1] * 0.1) for curve in sld] for sld in dat.sldProfiles ], - "reflectivity-x-data": [[curve[:, 0]] for curve in dat.reflectivity], - "sld-x-data": [[[profile[:, 0]] for profile in sld] for sld in dat.sldProfiles], } - return RATplot.plot_ref_sld_helper(data=dat, fig=figure, confidence_intervals=confidence_intervals) + RATplot.plot_ref_sld_helper(data=dat, fig=figure, confidence_intervals=confidence_intervals) + return figure @pytest.mark.parametrize("fig", [False, True], indirect=True) -def test_figure_axis_formating(fig: plt.figure) -> None: - """Tests the axis formating of the figure.""" +def test_figure_axis_formatting(fig: plt.figure) -> None: + """Tests the axis formatting of the figure.""" ref_plot = fig.axes[0] sld_plot = fig.axes[1] @@ -107,31 +106,23 @@ def test_figure_axis_formating(fig: plt.figure) -> None: ] -def test_ref_sld_color_formating(fig: plt.figure) -> None: - """Tests the color formating of the figure.""" +def test_ref_sld_color_formatting(fig: plt.figure) -> None: + """Tests the color formatting of the figure.""" ref_plot = fig.axes[0] sld_plot = fig.axes[1] - assert len(ref_plot.get_lines()) == 3 + assert len(ref_plot.get_lines()) == 6 assert len(sld_plot.get_lines()) == 6 - for axis_ix in range(len(ref_plot.get_lines())): - ax1 = axis_ix * 2 - ax2 = ax1 + 1 - + for i in range(0, len(ref_plot.get_lines()), 2): # 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[i // 2][2][0]._original_edgecolor == ref_plot.get_lines()[i].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()[i].get_color() == sld_plot.get_lines()[i + 1].get_color() -@pytest.mark.parametrize("bayes", [65, 95]) -def test_ref_sld_bayes(fig, bayes_fig, bayes): +def test_ref_sld_bayes(fig, bayes_fig): """Test that shading is correctly added to the figure when confidence intervals are supplied.""" # the shading is of type PolyCollection for axes in fig.axes: @@ -142,34 +133,31 @@ def test_ref_sld_bayes(fig, bayes_fig, bayes): assert any(isinstance(comp, PolyCollection) for comp in components) -@patch("RATapi.utils.plotting.makeSLDProfileXY") +@patch("ratapi.utils.plotting.makeSLDProfile") def test_sld_profile_function_call(mock: MagicMock) -> None: - """Tests the makeSLDProfileXY function called with + """Tests the makeSLDProfile function called with correct args. """ - RATplot.plot_ref_sld_helper(data()) + RATplot.plot_ref_sld_helper(data(), plt.subplots(1, 2)[0]) assert mock.call_count == 3 assert mock.call_args_list[0].args[0] == 2.07e-06 assert mock.call_args_list[0].args[1] == 6.28e-06 - assert mock.call_args_list[0].args[2] == 0.0 - assert mock.call_args_list[0].args[4] == 82 - assert mock.call_args_list[0].args[5] == 1.0 + assert mock.call_args_list[0].args[3] == 0.0 + assert mock.call_args_list[0].args[4] == 1 assert mock.call_args_list[1].args[0] == 2.07e-06 assert mock.call_args_list[1].args[1] == 1.83e-06 - assert mock.call_args_list[1].args[2] == 0.0 - assert mock.call_args_list[1].args[4] == 128 - assert mock.call_args_list[1].args[5] == 1.0 + assert mock.call_args_list[1].args[3] == 0.0 + assert mock.call_args_list[1].args[4] == 1 assert mock.call_args_list[2].args[0] == 2.07e-06 assert mock.call_args_list[2].args[1] == -5.87e-07 - assert mock.call_args_list[2].args[2] == 0.0 - assert mock.call_args_list[2].args[4] == 153 - assert mock.call_args_list[2].args[5] == 1.0 + assert mock.call_args_list[2].args[3] == 0.0 + assert mock.call_args_list[2].args[4] == 1 -@patch("RATapi.utils.plotting.makeSLDProfileXY") +@patch("ratapi.utils.plotting.makeSLDProfile") def test_live_plot(mock: MagicMock) -> None: plot_data = data() @@ -182,24 +170,21 @@ def test_live_plot(mock: MagicMock) -> None: assert mock.call_count == 3 assert mock.call_args_list[0].args[0] == 2.07e-06 assert mock.call_args_list[0].args[1] == 6.28e-06 - assert mock.call_args_list[0].args[2] == 0.0 - assert mock.call_args_list[0].args[4] == 82 - assert mock.call_args_list[0].args[5] == 1.0 + assert mock.call_args_list[0].args[3] == 0.0 + assert mock.call_args_list[0].args[4] == 1 assert mock.call_args_list[1].args[0] == 2.07e-06 assert mock.call_args_list[1].args[1] == 1.83e-06 - assert mock.call_args_list[1].args[2] == 0.0 - assert mock.call_args_list[1].args[4] == 128 - assert mock.call_args_list[1].args[5] == 1.0 + assert mock.call_args_list[1].args[3] == 0.0 + assert mock.call_args_list[1].args[4] == 1 assert mock.call_args_list[2].args[0] == 2.07e-06 assert mock.call_args_list[2].args[1] == -5.87e-07 - assert mock.call_args_list[2].args[2] == 0.0 - assert mock.call_args_list[2].args[4] == 153 - assert mock.call_args_list[2].args[5] == 1.0 + assert mock.call_args_list[2].args[3] == 0.0 + assert mock.call_args_list[2].args[4] == 1 -@patch("RATapi.utils.plotting.plot_ref_sld_helper") +@patch("ratapi.utils.plotting.plot_ref_sld_helper") def test_plot_ref_sld(mock: MagicMock, input_project, reflectivity_calculation_results) -> None: RATplot.plot_ref_sld(input_project, reflectivity_calculation_results) mock.assert_called_once() @@ -209,10 +194,18 @@ def test_plot_ref_sld(mock: MagicMock, input_project, reflectivity_calculation_r assert figure.axes[0].get_subplotspec().get_gridspec().get_geometry() == (1, 2) assert len(figure.axes) == 2 + for reflectivity, reflectivity_results in zip( + data.reflectivity, reflectivity_calculation_results.reflectivity, strict=False + ): + assert (reflectivity == reflectivity_results).all() + for sldProfile, result_sld_profile in zip( + data.sldProfiles, reflectivity_calculation_results.sldProfiles, strict=False + ): + for sld, sld_results in zip(sldProfile, result_sld_profile, strict=False): + assert (sld == sld_results).all() + assert data.modelType == input_project.model - assert data.reflectivity == reflectivity_calculation_results.reflectivity assert data.shiftedData == reflectivity_calculation_results.shiftedData - assert data.sldProfiles == reflectivity_calculation_results.sldProfiles assert data.resampledLayers == reflectivity_calculation_results.resampledLayers assert data.dataPresent.size == 0 assert (data.subRoughs == reflectivity_calculation_results.contrastParams.subRoughs).all() @@ -223,12 +216,12 @@ def test_plot_ref_sld(mock: MagicMock, input_project, reflectivity_calculation_r def test_ref_sld_subplot_correction(): """Test that if an incorrect number of subplots is corrected in the figure helper.""" fig = plt.subplots(1, 3)[0] - ref_sld_fig = RATplot.plot_ref_sld_helper(data=data(), fig=fig) - assert ref_sld_fig.axes[0].get_subplotspec().get_gridspec().get_geometry() == (1, 2) - assert len(ref_sld_fig.axes) == 2 + RATplot.plot_ref_sld_helper(data=data(), fig=fig) + assert fig.axes[0].get_subplotspec().get_gridspec().get_geometry() == (1, 2) + assert len(fig.axes) == 2 -@patch("RATapi.utils.plotting.plot_ref_sld_helper") +@patch("ratapi.utils.plotting.plot_ref_sld_helper") def test_plot_ref_sld_bayes_validation(mock, input_project, reflectivity_calculation_results, dream_results): """Test that plot_ref_sld correctly throws errors for bad Bayesian input.""" RATplot.plot_ref_sld(input_project, dream_results) @@ -304,7 +297,7 @@ def test_hist(dream_results, param, hist_settings, est_dens): # assert title is as expected # also tests string to index conversion - assert ax.get_title() == fill(dream_results.fitNames[param] if isinstance(param, int) else param, 20) + assert ax.get_title(loc="left") == dream_results.fitNames[param] if isinstance(param, int) else param # assert range is default, unless given # this tests non-default hist_settings propagates correctly @@ -350,8 +343,8 @@ def test_contour(dream_results, x_param, y_param, hist2d_settings): y_param_chain = dream_results.chain[:, y_param_index] x_expected_range = (x_param_chain.min(), x_param_chain.max()) y_expected_range = (y_param_chain.min(), y_param_chain.max()) - assert ax.get_xbound() == y_expected_range - assert ax.get_ybound() == x_expected_range + assert ax.get_xbound() == x_expected_range + assert ax.get_ybound() == y_expected_range # plt.close(fig) @@ -388,8 +381,10 @@ def test_corner(dream_results, params): assert current_axes.get_xbound() == axes[-1][j].get_xbound() elif i == j: # check title is correct - assert current_axes.get_title() == fill( - dream_results.fitNames[params[i]] if isinstance(params[i], int) else params[i], 20 + assert ( + current_axes.get_title(loc="left") == dream_results.fitNames[params[i]] + if isinstance(params[i], int) + else params[i] ) plt.close(fig) @@ -398,7 +393,7 @@ def test_corner(dream_results, params): @pytest.mark.parametrize( "params", [None, [2, 3], [1, 5, "D2O"], ["Bilayer Heads Thickness", "Bilayer Heads Hydration", "D2O"]] ) -@patch("RATapi.plotting.panel_plot_helper") +@patch("ratapi.plotting.panel_plot_helper") def test_hist_panel(mock_panel_helper: MagicMock, params, dream_results): """Test chain panel name-to-index (panel helper has already been tested)""" fig = RATplot.plot_hists(dream_results, params, return_fig=True) @@ -422,7 +417,7 @@ def test_hist_panel(mock_panel_helper: MagicMock, params, dream_results): ({"default": "normal", 1: "kernel"}, "DEFAULT_WITH_1CHANGE_DICT"), ], ) -@patch("RATapi.plotting.plot_one_hist") +@patch("ratapi.plotting.plot_one_hist") def test_standardise_est_dens(mock_plot_hist: MagicMock, input, expected_dict, dream_results): """Test estimated density is correctly standardised.""" _ = RATplot.plot_hists(dream_results, estimated_density=input, return_fig=True) @@ -455,7 +450,7 @@ def test_est_dens_error(dream_results, input): @pytest.mark.parametrize( "params", [None, [2, 3], [1, 5, "D2O"], ["Bilayer Heads Thickness", "Bilayer Heads Hydration", "D2O"]] ) -@patch("RATapi.plotting.panel_plot_helper") +@patch("ratapi.plotting.panel_plot_helper") def test_chain_panel(mock_panel_helper: MagicMock, params, dream_results): """Test chain panel name-to-index (panel helper has already been tested)""" # return fig just to avoid plt.show() being called @@ -468,9 +463,9 @@ def test_chain_panel(mock_panel_helper: MagicMock, params, dream_results): assert param == (dream_results.fitNames.index(param) if isinstance(param, str) else param) -@patch("RATapi.plotting.plot_ref_sld") -@patch("RATapi.plotting.plot_hists") -@patch("RATapi.plotting.plot_corner") +@patch("ratapi.plotting.plot_ref_sld") +@patch("ratapi.plotting.plot_hists") +@patch("ratapi.plotting.plot_corner") def test_bayes_calls( mock_corner: MagicMock, mock_hists: MagicMock, mock_ref_sld: MagicMock, input_project, dream_results ): @@ -487,3 +482,74 @@ def test_bayes_validation(input_project, reflectivity_calculation_results): ValueError, match=r"Bayes plots are only available for the results of Bayesian analysis \(NS or DREAM\)" ): RATplot.plot_bayes(input_project, reflectivity_calculation_results) + + +@pytest.mark.parametrize("data", [data(), domains_data()]) +def test_extract_plot_data(data) -> None: + plot_data = RATplot._extract_plot_data(data, False, True, 50) + assert len(plot_data["ref"]) == len(data.reflectivity) + assert len(plot_data["sld"]) == len(data.shiftedData) + + with pytest.raises(ValueError, match=r"Parameter `shift_value` must be between 0 and 100"): + RATplot._extract_plot_data(data, False, True, -0.1) + + with pytest.raises(ValueError, match=r"Parameter `shift_value` must be between 0 and 100"): + RATplot._extract_plot_data(data, False, True, 100.5) + + +def test_moving_average() -> None: + """Test the moving_average function.""" + data_to_average = np.arange(0, 20) + mov_avg = RATplot.moving_average(data_to_average) + assert mov_avg == [ + 1.5, + 2.0, + 2.5, + 3.0, + 3.5, + 4.5, + 5.5, + 6.5, + 7.5, + 8.5, + 9.5, + 10.5, + 11.5, + 12.5, + 13.5, + 14.5, + 15.5, + 16.0, + 16.5, + 17.0, + ] + + mov_avg = RATplot.moving_average(data_to_average, window_size=2) + assert mov_avg == [ + 0.0, + 0.5, + 1.5, + 2.5, + 3.5, + 4.5, + 5.5, + 6.5, + 7.5, + 8.5, + 9.5, + 10.5, + 11.5, + 12.5, + 13.5, + 14.5, + 15.5, + 16.5, + 17.5, + 18.5, + ] + + with pytest.raises(ValueError): + RATplot.moving_average(data_to_average, window_size=-1) + + with pytest.raises(ValueError): + RATplot.moving_average(data_to_average, window_size=len(data_to_average) + 1) diff --git a/tests/test_project.py b/tests/test_project.py index 71cee161..35d5864e 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -1,17 +1,19 @@ """Test the project module.""" import copy -import os -import shutil +import re import tempfile -from typing import Callable +import warnings +from collections.abc import Callable +from pathlib import Path +from typing import get_args, get_origin import numpy as np import pydantic import pytest -import RATapi -from RATapi.utils.enums import Calculations, LayerModels, TypeOptions +import ratapi +from ratapi.utils.enums import Calculations, LayerModels, TypeOptions layer_params = {"thickness": "Test Thickness", "SLD": "Test SLD", "roughness": "Test Roughness"} absorption_layer_params = { @@ -21,12 +23,29 @@ "roughness": "Test Roughness", } +model_classes = { + "parameters": ratapi.models.Parameter, + "bulk_in": ratapi.models.Parameter, + "bulk_out": ratapi.models.Parameter, + "scalefactors": ratapi.models.Parameter, + "domain_ratios": ratapi.models.Parameter, + "background_parameters": ratapi.models.Parameter, + "resolution_parameters": ratapi.models.Parameter, + "backgrounds": ratapi.models.Background, + "resolutions": ratapi.models.Resolution, + "custom_files": ratapi.models.CustomFile, + "data": ratapi.models.Data, + "layers": ratapi.models.Layer, + "domain_contrasts": ratapi.models.DomainContrast, + "contrasts": ratapi.models.Contrast, +} + @pytest.fixture def test_project(): """Add parameters to the default project, so each ClassList can be tested properly.""" - test_project = RATapi.Project( - data=RATapi.ClassList([RATapi.models.Data(name="Simulation", data=np.array([[1.0, 1.0, 1.0]]))]), + test_project = ratapi.Project( + data=ratapi.ClassList([ratapi.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") @@ -56,59 +75,59 @@ def default_project_str(): """A string of the output of str() for a Project model with no parameters specified.""" return ( "Calculation: ---------------------------------------------------------------------------------------\n\n" - "non polarised\n\n" + "normal\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" + "+-------+---------------------+-----+-------+-----+------+\n" + "| index | name | min | value | max | fit |\n" + "+-------+---------------------+-----+-------+-----+------+\n" + "| 0 | Substrate Roughness | 1.0 | 3.0 | 5.0 | True |\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" + "+-------+---------+-----+-------+-----+-------+\n" + "| index | name | min | value | max | fit |\n" + "+-------+---------+-----+-------+-----+-------+\n" + "| 0 | SLD Air | 0.0 | 0.0 | 0.0 | False |\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" + "+-------+---------+---------+----------+----------+-------+\n" + "| index | name | min | value | max | fit |\n" + "+-------+---------+---------+----------+----------+-------+\n" + "| 0 | SLD D2O | 6.2e-06 | 6.35e-06 | 6.35e-06 | False |\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" + "+-------+---------------+------+-------+------+-------+\n" + "| index | name | min | value | max | fit |\n" + "+-------+---------------+------+-------+------+-------+\n" + "| 0 | Scalefactor 1 | 0.02 | 0.23 | 0.25 | False |\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" + "+-------+--------------------+-------+-------+-------+-------+\n" + "| index | name | min | value | max | fit |\n" + "+-------+--------------------+-------+-------+-------+-------+\n" + "| 0 | Background Param 1 | 1e-07 | 1e-06 | 1e-05 | False |\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" + "+-------+--------------+----------+--------------------+\n" + "| index | name | type | source |\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" + "+-------+--------------------+------+-------+------+-------+\n" + "| index | name | min | value | max | fit |\n" + "+-------+--------------------+------+-------+------+-------+\n" + "| 0 | Resolution Param 1 | 0.01 | 0.03 | 0.05 | False |\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" + "+-------+--------------+----------+--------------------+\n" + "| index | name | type | source |\n" + "+-------+--------------+----------+--------------------+\n" + "| 0 | Resolution 1 | constant | Resolution Param 1 |\n" + "+-------+--------------+----------+--------------------+\n\n" "Data: ----------------------------------------------------------------------------------------------\n\n" "+-------+------------+------+------------+------------------+\n" "| index | name | data | data range | simulation range |\n" @@ -118,71 +137,21 @@ def default_project_str(): ) -@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' - "import RATapi\nfrom RATapi.models import *\nfrom numpy import array, inf\n\n" - "problem = RATapi.Project(\n" - " name='', calculation='non polarised', model='standard layers', geometry='air/substrate'," - " absorption=False,\n" - " parameters=RATapi.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=RATapi.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=RATapi.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=RATapi.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=RATapi.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=RATapi.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=RATapi.ClassList([Background(name='Background 1', type='constant'," - " value_1='Background Param 1', value_2='', value_3='', value_4='', value_5='')]),\n" - " resolutions=RATapi.ClassList([Resolution(name='Resolution 1', type='constant'," - " value_1='Resolution Param 1', value_2='', value_3='', value_4='', value_5='')]),\n" - " custom_files=RATapi.ClassList([CustomFile(name='Test Custom File', filename='', function_name=''," - " language='python', path='')]),\n" - " data=RATapi.ClassList([Data(name='Simulation', data=array([[1., 1., 1.]]), data_range=[1.0, 1.0]," - " simulation_range=[1.0, 1.0])]),\n" - " layers=RATapi.ClassList([Layer(name='Test Layer', thickness='Test Thickness', SLD='Test SLD'," - " roughness='Test Roughness', hydration='', hydrate_with='bulk out')]),\n" - " contrasts=RATapi.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" - ) - - -@pytest.fixture -def temp_dir(): - path = tempfile.mkdtemp() - yield path - shutil.rmtree(path) - - def test_classlists(test_project) -> None: """The ClassLists in the "Project" model should contain instances of the models given by the dictionary "model_in_classlist". """ - for key, value in RATapi.project.model_in_classlist.items(): - class_list = getattr(test_project, key) - assert class_list._class_handle.__name__ == value + for model in (fields := ratapi.Project.model_fields): + if get_origin(fields[model].annotation) == ratapi.ClassList: + class_list = getattr(test_project, model) + assert class_list._class_handle == get_args(fields[model].annotation)[0] def test_classlists_specific_cases() -> None: """The ClassLists in the "Project" model should contain instances of specific models given various non-default options. """ - project = RATapi.Project(calculation=Calculations.Domains, absorption=True) + project = ratapi.Project(calculation=Calculations.Domains, absorption=True) assert project.layers._class_handle.__name__ == "AbsorptionLayer" assert project.contrasts._class_handle.__name__ == "ContrastWithRatio" @@ -190,33 +159,33 @@ def test_classlists_specific_cases() -> None: @pytest.mark.parametrize( ["input_model", "model_params"], [ - (RATapi.models.Background, {}), - (RATapi.models.Contrast, {}), - (RATapi.models.ContrastWithRatio, {}), - (RATapi.models.CustomFile, {}), - (RATapi.models.Data, {}), - (RATapi.models.DomainContrast, {}), - (RATapi.models.Layer, layer_params), - (RATapi.models.AbsorptionLayer, absorption_layer_params), - (RATapi.models.Resolution, {}), + (ratapi.models.Background, {}), + (ratapi.models.Contrast, {}), + (ratapi.models.ContrastWithRatio, {}), + (ratapi.models.CustomFile, {}), + (ratapi.models.Data, {}), + (ratapi.models.DomainContrast, {}), + (ratapi.models.Layer, layer_params), + (ratapi.models.AbsorptionLayer, absorption_layer_params), + (ratapi.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"', + match="1 validation error for Project\nparameters\n " + "Value error, This ClassList only supports elements of type Parameter. In the input list:\n" + f" index 0 is of type {input_model.__name__}", ): - RATapi.Project(parameters=RATapi.ClassList(input_model(**model_params))) + ratapi.Project(parameters=ratapi.ClassList(input_model(**model_params))) @pytest.mark.parametrize( ["input_model", "model_params", "absorption", "actual_model_name"], [ - (RATapi.models.Layer, layer_params, True, "AbsorptionLayer"), - (RATapi.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), + (ratapi.models.Layer, layer_params, True, "AbsorptionLayer"), + (ratapi.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), ], ) def test_initialise_wrong_layers( @@ -231,46 +200,57 @@ def test_initialise_wrong_layers( 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}"', + f'"The layers attribute contains {input_model.__name__}s, but the absorption parameter is ' + f'{absorption}. The attribute should be a ClassList of {actual_model_name} instead."', ): - RATapi.Project(absorption=absorption, layers=RATapi.ClassList(input_model(**model_params))) + ratapi.Project(absorption=absorption, layers=ratapi.ClassList(input_model(**model_params))) @pytest.mark.parametrize( ["input_model", "calculation", "actual_model_name"], [ - (RATapi.models.Contrast, Calculations.Domains, "ContrastWithRatio"), - (RATapi.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast"), + (ratapi.models.Contrast, Calculations.Domains, "ContrastWithRatio"), + (ratapi.models.ContrastWithRatio, Calculations.Normal, "Contrast"), ], ) def test_initialise_wrong_contrasts( - input_model: RATapi.models, calculation: Calculations, actual_model_name: str + input_model: ratapi.models.RATModel, 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. + """If the "Project" model is initialised with the incorrect contrast model given the value of calculation, we + should raise a ValidationError. """ + word = "without" if calculation == Calculations.Domains else "with" 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}"', + match=f"1 validation error for Project\ncontrasts\n" + f' Value error, "The contrasts attribute contains contrasts {word} ratio, ' + f'but the calculation is {calculation}"', ): - RATapi.Project(calculation=calculation, contrasts=RATapi.ClassList(input_model())) + ratapi.Project(calculation=calculation, contrasts=ratapi.ClassList(input_model())) + + +@pytest.mark.parametrize( + "calculation, model", + [(Calculations.Domains, ratapi.models.ContrastWithRatio), (Calculations.Normal, ratapi.models.Contrast)], +) +def test_initialise_ambiguous_contrasts(calculation: Calculations, model: ratapi.models.RATModel): + """If a sequence of dictionaries is passed to 'contrasts', convert them to the correct model for the calculation.""" + proj = ratapi.Project(calculation=calculation, contrasts=ratapi.ClassList([{"name": "Contrast 1"}])) + assert proj.contrasts._class_handle == model def test_initialise_without_substrate_roughness() -> None: """If the "Project" model is initialised without "Substrate Roughness" as a parameter, add it as a protected parameter to the front of the "parameters" ClassList. """ - project = RATapi.Project(parameters=RATapi.ClassList(RATapi.models.Parameter(name="Test Parameter"))) - assert project.parameters[0] == RATapi.models.ProtectedParameter( + project = ratapi.Project(parameters=ratapi.ClassList(ratapi.models.Parameter(name="Test Parameter"))) + assert project.parameters[0] == ratapi.models.ProtectedParameter( name="Substrate Roughness", min=1.0, value=3.0, max=5.0, fit=True, - prior_type=RATapi.models.Priors.Uniform, + prior_type=ratapi.models.Priors.Uniform, mu=0.0, sigma=np.inf, ) @@ -279,56 +259,67 @@ def test_initialise_without_substrate_roughness() -> None: @pytest.mark.parametrize( "input_parameter", [ - RATapi.models.Parameter(name="Substrate Roughness"), - RATapi.models.Parameter(name="SUBSTRATE ROUGHNESS"), - RATapi.models.Parameter(name="substrate roughness"), + ratapi.models.Parameter(name="Substrate Roughness"), + ratapi.models.Parameter(name="SUBSTRATE ROUGHNESS"), + ratapi.models.Parameter(name="substrate roughness"), ], ) -def test_initialise_without_protected_substrate_roughness(input_parameter: RATapi.models.Parameter) -> None: +def test_initialise_without_protected_substrate_roughness(input_parameter: ratapi.models.Parameter) -> None: """If the "Project" model is initialised without "Substrate Roughness" as a protected parameter, add it to the front of the "parameters" ClassList. """ - project = RATapi.Project(parameters=RATapi.ClassList(input_parameter)) - assert project.parameters[0] == RATapi.models.ProtectedParameter(name=input_parameter.name) + project = ratapi.Project(parameters=ratapi.ClassList(input_parameter)) + assert project.parameters[0] == ratapi.models.ProtectedParameter(name=input_parameter.name) def test_initialise_without_simulation() -> None: """If the "Project" model is initialised without "Simulation" in the "data" ClassList, add it to the front of the "data" ClassList. """ - project = RATapi.Project(parameters=RATapi.ClassList(RATapi.models.Parameter(name="Test Parameter"))) - assert project.data[0] == RATapi.models.Data(name="Simulation", simulation_range=[0.005, 0.7]) + project = ratapi.Project(parameters=ratapi.ClassList(ratapi.models.Parameter(name="Test Parameter"))) + assert project.data[0] == ratapi.models.Data(name="Simulation", simulation_range=[0.005, 0.7]) @pytest.mark.parametrize( - ["field", "wrong_input_model", "model_params"], + ["field", "model_type", "wrong_input_model", "model_params"], [ - ("backgrounds", RATapi.models.Resolution, {}), - ("contrasts", RATapi.models.Layer, layer_params), - ("domain_contrasts", RATapi.models.Parameter, {}), - ("custom_files", RATapi.models.Data, {}), - ("data", RATapi.models.Contrast, {}), - ("layers", RATapi.models.DomainContrast, {}), - ("parameters", RATapi.models.CustomFile, {}), - ("resolutions", RATapi.models.Background, {}), + ("backgrounds", "Background", ratapi.models.Resolution, {}), + ("contrasts", "Contrast", ratapi.models.Layer, layer_params), + ("domain_contrasts", "DomainContrast", ratapi.models.Parameter, {}), + ("custom_files", "CustomFile", ratapi.models.Data, {}), + ("data", "Data", ratapi.models.Contrast, {}), + ("layers", "Layer", ratapi.models.DomainContrast, {}), + ("parameters", "Parameter", ratapi.models.CustomFile, {}), + ("resolutions", "Resolution", ratapi.models.Background, {}), ], ) -def test_assign_wrong_classes(test_project, field: str, wrong_input_model: Callable, model_params: dict) -> None: +def test_assign_wrong_classes( + test_project, field: str, model_type: str, wrong_input_model: Callable, model_params: dict +) -> None: """If we assign incorrect classes to the "Project" model, we should raise a ValidationError.""" + if field == "contrasts": + field_name = "contrasts.no_ratio" + elif field == "layers": + field_name = "layers.no_abs" + else: + field_name = 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'"{RATapi.project.model_in_classlist[field]}"', + match=( + f"1 validation error for Project\n{field_name}\n" + f" Value error, This ClassList only supports elements of type {model_type}. In the input list:\n" + f" index 0 is of type {wrong_input_model.__name__}" + ), ): - setattr(test_project, field, RATapi.ClassList(wrong_input_model(**model_params))) + setattr(test_project, field, ratapi.ClassList(wrong_input_model(**model_params))) @pytest.mark.parametrize( ["wrong_input_model", "model_params", "absorption", "actual_model_name"], [ - (RATapi.models.Layer, layer_params, True, "AbsorptionLayer"), - (RATapi.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), + (ratapi.models.Layer, layer_params, True, "AbsorptionLayer"), + (ratapi.models.AbsorptionLayer, absorption_layer_params, False, "Layer"), ], ) def test_assign_wrong_layers( @@ -338,33 +329,34 @@ def test_assign_wrong_layers( actual_model_name: str, ) -> None: """If we assign incorrect classes to the "Project" model, we should raise a ValidationError.""" - project = RATapi.Project(absorption=absorption) + project = ratapi.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}"', + f'"The layers attribute contains {wrong_input_model.__name__}s, but the absorption parameter is ' + f'{absorption}. The attribute should be a ClassList of {actual_model_name} instead."', ): - project.layers = RATapi.ClassList(wrong_input_model(**model_params)) + project.layers = ratapi.ClassList(wrong_input_model(**model_params)) @pytest.mark.parametrize( ["wrong_input_model", "calculation", "actual_model_name"], [ - (RATapi.models.Contrast, Calculations.Domains, "ContrastWithRatio"), - (RATapi.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast"), + (ratapi.models.Contrast, Calculations.Domains, "ContrastWithRatio"), + (ratapi.models.ContrastWithRatio, Calculations.Normal, "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 = RATapi.Project(calculation=calculation) + project = ratapi.Project(calculation=calculation) + word = "without" if calculation == Calculations.Domains else "with" 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}"', + match=f"1 validation error for Project\ncontrasts\n" + f' Value error, "The contrasts attribute contains contrasts {word} ratio, but the calculation is ' + f'{calculation}"', ): - project.contrasts = RATapi.ClassList(wrong_input_model()) + project.contrasts = ratapi.ClassList(wrong_input_model()) @pytest.mark.parametrize( @@ -381,10 +373,10 @@ def test_assign_wrong_contrasts(wrong_input_model: Callable, calculation: Calcul ) 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(RATapi.models, RATapi.project.model_in_classlist[field]) + input_model = model_classes[field] with pytest.raises( pydantic.ValidationError, - match=f"1 validation error for Project\n{field}\n Input should be " f"an instance of ClassList", + match=f"1 validation error for Project\n{field}\n Input should be an instance of ClassList", ): setattr(test_project, field, input_model(**model_params)) @@ -403,7 +395,7 @@ def test_wrapped_routines(test_project) -> None: "extend", "set_fields", ] - for class_list in RATapi.project.class_lists: + for class_list in ratapi.project.class_lists: attribute = getattr(test_project, class_list) for methodName in wrapped_methods: assert hasattr(getattr(attribute, methodName), "__wrapped__") @@ -419,9 +411,9 @@ def test_set_domain_ratios(test_project) -> None: @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.Normal, "model": LayerModels.StandardLayers}), + ({"calculation": Calculations.Normal, "model": LayerModels.CustomLayers}), + ({"calculation": Calculations.Normal, "model": LayerModels.CustomXY}), ({"calculation": Calculations.Domains, "model": LayerModels.CustomLayers}), ({"calculation": Calculations.Domains, "model": LayerModels.CustomXY}), ], @@ -430,7 +422,7 @@ 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 = RATapi.Project(**project_parameters) + project = ratapi.Project(**project_parameters) assert project.domain_contrasts == [] project.domain_contrasts.append(name="New Domain Contrast") assert project.domain_contrasts == [] @@ -445,17 +437,57 @@ def test_set_domain_contrasts(project_parameters: dict) -> None: ) 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 = RATapi.Project(**project_parameters) + project = ratapi.Project(**project_parameters) assert project.layers == [] project.layers.append(name="New Layer", thickness="Test Thickness", SLD="Test SLD", roughness="Test Roughness") assert project.layers == [] +@pytest.mark.parametrize( + "project_parameters", + [ + ( + { + "model": LayerModels.CustomLayers, + "contrasts": [ratapi.models.Contrast(name="Test Contrast", repeat_layers=2)], + } + ), + ({"model": LayerModels.CustomXY, "contrasts": [ratapi.models.Contrast(name="Test Contrast", repeat_layers=2)]}), + ], +) +def test_set_repeat_layers(project_parameters: dict) -> None: + """If we are using a custom layers of custom XY model, the "resample" field of all the contrasts should always + be 1.""" + with pytest.warns( + match='For a custom layers or custom XY calculation, the "repeat_layers" setting for each ' + "contrast is not valid - resetting to 1." + ): + project = ratapi.Project(**project_parameters) + assert all(contrast.repeat_layers == 1 for contrast in project.contrasts) + + +@pytest.mark.parametrize( + "project_parameters", + [ + ({"model": LayerModels.CustomXY, "contrasts": [ratapi.models.Contrast(name="Test Contrast")]}), + ], +) +def test_set_resample(project_parameters: dict) -> None: + """If we are using a custom XY model, the "resample" field of all the contrasts should always be True.""" + project = ratapi.Project(**project_parameters) + assert all(contrast.resample for contrast in project.contrasts) + with pytest.warns( + match='For a custom XY calculation, "resample" must be True for each contrast - resetting to True.' + ): + project.contrasts.append(name="New Contrast", resample=False) + assert all(contrast.resample for contrast in project.contrasts) + + @pytest.mark.parametrize( ["input_calculation", "input_contrast", "new_calculation", "new_contrast_model", "num_domain_ratios"], [ - (Calculations.NonPolarised, RATapi.models.Contrast, Calculations.Domains, "ContrastWithRatio", 1), - (Calculations.Domains, RATapi.models.ContrastWithRatio, Calculations.NonPolarised, "Contrast", 0), + (Calculations.Normal, ratapi.models.Contrast, Calculations.Domains, "ContrastWithRatio", 1), + (Calculations.Domains, ratapi.models.ContrastWithRatio, Calculations.Normal, "Contrast", 0), ], ) def test_set_calculation( @@ -468,7 +500,7 @@ def test_set_calculation( """When changing the value of the calculation option, the "contrasts" ClassList should switch to using the appropriate Contrast model. """ - project = RATapi.Project(calculation=input_calculation, contrasts=RATapi.ClassList(input_contrast())) + project = ratapi.Project(calculation=input_calculation, contrasts=ratapi.ClassList(input_contrast())) project.calculation = new_calculation assert project.calculation is new_calculation @@ -480,9 +512,9 @@ def test_set_calculation( @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.Normal, LayerModels.StandardLayers, ["Test Layer"]), + (Calculations.Normal, LayerModels.CustomLayers, []), + (Calculations.Normal, LayerModels.CustomXY, []), (Calculations.Domains, LayerModels.StandardLayers, []), (Calculations.Domains, LayerModels.CustomLayers, []), (Calculations.Domains, LayerModels.CustomXY, []), @@ -533,13 +565,13 @@ def test_check_contrast_model_length( """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 = RATapi.ClassList(RATapi.models.Parameter(name="Test Domain Ratio")) - test_contrasts = RATapi.ClassList(RATapi.models.ContrastWithRatio(model=test_contrast_model)) + test_domain_ratios = ratapi.ClassList(ratapi.models.Parameter(name="Test Domain Ratio")) + test_contrasts = ratapi.ClassList(ratapi.models.ContrastWithRatio(model=test_contrast_model)) with pytest.raises( pydantic.ValidationError, match=f"1 validation error for Project\n Value error, {error_message}", ): - RATapi.Project( + ratapi.Project( calculation=Calculations.Domains, model=input_model, domain_ratios=test_domain_ratios, @@ -550,8 +582,8 @@ def test_check_contrast_model_length( @pytest.mark.parametrize( ["input_layer", "model_params", "input_absorption", "new_layer_model"], [ - (RATapi.models.Layer, layer_params, False, "AbsorptionLayer"), - (RATapi.models.AbsorptionLayer, absorption_layer_params, True, "Layer"), + (ratapi.models.Layer, layer_params, False, "AbsorptionLayer"), + (ratapi.models.AbsorptionLayer, absorption_layer_params, True, "Layer"), ], ) def test_set_absorption( @@ -563,16 +595,16 @@ def test_set_absorption( """When changing the value of the absorption option, the "layers" ClassList should switch to using the appropriate Layer model. """ - project = RATapi.Project( + project = ratapi.Project( absorption=input_absorption, - parameters=RATapi.ClassList( + parameters=ratapi.ClassList( [ - RATapi.models.Parameter(name="Test Thickness"), - RATapi.models.Parameter(name="Test SLD"), - RATapi.models.Parameter(name="Test Roughness"), + ratapi.models.Parameter(name="Test Thickness"), + ratapi.models.Parameter(name="Test SLD"), + ratapi.models.Parameter(name="Test Roughness"), ], ), - layers=RATapi.ClassList(input_layer(**model_params)), + layers=ratapi.ClassList(input_layer(**model_params)), ) project.absorption = not input_absorption @@ -592,12 +624,12 @@ def test_set_absorption( ) def test_check_protected_parameters(delete_operation) -> None: """If we try to remove a protected parameter, we should raise an error.""" - project = RATapi.Project() + project = ratapi.Project() with pytest.raises( pydantic.ValidationError, - match="1 validation error for Project\n Value error, Can't delete" - " the protected parameters: Substrate Roughness", + match="1 validation error for Project\n Value error, " + "Can't delete the protected parameters: Substrate Roughness", ): eval(delete_operation) @@ -606,50 +638,63 @@ def test_check_protected_parameters(delete_operation) -> None: @pytest.mark.parametrize( - ["model", "field"], + ["model", "fields"], [ - ("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"), + ("background_parameters", ["source"]), + ("resolution_parameters", ["source"]), + ("parameters", ["roughness"]), + ("data", ["data", "source"]), + ("custom_files", ["source", "source"]), + ("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: +def test_rename_models(test_project, model: str, fields: list[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. """ + if model == "data": + test_project.backgrounds[0] = ratapi.models.Background(type="data", source="Simulation") + if model == "custom_files": + test_project.backgrounds[0] = ratapi.models.Background(type="function", source="Test Custom File") + # workaround until function resolutions are added + # test_project.resolutions[0] = ratapi.models.Resolution(type="function", source="Test Custom File") + test_project.resolution_parameters.append(ratapi.models.Parameter(name="New Name")) + test_project.resolutions[0] = ratapi.models.Resolution(type="constant", source="New Name") + getattr(test_project, model).set_fields(-1, name="New Name") - attribute = RATapi.project.model_names_used_in[model].attribute - assert getattr(getattr(test_project, attribute)[-1], field) == "New Name" + model_name_lists = ratapi.project.model_names_used_in[model] + for model_name_list, field in zip(model_name_lists, fields, strict=False): + attribute = model_name_list.attribute + assert getattr(getattr(test_project, attribute)[-1], field) == "New Name" @pytest.mark.parametrize( - "field", + "background_type, expected_field", [ - "value_1", - "value_2", - "value_3", - "value_4", - "value_5", + [TypeOptions.Constant, "background_parameters"], + [TypeOptions.Data, "data"], + [TypeOptions.Function, "custom_files"], ], ) -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. +def test_allowed_backgrounds(background_type, expected_field) -> None: """ - test_background = RATapi.models.Background(**{field: "undefined"}) + If the source field of the Background model is set to a value that is not specified in the appropriate ClassList, + we should raise a ValidationError. + """ + test_background = ratapi.models.Background(type=background_type, source="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".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "source" field of ' + f'backgrounds[0] must be defined in "{expected_field}". Please add "undefined" to "{expected_field}" ' + f'before including it in "backgrounds".' + ), ): - RATapi.Project(backgrounds=RATapi.ClassList(test_background)) + ratapi.Project(backgrounds=ratapi.ClassList(test_background)) @pytest.mark.parametrize( @@ -664,24 +709,26 @@ 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 = RATapi.models.Layer(**{**layer_params, field: "undefined"}) + test_layer = ratapi.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".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" ' + f'field of layers[0] must be defined in "parameters". Please add "undefined" to "parameters" ' + f'before including it in "layers".' + ), ): - RATapi.Project( + ratapi.Project( absorption=False, - parameters=RATapi.ClassList( + parameters=ratapi.ClassList( [ - RATapi.models.Parameter(name="Test Thickness"), - RATapi.models.Parameter(name="Test SLD"), - RATapi.models.Parameter(name="Test Roughness"), + ratapi.models.Parameter(name="Test Thickness"), + ratapi.models.Parameter(name="Test SLD"), + ratapi.models.Parameter(name="Test Roughness"), ], ), - layers=RATapi.ClassList(test_layer), + layers=ratapi.ClassList(test_layer), ) @@ -698,49 +745,51 @@ 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 = RATapi.models.AbsorptionLayer(**{**absorption_layer_params, field: "undefined"}) + test_layer = ratapi.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".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" field of ' + f'layers[0] must be defined in "parameters". Please add "undefined" to "parameters" before including it ' + f'in "layers".' + ), ): - RATapi.Project( + ratapi.Project( absorption=True, - parameters=RATapi.ClassList( + parameters=ratapi.ClassList( [ - RATapi.models.Parameter(name="Test Thickness"), - RATapi.models.Parameter(name="Test SLD"), - RATapi.models.Parameter(name="Test Roughness"), + ratapi.models.Parameter(name="Test Thickness"), + ratapi.models.Parameter(name="Test SLD"), + ratapi.models.Parameter(name="Test Roughness"), ], ), - layers=RATapi.ClassList(test_layer), + layers=ratapi.ClassList(test_layer), ) @pytest.mark.parametrize( - "field", + "resolution_type, expected_field", [ - "value_1", - "value_2", - "value_3", - "value_4", - "value_5", + [TypeOptions.Constant, "resolution_parameters"], + # uncomment when function resolutions are added! + # [TypeOptions.Function, "custom_files"], ], ) -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 +def test_allowed_resolutions(resolution_type, expected_field) -> None: + """If the "value" fields of the Resolution model are set to values that are not specified in the resolution parameters, we should raise a ValidationError. """ - test_resolution = RATapi.models.Resolution(**{field: "undefined"}) + test_resolution = ratapi.models.Resolution(type=resolution_type, source="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".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "source" field of ' + f'resolutions[0] must be defined in "{expected_field}". Please add "undefined" to "{expected_field}" ' + f'before including it in "resolutions".' + ), ): - RATapi.Project(resolutions=RATapi.ClassList(test_resolution)) + ratapi.Project(resolutions=ratapi.ClassList(test_resolution)) @pytest.mark.parametrize( @@ -758,14 +807,16 @@ 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 = RATapi.models.Contrast(**{field: "undefined"}) + test_contrast = ratapi.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}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" field of ' + f'contrasts[0] must be defined in "{model_name}". Please add "undefined" to "{model_name}" before ' + f'including it in "contrasts".' + ), ): - RATapi.Project(calculation=Calculations.NonPolarised, contrasts=RATapi.ClassList(test_contrast)) + ratapi.Project(calculation=Calculations.Normal, contrasts=ratapi.ClassList(test_contrast)) @pytest.mark.parametrize( @@ -784,14 +835,16 @@ 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 = RATapi.models.ContrastWithRatio(**{field: "undefined"}) + test_contrast = ratapi.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}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" field of ' + f'contrasts[0] must be defined in "{model_name}". Please add "undefined" to "{model_name}" before ' + f'including it in "contrasts".' + ), ): - RATapi.Project(calculation=Calculations.Domains, contrasts=RATapi.ClassList(test_contrast)) + ratapi.Project(calculation=Calculations.Domains, contrasts=ratapi.ClassList(test_contrast)) @pytest.mark.parametrize( @@ -800,37 +853,37 @@ def test_allowed_contrasts_with_ratio(field: str, model_name: str) -> None: ( Calculations.Domains, LayerModels.StandardLayers, - RATapi.models.ContrastWithRatio(name="Test Contrast", model=["undefined", "undefined"]), + ratapi.models.ContrastWithRatio(name="Test Contrast", model=["undefined", "undefined"]), "domain_contrasts", ), ( Calculations.Domains, LayerModels.CustomLayers, - RATapi.models.ContrastWithRatio(name="Test Contrast", model=["undefined"]), + ratapi.models.ContrastWithRatio(name="Test Contrast", model=["undefined"]), "custom_files", ), ( Calculations.Domains, LayerModels.CustomXY, - RATapi.models.ContrastWithRatio(name="Test Contrast", model=["undefined"]), + ratapi.models.ContrastWithRatio(name="Test Contrast", model=["undefined"]), "custom_files", ), ( - Calculations.NonPolarised, + Calculations.Normal, LayerModels.StandardLayers, - RATapi.models.Contrast(name="Test Contrast", model=["undefined", "undefined", "undefined"]), + ratapi.models.Contrast(name="Test Contrast", model=["undefined", "undefined", "undefined"]), "layers", ), ( - Calculations.NonPolarised, + Calculations.Normal, LayerModels.CustomLayers, - RATapi.models.Contrast(name="Test Contrast", model=["undefined"]), + ratapi.models.Contrast(name="Test Contrast", model=["undefined"]), "custom_files", ), ( - Calculations.NonPolarised, + Calculations.Normal, LayerModels.CustomXY, - RATapi.models.Contrast(name="Test Contrast", model=["undefined"]), + ratapi.models.Contrast(name="Test Contrast", model=["undefined"]), "custom_files", ), ], @@ -838,38 +891,43 @@ def test_allowed_contrasts_with_ratio(field: str, model_name: str) -> None: def test_allowed_contrast_models( input_calc: Calculations, input_model: LayerModels, - test_contrast: "RATapi.models", + test_contrast: "ratapi.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. """ + missing_values = list(set(test_contrast.model)) 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}".', + match=re.escape( + f"1 validation error for Project\n Value error, The value{'s' if len(missing_values) > 1 else ''}: " + f'"{", ".join(missing_values)}" used in the "model" field of contrasts[0] must be defined in ' + f'"{field_name}". Please add all required values to "{field_name}" before including them in "contrasts".' + ), ): - RATapi.Project(calculation=input_calc, model=input_model, contrasts=RATapi.ClassList(test_contrast)) + ratapi.Project(calculation=input_calc, model=input_model, contrasts=ratapi.ClassList(test_contrast)) 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 = RATapi.models.DomainContrast(name="Test Domain Contrast", model=["undefined"]) + test_contrast = ratapi.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".', + match=re.escape( + '1 validation error for Project\n Value error, The value: "undefined" used in the "model" field of ' + 'domain_contrasts[0] must be defined in "layers". Please add all required values to "layers" before ' + 'including them in "domain_contrasts".' + ), ): - RATapi.Project(calculation=Calculations.Domains, domain_contrasts=RATapi.ClassList(test_contrast)) + ratapi.Project(calculation=Calculations.Domains, domain_contrasts=ratapi.ClassList(test_contrast)) def test_str(default_project_str: str) -> None: """We should be able to print the "Project" model as a formatted list of the fields.""" - assert str(RATapi.Project()) == default_project_str + assert str(ratapi.Project()) == default_project_str def test_get_all_names(test_project) -> None: @@ -914,10 +972,11 @@ def test_get_all_protected_parameters(test_project) -> None: ) 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 = RATapi.Project.model_construct( - layers=RATapi.ClassList(RATapi.models.Layer(**dict(layer_params, roughness=test_value))) + allowed_values = ["Substrate Roughness"] + project = ratapi.Project.model_construct( + layers=ratapi.ClassList(ratapi.models.Layer(**dict(layer_params, roughness=test_value))) ) - assert project.check_allowed_values("layers", ["roughness"], ["Substrate Roughness"]) is None + assert project.check_allowed_values("layers", ["roughness"], allowed_values, allowed_values) is None @pytest.mark.parametrize( @@ -928,14 +987,18 @@ def test_check_allowed_values(test_value: str) -> None: ) 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 = RATapi.Project.model_construct( - layers=RATapi.ClassList(RATapi.models.Layer(**dict(layer_params, roughness=test_value))) + project = ratapi.Project.model_construct( + layers=ratapi.ClassList(ratapi.models.Layer(**dict(layer_params, roughness=test_value))) ) + allowed_values = ["Substrate Roughness"] with pytest.raises( ValueError, - match=f'The value "{test_value}" in the "roughness" field of "layers" must be defined in "parameters".', + match=re.escape( + f'The value "{test_value}" used in the "roughness" field of layers[0] must be defined in "parameters". ' + f'Please add "{test_value}" to "parameters" before including it in "layers".' + ), ): - project.check_allowed_values("layers", ["roughness"], ["Substrate Roughness"]) + project.check_allowed_values("layers", ["roughness"], allowed_values, allowed_values) @pytest.mark.parametrize( @@ -947,18 +1010,13 @@ def test_check_allowed_values_not_on_list(test_value: str) -> None: ) def test_check_allowed_background_resolution_values_constant(test_value: str) -> None: """We should not raise an error if string values are defined and on the appropriate list of allowed values.""" - project = RATapi.Project.model_construct( - backgrounds=RATapi.ClassList(RATapi.models.Background(type=TypeOptions.Constant, value_1=test_value)) - ) - assert ( - project.check_allowed_background_resolution_values( - "backgrounds", ["value_1"], ["Background Param 1"], ["Simulation"] - ) - is None + project = ratapi.Project.model_construct( + background_parameters=ratapi.ClassList(ratapi.models.Parameter(name="Background Param 1")), + backgrounds=ratapi.ClassList(ratapi.models.Background(type=TypeOptions.Constant, source=test_value)), ) + assert project.check_allowed_source("backgrounds") is None -@pytest.mark.skip("Data backgrounds not currently supported.") @pytest.mark.parametrize( "test_value", [ @@ -968,15 +1026,10 @@ def test_check_allowed_background_resolution_values_constant(test_value: str) -> ) def test_check_allowed_background_resolution_values_data(test_value: str) -> None: """We should not raise an error if string values are defined and on the appropriate list of allowed values.""" - project = RATapi.Project.model_construct( - backgrounds=RATapi.ClassList(RATapi.models.Background(type=TypeOptions.Data, value_1=test_value)) - ) - assert ( - project.check_allowed_background_resolution_values( - "backgrounds", ["value_1"], ["Background Param 1"], ["Simulation"] - ) - is None + project = ratapi.Project.model_construct( + backgrounds=ratapi.ClassList(ratapi.models.Background(type=TypeOptions.Data, source=test_value)) ) + assert project.check_allowed_source("backgrounds") is None @pytest.mark.parametrize( @@ -987,20 +1040,22 @@ def test_check_allowed_background_resolution_values_not_on_constant_list(test_va """If string values are defined and are not included on the correct list of allowed values we should raise a ValueError. """ - project = RATapi.Project.model_construct( - backgrounds=RATapi.ClassList(RATapi.models.Background(type=TypeOptions.Constant, value_1=test_value)) + project = ratapi.Project.model_construct( + backgrounds=ratapi.ClassList(ratapi.models.Background(type=TypeOptions.Constant, source=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".', + match=re.escape( + f'The value "{test_value}" used in the "source" field of backgrounds[0] must be defined in ' + f'"background_parameters". Please add "{test_value}" to "background_parameters" before including it in ' + f'"backgrounds".' + ), ): - project.check_allowed_background_resolution_values( - "backgrounds", ["value_1"], ["Background Param 1"], ["Simulation"] + project.check_allowed_source( + "backgrounds", ) -@pytest.mark.skip("Data backgrounds not currently supported.") @pytest.mark.parametrize( "test_value", [ @@ -1012,16 +1067,17 @@ def test_check_allowed_background_resolution_values_on_data_list(test_value: str """If string values are defined and are not included on the correct list of allowed values we should raise a ValueError. """ - project = RATapi.Project.model_construct( - backgrounds=RATapi.ClassList(RATapi.models.Background(type=TypeOptions.Data, value_1=test_value)) + project = ratapi.Project.model_construct( + backgrounds=ratapi.ClassList(ratapi.models.Background(type=TypeOptions.Data, source=test_value)) ) with pytest.raises( ValueError, - match=f'The value "{test_value}" in the "value_1" field of "backgrounds" must be ' f'defined in "data".', + match=re.escape( + f'The value "{test_value}" used in the "source" field of backgrounds[0] must be defined in "data". Please ' + f'add "{test_value}" to "data" before including it in "backgrounds".' + ), ): - project.check_allowed_background_resolution_values( - "backgrounds", ["value_1"], ["Background Param 1"], ["Simulation"] - ) + project.check_allowed_source("backgrounds") @pytest.mark.parametrize( @@ -1035,53 +1091,92 @@ 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. """ - project = RATapi.Project.model_construct( - contrasts=RATapi.ClassList(RATapi.models.Contrast(name="Test Contrast", model=test_values)), + project = ratapi.Project.model_construct( + contrasts=ratapi.ClassList(ratapi.models.Contrast(name="Test Contrast", model=test_values)), ) - assert project.check_contrast_model_allowed_values("contrasts", ["Test Layer"], "layers") is None + assert project.check_contrast_model_allowed_values("contrasts", ["Test Layer"], ["Test Layer"], "layers") is None @pytest.mark.parametrize( "test_values", [ - ["Undefined Param"], - ["Test Layer", "Undefined Param"], + ["Undefined Param 1"], + ["Test Layer", "Undefined Param 1"], + ["Undefined Param 1 ", "Test Layer", "Undefined Param 2"], ], ) 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 = RATapi.Project.model_construct( - contrasts=RATapi.ClassList(RATapi.models.Contrast(name="Test Contrast", model=test_values)), + project = ratapi.Project.model_construct( + contrasts=ratapi.ClassList(ratapi.models.Contrast(name="Test Contrast", model=test_values)), ) + allowed_values = ["Test Layer"] + missing_values = list(set(test_values) - set(allowed_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".', + match=re.escape( + f'The value{"s" if len(missing_values) > 1 else ""}: "{", ".join(str(i) for i in missing_values)}" used ' + f'in the "model" field of contrasts[0] must be defined in "layers". Please add all required values to ' + f'"layers" before including them in "contrasts".' + ), ): - project.check_contrast_model_allowed_values("contrasts", ["Test Layer"], "layers") + project.check_contrast_model_allowed_values("contrasts", allowed_values, allowed_values, "layers") + + +@pytest.mark.parametrize( + "test_values", + [ + ["Undefined Param 1"], + ["Test Layer", "Undefined Param 1"], + ["Undefined Param 1", "Test Layer", "Undefined Param 2"], + ], +) +def test_check_allowed_contrast_model_removed_from_list(test_values: list[str]) -> None: + """If string values are defined in a non-empty list and any of them have been removed from the list of allowed + values we should raise a ValueError. + """ + project = ratapi.Project.model_construct( + contrasts=ratapi.ClassList(ratapi.models.Contrast(name="Test Contrast", model=test_values)), + ) + previous_values = ["Test Layer", "Undefined Param 1", "Undefined Param 2"] + allowed_values = ["Test Layer"] + missing_values = list(set(test_values) - set(allowed_values)) + with pytest.raises( + ValueError, + match=re.escape( + f'The value{"s" if len(missing_values) > 1 else ""}: "{", ".join(str(i) for i in missing_values)}" used ' + f'in the "model" field of contrasts[0] must be defined in "layers". Please remove all unnecessary values ' + f'from "model" before attempting to delete them.' + ), + ): + project.check_contrast_model_allowed_values("contrasts", allowed_values, previous_values, "layers") @pytest.mark.parametrize( ["input_calc", "input_model", "expected_field_name"], [ (Calculations.Domains, LayerModels.StandardLayers, "domain_contrasts"), - (Calculations.NonPolarised, LayerModels.StandardLayers, "layers"), + (Calculations.Normal, LayerModels.StandardLayers, "layers"), (Calculations.Domains, LayerModels.CustomLayers, "custom_files"), - (Calculations.NonPolarised, LayerModels.CustomLayers, "custom_files"), + (Calculations.Normal, LayerModels.CustomLayers, "custom_files"), (Calculations.Domains, LayerModels.CustomXY, "custom_files"), - (Calculations.NonPolarised, LayerModels.CustomXY, "custom_files"), + (Calculations.Normal, 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. """ - project = RATapi.Project(calculation=input_calc, model=input_model) + project = ratapi.Project(calculation=input_calc, model=input_model) assert project.get_contrast_model_field() == expected_field_name +@pytest.mark.parametrize( + "project", + ["r1_default_project", "r1_monolayer", "input_project"], +) @pytest.mark.parametrize( "input_filename", [ @@ -1089,25 +1184,21 @@ def test_get_contrast_model_field(input_calc: Calculations, input_model: LayerMo "test_script", ], ) -def test_write_script(test_project, temp_dir, test_project_script, input_filename: str) -> None: +def test_write_script(project, request, temp_dir, 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 = request.getfixturevalue(project) + test_project.write_script("problem", Path(temp_dir, input_filename)) # Test the file is written in the correct place - 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) as f: - script = f.read() - - assert script == test_project_script + script_path = Path(temp_dir, "test_script.py") + assert script_path.exists() # Test we get the project object we expect when running the script - exec(script) - new_project = locals()["problem"] + local_dict = {} + exec(script_path.read_text(), globals(), local_dict) + new_project = local_dict["problem"] - for class_list in RATapi.project.class_lists: + for class_list in ratapi.project.class_lists: assert getattr(new_project, class_list) == getattr(test_project, class_list) @@ -1129,16 +1220,8 @@ def test_write_script_wrong_extension(test_project, extension: str) -> None: @pytest.mark.parametrize( ["class_list", "model_type", "field"], [ - ("backgrounds", "constant", "value_1"), - ("backgrounds", "constant", "value_2"), - ("backgrounds", "constant", "value_3"), - ("backgrounds", "constant", "value_4"), - ("backgrounds", "constant", "value_5"), - ("resolutions", "constant", "value_1"), - ("resolutions", "constant", "value_2"), - ("resolutions", "constant", "value_3"), - ("resolutions", "constant", "value_4"), - ("resolutions", "constant", "value_5"), + ("backgrounds", "constant", "source"), + ("resolutions", "constant", "source"), ("layers", "", "thickness"), ("layers", "", "SLD"), ("layers", "", "roughness"), @@ -1150,20 +1233,24 @@ def test_write_script_wrong_extension(test_project, extension: str) -> None: ("contrasts", "", "resolution"), ], ) +@pytest.mark.filterwarnings("ignore:The following values are not recognised by this*:UserWarning") def test_wrap_set(test_project, class_list: str, model_type: 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) class_list_str = f"{class_list}{f'.{model_type}' if model_type else ''}.{field}" + index = 0 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'"{RATapi.project.values_defined_in[class_list_str]}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" field of ' + f'{class_list}[{index}] must be defined in "{ratapi.project.values_defined_in[class_list_str]}". Please ' + f'add "undefined" to "{ratapi.project.values_defined_in[class_list_str]}" before including it in ' + f'"{class_list}".' + ), ): - test_attribute.set_fields(0, **{field: "undefined"}) + test_attribute.set_fields(index, **{field: "undefined"}) # Ensure invalid model was not changed assert test_attribute == orig_class_list @@ -1172,8 +1259,8 @@ def test_wrap_set(test_project, class_list: str, model_type: str, field: str) -> @pytest.mark.parametrize( ["class_list", "parameter", "field"], [ - ("background_parameters", "Background Param 1", "value_1"), - ("resolution_parameters", "Resolution Param 1", "value_1"), + ("background_parameters", "Background Param 1", "source"), + ("resolution_parameters", "Resolution Param 1", "source"), ("parameters", "Test SLD", "SLD"), ("data", "Simulation", "data"), ("backgrounds", "Background 1", "background"), @@ -1189,12 +1276,17 @@ def test_wrap_del(test_project, class_list: str, parameter: str, field: str) -> orig_class_list = copy.deepcopy(test_attribute) index = test_attribute.index(parameter) + sub_attribute_name = ratapi.project.model_names_used_in[class_list][0].attribute + sub_attribute = getattr(test_project, sub_attribute_name) + sub_index = [i for i, _ in enumerate(sub_attribute) if getattr(sub_attribute[i], field) == parameter][0] + 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'"{RATapi.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "{parameter}" used in the "{field}" field of ' + f'{sub_attribute_name}[{sub_index}] must be defined in "{class_list}". Please remove "{parameter}" from ' + f'"{sub_attribute_name}[{sub_index}].{field}" before attempting to delete it.' + ), ): del test_attribute[index] @@ -1205,16 +1297,8 @@ def test_wrap_del(test_project, class_list: str, parameter: str, field: str) -> @pytest.mark.parametrize( ["class_list", "model_type", "field", "model_params"], [ - ("backgrounds", "constant", "value_1", {}), - ("backgrounds", "constant", "value_2", {}), - ("backgrounds", "constant", "value_3", {}), - ("backgrounds", "constant", "value_4", {}), - ("backgrounds", "constant", "value_5", {}), - ("resolutions", "constant", "value_1", {}), - ("resolutions", "constant", "value_2", {}), - ("resolutions", "constant", "value_3", {}), - ("resolutions", "constant", "value_4", {}), - ("resolutions", "constant", "value_5", {}), + ("backgrounds", "constant", "source", {}), + ("resolutions", "constant", "source", {}), ("layers", "", "thickness", layer_params), ("layers", "", "SLD", layer_params), ("layers", "", "roughness", layer_params), @@ -1226,19 +1310,22 @@ def test_wrap_del(test_project, class_list: str, parameter: str, field: str) -> ("contrasts", "", "resolution", {}), ], ) +@pytest.mark.filterwarnings("ignore:The following values are not recognised by this*:UserWarning") def test_wrap_iadd(test_project, class_list: str, model_type: 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(RATapi.models, RATapi.project.model_in_classlist[class_list]) + input_model = model_classes[class_list] class_list_str = f"{class_list}{f'.{model_type}' if model_type else ''}.{field}" 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'"{RATapi.project.values_defined_in[class_list_str]}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" ' + f"field of {class_list}[{len(test_attribute)}] must be defined in " + f'"{ratapi.project.values_defined_in[class_list_str]}". Please add "undefined" to ' + f'"{ratapi.project.values_defined_in[class_list_str]}" before including it in "{class_list}".' + ), ): test_attribute += [input_model(**{**model_params, field: "undefined"})] @@ -1249,16 +1336,8 @@ def test_wrap_iadd(test_project, class_list: str, model_type: str, field: str, m @pytest.mark.parametrize( ["class_list", "model_type", "field", "model_params"], [ - ("backgrounds", "constant", "value_1", {}), - ("backgrounds", "constant", "value_2", {}), - ("backgrounds", "constant", "value_3", {}), - ("backgrounds", "constant", "value_4", {}), - ("backgrounds", "constant", "value_5", {}), - ("resolutions", "constant", "value_1", {}), - ("resolutions", "constant", "value_2", {}), - ("resolutions", "constant", "value_3", {}), - ("resolutions", "constant", "value_4", {}), - ("resolutions", "constant", "value_5", {}), + ("backgrounds", "constant", "source", {}), + ("resolutions", "constant", "source", {}), ("layers", "", "thickness", layer_params), ("layers", "", "SLD", layer_params), ("layers", "", "roughness", layer_params), @@ -1270,19 +1349,23 @@ def test_wrap_iadd(test_project, class_list: str, model_type: str, field: str, m ("contrasts", "", "resolution", {}), ], ) +@pytest.mark.filterwarnings("ignore:The following values are not recognised by this*:UserWarning") def test_wrap_append(test_project, class_list: str, model_type: 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(RATapi.models, RATapi.project.model_in_classlist[class_list]) + + input_model = model_classes[class_list] class_list_str = f"{class_list}{f'.{model_type}' if model_type else ''}.{field}" 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'"{RATapi.project.values_defined_in[class_list_str]}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" ' + f"field of {class_list}[{len(test_attribute)}] must be defined in " + f'"{ratapi.project.values_defined_in[class_list_str]}". Please add "undefined" to ' + f'"{ratapi.project.values_defined_in[class_list_str]}" before including it in "{class_list}".' + ), ): test_attribute.append(input_model(**{**model_params, field: "undefined"})) @@ -1293,16 +1376,8 @@ def test_wrap_append(test_project, class_list: str, model_type: str, field: str, @pytest.mark.parametrize( ["class_list", "model_type", "field", "model_params"], [ - ("backgrounds", "constant", "value_1", {}), - ("backgrounds", "constant", "value_2", {}), - ("backgrounds", "constant", "value_3", {}), - ("backgrounds", "constant", "value_4", {}), - ("backgrounds", "constant", "value_5", {}), - ("resolutions", "constant", "value_1", {}), - ("resolutions", "constant", "value_2", {}), - ("resolutions", "constant", "value_3", {}), - ("resolutions", "constant", "value_4", {}), - ("resolutions", "constant", "value_5", {}), + ("backgrounds", "constant", "source", {}), + ("resolutions", "constant", "source", {}), ("layers", "", "thickness", layer_params), ("layers", "", "SLD", layer_params), ("layers", "", "roughness", layer_params), @@ -1314,21 +1389,25 @@ def test_wrap_append(test_project, class_list: str, model_type: str, field: str, ("contrasts", "", "resolution", {}), ], ) +@pytest.mark.filterwarnings("ignore:The following values are not recognised by this*:UserWarning") def test_wrap_insert(test_project, class_list: str, model_type: 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(RATapi.models, RATapi.project.model_in_classlist[class_list]) + input_model = model_classes[class_list] class_list_str = f"{class_list}{f'.{model_type}' if model_type else ''}.{field}" + index = 0 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'"{RATapi.project.values_defined_in[class_list_str]}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" ' + f"field of {class_list}[{index}] must be defined in " + f'"{ratapi.project.values_defined_in[class_list_str]}". Please add "undefined" to ' + f'"{ratapi.project.values_defined_in[class_list_str]}" before including it in "{class_list}".' + ), ): - test_attribute.insert(0, input_model(**{**model_params, field: "undefined"})) + test_attribute.insert(index, input_model(**{**model_params, field: "undefined"})) # Ensure invalid model was not inserted assert test_attribute == orig_class_list @@ -1337,11 +1416,13 @@ def test_wrap_insert(test_project, class_list: str, model_type: str, field: str, @pytest.mark.parametrize( ["class_list", "field"], [ + ("backgrounds", "source"), ("backgrounds", "value_1"), ("backgrounds", "value_2"), ("backgrounds", "value_3"), ("backgrounds", "value_4"), ("backgrounds", "value_5"), + ("resolutions", "source"), ("resolutions", "value_1"), ("resolutions", "value_2"), ("resolutions", "value_3"), @@ -1355,11 +1436,12 @@ def test_wrap_insert(test_project, class_list: str, model_type: str, field: str, ("contrasts", "resolution"), ], ) +@pytest.mark.filterwarnings("ignore:The following values are not recognised by this*:UserWarning") 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) orig_class_list = copy.deepcopy(test_attribute) - input_model = getattr(RATapi.models, RATapi.project.model_in_classlist[class_list]) + input_model = model_classes[class_list] with pytest.raises(TypeError): test_attribute.insert(input_model) @@ -1371,8 +1453,8 @@ def test_wrap_insert_type_error(test_project, class_list: str, field: str) -> No @pytest.mark.parametrize( ["class_list", "parameter", "field"], [ - ("background_parameters", "Background Param 1", "value_1"), - ("resolution_parameters", "Resolution Param 1", "value_1"), + ("background_parameters", "Background Param 1", "source"), + ("resolution_parameters", "Resolution Param 1", "source"), ("parameters", "Test SLD", "SLD"), ("data", "Simulation", "data"), ("backgrounds", "Background 1", "background"), @@ -1388,12 +1470,17 @@ def test_wrap_pop(test_project, class_list: str, parameter: str, field: str) -> orig_class_list = copy.deepcopy(test_attribute) index = test_attribute.index(parameter) + sub_attribute_name = ratapi.project.model_names_used_in[class_list][0].attribute + sub_attribute = getattr(test_project, sub_attribute_name) + sub_index = [i for i, _ in enumerate(sub_attribute) if getattr(sub_attribute[i], field) == parameter][0] + 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'"{RATapi.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "{parameter}" used in the "{field}" field of ' + f'{sub_attribute_name}[{sub_index}] must be defined in "{class_list}". Please remove "{parameter}" from ' + f'"{sub_attribute_name}[{sub_index}].{field}" before attempting to delete it.' + ), ): test_attribute.pop(index) @@ -1404,8 +1491,8 @@ def test_wrap_pop(test_project, class_list: str, parameter: str, field: str) -> @pytest.mark.parametrize( ["class_list", "parameter", "field"], [ - ("background_parameters", "Background Param 1", "value_1"), - ("resolution_parameters", "Resolution Param 1", "value_1"), + ("background_parameters", "Background Param 1", "source"), + ("resolution_parameters", "Resolution Param 1", "source"), ("parameters", "Test SLD", "SLD"), ("data", "Simulation", "data"), ("backgrounds", "Background 1", "background"), @@ -1420,12 +1507,17 @@ def test_wrap_remove(test_project, class_list: str, parameter: str, field: str) test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) + sub_attribute_name = ratapi.project.model_names_used_in[class_list][0].attribute + sub_attribute = getattr(test_project, sub_attribute_name) + sub_index = [i for i, _ in enumerate(sub_attribute) if getattr(sub_attribute[i], field) == parameter][0] + 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'"{RATapi.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "{parameter}" used in the "{field}" field of ' + f'{sub_attribute_name}[{sub_index}] must be defined in "{class_list}". Please remove "{parameter}" from ' + f'"{sub_attribute_name}[{sub_index}].{field}" before attempting to delete it.' + ), ): test_attribute.remove(parameter) @@ -1436,8 +1528,8 @@ def test_wrap_remove(test_project, class_list: str, parameter: str, field: str) @pytest.mark.parametrize( ["class_list", "parameter", "field"], [ - ("background_parameters", "Background Param 1", "value_1"), - ("resolution_parameters", "Resolution Param 1", "value_1"), + ("background_parameters", "Background Param 1", "source"), + ("resolution_parameters", "Resolution Param 1", "source"), ("parameters", "Test Thickness", "thickness"), ("data", "Simulation", "data"), ("backgrounds", "Background 1", "background"), @@ -1452,12 +1544,17 @@ def test_wrap_clear(test_project, class_list: str, parameter: str, field: str) - test_attribute = getattr(test_project, class_list) orig_class_list = copy.deepcopy(test_attribute) + sub_attribute_name = ratapi.project.model_names_used_in[class_list][0].attribute + sub_attribute = getattr(test_project, sub_attribute_name) + sub_index = [i for i, _ in enumerate(sub_attribute) if getattr(sub_attribute[i], field) == parameter][0] + 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'"{RATapi.project.model_names_used_in[class_list].attribute}" ' - f'must be defined in "{class_list}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "{parameter}" used in the "{field}" field of ' + f'{sub_attribute_name}[{sub_index}] must be defined in "{class_list}". Please remove "{parameter}" from ' + f'"{sub_attribute_name}[{sub_index}].{field}" before attempting to delete it.' + ), ): test_attribute.clear() @@ -1468,16 +1565,8 @@ def test_wrap_clear(test_project, class_list: str, parameter: str, field: str) - @pytest.mark.parametrize( ["class_list", "model_type", "field", "model_params"], [ - ("backgrounds", "constant", "value_1", {}), - ("backgrounds", "constant", "value_2", {}), - ("backgrounds", "constant", "value_3", {}), - ("backgrounds", "constant", "value_4", {}), - ("backgrounds", "constant", "value_5", {}), - ("resolutions", "constant", "value_1", {}), - ("resolutions", "constant", "value_2", {}), - ("resolutions", "constant", "value_3", {}), - ("resolutions", "constant", "value_4", {}), - ("resolutions", "constant", "value_5", {}), + ("backgrounds", "constant", "source", {}), + ("resolutions", "constant", "source", {}), ("layers", "", "thickness", layer_params), ("layers", "", "SLD", layer_params), ("layers", "", "roughness", layer_params), @@ -1489,21 +1578,85 @@ def test_wrap_clear(test_project, class_list: str, parameter: str, field: str) - ("contrasts", "", "resolution", {}), ], ) +@pytest.mark.filterwarnings("ignore:The following values are not recognised by this*:UserWarning") def test_wrap_extend(test_project, class_list: str, model_type: 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(RATapi.models, RATapi.project.model_in_classlist[class_list]) + input_model = model_classes[class_list] class_list_str = f"{class_list}{f'.{model_type}' if model_type else ''}.{field}" 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'"{RATapi.project.values_defined_in[class_list_str]}".', + match=re.escape( + f'1 validation error for Project\n Value error, The value "undefined" used in the "{field}" ' + f"field of {class_list}[{len(test_attribute)}] must be defined in " + f'"{ratapi.project.values_defined_in[class_list_str]}". Please add "undefined" to ' + f'"{ratapi.project.values_defined_in[class_list_str]}" before including it in "{class_list}".' + ), ): test_attribute.extend([input_model(**{**model_params, field: "undefined"})]) # Ensure invalid model was not appended assert test_attribute == orig_class_list + + +@pytest.mark.parametrize( + "project", + [ + "r1_default_project", + "r1_monolayer", + "r1_monolayer_8_contrasts", + "r1_orso_polymer", + "r1_motofit_bench_mark", + "dspc_standard_layers", + "dspc_custom_layers", + "dspc_custom_xy", + "domains_standard_layers", + "domains_custom_layers", + "domains_custom_xy", + "absorption", + "absorption_different_function", + ], +) +def test_save_load(project, request): + """Test that saving and loading a project returns the same project.""" + original_project = request.getfixturevalue(project) + + with tempfile.TemporaryDirectory() as tmp: + # ignore relative path warnings + path = Path(tmp, "project.json") + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + original_project.save(path) + converted_project = ratapi.Project.load(path) + + for field in ratapi.Project.model_fields: + assert getattr(converted_project, field) == getattr(original_project, field) + + +def test_relative_paths(): + """Test that ``try_relative_to`` correctly creates relative paths to subfolders.""" + + cur_path = Path(".").resolve() + data_path = cur_path / "data/myfile.dat" + assert Path(ratapi.project.try_relative_to(data_path, cur_path)) == Path("data/myfile.dat") + + # relative path will be left relative. + data_path = "data/myfile.dat" + assert Path(ratapi.project.try_relative_to(data_path, cur_path)) == Path("data/myfile.dat") + + +def test_relative_paths_warning(): + """Test that we get a warning for trying to walk up paths.""" + + cur_path = Path(".").resolve() + data_path = cur_path / "tmp/project/data/mydata.dat" + relative_path = cur_path / "tmp/project/project_path/myproj.dat" + + with pytest.warns( + match="Could not write custom file path as relative to the project directory, " + "which means that it may not work on other devices. If you would like to share your project, " + "make sure your custom files are in a subfolder of the project save location.", + ): + assert Path(ratapi.project.try_relative_to(data_path, relative_path)) == data_path diff --git a/tests/test_run.py b/tests/test_run.py index a103376a..3c85fbcd 100644 --- a/tests/test_run.py +++ b/tests/test_run.py @@ -3,17 +3,19 @@ We use the example for both a reflectivity calculation, and Bayesian analysis using the Dream algorithm. """ +import io +from contextlib import redirect_stdout from unittest import mock import numpy as np import pytest -import RATapi -import RATapi.outputs -import RATapi.rat_core -from RATapi.events import EventTypes, ProgressEventData, notify -from RATapi.run import ProgressBar -from RATapi.utils.enums import Calculations, Geometries, LayerModels, Procedures +import ratapi +import ratapi.outputs +import ratapi.rat_core +from ratapi.events import EventTypes, ProgressEventData, notify +from ratapi.run import ProgressBar, TextOutput +from ratapi.utils.enums import Calculations, Geometries, LayerModels, Procedures from tests.utils import check_results_equal @@ -22,8 +24,8 @@ def reflectivity_calculation_problem(): """The output C++ ProblemDefinition object for a reflectivity calculation of the project set out in "DSPC_standard_layers.py". """ - problem = RATapi.rat_core.ProblemDefinition() - problem.TF = Calculations.NonPolarised + problem = ratapi.rat_core.ProblemDefinition() + problem.TF = Calculations.Normal problem.modelType = LayerModels.StandardLayers problem.geometry = Geometries.SubstrateLiquid problem.useImaginary = False @@ -52,28 +54,43 @@ def reflectivity_calculation_problem(): 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]) + problem.bulkIns = np.array([2.073e-06]) + problem.bulkOuts = np.array([5.98e-06, 2.21e-06]) problem.scalefactors = np.array([0.1, 0.15]) - problem.domainRatio = np.array([]) + problem.domainRatios = np.array([]) problem.backgroundParams = np.array([2.23e-06, 3.38e-06]) problem.resolutionParams = np.array([0.03]) problem.contrastBulkIns = np.array([1.0, 1.0]) problem.contrastBulkOuts = np.array([1.0, 2.0]) - problem.contrastQzshifts = np.array([0.0, 0.0]) problem.contrastScalefactors = np.array([1.0, 2.0]) - problem.contrastBackgroundParams = np.array([1.0, 2.0]) - problem.contrastBackgroundActions = np.array([1.0, 1.0]) - problem.contrastResolutionParams = np.array([1.0, 1.0]) + problem.contrastBackgroundParams = [[1.0], [2.0]] + problem.contrastBackgroundTypes = ["constant", "constant"] + problem.contrastBackgroundActions = [1.0, 1.0] + problem.contrastResolutionParams = [[1.0], [1.0]] + problem.contrastResolutionTypes = ["constant", "constant"] problem.contrastCustomFiles = np.array([np.nan, np.nan]) problem.contrastDomainRatios = np.array([0.0, 0.0]) problem.resample = np.array([0.0, 0.0]) problem.dataPresent = np.array([1.0, 1.0]) - problem.oilChiDataPresent = np.array([0.0, 0.0]) + problem.dataLimits = [[0.011403, 0.59342], [0.011403, 0.59342]] + problem.simulationLimits = [[0.011403, 0.59342], [0.011403, 0.59342]] problem.numberOfContrasts = 2.0 problem.numberOfLayers = 6.0 + problem.repeatLayers = [1.0, 1.0] + problem.layersDetails = [ + np.array([2.0]), + np.array([4.0]), + np.array([10.0]), + np.array([8.0]), + np.array([13.0]), + np.array([16.0]), + ] + problem.contrastLayers = [ + np.array([[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 5.0]]), + np.array([[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 5.0]]), + ] problem.numberOfDomainContrasts = 0.0 + problem.domainContrastLayers = [] problem.fitParams = np.array( [ 3.000e00, @@ -96,21 +113,6 @@ def reflectivity_calculation_problem(): 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], @@ -133,21 +135,45 @@ def reflectivity_calculation_problem(): [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], - ], + problem.names.params = [ + "Substrate Roughness", + "Oxide Thickness", + "Oxide SLD", + "SAM Tails Thickness", + "SAM Tails SLD", + "SAM Tails Hydration", + "SAM Roughness", + "CW Thickness", + "CW SLD", + "SAM Heads Thickness", + "SAM Heads SLD", + "SAM Heads Hydration", + "Bilayer Heads Thickness", + "Bilayer Heads SLD", + "Bilayer Roughness", + "Bilayer Tails Thickness", + "Bilayer Tails SLD", + "Bilayer Tails Hydration", + "Bilayer Heads Hydration", + "CW Hydration", + "Oxide Hydration", + ] + problem.names.backgroundParams = ["Background parameter D2O", "Background parameter SMW"] + problem.names.scalefactors = ["Scalefactor 1", "Scalefactor 2"] + problem.names.bulkIns = ["Silicon"] + problem.names.bulkOuts = ["D2O", "SMW"] + problem.names.resolutionParams = ["Resolution Param 1"] + problem.names.domainRatios = [] + problem.names.contrasts = ["D2O", "SMW"] + problem.checks.params = np.array( + [1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0] ) + problem.checks.backgroundParams = np.array([1.0, 1.0]) + problem.checks.scalefactors = np.array([0.0, 0.0]) + problem.checks.bulkIns = np.array([0.0]) + problem.checks.bulkOuts = np.array([1.0, 1.0]) + problem.checks.resolutionParams = np.array([0.0]) + problem.checks.domainRatios = np.array([]) return problem @@ -159,8 +185,8 @@ def dream_problem(): This optimisation used the parameters: nSamples=50000, nChains=10. """ - problem = RATapi.rat_core.ProblemDefinition() - problem.TF = Calculations.NonPolarised + problem = ratapi.rat_core.ProblemDefinition() + problem.TF = Calculations.Normal problem.modelType = LayerModels.StandardLayers problem.geometry = Geometries.SubstrateLiquid problem.useImaginary = False @@ -189,28 +215,43 @@ def dream_problem(): 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]) + problem.bulkIns = np.array([2.073e-06]) + problem.bulkOuts = np.array([6.01489149e-06, 1.59371685e-06]) problem.scalefactors = np.array([0.1, 0.15]) - problem.domainRatio = np.array([]) + problem.domainRatios = np.array([]) problem.backgroundParams = np.array([2.37113128e-06, 1.99006694e-06]) problem.resolutionParams = np.array([0.03]) problem.contrastBulkIns = np.array([1.0, 1.0]) problem.contrastBulkOuts = np.array([1.0, 2.0]) - problem.contrastQzshifts = np.array([0.0, 0.0]) problem.contrastScalefactors = np.array([1.0, 2.0]) - problem.contrastBackgroundParams = np.array([1.0, 2.0]) - problem.contrastBackgroundActions = np.array([1.0, 1.0]) - problem.contrastResolutionParams = np.array([1.0, 1.0]) + problem.contrastBackgroundParams = [[1.0], [2.0]] + problem.contrastBackgroundTypes = ["constant", "constant"] + problem.contrastBackgroundActions = [1.0, 1.0] + problem.contrastResolutionParams = [[1.0], [1.0]] + problem.contrastResolutionTypes = ["constant", "constant"] problem.contrastCustomFiles = np.array([np.nan, np.nan]) problem.contrastDomainRatios = np.array([0.0, 0.0]) problem.resample = np.array([0.0, 0.0]) problem.dataPresent = np.array([1.0, 1.0]) - problem.oilChiDataPresent = np.array([0.0, 0.0]) + problem.dataLimits = [[0.011403, 0.59342], [0.011403, 0.59342]] + problem.simulationLimits = [[0.011403, 0.59342], [0.011403, 0.59342]] problem.numberOfContrasts = 2.0 problem.numberOfLayers = 6.0 + problem.repeatLayers = [1.0, 1.0] + problem.layersDetails = [ + np.array([2.0]), + np.array([4.0]), + np.array([10.0]), + np.array([8.0]), + np.array([13.0]), + np.array([16.0]), + ] + problem.contrastLayers = [ + np.array([[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 5.0]]), + np.array([[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0, 5.0]]), + ] problem.numberOfDomainContrasts = 0.0 + problem.domainContrastLayers = [] problem.fitParams = np.array( [ 6.19503045e00, @@ -233,22 +274,6 @@ def dream_problem(): 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], @@ -271,22 +296,45 @@ def dream_problem(): [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], - ], + problem.names.params = [ + "Substrate Roughness", + "Oxide Thickness", + "Oxide SLD", + "SAM Tails Thickness", + "SAM Tails SLD", + "SAM Tails Hydration", + "SAM Roughness", + "CW Thickness", + "CW SLD", + "SAM Heads Thickness", + "SAM Heads SLD", + "SAM Heads Hydration", + "Bilayer Heads Thickness", + "Bilayer Heads SLD", + "Bilayer Roughness", + "Bilayer Tails Thickness", + "Bilayer Tails SLD", + "Bilayer Tails Hydration", + "Bilayer Heads Hydration", + "CW Hydration", + "Oxide Hydration", + ] + problem.names.backgroundParams = ["Background parameter D2O", "Background parameter SMW"] + problem.names.scalefactors = ["Scalefactor 1", "Scalefactor 2"] + problem.names.bulkIns = ["Silicon"] + problem.names.bulkOuts = ["D2O", "SMW"] + problem.names.resolutionParams = ["Resolution Param 1"] + problem.names.domainRatios = [] + problem.names.contrasts = ["D2O", "SMW"] + problem.checks.params = np.array( + [1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0] ) + problem.checks.backgroundParams = np.array([1.0, 1.0]) + problem.checks.scalefactors = np.array([0.0, 0.0]) + problem.checks.bulkIns = np.array([0.0]) + problem.checks.bulkOuts = np.array([1.0, 1.0]) + problem.checks.resolutionParams = np.array([0.0]) + problem.checks.domainRatios = np.array([]) return problem @@ -314,12 +362,12 @@ def test_run(test_procedure, test_output_problem, test_output_results, test_baye test_results = request.getfixturevalue(test_results) with mock.patch.object( - RATapi.rat_core, + ratapi.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 = RATapi.run(input_project, RATapi.Controls(procedure=test_procedure)) + project, results = ratapi.run(input_project, ratapi.Controls(procedure=test_procedure)) check_results_equal(test_results, results) @@ -329,13 +377,25 @@ def test_progress_bar() -> None: event.message = "TESTING" event.percent = 0.2 with ProgressBar() as bar: - assert bar.n == 0 + assert bar.pbar is None notify(EventTypes.Progress, event) - assert bar.desc == "TESTING" - assert bar.n == 20 + assert bar.pbar.desc == "TESTING" + assert bar.pbar.n == 20 event.message = "AGAIN" event.percent = 0.6 notify(EventTypes.Progress, event) - assert bar.desc == "AGAIN" - assert bar.n == 60 + assert bar.pbar.desc == "AGAIN" + assert bar.pbar.n == 60 + + +def test_text_output() -> None: + with io.StringIO() as buf, redirect_stdout(buf), TextOutput(): + assert buf.getvalue() == "" + notify(EventTypes.Message, "Hello World") + assert buf.getvalue() == "Hello World" + + with io.StringIO() as buf, redirect_stdout(buf), TextOutput(display=False): + assert buf.getvalue() == "" + notify(EventTypes.Message, "Hello World") + assert buf.getvalue() == "" diff --git a/tests/test_wrappers.py b/tests/test_wrappers.py index 44be0756..782e833c 100644 --- a/tests/test_wrappers.py +++ b/tests/test_wrappers.py @@ -3,21 +3,21 @@ import pytest -import RATapi.wrappers +import ratapi.wrappers def test_matlab_wrapper() -> None: with ( - mock.patch.object(RATapi.wrappers.MatlabWrapper, "loader", None), + mock.patch.object(ratapi.wrappers.MatlabWrapper, "loader", None), pytest.raises(ImportError), ): - RATapi.wrappers.MatlabWrapper("demo.m") + ratapi.wrappers.MatlabWrapper("demo.m") mocked_matlab_future = mock.MagicMock() mocked_engine = mock.MagicMock() mocked_matlab_future.result.return_value = mocked_engine - with mock.patch.object(RATapi.wrappers.MatlabWrapper, "loader", mocked_matlab_future): - wrapper = RATapi.wrappers.MatlabWrapper("demo.m") + with mock.patch.object(ratapi.wrappers.MatlabWrapper, "loader", mocked_matlab_future): + wrapper = ratapi.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(".") @@ -25,22 +25,28 @@ def test_matlab_wrapper() -> None: handle = wrapper.getHandle() mocked_engine.demo.return_value = ([2], 5) - result = handle([1], [2], [3], 0) + result = handle([1], [2], [3], 1) assert result == ([2], 5) assert wrapper.engine.demo.call_args[0] == ([1], [2], [3], 1) mocked_engine.demo.assert_called_once() mocked_engine.demo.return_value = ([3, 1], 7) - result = handle([4], [5], [6], 1, 1) + result = handle([4], [5], [6], 2, 2) assert result == ([3, 1], 7) assert wrapper.engine.demo.call_args[0] == ([4], [5], [6], 2, 2) assert mocked_engine.demo.call_count == 2 + mocked_engine.demo.return_value = [4, 7] + result = handle([3], [9]) + assert result == [4, 7] + assert wrapper.engine.demo.call_args[0] == ([3], [9]) + assert mocked_engine.demo.call_count == 3 + def test_dylib_wrapper() -> None: mocked_engine = mock.MagicMock() - with mock.patch("RATapi.wrappers.RATapi.rat_core.DylibEngine", mocked_engine): - wrapper = RATapi.wrappers.DylibWrapper("demo.dylib", "demo") + with mock.patch("ratapi.wrappers.ratapi.rat_core.DylibEngine", mocked_engine): + wrapper = ratapi.wrappers.DylibWrapper("demo.dylib", "demo") mocked_engine.assert_called_once_with("demo.dylib", "demo") wrapper.engine.invoke.return_value = ([2], 5) diff --git a/tests/utils.py b/tests/utils.py index 91ac0f1f..5387b30a 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -1,6 +1,6 @@ import numpy as np -import RATapi.outputs +import ratapi.outputs class InputAttributes: @@ -30,37 +30,33 @@ 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, RATapi.outputs.Results) and isinstance(expected_results, RATapi.outputs.Results) + isinstance(actual_results, ratapi.outputs.Results) and isinstance(expected_results, ratapi.outputs.Results) ) or ( - isinstance(actual_results, RATapi.outputs.BayesResults) - and isinstance(expected_results, RATapi.outputs.BayesResults) + isinstance(actual_results, ratapi.outputs.BayesResults) + and isinstance(expected_results, ratapi.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 list_field in ratapi.outputs.results_fields["list_fields"]: + for a, b in zip(getattr(actual_results, list_field), getattr(expected_results, list_field), strict=False): assert (a == b).all() - for list_field in double_list_fields: + for list_field in ratapi.outputs.results_fields["double_list_fields"]: actual_list = getattr(actual_results, list_field) 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], strict=False): assert (a == b).all() # Compare the final fields @@ -74,8 +70,8 @@ def check_results_equal(actual_results, expected_results) -> None: for field in contrast_param_fields: assert (getattr(actual_results.contrastParams, field) == getattr(expected_results.contrastParams, field)).all() - if isinstance(actual_results, RATapi.outputs.BayesResults) and isinstance( - expected_results, RATapi.outputs.BayesResults + if isinstance(actual_results, ratapi.outputs.BayesResults) and isinstance( + expected_results, ratapi.outputs.BayesResults ): check_bayes_fields_equal(actual_results, expected_results) @@ -86,80 +82,27 @@ def check_bayes_fields_equal(actual_results, expected_results) -> None: 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"], - } - - for subclass in subclasses: + for subclass in ratapi.outputs.bayes_results_subclasses: actual_subclass = getattr(actual_results, subclass) expected_subclass = getattr(expected_results, subclass) - for field in param_fields[subclass]: + for field in ratapi.outputs.bayes_results_fields["param_fields"][subclass]: 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 field in ratapi.outputs.bayes_results_fields["list_fields"][subclass]: + for a, b in zip(getattr(actual_subclass, field), getattr(expected_subclass, field), strict=False): assert (a == b).all() - for field in double_list_fields[subclass]: + for field in ratapi.outputs.bayes_results_fields["double_list_fields"][subclass]: actual_list = getattr(actual_subclass, field) 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], strict=False): assert (a == b).all() # Need to account for the arrays that are initialised as "NaN" in the compiled code - for array in array_fields[subclass]: + for array in ratapi.outputs.bayes_results_fields["array_fields"][subclass]: actual_array = getattr(actual_subclass, array) expected_array = getattr(expected_subclass, array) for i in range(len(actual_array)):