diff --git a/.github/workflows/test-fair-database.yml b/.github/workflows/test-fair-database.yml new file mode 100644 index 000000000..9652a8377 --- /dev/null +++ b/.github/workflows/test-fair-database.yml @@ -0,0 +1,54 @@ +name: Tests + +on: + [push, pull_request] + +defaults: + run: + shell: bash + +jobs: + unit-test: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest, ubuntu-latest, windows-latest] + python-version: ['3.12'] + fail-fast: false + + steps: + + - name: Obtain SasData source from git + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: | + **/test.yml + **/requirements*.txt + + ### Installation of build-dependencies + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + python -m pip install wheel setuptools + python -m pip install -r requirements.txt + python -m pip install -r sasdata/fair_database/requirements.txt + + ### Build and test sasdata + + - name: Build sasdata + run: | + # BUILD SASDATA + python -m pip install -e . + + ### Build documentation (if enabled) + + - name: Test with Django tests + run: | + python sasdata/fair_database/manage.py test sasdata.fair_database diff --git a/.gitignore b/.gitignore index 4485f2bcb..a24aa7e04 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ **/build /dist .mplconfig +**/db.sqlite3 # INSTALL.md recommends a venv that should not be committed venv @@ -41,6 +42,11 @@ venv tests.log /.pytest_cache +# Unit test / coverage reports +htmlcov/ +.coverage +.cache/ + # Installer files /installers/build /installers/dist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e75be384f..f1958b339 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,10 +1,19 @@ -default_install_hook_types: [pre-commit, pre-push] - repos: - - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.1 - hooks: - # Run the linter, applying any available fixes - - id: ruff-check - stages: [ pre-commit, pre-push ] - args: [ --fix-only ] +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + files: "sasdata/fair_database/.*" +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.9.2 + hooks: + - id: ruff + args: [--fix, --exit-non-zero-on-fix] + files: "sasdata/fair_database/.*" + - id: ruff-format + files: "sasdata/fair_database/.*" +- repo: https://github.com/codespell-project/codespell + rev: v2.3.0 + hooks: + - id: codespell + files: "sasdata/fair_database/.*" diff --git a/requirements.txt b/requirements.txt index 463703b10..a1609faa1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -16,4 +16,3 @@ html5lib # Other stuff matplotlib -pre-commit diff --git a/sasdata/ascii_reader_metadata.py b/sasdata/ascii_reader_metadata.py index 7a2fa01ad..d507bbb3f 100644 --- a/sasdata/ascii_reader_metadata.py +++ b/sasdata/ascii_reader_metadata.py @@ -1,5 +1,5 @@ -import re from dataclasses import dataclass, field +from re import split as re_split from typing import TypeVar initial_metadata = { @@ -10,27 +10,11 @@ 'process': ['name', 'date', 'description', 'term', 'notes'], 'sample': ['name', 'sample_id', 'thickness', 'transmission', 'temperature', 'position', 'orientation', 'details'], 'transmission_spectrum': ['name', 'timestamp', 'transmission', 'transmission_deviation'], - 'magnetic': ['demagnetizing_field', 'saturation_magnetization', 'applied_magnetic_field', 'counting_index'], 'other': ['title', 'run', 'definition'] } -CASING_REGEX = r'[A-Z][a-z]*' - -# First item has the highest precedence. -SEPARATOR_PRECEDENCE = [ - '_', - '-', -] -# If none of these characters exist in that string, use casing. See init_separator - T = TypeVar('T') -# TODO: There may be a better place for this. -pairings = {'I': 'dI', 'Q': 'dQ', 'Qx': 'dQx', 'Qy': 'dQy'} -pairing_error = {value: key for key, value in pairings.items()} -# Allows this to be bidirectional. -bidirectional_pairings = pairings | pairing_error - @dataclass class AsciiMetadataCategory[T]: values: dict[str, T] = field(default_factory=dict) @@ -42,68 +26,13 @@ def default_categories() -> dict[str, AsciiMetadataCategory[str | int]]: class AsciiReaderMetadata: # Key is the filename. filename_specific_metadata: dict[str, dict[str, AsciiMetadataCategory[str]]] = field(default_factory=dict) - # True instead of str means use the casing to separate the filename. - filename_separator: dict[str, str | bool] = field(default_factory=dict) + filename_separator: dict[str, str] = field(default_factory=dict) master_metadata: dict[str, AsciiMetadataCategory[int]] = field(default_factory=default_categories) - def init_separator(self, filename: str): - separator = next(filter(lambda c: c in SEPARATOR_PRECEDENCE, filename), True) - self.filename_separator[filename] = separator - - def filename_components(self, filename: str, cut_off_extension: bool = True, capture: bool = False) -> list[str]: - """Split the filename into several components based on the current separator for that file.""" - separator = self.filename_separator[filename] - # FIXME: This sort of string construction may be an issue. Might need an alternative. - base_str = '({})' if capture else '{}' - if isinstance(separator, str): - splitted = re.split(base_str.replace('{}', separator), filename) - else: - splitted = re.findall(base_str.replace('{}', CASING_REGEX), filename) - # If the last component has a file extensions, remove it. - last_component = splitted[-1] - if cut_off_extension and '.' in last_component: - pos = last_component.index('.') - last_component = last_component[:pos] - splitted[-1] = last_component - return splitted - - def purge_unreachable(self, filename: str): - """This is used when the separator has changed. If lets say we now have 2 components when there were 5 but the - 3rd component was selected, this will now produce an index out of range exception. Thus we'll need to purge this - to stop exceptions from happening.""" - components = self.filename_components(filename) - component_length = len(components) - # Converting to list as this mutates the dictionary as it goes through it. - for category_name, category in list(self.master_metadata.items()): - for key, value in list(category.values.items()): - if value >= component_length: - del self.master_metadata[category_name].values[key] + def filename_components(self, filename: str) -> list[str]: + return re_split(self.filename_separator[filename], filename) - def all_file_metadata(self, filename: str) -> dict[str, AsciiMetadataCategory[str]]: - """Return all of the metadata for known for the specified filename. This - will combin the master metadata specified for all files with the - metadata specific to that filename.""" - file_metadata = self.filename_specific_metadata[filename] - components = self.filename_components(filename) - # The ordering here is important. If there are conflicts, the second dictionary will override the first one. - # Conflicts shouldn't really be happening anyway but if they do, we're gonna go with the master metadata taking - # precedence for now. - return_metadata: dict[str, AsciiMetadataCategory[str]] = {} - for category_name, category in (file_metadata | self.master_metadata).items(): - combined_category_dict = category.values | self.master_metadata[category_name].values - new_category_dict: dict[str, str] = {} - for key, value in combined_category_dict.items(): - if isinstance(value, str): - new_category_dict[key] = value - elif isinstance(value, int): - new_category_dict[key] = components[value] - else: - raise TypeError(f'Invalid value for {key} in {category_name}') - new_category = AsciiMetadataCategory(new_category_dict) - return_metadata[category_name] = new_category - return return_metadata def get_metadata(self, category: str, value: str, filename: str, error_on_not_found=False) -> str | None: - """Get a particular piece of metadata for the filename.""" components = self.filename_components(filename) # We prioritise the master metadata. @@ -122,10 +51,6 @@ def get_metadata(self, category: str, value: str, filename: str, error_on_not_fo return None def update_metadata(self, category: str, key: str, filename: str, new_value: str | int): - """Update the metadata for a filename. If the new_value is a string, - then this new metadata will be specific to that file. Otherwise, if - new_value is an integer, then this will represent the component of the - filename that this metadata applies to all.""" if isinstance(new_value, str): self.filename_specific_metadata[filename][category].values[key] = new_value # TODO: What about the master metadata? Until that's gone, that still takes precedence. @@ -135,7 +60,6 @@ def update_metadata(self, category: str, key: str, filename: str, new_value: str raise TypeError('Invalid type for new_value') def clear_metadata(self, category: str, key: str, filename: str): - """Remove any metadata recorded for a certain filename.""" category_obj = self.filename_specific_metadata[filename][category] if key in category_obj.values: del category_obj.values[key] @@ -143,7 +67,5 @@ def clear_metadata(self, category: str, key: str, filename: str): del self.master_metadata[category].values[key] def add_file(self, new_filename: str): - """Add a filename to the metadata, filling it with some default - categories.""" # TODO: Fix typing here. Pyright is showing errors. self.filename_specific_metadata[new_filename] = default_categories() diff --git a/sasdata/checklist.txt b/sasdata/checklist.txt new file mode 100644 index 000000000..c25c7d895 --- /dev/null +++ b/sasdata/checklist.txt @@ -0,0 +1,3 @@ +Things to check once everything is in place: + +1) Do any centigrade fields read in incorrectly? \ No newline at end of file diff --git a/sasdata/data.py b/sasdata/data.py index fd294a432..596d12097 100644 --- a/sasdata/data.py +++ b/sasdata/data.py @@ -1,150 +1,40 @@ -import typing -import h5py -import numpy as np -from h5py._hl.group import Group as HDF5Group -from sasdata import dataset_types -from sasdata.dataset_types import DatasetType -from sasdata.metadata import Metadata, MetadataEncoder -from sasdata.quantities.quantity import Quantity + +from sasdata.metadata import Metadata +from sasdata.quantities.quantity import NamedQuantity class SasData: - def __init__( - self, - name: str, - data_contents: dict[str, Quantity], - dataset_type: DatasetType, - metadata: Metadata, - verbose: bool = False, - ): + def __init__(self, name: str, + data_contents: list[NamedQuantity], + raw_metadata: Group, + verbose: bool=False): + self.name = name - # validate data contents - if not all([key in dataset_type.optional or key in dataset_type.required for key in data_contents]): - raise ValueError(f"Columns don't match the dataset type: {[key for key in data_contents]}") self._data_contents = data_contents + self._raw_metadata = raw_metadata self._verbose = verbose - self.metadata = metadata - - # TODO: Could this be optional? - self.dataset_type: DatasetType = dataset_type + self.metadata = Metadata(AccessorTarget(raw_metadata, verbose=verbose)) # Components that need to be organised after creation - self.mask = None # TODO: fill out - self.model_requirements = None # TODO: fill out - - # TODO: Handle the other data types. - @property - def ordinate(self) -> Quantity: - match self.dataset_type: - case dataset_types.one_dim | dataset_types.two_dim: - return self._data_contents["I"] - case dataset_types.sesans: - return self._data_contents["Depolarisation"] - case _: - return None + self.ordinate: NamedQuantity[np.ndarray] = None # TODO: fill out + self.abscissae: list[NamedQuantity[np.ndarray]] = None # TODO: fill out + self.mask = None # TODO: fill out + self.model_requirements = None # TODO: fill out - @property - def abscissae(self) -> Quantity: - match self.dataset_type: - case dataset_types.one_dim: - return self._data_contents["Q"] - case dataset_types.two_dim: - # Type hinting is a bit lacking. Assume each part of the zip is a scalar value. - data_contents = np.array( - list( - zip( - self._data_contents["Qx"].value, - self._data_contents["Qy"].value, - ) - ) - ) - # Use this value to extract units etc. Assume they will be the same for Qy. - reference_data_content = self._data_contents["Qx"] - # TODO: If this is a derived quantity then we are going to lose that - # information. - # - # TODO: Won't work when there's errors involved. On reflection, we - # probably want to avoid creating a new Quantity but at the moment I - # can't see a way around it. - return Quantity(data_contents, reference_data_content.units) - case dataset_types.sesans: - return self._data_contents["SpinEchoLength"] - case _: - None - - def __getitem__(self, item: str): - return self._data_contents[item] - - def summary(self, indent=" "): + def summary(self, indent = " ", include_raw=False): s = f"{self.name}\n" - for data in sorted(self._data_contents, reverse=True): + for data in self._data_contents: s += f"{indent}{data}\n" s += "Metadata:\n" s += "\n" s += self.metadata.summary() - return s - - @staticmethod - def from_json(obj): - return SasData( - name=obj["name"], - dataset_type=DatasetType( - name=obj["type"]["name"], - required=obj["type"]["required"], - optional=obj["type"]["optional"], - expected_orders=obj["type"]["expected_orders"], - ), - data_contents=obj["data_contents"], - metadata=Metadata.from_json(obj["metadata"]), - ) + if include_raw: + s += key_tree(self._raw_metadata) - def _save_h5(self, sasentry: HDF5Group): - """Export data into HDF5 file""" - sasentry.attrs["name"] = self.name - self.metadata.as_h5(sasentry) - - # We export each data set into its own entry, so we only ever - # need sasdata01 - group = sasentry.create_group("sasdata01") - for idx, (key, sasdata) in enumerate(self._data_contents.items()): - sasdata.as_h5(group, key) - - - @staticmethod - def save_h5(data: dict[str, typing.Self], path: str | typing.BinaryIO): - with h5py.File(path, "w") as f: - for idx, (key, data) in enumerate(data.items()): - sasentry = f.create_group(f"sasentry{idx+1:02d}") - if not key.startswith("sasentry"): - sasentry.attrs["sasview_key"] = key - data._save_h5(sasentry) - - - -class SasDataEncoder(MetadataEncoder): - def default(self, obj): - match obj: - case DatasetType(): - return { - "name": obj.name, - "required": obj.required, - "optional": obj.optional, - "expected_orders": obj.expected_orders, - } - case SasData(): - return { - "name": obj.name, - "data_contents": obj._data_contents, - "type": obj.dataset_type, - "mask": obj.mask, - "metadata": obj.metadata, - "model_requirements": obj.model_requirements, - } - case _: - return super().default(obj) + return s diff --git a/sasdata/data_backing.py b/sasdata/data_backing.py index 8553cd5dd..210ac33ca 100644 --- a/sasdata/data_backing.py +++ b/sasdata/data_backing.py @@ -27,7 +27,7 @@ def summary(self, indent_amount: int = 0, indent: str = " ") -> str: s += f"{indent*(indent_amount+1)}{shorten_string(str(self.data))}\n" for key in self.attributes: value = self.attributes[key] - if isinstance(value, (Group | Dataset)): + if isinstance(value, (Group, Dataset)): value_string = value.summary(indent_amount+1, indent) else: value_string = f"{indent * (indent_amount+1)}{key}: {shorten_string(repr(value))}\n" diff --git a/sasdata/data_util/nxsunit.py b/sasdata/data_util/nxsunit.py index a5c3ab536..2fa8891cb 100644 --- a/sasdata/data_util/nxsunit.py +++ b/sasdata/data_util/nxsunit.py @@ -51,8 +51,8 @@ __all__ = ['Converter', 'standardize_units'] T = TypeVar('T') ConversionType = float | tuple[float, float] -DIMENSIONS = {} # type: Dict[str, Dict[str, ConversionType]] -AMBIGUITIES = {} # type: Dict[str, str] +DIMENSIONS: dict[str, dict[str, ConversionType]] = {} +AMBIGUITIES: dict[str, str] = {} PREFIX = dict(peta=1e15, tera=1e12, giga=1e9, mega=1e6, kilo=1e3, deci=1e-1, centi=1e-2, milli=1e-3, mili=1e-3, micro=1e-6, nano=1e-9, pico=1e-12, femto=1e-15) SHORT_PREFIX = dict(P=1e15, T=1e12, G=1e9, M=1e6, k=1e3, d=1e-1, c=1e-2, m=1e-3, u=1e-6, n=1e-9, p=1e-12, f=1e-15) @@ -258,7 +258,7 @@ def _build_all_units(): # APS files may be using 'a.u.' for 'arbitrary units'. Other # facilities are leaving the units blank, using ??? or not even # writing the units attributes. - unknown = {} # type: Dict[str, ConversionType] + unknown: dict[str, ConversionType] = {} unknown.update( {'None': 1, '???': 1, '': 1, 'A.U.': 1, 'a.u.': 1, 'arbitrary': 1, 'arbitrary units': 1, 'Counts': 1, 'counts': 1, 'Cts': 1, 'cts': 1, 'unitless': 1, 'unknown': 1, 'Unknown': 1, 'Unk': 1} @@ -356,15 +356,15 @@ class Converter: value name. """ #: Name of the source units (km, Ang, us, ...) - _units = None # type: List[str] + _units: list[str] = None #: Type of the source units (distance, time, frequency, ...) - dimension = None # type: List[str] + dimension: list[str] = None #: Scale converter, mapping unit name to scale factor or (scale, offset) #: for temperature units. - scalemap = None # type: List[Dict[str, ConversionType]] + scalemap: list[dict[str, ConversionType]] = None #: Scale base for the source units - scalebase = None # type: float - scaleoffset = None # type: float + scalebase: float = None + scaleoffset: float = None @property def units(self) -> str: @@ -375,7 +375,7 @@ def units(self, unit: str): self._units = standardize_units(unit) def __init__(self, units: str | None = None, dimension: list[str] | None = None): - self.units = units if units is not None else 'a.u.' # type: str + self.units: str = units if units is not None else 'a.u.' # Lookup dimension if not given if dimension: diff --git a/sasdata/dataloader/data_info.py b/sasdata/dataloader/data_info.py index 16676a4bc..4cbfc4c11 100644 --- a/sasdata/dataloader/data_info.py +++ b/sasdata/dataloader/data_info.py @@ -768,7 +768,7 @@ def is_slit_smeared(self): :return: True is slit smearing info is present, False otherwise """ def _check(v): - return (isinstance(v.__class__ == list | np.ndarray) + return (isinstance(v.__class__, list | np.ndarray) and len(v) > 0 and min(v) > 0) return _check(self.dxl) or _check(self.dxw) diff --git a/sasdata/dataloader/readers/danse_reader.py b/sasdata/dataloader/readers/danse_reader.py index d1851c77d..10a1c515c 100644 --- a/sasdata/dataloader/readers/danse_reader.py +++ b/sasdata/dataloader/readers/danse_reader.py @@ -11,7 +11,6 @@ #This work benefited from DANSE software developed under NSF award DMR-0520547. #copyright 2008, University of Tennessee ############################################################################# -import logging import os import numpy as np diff --git a/sasdata/dataloader/readers/red2d_reader.py b/sasdata/dataloader/readers/red2d_reader.py index 3d468911d..d84af6155 100644 --- a/sasdata/dataloader/readers/red2d_reader.py +++ b/sasdata/dataloader/readers/red2d_reader.py @@ -82,7 +82,6 @@ def get_file_contents(self): wavelength = None distance = None - transmission = None pixel_x = None pixel_y = None diff --git a/sasdata/dataset_types.py b/sasdata/dataset_types.py index ffccd9653..c7d2f5927 100644 --- a/sasdata/dataset_types.py +++ b/sasdata/dataset_types.py @@ -19,7 +19,7 @@ class DatasetType: one_dim = DatasetType( name="1D I vs Q", required=["Q", "I"], - optional=["dI", "dQ", "Shadowfactor", "Qmean", "dQl", "dQw"], + optional=["dI", "dQ", "shadow"], expected_orders=[ ["Q", "I", "dI"], ["Q", "dQ", "I", "dI"]]) @@ -27,16 +27,25 @@ class DatasetType: two_dim = DatasetType( name="2D I vs Q", required=["Qx", "Qy", "I"], - optional=["dQx", "dQy", "dI", "Qz", "ShadowFactor", "mask"], + optional=["dQx", "dQy", "dQz", "dI", "Qz", "shadow"], expected_orders=[ ["Qx", "Qy", "I"], ["Qx", "Qy", "I", "dI"], ["Qx", "Qy", "dQx", "dQy", "I", "dI"]]) +three_dim = DatasetType( + name="3D I vs Q", + required=["Qx", "Qy", "Qz", "I"], + optional=["dQx", "dQy", "dQz", "dI", "ShadowFactor", "mask"], + expected_orders=[ + ["Qx", "Qy", "Qz", "I"], + ["Qx", "Qy", "Qz", "I", "dI"], + ["Qx", "Qy", "Qz", "dQx", "dQy", "dQz", "I", "dI"]]) + sesans = DatasetType( name="SESANS", - required=["SpinEchoLength", "Depolarisation", "Wavelength"], - optional=["Transmission", "Polarisation"], + required=["z", "G"], + optional=["stuff", "other stuff", "more stuff"], expected_orders=[["z", "G"]]) dataset_types = {dataset.name for dataset in [one_dim, two_dim, sesans]} @@ -59,11 +68,8 @@ class DatasetType: "dQx": units.inverse_length, "dQy": units.inverse_length, "dQz": units.inverse_length, - "SpinEchoLength": units.length, - "Depolarisation": units.inverse_volume, - "Wavelength": units.length, - "Transmission": units.dimensionless, - "Polarisation": units.dimensionless, + "z": units.length, + "G": units.area, "shadow": units.dimensionless, "temperature": units.temperature, "magnetic field": units.magnetic_flux_density diff --git a/sasdata/default_units.py b/sasdata/default_units.py index b71fed42f..bbb275664 100644 --- a/sasdata/default_units.py +++ b/sasdata/default_units.py @@ -5,18 +5,13 @@ from sasdata.quantities.units import NamedUnit default_units = { - "Q": [unit.per_nanometer, unit.per_angstrom, unit.per_meter], - "I": [unit.per_centimeter, unit.per_meter], - "dQ": "Q", - "dI": "I", + 'Q': [unit.per_nanometer, unit.per_angstrom, unit.per_meter], + 'I': [unit.per_centimeter, unit.per_meter] } def defaults_or_fallback(column_name: str) -> list[NamedUnit]: - value = default_units.get(column_name, unit_kinds[column_name].units) - if isinstance(value, str): - return defaults_or_fallback(value) - return value + return default_units.get(column_name, unit_kinds[column_name].units) def first_default_for_fallback(column_name: str) -> NamedUnit: diff --git a/sasdata/distributions.py b/sasdata/distributions.py new file mode 100644 index 000000000..6ad149e0e --- /dev/null +++ b/sasdata/distributions.py @@ -0,0 +1,11 @@ + + +class DistributionModel: + + + @property + def is_density(self) -> bool: + return False + + def standard_deviation(self) -> Quantity: + return NotImplementedError("Variance not implemented yet") diff --git a/sasdata/fair_database/__init__.py b/sasdata/fair_database/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/fair_database/data/__init__.py b/sasdata/fair_database/data/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/fair_database/data/admin.py b/sasdata/fair_database/data/admin.py new file mode 100644 index 000000000..2134875a6 --- /dev/null +++ b/sasdata/fair_database/data/admin.py @@ -0,0 +1,11 @@ +from data import models +from django.contrib import admin + +admin.site.register(models.DataFile) +admin.site.register(models.Session) +admin.site.register(models.PublishedState) +admin.site.register(models.DataSet) +admin.site.register(models.MetaData) +admin.site.register(models.Quantity) +admin.site.register(models.OperationTree) +admin.site.register(models.ReferenceQuantity) diff --git a/sasdata/fair_database/data/apps.py b/sasdata/fair_database/data/apps.py new file mode 100644 index 000000000..b882be950 --- /dev/null +++ b/sasdata/fair_database/data/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class DataConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "data" diff --git a/sasdata/fair_database/data/forms.py b/sasdata/fair_database/data/forms.py new file mode 100644 index 000000000..519556e2f --- /dev/null +++ b/sasdata/fair_database/data/forms.py @@ -0,0 +1,9 @@ +from data.models import DataFile +from django import forms + + +# Create the form class. +class DataFileForm(forms.ModelForm): + class Meta: + model = DataFile + fields = ["file", "is_public"] diff --git a/sasdata/fair_database/data/migrations/0001_initial.py b/sasdata/fair_database/data/migrations/0001_initial.py new file mode 100644 index 000000000..e8f7219a6 --- /dev/null +++ b/sasdata/fair_database/data/migrations/0001_initial.py @@ -0,0 +1,332 @@ +# Generated by Django 5.1.6 on 2025-04-23 18:08 + +import data.models +import django.core.files.storage +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + initial = True + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="DataFile", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "is_public", + models.BooleanField( + default=False, help_text="opt in to make your data public" + ), + ), + ( + "file_name", + models.CharField( + blank=True, + default=None, + help_text="File name", + max_length=200, + null=True, + ), + ), + ( + "file", + models.FileField( + default=None, + help_text="This is a file", + storage=django.core.files.storage.FileSystemStorage(), + upload_to="uploaded_files", + ), + ), + ( + "current_user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "users", + models.ManyToManyField( + blank=True, related_name="+", to=settings.AUTH_USER_MODEL + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="DataSet", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "is_public", + models.BooleanField( + default=False, help_text="opt in to make your data public" + ), + ), + ("name", models.CharField(max_length=200)), + ( + "current_user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + ("files", models.ManyToManyField(to="data.datafile")), + ( + "users", + models.ManyToManyField( + blank=True, related_name="+", to=settings.AUTH_USER_MODEL + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="MetaData", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(default="Title", max_length=500)), + ("run", models.JSONField(default=data.models.empty_list)), + ("definition", models.TextField(blank=True, null=True)), + ("instrument", models.JSONField(blank=True, null=True)), + ("process", models.JSONField(default=data.models.empty_list)), + ("sample", models.JSONField(blank=True, null=True)), + ( + "dataset", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="metadata", + to="data.dataset", + ), + ), + ], + ), + migrations.CreateModel( + name="Quantity", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("value", models.JSONField()), + ("variance", models.JSONField()), + ("units", models.CharField(max_length=200)), + ("hash", models.IntegerField()), + ("label", models.CharField(max_length=50)), + ( + "dataset", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="data_contents", + to="data.dataset", + ), + ), + ], + ), + migrations.CreateModel( + name="OperationTree", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "operation", + models.CharField( + choices=[ + ("zero", "0 [Add.Id.]"), + ("one", "1 [Mul.Id.]"), + ("constant", "Constant"), + ("variable", "Variable"), + ("neg", "Neg"), + ("reciprocal", "Inv"), + ("add", "Add"), + ("sub", "Sub"), + ("mul", "Mul"), + ("div", "Div"), + ("pow", "Pow"), + ("transpose", "Transpose"), + ("dot", "Dot"), + ("matmul", "MatMul"), + ("tensor_product", "TensorProduct"), + ], + max_length=20, + ), + ), + ("parameters", models.JSONField(default=data.models.empty_dict)), + ("label", models.CharField(blank=True, max_length=10, null=True)), + ( + "child_operation", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="parent_operations", + to="data.operationtree", + ), + ), + ( + "quantity", + models.OneToOneField( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="operation_tree", + to="data.quantity", + ), + ), + ], + ), + migrations.CreateModel( + name="ReferenceQuantity", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("value", models.JSONField()), + ("variance", models.JSONField()), + ("units", models.CharField(max_length=200)), + ("hash", models.IntegerField()), + ( + "derived_quantity", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="references", + to="data.quantity", + ), + ), + ], + ), + migrations.CreateModel( + name="Session", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "is_public", + models.BooleanField( + default=False, help_text="opt in to make your data public" + ), + ), + ("title", models.CharField(max_length=200)), + ( + "current_user", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to=settings.AUTH_USER_MODEL, + ), + ), + ( + "users", + models.ManyToManyField( + blank=True, related_name="+", to=settings.AUTH_USER_MODEL + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="PublishedState", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("published", models.BooleanField(default=False)), + ("doi", models.URLField()), + ( + "session", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="published_state", + to="data.session", + ), + ), + ], + ), + migrations.AddField( + model_name="dataset", + name="session", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="datasets", + to="data.session", + ), + ), + ] diff --git a/sasdata/fair_database/data/migrations/__init__.py b/sasdata/fair_database/data/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/fair_database/data/models.py b/sasdata/fair_database/data/models.py new file mode 100644 index 000000000..3a36dc831 --- /dev/null +++ b/sasdata/fair_database/data/models.py @@ -0,0 +1,232 @@ +from django.contrib.auth.models import User +from django.core.files.storage import FileSystemStorage +from django.db import models + + +# method for empty list default value +def empty_list(): + return [] + + +# method for empty dictionary default value +def empty_dict(): + return {} + + +class Data(models.Model): + """Base model for data with access-related information.""" + + # owner of the data + current_user = models.ForeignKey( + User, blank=True, null=True, on_delete=models.CASCADE, related_name="+" + ) + + # users that have been granted view access to the data + users = models.ManyToManyField(User, blank=True, related_name="+") + + # is the data public? + is_public = models.BooleanField( + default=False, help_text="opt in to make your data public" + ) + + class Meta: + abstract = True + + +class DataFile(Data): + """Database model for file contents.""" + + # file name + file_name = models.CharField( + max_length=200, default=None, blank=True, null=True, help_text="File name" + ) + + # imported data + # user can either import a file path or actual file + file = models.FileField( + blank=False, + default=None, + help_text="This is a file", + upload_to="uploaded_files", + storage=FileSystemStorage(), + ) + + +class DataSet(Data): + """Database model for a set of data and associated metadata.""" + + # dataset name + name = models.CharField(max_length=200) + + # associated files + files = models.ManyToManyField(DataFile) + + # session the dataset is a part of, if any + session = models.ForeignKey( + "Session", + on_delete=models.CASCADE, + related_name="datasets", + blank=True, + null=True, + ) + + # TODO: update based on SasData class in data.py + # type of dataset + # dataset_type = models.JSONField() + + +class Quantity(models.Model): + """Database model for data quantities such as the ordinate and abscissae.""" + + # data value + value = models.JSONField() + + # variance of the data + variance = models.JSONField() + + # units + units = models.CharField(max_length=200) + + # hash value + hash = models.IntegerField() + + # label, e.g. Q or I(Q) + label = models.CharField(max_length=50) + + # data set the quantity is a part of + dataset = models.ForeignKey( + DataSet, on_delete=models.CASCADE, related_name="data_contents" + ) + + +class ReferenceQuantity(models.Model): + """ + Database models for quantities referenced by variables in an OperationTree. + + Corresponds to the references dictionary in the QuantityHistory class in + sasdata/quantity.py. ReferenceQuantities should be essentially the same as + Quantities but with no operations performed on them and therefore no + OperationTree. + """ + + # data value + value = models.JSONField() + + # variance of the data + variance = models.JSONField() + + # units + units = models.CharField(max_length=200) + + # hash value + hash = models.IntegerField() + + # Quantity whose OperationTree this is a reference for + derived_quantity = models.ForeignKey( + Quantity, + related_name="references", + on_delete=models.CASCADE, + ) + + +# TODO: update based on changes in sasdata/metadata.py +class MetaData(models.Model): + """Database model for scattering metadata""" + + # title + title = models.CharField(max_length=500, default="Title") + + # run + run = models.JSONField(default=empty_list) + + # definition + definition = models.TextField(blank=True, null=True) + + # instrument + instrument = models.JSONField(blank=True, null=True) + + # process + process = models.JSONField(default=empty_list) + + # sample + sample = models.JSONField(blank=True, null=True) + + # associated dataset + dataset = models.OneToOneField( + DataSet, on_delete=models.CASCADE, related_name="metadata" + ) + + +class OperationTree(models.Model): + """Database model for tree of operations performed on a DataSet.""" + + # possible operations + OPERATION_CHOICES = { + "zero": "0 [Add.Id.]", + "one": "1 [Mul.Id.]", + "constant": "Constant", + "variable": "Variable", + "neg": "Neg", + "reciprocal": "Inv", + "add": "Add", + "sub": "Sub", + "mul": "Mul", + "div": "Div", + "pow": "Pow", + "transpose": "Transpose", + "dot": "Dot", + "matmul": "MatMul", + "tensor_product": "TensorProduct", + } + + # operation + operation = models.CharField(max_length=20, choices=OPERATION_CHOICES) + + # parameters + parameters = models.JSONField(default=empty_dict) + + # label (a or b) if the operation is a parameter of a child operation + # maintains ordering of binary operation parameters + label = models.CharField(max_length=10, blank=True, null=True) + + # operation this operation is a parameter for, if any + child_operation = models.ForeignKey( + "self", + on_delete=models.CASCADE, + related_name="parent_operations", + blank=True, + null=True, + ) + + # quantity the operation produces + # only set for base of tree (the quantity's most recent operation) + quantity = models.OneToOneField( + Quantity, + on_delete=models.CASCADE, + blank=True, + null=True, + related_name="operation_tree", + ) + + +class Session(Data): + """Database model for a project save state.""" + + # title + title = models.CharField(max_length=200) + + +class PublishedState(models.Model): + """Database model for a project published state.""" + + # published + published = models.BooleanField(default=False) + + # TODO: update doi as needed when DOI generation is implemented + # doi + doi = models.URLField() + + # session + session = models.OneToOneField( + Session, on_delete=models.CASCADE, related_name="published_state" + ) diff --git a/sasdata/fair_database/data/serializers.py b/sasdata/fair_database/data/serializers.py new file mode 100644 index 000000000..dfb7ece52 --- /dev/null +++ b/sasdata/fair_database/data/serializers.py @@ -0,0 +1,529 @@ +from data import models +from django.core.exceptions import ObjectDoesNotExist +from fair_database import permissions +from rest_framework import serializers + +# TODO: more custom validation, particularly for specific nested dictionary structures +# TODO: custom update methods for nested structures + + +# Determine if an operation does not have parent operations +def constant_or_variable(operation: str): + return operation in ["zero", "one", "constant", "variable"] + + +# Determine if an operation has two parent operations +def binary(operation: str): + return operation in ["add", "sub", "mul", "div", "dot", "matmul", "tensor_product"] + + +class DataFileSerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the DataFile model.""" + + class Meta: + model = models.DataFile + fields = "__all__" + + # TODO: check partial updates + # Check that private data has an owner + def validate(self, data): + if not self.context["is_public"] and not data["current_user"]: + raise serializers.ValidationError("private data must have an owner") + return data + + +class AccessManagementSerializer(serializers.Serializer): + """ + Serialization, deserialization, and validation for granting and revoking + access to instances of any exposed model. + """ + + # The username of a user + username = serializers.CharField(max_length=200, required=False) + # Whether that user has access + access = serializers.BooleanField() + + +class MetaDataSerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the MetaData model.""" + + # associated dataset + dataset = serializers.PrimaryKeyRelatedField( + queryset=models.DataSet, required=False, allow_null=True + ) + + class Meta: + model = models.MetaData + fields = "__all__" + + # Serialize an entry in MetaData + def to_representation(self, instance): + data = super().to_representation(instance) + if "dataset" in data: + data.pop("dataset") + return data + + +class OperationTreeSerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the OperationTree model.""" + + # associated quantity, for root operation + quantity = serializers.PrimaryKeyRelatedField( + queryset=models.Quantity, required=False, allow_null=True + ) + # operation this operation is a parameter for, for non-root operations + child_operation = serializers.PrimaryKeyRelatedField( + queryset=models.OperationTree, required=False, allow_null=True + ) + # parameter label, for non-root operations + label = serializers.CharField(max_length=10, required=False) + + class Meta: + model = models.OperationTree + fields = ["operation", "parameters", "quantity", "label", "child_operation"] + + # Validate parent operations + def validate_parameters(self, value): + if "a" in value: + serializer = OperationTreeSerializer(data=value["a"]) + serializer.is_valid(raise_exception=True) + if "b" in value: + serializer = OperationTreeSerializer(data=value["b"]) + serializer.is_valid(raise_exception=True) + return value + + # Check that the operation has the correct parameters + def validate(self, data): + expected_parameters = { + "zero": [], + "one": [], + "constant": ["value"], + "variable": ["hash_value", "name"], + "neg": ["a"], + "reciprocal": ["a"], + "add": ["a", "b"], + "sub": ["a", "b"], + "mul": ["a", "b"], + "div": ["a", "b"], + "pow": ["a", "power"], + "transpose": ["a", "axes"], + "dot": ["a", "b"], + "matmul": ["a", "b"], + "tensor_product": ["a", "b", "a_index", "b_index"], + } + + for parameter in expected_parameters[data["operation"]]: + if parameter not in data["parameters"]: + raise serializers.ValidationError( + data["operation"] + " requires parameter " + parameter + ) + + return data + + # Serialize an OperationTree instance + def to_representation(self, instance): + data = {"operation": instance.operation, "parameters": instance.parameters} + for parent_operation in instance.parent_operations.all(): + data["parameters"][parent_operation.label] = self.to_representation( + parent_operation + ) + return data + + # Create an OperationTree instance + def create(self, validated_data): + parent_operation1 = None + parent_operation2 = None + if not constant_or_variable(validated_data["operation"]): + parent_operation1 = validated_data["parameters"].pop("a") + parent_operation1["label"] = "a" + if binary(validated_data["operation"]): + parent_operation2 = validated_data["parameters"].pop("b") + parent_operation2["label"] = "b" + operation_tree = models.OperationTree.objects.create(**validated_data) + if parent_operation1: + parent_operation1["child_operation"] = operation_tree + OperationTreeSerializer.create( + OperationTreeSerializer(), validated_data=parent_operation1 + ) + if parent_operation2: + parent_operation2["child_operation"] = operation_tree + OperationTreeSerializer.create( + OperationTreeSerializer(), validated_data=parent_operation2 + ) + return operation_tree + + +class ReferenceQuantitySerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the ReferenceQuantity model.""" + + # quantity whose operation tree this is a reference for + derived_quantity = serializers.PrimaryKeyRelatedField( + queryset=models.Quantity, required=False + ) + + class Meta: + model = models.ReferenceQuantity + fields = ["value", "variance", "units", "hash", "derived_quantity"] + + # serialize a ReferenceQuantity instance + def to_representation(self, instance): + data = super().to_representation(instance) + if "derived_quantity" in data: + data.pop("derived_quantity") + return data + + # create a ReferenceQuantity instance + def create(self, validated_data): + if "label" in validated_data: + validated_data.pop("label") + if "history" in validated_data: + validated_data.pop("history") + return models.ReferenceQuantity.objects.create(**validated_data) + + +class QuantitySerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the Quantity model.""" + + # associated operation tree + operation_tree = OperationTreeSerializer(read_only=False, required=False) + # references for the operation tree + references = ReferenceQuantitySerializer(many=True, read_only=False, required=False) + # quantity label + label = serializers.CharField(max_length=20) + # dataset this is a part of + dataset = serializers.PrimaryKeyRelatedField( + queryset=models.DataSet, required=False, allow_null=True + ) + # serialized JSON form of operation tree and references + history = serializers.JSONField(required=False, allow_null=True) + + class Meta: + model = models.Quantity + fields = [ + "value", + "variance", + "units", + "hash", + "operation_tree", + "references", + "label", + "dataset", + "history", + ] + + # validate references + def validate_history(self, value): + if "references" in value: + for ref in value["references"]: + serializer = ReferenceQuantitySerializer(data=ref) + serializer.is_valid(raise_exception=True) + + # TODO: should variable-only history be assumed to refer to the same Quantity and ignored? + # Extract operation tree from history + def to_internal_value(self, data): + if "history" in data: + data_copy = data.copy() + if "operation_tree" in data["history"]: + operations = data["history"]["operation_tree"] + if ( + "operation" in operations + and not operations["operation"] == "variable" + ): + data_copy["operation_tree"] = operations + return_data = super().to_internal_value(data_copy) + return_data["history"] = data["history"] + return return_data + else: + return super().to_internal_value(data_copy) + return super().to_internal_value(data) + + # Serialize a Quantity instance + def to_representation(self, instance): + data = super().to_representation(instance) + if "dataset" in data: + data.pop("dataset") + if "derived_quantity" in data: + data.pop("derived_quantity") + data["history"] = {} + data["history"]["operation_tree"] = data.pop("operation_tree") + data["history"]["references"] = data.pop("references") + return data + + # Create a Quantity instance + def create(self, validated_data): + operations_tree = None + references = None + if "operation_tree" in validated_data: + operations_tree = validated_data.pop("operation_tree") + if "history" in validated_data: + history = validated_data.pop("history") + if history and "references" in history: + references = history.pop("references") + quantity = models.Quantity.objects.create(**validated_data) + if operations_tree: + operations_tree["quantity"] = quantity + OperationTreeSerializer.create( + OperationTreeSerializer(), validated_data=operations_tree + ) + if references: + for ref in references: + ref["derived_quantity"] = quantity + ReferenceQuantitySerializer.create( + ReferenceQuantitySerializer(), validated_data=ref + ) + return quantity + + +class DataSetSerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the DataSet model.""" + + # associated metadata + metadata = MetaDataSerializer(read_only=False) + # associated files + files = serializers.PrimaryKeyRelatedField( + required=False, many=True, allow_null=True, queryset=models.DataFile.objects + ) + # quantities that make up the dataset + data_contents = QuantitySerializer(many=True, read_only=False) + # session the dataset is a part of, if any + session = serializers.PrimaryKeyRelatedField( + queryset=models.Session, required=False, allow_null=True + ) + # TODO: handle files better + + class Meta: + model = models.DataSet + fields = [ + "id", + "name", + "files", + "metadata", + "data_contents", + "is_public", + "current_user", + "users", + "session", + ] + + # Serialize a DataSet instance + def to_representation(self, instance): + data = super().to_representation(instance) + if "request" in self.context: + files = [ + file.id + for file in instance.files.all() + if ( + file.is_public + or permissions.has_access(self.context["request"], file) + ) + ] + data["files"] = files + return data + + # Check that files exist and user has access to them + def validate_files(self, value): + for file in value: + if not file.is_public and not permissions.has_access( + self.context["request"], file + ): + raise serializers.ValidationError( + "You do not have access to file " + str(file.id) + ) + return value + + # Check that private data has an owner + def validate(self, data): + if ( + not self.context["request"].user.is_authenticated + and "is_public" in data + and not data["is_public"] + ): + raise serializers.ValidationError("private data must have an owner") + if "current_user" in data and ( + data["current_user"] == "" or data["current_user"] is None + ): + if "is_public" in data: + if not data["is_public"]: + raise serializers.ValidationError("private data must have an owner") + else: + if not self.instance.is_public: + raise serializers.ValidationError("private data must have an owner") + return data + + # Create a DataSet instance + def create(self, validated_data): + files = [] + if self.context["request"].user.is_authenticated: + validated_data["current_user"] = self.context["request"].user + metadata_raw = validated_data.pop("metadata") + data_contents = validated_data.pop("data_contents") + if "files" in validated_data: + files = validated_data.pop("files") + dataset = models.DataSet.objects.create(**validated_data) + dataset.files.set(files) + metadata_raw["dataset"] = dataset + MetaDataSerializer.create(MetaDataSerializer(), validated_data=metadata_raw) + for d in data_contents: + d["dataset"] = dataset + QuantitySerializer.create(QuantitySerializer(), validated_data=d) + return dataset + + # TODO: account for updating other attributes + # Update a DataSet instance + def update(self, instance, validated_data): + if "metadata" in validated_data: + metadata_raw = validated_data.pop("metadata") + new_metadata = MetaDataSerializer.update( + MetaDataSerializer(), instance.metadata, validated_data=metadata_raw + ) + instance.metadata = new_metadata + instance.save() + return super().update(instance, validated_data) + + +class PublishedStateSerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the PublishedState model.""" + + # associated session + session = serializers.PrimaryKeyRelatedField( + queryset=models.Session.objects, required=False, allow_null=True + ) + + class Meta: + model = models.PublishedState + fields = "__all__" + + # check that session does not already have a published state + def validate_session(self, value): + try: + published = value.published_state + if published is not None: + raise serializers.ValidationError( + "Only one published state per session" + ) + except models.Session.published_state.RelatedObjectDoesNotExist: + return value + + # set a placeholder DOI + def to_internal_value(self, data): + data_copy = data.copy() + data_copy["doi"] = "http://127.0.0.1:8000/v1/data/session/" + return super().to_internal_value(data_copy) + + # create a PublishedState instance + def create(self, validated_data): + # TODO: generate DOI + validated_data["doi"] = ( + "http://127.0.0.1:8000/v1/data/session/" + + str(validated_data["session"].id) + + "/" + ) + return models.PublishedState.objects.create(**validated_data) + + +class PublishedStateUpdateSerializer(serializers.ModelSerializer): + """Serialization for PublishedState updates. Restricts changes to published field.""" + + class Meta: + model = models.PublishedState + fields = ["published"] + + +class SessionSerializer(serializers.ModelSerializer): + """Serialization, deserialization, and validation for the Session model.""" + + # datasets that make up the session + datasets = DataSetSerializer(read_only=False, many=True) + # associated published state, if any + published_state = PublishedStateSerializer(read_only=False, required=False) + + class Meta: + model = models.Session + fields = [ + "id", + "title", + "published_state", + "datasets", + "current_user", + "is_public", + "users", + ] + + # disallow private unowned sessions + def validate(self, data): + if ( + not self.context["request"].user.is_authenticated + and "is_public" in data + and not data["is_public"] + ): + raise serializers.ValidationError("private sessions must have an owner") + if "current_user" in data and data["current_user"] == "": + if "is_public" in data: + if not "is_public": + raise serializers.ValidationError( + "private sessions must have an owner" + ) + else: + if not self.instance.is_public: + raise serializers.ValidationError( + "private sessions must have an owner" + ) + return data + + # propagate is_public to datasets + def to_internal_value(self, data): + data_copy = data.copy() + if "is_public" in data: + if "datasets" in data: + for dataset in data_copy["datasets"]: + dataset["is_public"] = data["is_public"] + return super().to_internal_value(data_copy) + + # serialize a session instance + def to_representation(self, instance): + session = super().to_representation(instance) + for dataset in session["datasets"]: + dataset.pop("session") + return session + + # Create a Session instance + def create(self, validated_data): + published_state = None + if self.context["request"].user.is_authenticated: + validated_data["current_user"] = self.context["request"].user + if "published_state" in validated_data: + published_state = validated_data.pop("published_state") + datasets = validated_data.pop("datasets") + session = models.Session.objects.create(**validated_data) + if published_state: + published_state["session"] = session + PublishedStateSerializer.create( + PublishedStateSerializer(), validated_data=published_state + ) + for dataset in datasets: + dataset["session"] = session + DataSetSerializer.create( + DataSetSerializer(context=self.context), validated_data=dataset + ) + return session + + # update a session instance + def update(self, instance, validated_data): + if "is_public" in validated_data: + for dataset in instance.datasets.all(): + dataset.is_public = validated_data["is_public"] + dataset.save() + if "published_state" in validated_data: + pb_raw = validated_data.pop("published_state") + try: + PublishedStateUpdateSerializer.update( + PublishedStateUpdateSerializer(), + instance.published_state, + validated_data=pb_raw, + ) + except ObjectDoesNotExist: + pb_raw["session"] = instance + PublishedStateSerializer.create( + PublishedStateSerializer(), validated_data=pb_raw + ) + return super().update(instance, validated_data) diff --git a/sasdata/fair_database/data/test/__init__.py b/sasdata/fair_database/data/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/fair_database/data/test/test_datafile.py b/sasdata/fair_database/data/test/test_datafile.py new file mode 100644 index 000000000..ac8dbb480 --- /dev/null +++ b/sasdata/fair_database/data/test/test_datafile.py @@ -0,0 +1,443 @@ +import os +import shutil + +from data.models import DataFile +from django.conf import settings +from django.contrib.auth.models import User +from django.db.models import Max +from django.test import TestCase +from rest_framework import status +from rest_framework.test import APIClient, APITestCase + + +# path to a file in example_data/1d_data +def find(filename): + return os.path.join( + os.path.dirname(__file__), "../../../example_data/1d_data", filename + ) + + +class TestLists(TestCase): + """Test get methods for DataFile.""" + + @classmethod + def setUpTestData(cls): + cls.public_test_data = DataFile.objects.create( + id=1, file_name="cyl_400_40.txt", is_public=True + ) + cls.public_test_data.file.save( + "cyl_400_40.txt", open(find("cyl_400_40.txt"), "rb") + ) + cls.user = User.objects.create_user( + username="testUser", password="secret", id=2 + ) + cls.private_test_data = DataFile.objects.create( + id=3, current_user=cls.user, file_name="cyl_400_20.txt", is_public=False + ) + cls.private_test_data.file.save( + "cyl_400_20.txt", open(find("cyl_400_20.txt"), "rb") + ) + cls.client_authenticated = APIClient() + cls.client_authenticated.force_authenticate(user=cls.user) + + # Test list public data + def test_does_list_public(self): + request = self.client_authenticated.get("/v1/data/file/") + self.assertEqual( + request.data, + {"public_data_ids": {1: "cyl_400_40.txt", 3: "cyl_400_20.txt"}}, + ) + + # Test list a user's private data + def test_does_list_user(self): + request = self.client_authenticated.get( + "/v1/data/file/", data={"username": "testUser"}, user=self.user + ) + self.assertEqual(request.data, {"user_data_ids": {3: "cyl_400_20.txt"}}) + + # Test list another user's public data + def test_list_other_user(self): + client_unauthenticated = APIClient() + request = client_unauthenticated.get( + "/v1/data/file/", data={"username": "testUser"}, user=self.user + ) + self.assertEqual(request.data, {"user_data_ids": {}}) + + # Test list a nonexistent user's data + def test_list_nonexistent_user(self): + request = self.client_authenticated.get( + "/v1/data/file/", data={"username": "fakeUser"} + ) + self.assertEqual(request.status_code, status.HTTP_404_NOT_FOUND) + + # Test loading a public data file + def test_does_load_data_info_public(self): + request = self.client_authenticated.get("/v1/data/file/1/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + + # Test loading private data with authorization + def test_does_load_data_info_private(self): + request = self.client_authenticated.get("/v1/data/file/3/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + + # Test loading data that does not exist + def test_load_data_info_nonexistent(self): + request = self.client_authenticated.get("/v1/data/file/5/") + self.assertEqual(request.status_code, status.HTTP_404_NOT_FOUND) + + @classmethod + def tearDownClass(cls): + cls.public_test_data.delete() + cls.private_test_data.delete() + cls.user.delete() + shutil.rmtree(settings.MEDIA_ROOT) + + +class TestingDatabase(APITestCase): + """Test non-get methods for DataFile.""" + + @classmethod + def setUpTestData(cls): + cls.user = User.objects.create_user( + username="testUser", password="secret", id=1 + ) + cls.data = DataFile.objects.create( + id=1, current_user=cls.user, file_name="cyl_400_20.txt", is_public=False + ) + cls.data.file.save("cyl_400_20.txt", open(find("cyl_400_20.txt"), "rb")) + cls.client_authenticated = APIClient() + cls.client_authenticated.force_authenticate(user=cls.user) + cls.client_unauthenticated = APIClient() + + # Test data upload creates data in database + def test_is_data_being_created(self): + file = open(find("cyl_400_40.txt"), "rb") + data = {"is_public": False, "file": file} + request = self.client_authenticated.post("/v1/data/file/", data=data) + max_id = DataFile.objects.aggregate(Max("id"))["id__max"] + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "current_user": "testUser", + "authenticated": True, + "file_id": max_id, + "file_alternative_name": "cyl_400_40.txt", + "is_public": False, + }, + ) + DataFile.objects.get(id=max_id).delete() + + # Test data upload w/out authenticated user + def test_is_data_being_created_no_user(self): + file = open(find("cyl_testdata.txt"), "rb") + data = {"is_public": True, "file": file} + request = self.client_unauthenticated.post("/v1/data/file/", data=data) + max_id = DataFile.objects.aggregate(Max("id"))["id__max"] + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "current_user": "", + "authenticated": False, + "file_id": max_id, + "file_alternative_name": "cyl_testdata.txt", + "is_public": True, + }, + ) + DataFile.objects.get(id=max_id).delete() + + # Test whether a user can overwrite data by specifying an in-use id + def test_no_data_overwrite(self): + file = open(find("apoferritin.txt")) + data = {"is_public": True, "file": file, id: 1} + request = self.client_authenticated.post("/v1/data/file/", data=data) + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual(DataFile.objects.get(id=1).file_name, "cyl_400_20.txt") + max_id = DataFile.objects.aggregate(Max("id"))["id__max"] + self.assertEqual( + request.data, + { + "current_user": "testUser", + "authenticated": True, + "file_id": max_id, + "file_alternative_name": "apoferritin.txt", + "is_public": True, + }, + ) + DataFile.objects.get(id=max_id).delete() + + # Test updating file + def test_does_file_upload_update(self): + file = open(find("cyl_testdata1.txt")) + data = {"file": file, "is_public": False} + request = self.client_authenticated.put("/v1/data/file/1/", data=data) + self.assertEqual( + request.data, + { + "current_user": "testUser", + "authenticated": True, + "file_id": 1, + "file_alternative_name": "cyl_testdata1.txt", + "is_public": False, + }, + ) + self.data.file.save("cyl_400_20.txt", open(find("cyl_400_20.txt"), "rb")) + self.data.file_name = "cyl_400_20.txt" + + # Test updating a public file + def test_public_file_upload_update(self): + data_object = DataFile.objects.create( + id=3, current_user=self.user, file_name="cyl_testdata2.txt", is_public=True + ) + data_object.file.save( + "cyl_testdata2.txt", open(find("cyl_testdata2.txt"), "rb") + ) + file = open(find("conalbumin.txt")) + data = {"file": file, "is_public": True} + request = self.client_authenticated.put("/v1/data/file/3/", data=data) + self.assertEqual( + request.data, + { + "current_user": "testUser", + "authenticated": True, + "file_id": 3, + "file_alternative_name": "conalbumin.txt", + "is_public": True, + }, + ) + data_object.delete() + + # Test file upload update fails when unauthorized + def test_unauthorized_file_upload_update(self): + file = open(find("cyl_400_40.txt")) + data = {"file": file, "is_public": False} + request = self.client_unauthenticated.put("/v1/data/file/1/", data=data) + self.assertEqual(request.status_code, status.HTTP_401_UNAUTHORIZED) + + # Test update nonexistent file fails + def test_file_upload_update_not_found(self): + file = open(find("cyl_400_40.txt")) + data = {"file": file, "is_public": False} + request = self.client_unauthenticated.put("/v1/data/file/5/", data=data) + self.assertEqual(request.status_code, status.HTTP_404_NOT_FOUND) + + # Test file download + def test_does_download(self): + request = self.client_authenticated.get( + "/v1/data/file/1/", data={"download": True} + ) + file_contents = b"".join(request.streaming_content) + test_file = open(find("cyl_400_20.txt"), "rb") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(file_contents, test_file.read()) + + # Test file download fails when unauthorized + def test_unauthorized_download(self): + request2 = self.client_unauthenticated.get( + "/v1/data/file/1/", data={"download": True} + ) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + + # Test download nonexistent file + def test_download_nonexistent(self): + request = self.client_authenticated.get( + "/v1/data/file/5/", data={"download": True} + ) + self.assertEqual(request.status_code, status.HTTP_404_NOT_FOUND) + + # Test deleting a file + def test_delete(self): + DataFile.objects.create( + id=6, current_user=self.user, file_name="test.txt", is_public=False + ) + request = self.client_authenticated.delete("/v1/data/file/6/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertFalse(DataFile.objects.filter(pk=6).exists()) + + # Test deleting a file fails when unauthorized + def test_delete_unauthorized(self): + request = self.client_unauthenticated.delete("/v1/data/file/1/") + self.assertEqual(request.status_code, status.HTTP_401_UNAUTHORIZED) + + @classmethod + def tearDownClass(cls): + cls.user.delete() + cls.data.delete() + shutil.rmtree(settings.MEDIA_ROOT) + + +class TestAccessManagement(TestCase): + """Test viewing and managing access for a file.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user(username="testUser", password="secret") + cls.user2 = User.objects.create_user(username="testUser2", password="secret2") + cls.private_test_data = DataFile.objects.create( + id=1, current_user=cls.user1, file_name="cyl_400_40.txt", is_public=False + ) + cls.private_test_data.file.save( + "cyl_400_40.txt", open(find("cyl_400_40.txt"), "rb") + ) + cls.shared_test_data = DataFile.objects.create( + id=2, current_user=cls.user1, file_name="cyl_400_20.txt", is_public=False + ) + cls.shared_test_data.file.save( + "cyl_400_20.txt", open(find("cyl_400_20.txt"), "rb") + ) + cls.shared_test_data.users.add(cls.user2) + cls.client_owner = APIClient() + cls.client_owner.force_authenticate(cls.user1) + cls.client_other = APIClient() + cls.client_other.force_authenticate(cls.user2) + + # test viewing no one with access + def test_view_no_access(self): + request = self.client_owner.get("/v1/data/file/1/users/") + data = { + "file": 1, + "file_name": "cyl_400_40.txt", + "is_public": False, + "users": [], + } + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(request.data, data) + + # test viewing list of users with access + def test_view_access(self): + request = self.client_owner.get("/v1/data/file/2/users/") + data = { + "file": 2, + "file_name": "cyl_400_20.txt", + "is_public": False, + "users": ["testUser2"], + } + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(request.data, data) + + # test granting another user access to private data + def test_grant_access(self): + data = {"username": "testUser2", "access": True} + request1 = self.client_owner.put("/v1/data/file/1/users/", data=data) + request2 = self.client_other.get("/v1/data/file/1/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + { + "username": "testUser2", + "file": 1, + "file_name": "cyl_400_40.txt", + "access": True, + }, + ) + + # test removing another user's access to private data + def test_remove_access(self): + data = {"username": "testUser2", "access": False} + request1 = self.client_other.get("/v1/data/file/2/") + request2 = self.client_owner.put("/v1/data/file/2/users/", data=data) + request3 = self.client_other.get("/v1/data/file/2/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual(request3.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + request2.data, + { + "username": "testUser2", + "file": 2, + "file_name": "cyl_400_20.txt", + "access": False, + }, + ) + + # test removing access from a user that already lacks access + def test_remove_no_access(self): + data = {"username": "testUser2", "access": False} + request1 = self.client_other.get("/v1/data/file/1/") + request2 = self.client_owner.put("/v1/data/file/1/users/", data=data) + request3 = self.client_other.get("/v1/data/file/1/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual(request3.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + request2.data, + { + "username": "testUser2", + "file": 1, + "file_name": "cyl_400_40.txt", + "access": False, + }, + ) + + # test owner's access cannot be removed + def test_cant_revoke_own_access(self): + data = {"username": "testUser", "access": False} + request1 = self.client_owner.put("/v1/data/file/1/users/", data=data) + request2 = self.client_owner.get("/v1/data/file/1/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + { + "username": "testUser", + "file": 1, + "file_name": "cyl_400_40.txt", + "access": True, + }, + ) + + # test giving access to a user that already has access + def test_grant_existing_access(self): + data = {"username": "testUser2", "access": True} + request1 = self.client_other.get("/v1/data/file/2/") + request2 = self.client_owner.put("/v1/data/file/2/users/", data=data) + request3 = self.client_other.get("/v1/data/file/2/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual(request3.status_code, status.HTTP_200_OK) + self.assertEqual( + request2.data, + { + "username": "testUser2", + "file": 2, + "file_name": "cyl_400_20.txt", + "access": True, + }, + ) + + # test that access is read-only for the file + def test_no_edit_access(self): + data = {"is_public": True} + request = self.client_other.put("/v1/data/file/2/", data=data) + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + self.assertFalse(self.shared_test_data.is_public) + + # test that only the owner can view who has access + def test_only_view_access_to_owned_file(self): + request1 = self.client_other.get("/v1/data/file/1/users/") + request2 = self.client_other.get("/v1/data/file/2/users/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + + # test that only the owner can change access + def test_only_edit_access_to_owned_file(self): + data1 = {"username": "testUser2", "access": True} + data2 = {"username": "testUser1", "access": False} + request1 = self.client_other.put("/v1/data/file/1/users/", data=data1) + request2 = self.client_other.put("/v1/data/file/2/users/", data=data2) + request3 = self.client_other.get("/v1/data/file/1/") + request4 = self.client_owner.get("/v1/data/file/2/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request3.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request4.status_code, status.HTTP_200_OK) + + @classmethod + def tearDownClass(cls): + cls.user1.delete() + cls.user2.delete() + cls.private_test_data.delete() + cls.shared_test_data.delete() + shutil.rmtree(settings.MEDIA_ROOT) diff --git a/sasdata/fair_database/data/test/test_dataset.py b/sasdata/fair_database/data/test/test_dataset.py new file mode 100644 index 000000000..aecfb7247 --- /dev/null +++ b/sasdata/fair_database/data/test/test_dataset.py @@ -0,0 +1,736 @@ +import os +import shutil + +from data.models import DataFile, DataSet, MetaData, OperationTree, Quantity +from django.conf import settings +from django.contrib.auth.models import User +from django.db.models import Max +from rest_framework import status +from rest_framework.test import APIClient, APITestCase + + +# path to a file in example_data/1d_data +def find(filename): + return os.path.join( + os.path.dirname(__file__), "../../../example_data/1d_data", filename + ) + + +class TestDataSet(APITestCase): + """Test HTTP methods of DataSetView.""" + + @classmethod + def setUpTestData(cls): + cls.empty_metadata = { + "title": "New Metadata", + "run": ["X"], + "description": "test", + "instrument": {}, + "process": {}, + "sample": {}, + } + cls.empty_data = [ + { + "value": 0, + "variance": 0, + "units": "no", + "hash": 0, + "label": "test", + "history": {"operation_tree": {}, "references": []}, + } + ] + cls.user1 = User.objects.create_user( + id=1, username="testUser1", password="secret" + ) + cls.user2 = User.objects.create_user( + id=2, username="testUser2", password="secret" + ) + cls.user3 = User.objects.create_user( + id=3, username="testUser3", password="secret" + ) + cls.public_dataset = DataSet.objects.create( + id=1, + current_user=cls.user1, + is_public=True, + name="Dataset 1", + ) + cls.private_dataset = DataSet.objects.create( + id=2, current_user=cls.user1, name="Dataset 2" + ) + cls.unowned_dataset = DataSet.objects.create( + id=3, is_public=True, name="Dataset 3" + ) + cls.private_dataset.users.add(cls.user3) + cls.auth_client1 = APIClient() + cls.auth_client2 = APIClient() + cls.auth_client3 = APIClient() + cls.auth_client1.force_authenticate(cls.user1) + cls.auth_client2.force_authenticate(cls.user2) + cls.auth_client3.force_authenticate(cls.user3) + + # Test a user can list their own private data + def test_list_private(self): + request = self.auth_client1.get("/v1/data/set/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + {"dataset_ids": {1: "Dataset 1", 2: "Dataset 2", 3: "Dataset 3"}}, + ) + + # Test a user can see others' public but not private data in list + def test_list_public(self): + request = self.auth_client2.get("/v1/data/set/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, {"dataset_ids": {1: "Dataset 1", 3: "Dataset 3"}} + ) + + # Test a user can see private data they have been granted access to + def test_list_granted_access(self): + request = self.auth_client3.get("/v1/data/set/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + {"dataset_ids": {1: "Dataset 1", 2: "Dataset 2", 3: "Dataset 3"}}, + ) + + # Test an unauthenticated user can list public data + def test_list_unauthenticated(self): + request = self.client.get("/v1/data/set/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, {"dataset_ids": {1: "Dataset 1", 3: "Dataset 3"}} + ) + + # Test a user can see all data listed by their username + def test_list_username(self): + request = self.auth_client1.get("/v1/data/set/", data={"username": "testUser1"}) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, {"dataset_ids": {1: "Dataset 1", 2: "Dataset 2"}} + ) + + # Test a user can list public data by another user's username + def test_list_username_2(self): + request = self.auth_client1.get("/v1/data/set/", {"username": "testUser2"}) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(request.data, {"dataset_ids": {}}) + + # Test an unauthenticated user can list public data by a username + def test_list_username_unauthenticated(self): + request = self.client.get("/v1/data/set/", {"username": "testUser1"}) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(request.data, {"dataset_ids": {1: "Dataset 1"}}) + + # Test listing by a username that doesn't exist + def test_list_wrong_username(self): + request = self.auth_client1.get("/v1/data/set/", {"username": "fakeUser1"}) + self.assertEqual(request.status_code, status.HTTP_404_NOT_FOUND) + + # TODO: test listing by other parameters if functionality is added for that + + # Test creating a dataset with associated metadata + def test_dataset_created(self): + dataset = { + "name": "New Dataset", + "metadata": self.empty_metadata, + "data_contents": self.empty_data, + } + request = self.auth_client1.post("/v1/data/set/", data=dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_metadata = new_dataset.metadata + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "dataset_id": max_id, + "name": "New Dataset", + "authenticated": True, + "current_user": "testUser1", + "is_public": False, + }, + ) + self.assertEqual(new_dataset.name, "New Dataset") + self.assertEqual(new_metadata.title, "New Metadata") + self.assertEqual(new_dataset.current_user.username, "testUser1") + new_dataset.delete() + new_metadata.delete() + + # Test creating a dataset while unauthenticated + def test_dataset_created_unauthenticated(self): + dataset = { + "name": "New Dataset", + "metadata": self.empty_metadata, + "is_public": True, + "data_contents": self.empty_data, + } + request = self.client.post("/v1/data/set/", data=dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_metadata = new_dataset.metadata + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "dataset_id": max_id, + "name": "New Dataset", + "authenticated": False, + "current_user": "", + "is_public": True, + }, + ) + self.assertEqual(new_dataset.name, "New Dataset") + self.assertIsNone(new_dataset.current_user) + new_dataset.delete() + new_metadata.delete() + + # Test creating a database with associated files + def test_dataset_created_with_files(self): + file = DataFile.objects.create( + id=1, file_name="cyl_testdata.txt", is_public=True + ) + file.file.save("cyl_testdata.txt", open(find("cyl_testdata.txt"))) + dataset = { + "name": "Dataset with file", + "metadata": self.empty_metadata, + "is_public": True, + "data_contents": self.empty_data, + "files": [1], + } + request = self.client.post("/v1/data/set/", data=dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "dataset_id": max_id, + "name": "Dataset with file", + "authenticated": False, + "current_user": "", + "is_public": True, + }, + ) + self.assertTrue(file in new_dataset.files.all()) + new_dataset.delete() + file.delete() + + # Test that a dataset cannot be associated with inaccessible files + def test_no_dataset_with_private_files(self): + file = DataFile.objects.create( + id=1, file_name="cyl_testdata.txt", is_public=False, current_user=self.user2 + ) + file.file.save("cyl_testdata.txt", open(find("cyl_testdata.txt"))) + dataset = { + "name": "Dataset with file", + "metadata": self.empty_metadata, + "is_public": True, + "data_contents": self.empty_data, + "files": [1], + } + request = self.client.post("/v1/data/set/", data=dataset, format="json") + file.delete() + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + + # Test that a dataset cannot be associated with nonexistent files + def test_no_dataset_with_nonexistent_files(self): + dataset = { + "name": "Dataset with file", + "metadata": self.empty_metadata, + "is_public": True, + "data_contents": self.empty_data, + "files": [2], + } + request = self.client.post("/v1/data/set/", data=dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + + # Test that a dataset cannot be created without metadata + def test_metadata_required(self): + dataset = { + "name": "No metadata", + "is_public": True, + "data_contents": self.empty_data, + } + request = self.auth_client1.post("/v1/data/set/", data=dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + + # Test that a private dataset cannot be created without an owner + def test_no_private_unowned_dataset(self): + dataset = { + "name": "Disallowed Dataset", + "metadata": self.empty_metadata, + "is_public": False, + "data_contents": self.empty_data, + } + request = self.client.post("/v1/data/set/", data=dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + + # Test whether a user can overwrite data by specifying an in-use id + def test_no_data_overwrite(self): + dataset = { + "id": 2, + "name": "Overwrite Dataset", + "metadata": self.empty_metadata, + "is_public": True, + "data_contents": self.empty_data, + } + request = self.auth_client2.post("/v1/data/set/", data=dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual(DataSet.objects.get(id=2).name, "Dataset 2") + self.assertEqual( + request.data, + { + "dataset_id": max_id, + "name": "Overwrite Dataset", + "authenticated": True, + "current_user": "testUser2", + "is_public": True, + }, + ) + DataSet.objects.get(id=max_id).delete() + + @classmethod + def tearDownClass(cls): + cls.public_dataset.delete() + cls.private_dataset.delete() + cls.unowned_dataset.delete() + cls.user1.delete() + cls.user2.delete() + cls.user3.delete() + shutil.rmtree(settings.MEDIA_ROOT) + + +class TestSingleDataSet(APITestCase): + """Tests for HTTP methods of SingleDataSetView.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user( + id=1, username="testUser1", password="secret" + ) + cls.user2 = User.objects.create_user( + id=2, username="testUser2", password="secret" + ) + cls.user3 = User.objects.create_user( + id=3, username="testUser3", password="secret" + ) + cls.public_dataset = DataSet.objects.create( + id=1, + current_user=cls.user1, + is_public=True, + name="Dataset 1", + ) + cls.private_dataset = DataSet.objects.create( + id=2, current_user=cls.user1, name="Dataset 2" + ) + cls.unowned_dataset = DataSet.objects.create( + id=3, is_public=True, name="Dataset 3" + ) + cls.metadata = MetaData.objects.create( + id=1, + title="Metadata", + run=0, + definition="test", + instrument="none", + process="none", + sample="none", + dataset=cls.public_dataset, + ) + cls.file = DataFile.objects.create( + id=1, file_name="cyl_testdata.txt", is_public=False, current_user=cls.user1 + ) + cls.file.file.save("cyl_testdata.txt", open(find("cyl_testdata.txt"))) + cls.private_dataset.users.add(cls.user3) + cls.public_dataset.files.add(cls.file) + cls.auth_client1 = APIClient() + cls.auth_client2 = APIClient() + cls.auth_client3 = APIClient() + cls.auth_client1.force_authenticate(cls.user1) + cls.auth_client2.force_authenticate(cls.user2) + cls.auth_client3.force_authenticate(cls.user3) + + # TODO: change load return data + # Test successfully accessing a private dataset + def test_load_private_dataset(self): + request1 = self.auth_client1.get("/v1/data/set/2/") + request2 = self.auth_client3.get("/v1/data/set/2/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + { + "id": 2, + "current_user": "testUser1", + "users": [3], + "is_public": False, + "name": "Dataset 2", + "files": [], + "metadata": None, + "data_contents": [], + "session": None, + }, + ) + + # Test successfully accessing a public dataset + def test_load_public_dataset(self): + request1 = self.client.get("/v1/data/set/1/") + request2 = self.auth_client2.get("/v1/data/set/1/") + request3 = self.auth_client1.get("/v1/data/set/1/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual(request3.status_code, status.HTTP_200_OK) + self.assertDictEqual( + request1.data, + { + "id": 1, + "current_user": "testUser1", + "users": [], + "is_public": True, + "name": "Dataset 1", + "files": [], + "metadata": { + "id": 1, + "title": "Metadata", + "run": 0, + "definition": "test", + "instrument": "none", + "process": "none", + "sample": "none", + }, + "data_contents": [], + "session": None, + }, + ) + self.assertEqual(request1.data, request2.data) + self.assertEqual( + request3.data, + { + "id": 1, + "current_user": "testUser1", + "users": [], + "is_public": True, + "name": "Dataset 1", + "files": [1], + "metadata": { + "id": 1, + "title": "Metadata", + "run": 0, + "definition": "test", + "instrument": "none", + "process": "none", + "sample": "none", + }, + "data_contents": [], + "session": None, + }, + ) + + # Test successfully accessing an unowned public dataset + def test_load_unowned_dataset(self): + request1 = self.auth_client1.get("/v1/data/set/3/") + request2 = self.client.get("/v1/data/set/3/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertDictEqual( + request1.data, + { + "id": 3, + "current_user": None, + "users": [], + "is_public": True, + "name": "Dataset 3", + "files": [], + "metadata": None, + "data_contents": [], + "session": None, + }, + ) + + # Test unsuccessfully accessing a private dataset + def test_load_private_dataset_unauthorized(self): + request1 = self.auth_client2.get("/v1/data/set/2/") + request2 = self.client.get("/v1/data/set/2/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + + # Test only owner can change a private dataset + def test_update_private_dataset(self): + request1 = self.auth_client1.put("/v1/data/set/2/", data={"is_public": True}) + request2 = self.auth_client3.put("/v1/data/set/2/", data={"is_public": False}) + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + request1.data, {"data_id": 2, "name": "Dataset 2", "is_public": True} + ) + self.assertTrue(DataSet.objects.get(id=2).is_public) + self.private_dataset.save() + self.assertFalse(DataSet.objects.get(id=2).is_public) + + # Test changing a public dataset + def test_update_public_dataset(self): + request1 = self.auth_client1.put( + "/v1/data/set/1/", data={"name": "Different name"} + ) + request2 = self.auth_client2.put("/v1/data/set/1/", data={"is_public": False}) + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + request1.data, {"data_id": 1, "name": "Different name", "is_public": True} + ) + self.assertEqual(DataSet.objects.get(id=1).name, "Different name") + self.public_dataset.save() + + # TODO: test invalid updates if and when those are figured out + + # Test changing an unowned dataset + def test_update_unowned_dataset(self): + request1 = self.auth_client1.put("/v1/data/set/3/", data={"current_user": 1}) + request2 = self.client.put("/v1/data/set/3/", data={"name": "Different name"}) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + + # Test updating metadata + def test_update_dataset_metadata(self): + new_metadata = { + "title": "Updated Metadata", + "run": ["X"], + "definition": "update test", + "instrument": "none", + "process": "none", + "sample": "none", + } + request = self.auth_client1.put( + "/v1/data/set/1/", data={"metadata": new_metadata}, format="json" + ) + dataset = DataSet.objects.get(id=1) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(dataset.metadata.title, "Updated Metadata") + self.assertEqual(dataset.metadata.id, 1) + self.assertEqual(len(MetaData.objects.all()), 1) + dataset.metadata.delete() + self.metadata = MetaData.objects.create( + id=1, + title="Metadata", + run=0, + definition="test", + instrument="none", + process="none", + sample="none", + dataset=self.public_dataset, + ) + + # Test partially updating metadata + def test_update_dataset_partial_metadata(self): + request = self.auth_client1.put( + "/v1/data/set/1/", + data={"metadata": {"title": "Different Title"}}, + format="json", + ) + dataset = DataSet.objects.get(id=1) + metadata = dataset.metadata + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(metadata.title, "Different Title") + self.assertEqual(metadata.definition, "test") + self.assertEqual(metadata.id, 1) + metadata.title = "Metadata" + metadata.save() + + # Test updating a dataset's files + def test_update_dataset_files(self): + request = self.auth_client1.put("/v1/data/set/2/", data={"files": [1]}) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(len(DataSet.objects.get(id=2).files.all()), 1) + self.private_dataset.files.remove(self.file) + + # Test replacing a dataset's files + def test_update_dataset_replace_files(self): + file = DataFile.objects.create( + id=2, file_name="cyl_testdata1.txt", is_public=True, current_user=self.user1 + ) + file.file.save("cyl_testdata1.txt", open(find("cyl_testdata1.txt"))) + request = self.auth_client1.put("/v1/data/set/1/", data={"files": [2]}) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(len(DataSet.objects.get(id=1).files.all()), 1) + self.assertTrue(file in DataSet.objects.get(id=1).files.all()) + self.public_dataset.files.add(self.file) + self.public_dataset.files.remove(file) + + # Test updating a dataset to have no files + def test_update_dataset_clear_files(self): + request = self.auth_client1.put("/v1/data/set/1/", data={"files": [""]}) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(len(DataSet.objects.get(id=1).files.all()), 0) + self.public_dataset.files.add(self.file) + + # Test that a dataset cannot be updated to be private and unowned + def test_update_dataset_no_private_unowned(self): + request1 = self.auth_client1.put("/v1/data/set/2/", data={"current_user": ""}) + request2 = self.auth_client1.put( + "/v1/data/set/1/", data={"current_user": "", "is_public": False} + ) + public_dataset = DataSet.objects.get(id=1) + self.assertEqual(request1.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(request2.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(DataSet.objects.get(id=2).current_user, self.user1) + self.assertEqual(public_dataset.current_user, self.user1) + self.assertTrue(public_dataset.is_public) + + # Test deleting a dataset + def test_delete_dataset(self): + quantity = Quantity.objects.create( + id=1, + value=0, + variance=0, + units="none", + hash=0, + label="test", + dataset=self.private_dataset, + ) + neg = OperationTree.objects.create(id=1, operation="neg", quantity=quantity) + OperationTree.objects.create( + id=2, operation="zero", parameters={}, child_operation=neg + ) + request = self.auth_client1.delete("/v1/data/set/2/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(request.data, {"success": True}) + self.assertRaises(DataSet.DoesNotExist, DataSet.objects.get, id=2) + self.assertRaises(Quantity.DoesNotExist, Quantity.objects.get, id=1) + self.assertRaises(OperationTree.DoesNotExist, OperationTree.objects.get, id=1) + self.assertRaises(OperationTree.DoesNotExist, OperationTree.objects.get, id=2) + self.private_dataset = DataSet.objects.create( + id=2, current_user=self.user1, name="Dataset 2" + ) + + # Test cannot delete a public dataset + def test_delete_public_dataset(self): + request = self.auth_client1.delete("/v1/data/set/1/") + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + + # Test cannot delete an unowned dataset + def test_delete_unowned_dataset(self): + request = self.auth_client1.delete("/v1/data/set/3/") + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + + # Test cannot delete another user's dataset + def test_delete_dataset_unauthorized(self): + request1 = self.auth_client2.delete("/v1/data/set/1/") + request2 = self.auth_client3.delete("/v1/data/set/2/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + + @classmethod + def tearDownClass(cls): + cls.public_dataset.delete() + cls.private_dataset.delete() + cls.unowned_dataset.delete() + cls.user1.delete() + cls.user2.delete() + cls.user3.delete() + cls.file.delete() + shutil.rmtree(settings.MEDIA_ROOT) + + +class TestDataSetAccessManagement(APITestCase): + """Tests for HTTP methods of DataSetUsersView.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user(username="testUser1", password="secret") + cls.user2 = User.objects.create_user(username="testUser2", password="secret") + cls.private_dataset = DataSet.objects.create( + id=1, current_user=cls.user1, name="Dataset 1" + ) + cls.shared_dataset = DataSet.objects.create( + id=2, current_user=cls.user1, name="Dataset 2" + ) + cls.shared_dataset.users.add(cls.user2) + cls.client_owner = APIClient() + cls.client_other = APIClient() + cls.client_owner.force_authenticate(cls.user1) + cls.client_other.force_authenticate(cls.user2) + + # Test listing no users with access + def test_list_access_private(self): + request1 = self.client_owner.get("/v1/data/set/1/users/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + {"data_id": 1, "name": "Dataset 1", "is_public": False, "users": []}, + ) + + # Test listing users with access + def test_list_access_shared(self): + request1 = self.client_owner.get("/v1/data/set/2/users/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + { + "data_id": 2, + "name": "Dataset 2", + "is_public": False, + "users": ["testUser2"], + }, + ) + + # Test only owner can view access + def test_list_access_unauthorized(self): + request = self.client_other.get("/v1/data/set/2/users/") + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + + # Test granting access to a dataset + def test_grant_access(self): + request1 = self.client_owner.put( + "/v1/data/set/1/users/", data={"username": "testUser2", "access": True} + ) + request2 = self.client_other.get("/v1/data/set/1/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertIn( # codespell:ignore + self.user2, DataSet.objects.get(id=1).users.all() + ) + self.assertEqual( + request1.data, + { + "username": "testUser2", + "data_id": 1, + "name": "Dataset 1", + "access": True, + }, + ) + self.private_dataset.users.remove(self.user2) + + # Test revoking access to a dataset + def test_revoke_access(self): + request1 = self.client_owner.put( + "/v1/data/set/2/users/", data={"username": "testUser2", "access": False} + ) + request2 = self.client_other.get("/v1/data/set/2/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertNotIn(self.user2, DataSet.objects.get(id=2).users.all()) + self.assertEqual( + request1.data, + { + "username": "testUser2", + "data_id": 2, + "name": "Dataset 2", + "access": False, + }, + ) + self.shared_dataset.users.add(self.user2) + + # Test only the owner can change access + def test_revoke_access_unauthorized(self): + request1 = self.client_other.put( + "/v1/data/set/2/users/", data={"username": "testUser2", "access": False} + ) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + + @classmethod + def tearDownClass(cls): + cls.private_dataset.delete() + cls.shared_dataset.delete() + cls.user1.delete() + cls.user2.delete() diff --git a/sasdata/fair_database/data/test/test_operation_tree.py b/sasdata/fair_database/data/test/test_operation_tree.py new file mode 100644 index 000000000..90a26d81b --- /dev/null +++ b/sasdata/fair_database/data/test/test_operation_tree.py @@ -0,0 +1,798 @@ +from data.models import DataSet, MetaData, OperationTree, Quantity, ReferenceQuantity +from django.contrib.auth.models import User +from django.db.models import Max +from rest_framework import status +from rest_framework.test import APIClient, APITestCase + + +class TestCreateOperationTree(APITestCase): + """Tests for creating datasets with operation trees.""" + + @classmethod + def setUpTestData(cls): + cls.dataset = { + "name": "Test Dataset", + "metadata": { + "title": "test metadata", + "run": 1, + "definition": "test", + "instrument": {"source": {}, "collimation": {}, "detectors": {}}, + }, + "data_contents": [ + { + "label": "test", + "value": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "variance": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "units": "none", + "hash": 0, + } + ], + "is_public": True, + } + cls.user = User.objects.create_user( + id=1, username="testUser", password="sasview!" + ) + cls.client = APIClient() + cls.client.force_authenticate(cls.user) + + @staticmethod + def get_operation_tree(quantity): + return quantity.operation_tree + + # Test creating quantity with no operations performed (variable-only history) + def test_operation_tree_created_variable(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "variable", + "parameters": {"hash_value": 0, "name": "test"}, + }, + "references": [ + { + "label": "test", + "value": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "variance": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "units": "none", + "hash": 0, + "history": {}, + } + ], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertRaises( + Quantity.operation_tree.RelatedObjectDoesNotExist, + self.get_operation_tree, + quantity=new_quantity, + ) + self.assertEqual(len(new_quantity.references.all()), 0) + + # Test creating quantity with unary operation + def test_operation_tree_created_unary(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "reciprocal", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + } + }, + }, + "references": [ + {"value": 5, "variance": 0, "units": "none", "hash": 111, "history": {}} + ], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + reciprocal = new_quantity.operation_tree + variable = reciprocal.parent_operations.all().get(label="a") + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + new_quantity.value, {"array_contents": [0, 0, 0, 0], "shape": [2, 2]} + ) + self.assertEqual(reciprocal.operation, "reciprocal") + self.assertEqual(variable.operation, "variable") + self.assertEqual(len(reciprocal.parent_operations.all()), 1) + self.assertEqual(reciprocal.parameters, {}) + self.assertEqual(len(ReferenceQuantity.objects.all()), 1) + self.assertEqual(len(new_quantity.references.all()), 1) + self.assertEqual(new_quantity.references.get(hash=111).value, 5) + + # Test creating quantity with binary operation + def test_operation_tree_created_binary(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "add", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "b": {"operation": "constant", "parameters": {"value": 5}}, + }, + }, + "references": [ + {"value": 5, "variance": 0, "units": "none", "hash": 111, "history": {}} + ], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + add = new_quantity.operation_tree + variable = add.parent_operations.get(label="a") + constant = add.parent_operations.get(label="b") + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual(add.operation, "add") + self.assertEqual(add.parameters, {}) + self.assertEqual(variable.operation, "variable") + self.assertEqual(variable.parameters, {"hash_value": 111, "name": "x"}) + self.assertEqual(constant.operation, "constant") + self.assertEqual(constant.parameters, {"value": 5}) + self.assertEqual(len(add.parent_operations.all()), 2) + self.assertEqual(len(new_quantity.references.all()), 1) + self.assertEqual(new_quantity.references.get(hash=111).value, 5) + + # Test creating quantity with exponent + def test_operation_tree_created_pow(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "pow", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "power": 2, + }, + }, + "references": [ + {"value": 5, "variance": 0, "units": "none", "hash": 111, "history": {}} + ], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + pow = new_quantity.operation_tree + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual(pow.operation, "pow") + self.assertEqual(pow.parameters, {"power": 2}) + self.assertEqual(len(new_quantity.references.all()), 1) + self.assertEqual(new_quantity.references.get(hash=111).value, 5) + + # Test creating a transposed quantity + def test_operation_tree_created_transpose(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "transpose", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "axes": [1, 0], + }, + }, + "references": [ + {"value": 5, "variance": 0, "units": "none", "hash": 111, "history": {}} + ], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + transpose = new_quantity.operation_tree + variable = transpose.parent_operations.get() + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual(transpose.operation, "transpose") + self.assertEqual(transpose.parameters, {"axes": [1, 0]}) + self.assertEqual(variable.operation, "variable") + self.assertEqual(variable.parameters, {"hash_value": 111, "name": "x"}) + self.assertEqual(len(new_quantity.references.all()), 1) + self.assertEqual(new_quantity.references.get(hash=111).value, 5) + + # Test creating a quantity with multiple operations + def test_operation_tree_created_nested(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "neg", + "parameters": { + "a": { + "operation": "mul", + "parameters": { + "a": { + "operation": "constant", + "parameters": {"value": {"type": "int", "value": 7}}, + }, + "b": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + }, + }, + }, + }, + "references": [ + {"value": 5, "variance": 0, "units": "none", "hash": 111, "history": {}} + ], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + negate = new_quantity.operation_tree + multiply = negate.parent_operations.get() + constant = multiply.parent_operations.get(label="a") + variable = multiply.parent_operations.get(label="b") + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual(negate.operation, "neg") + self.assertEqual(negate.parameters, {}) + self.assertEqual(multiply.operation, "mul") + self.assertEqual(multiply.parameters, {}) + self.assertEqual(constant.operation, "constant") + self.assertEqual(constant.parameters, {"value": {"type": "int", "value": 7}}) + self.assertEqual(variable.operation, "variable") + self.assertEqual(variable.parameters, {"hash_value": 111, "name": "x"}) + self.assertEqual(len(new_quantity.references.all()), 1) + self.assertEqual(new_quantity.references.get(hash=111).value, 5) + + # Test creating a quantity with tensordot + def test_operation_tree_created_tensor(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "tensor_product", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "b": {"operation": "constant", "parameters": {"value": 5}}, + "a_index": 1, + "b_index": 1, + }, + }, + "references": [ + {"value": 5, "variance": 0, "units": "none", "hash": 111, "history": {}} + ], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + tensor = new_quantity.operation_tree + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual(tensor.operation, "tensor_product") + self.assertEqual(tensor.parameters, {"a_index": 1, "b_index": 1}) + self.assertEqual(len(new_quantity.references.all()), 1) + self.assertEqual(new_quantity.references.get(hash=111).value, 5) + + # Test creating a quantity with no history + def test_operation_tree_created_no_history(self): + if "history" in self.dataset["data_contents"][0]: + self.dataset["data_contents"][0].pop("history") + request = self.client.post( + "/v1/data/set/", data=self.dataset, format="json" + ) + max_id = DataSet.objects.aggregate(Max("id"))["id__max"] + new_dataset = DataSet.objects.get(id=max_id) + new_quantity = new_dataset.data_contents.get(hash=0) + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertIsNone(new_quantity.operation_tree) + self.assertEqual(len(new_quantity.references.all()), 0) + + def tearDown(self): + DataSet.objects.all().delete() + MetaData.objects.all().delete() + Quantity.objects.all().delete() + OperationTree.objects.all().delete() + + @classmethod + def tearDownClass(cls): + cls.user.delete() + + +class TestCreateInvalidOperationTree(APITestCase): + """Tests for creating datasets with invalid operation trees.""" + + @classmethod + def setUpTestData(cls): + cls.dataset = { + "name": "Test Dataset", + "metadata": { + "title": "test metadata", + "run": 1, + "definition": "test", + "instrument": {"source": {}, "collimation": {}, "detectors": {}}, + }, + "data_contents": [ + { + "label": "test", + "value": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "variance": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "units": "none", + "hash": 0, + } + ], + "is_public": True, + } + cls.user = User.objects.create_user( + id=1, username="testUser", password="sasview!" + ) + cls.client = APIClient() + cls.client.force_authenticate(cls.user) + + # Test creating a quantity with an invalid operation + def test_create_operation_tree_invalid(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": {"operation": "fix", "parameters": {}}, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # Test creating a quantity with a nested invalid operation + def test_create_operation_tree_invalid_nested(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "reciprocal", + "parameters": { + "a": { + "operation": "fix", + "parameters": {}, + } + }, + }, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # Test creating a unary operation with a missing parameter fails + def test_create_missing_parameter_unary(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": {"operation": "neg", "parameters": {}}, + "references": {}, + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # Test creating a binary operation with a missing parameter fails + def test_create_missing_parameter_binary(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "add", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + } + }, + }, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # TODO: should variable-only history be ignored? + # Test creating a variable with a missing parameter fails + def test_create_missing_parameter_variable(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "neg", + "parameters": { + "a": {"operation": "variable", "parameters": {"name": "x"}} + }, + }, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # Test creating a constant with a missing parameter fails + def test_create_missing_parameter_constant(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "neg", + "parameters": {"a": {"operation": "constant", "parameters": {}}}, + }, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # Test creating an exponent with a missing parameter fails + def test_create_missing_parameter_pow(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "pow", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + }, + }, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # Test creating a transpose with a missing parameter fails + def test_create_missing_parameter_transpose(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "transpose", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + }, + }, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # Test creating a tensor with a missing parameter fails + def test_create_missing_parameter_tensor(self): + self.dataset["data_contents"][0]["history"] = { + "operation_tree": { + "operation": "tensor_product", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "b": {"operation": "constant", "parameters": {"value": 5}}, + "b_index": 1, + }, + }, + "references": [], + } + request = self.client.post("/v1/data/set/", data=self.dataset, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(DataSet.objects.all()), 0) + self.assertEqual(len(Quantity.objects.all()), 0) + self.assertEqual(len(OperationTree.objects.all()), 0) + + # TODO: Test variables have corresponding reference quantities + + @classmethod + def tearDownClass(cls): + cls.user.delete() + + +class TestGetOperationTree(APITestCase): + """Tests for retrieving datasets with operation trees.""" + + @classmethod + def setUpTestData(cls): + cls.user = User.objects.create_user( + id=1, username="testUser", password="sasview!" + ) + cls.dataset = DataSet.objects.create( + id=1, + current_user=cls.user, + name="Test Dataset", + is_public=True, + ) + cls.quantity = Quantity.objects.create( + id=1, + value=0, + variance=0, + label="test", + units="none", + hash=1, + dataset=cls.dataset, + ) + cls.variable = OperationTree.objects.create( + id=1, operation="variable", parameters={"hash_value": 111, "name": "x"} + ) + cls.constant = OperationTree.objects.create( + id=2, operation="constant", parameters={"value": 1} + ) + cls.ref_quantity = ReferenceQuantity.objects.create( + id=1, + value=5, + variance=0, + units="none", + hash=111, + derived_quantity=cls.quantity, + ) + cls.client = APIClient() + cls.client.force_authenticate(cls.user) + + # Test accessing a quantity with no operations performed + def test_get_operation_tree_none(self): + self.ref_quantity.delete() + request = self.client.get("/v1/data/set/1/") + self.ref_quantity = ReferenceQuantity.objects.create( + id=1, + value=5, + variance=0, + units="none", + hash=111, + derived_quantity=self.quantity, + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data["data_contents"][0], + { + "label": "test", + "value": 0, + "variance": 0, + "units": "none", + "hash": 1, + "history": { + "operation_tree": None, + "references": [], + }, + }, + ) + + # Test accessing quantity with unary operation + def test_get_operation_tree_unary(self): + inv = OperationTree.objects.create( + id=3, + operation="reciprocal", + quantity=self.quantity, + ) + self.variable.label = "a" + self.variable.child_operation = inv + self.variable.save() + request = self.client.get("/v1/data/set/1/") + self.variable.child_operation = None + self.variable.save() + inv.delete() + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data["data_contents"][0], + { + "label": "test", + "value": 0, + "variance": 0, + "units": "none", + "hash": 1, + "history": { + "operation_tree": { + "operation": "reciprocal", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + } + }, + }, + "references": [ + { + "value": 5, + "variance": 0, + "units": "none", + "hash": 111, + } + ], + }, + }, + ) + + # Test accessing quantity with binary operation + def test_get_operation_tree_binary(self): + add = OperationTree.objects.create( + id=3, + operation="add", + quantity=self.quantity, + ) + self.variable.label = "a" + self.variable.child_operation = add + self.variable.save() + self.constant.label = "b" + self.constant.child_operation = add + self.constant.save() + request = self.client.get("/v1/data/set/1/") + self.variable.child_operation = None + self.constant.child_operation = None + self.variable.save() + self.constant.save() + add.delete() + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data["data_contents"][0]["history"]["operation_tree"], + { + "operation": "add", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "b": { + "operation": "constant", + "parameters": {"value": 1}, + }, + }, + }, + ) + + # Test accessing a quantity with exponent + def test_get_operation_tree_pow(self): + power = OperationTree.objects.create( + id=3, + operation="pow", + parameters={"power": 2}, + quantity=self.quantity, + ) + self.variable.label = "a" + self.variable.child_operation = power + self.variable.save() + request = self.client.get("/v1/data/set/1/") + self.variable.child_operation = None + self.variable.save() + power.delete() + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data["data_contents"][0]["history"]["operation_tree"], + { + "operation": "pow", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "power": 2, + }, + }, + ) + + # Test accessing a quantity with multiple operations + def test_get_operation_tree_nested(self): + neg = OperationTree.objects.create( + id=4, operation="neg", quantity=self.quantity + ) + multiply = OperationTree.objects.create( + id=3, operation="mul", child_operation=neg, label="a" + ) + self.constant.label = "a" + self.constant.child_operation = multiply + self.constant.save() + self.variable.label = "b" + self.variable.child_operation = multiply + self.variable.save() + request = self.client.get("/v1/data/set/1/") + self.constant.child_operation = None + self.variable.child_operation = None + self.constant.save() + self.variable.save() + neg.delete() + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data["data_contents"][0]["history"]["operation_tree"], + { + "operation": "neg", + "parameters": { + "a": { + "operation": "mul", + "parameters": { + "a": { + "operation": "constant", + "parameters": {"value": 1}, + }, + "b": { + "operation": "variable", + "parameters": { + "hash_value": 111, + "name": "x", + }, + }, + }, + } + }, + }, + ) + + # Test accessing a transposed quantity + def test_get_operation_tree_transpose(self): + trans = OperationTree.objects.create( + id=3, + operation="transpose", + parameters={"axes": (1, 0)}, + quantity=self.quantity, + ) + self.variable.label = "a" + self.variable.child_operation = trans + self.variable.save() + request = self.client.get("/v1/data/set/1/") + self.variable.child_operation = None + self.variable.save() + trans.delete() + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data["data_contents"][0]["history"]["operation_tree"], + { + "operation": "transpose", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "axes": [1, 0], + }, + }, + ) + + # Test accessing a quantity with tensordot + def test_get_operation_tree_tensordot(self): + tensor = OperationTree.objects.create( + id=3, + operation="tensor_product", + parameters={"a_index": 1, "b_index": 1}, + quantity=self.quantity, + ) + self.variable.label = "a" + self.variable.child_operation = tensor + self.variable.save() + self.constant.label = "b" + self.constant.child_operation = tensor + self.constant.save() + request = self.client.get("/v1/data/set/1/") + self.variable.child_operation = None + self.constant.child_operation = None + self.variable.save() + self.constant.save() + tensor.delete() + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data["data_contents"][0]["history"]["operation_tree"], + { + "operation": "tensor_product", + "parameters": { + "a": { + "operation": "variable", + "parameters": {"hash_value": 111, "name": "x"}, + }, + "b": { + "operation": "constant", + "parameters": {"value": 1}, + }, + "a_index": 1, + "b_index": 1, + }, + }, + ) + + @classmethod + def tearDownClass(cls): + cls.user.delete() + cls.quantity.delete() + cls.dataset.delete() + cls.variable.delete() + cls.constant.delete() diff --git a/sasdata/fair_database/data/test/test_published_state.py b/sasdata/fair_database/data/test/test_published_state.py new file mode 100644 index 000000000..20072f3b1 --- /dev/null +++ b/sasdata/fair_database/data/test/test_published_state.py @@ -0,0 +1,582 @@ +from data.models import PublishedState, Session +from django.contrib.auth.models import User +from django.db.models import Max +from rest_framework import status +from rest_framework.test import APIClient, APITestCase + + +# TODO: account for non-placeholder doi +# Get the placeholder DOI for a session based on id +def doi_generator(id: int): + return "http://127.0.0.1:8000/v1/data/session/" + str(id) + "/" + + +class TestPublishedState(APITestCase): + """Test HTTP methods of PublishedStateView.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user( + id=1, username="testUser1", password="secret" + ) + cls.user2 = User.objects.create_user( + id=2, username="testUser2", password="secret" + ) + cls.public_session = Session.objects.create( + id=1, current_user=cls.user1, title="Public Session", is_public=True + ) + cls.private_session = Session.objects.create( + id=2, current_user=cls.user1, title="Private Session", is_public=False + ) + cls.unowned_session = Session.objects.create( + id=3, title="Unowned Session", is_public=True + ) + cls.unpublished_session = Session.objects.create( + id=4, current_user=cls.user1, title="Publishable Session", is_public=True + ) + cls.public_ps = PublishedState.objects.create( + id=1, + doi=doi_generator(1), + published=True, + session=cls.public_session, + ) + cls.private_ps = PublishedState.objects.create( + id=2, + doi=doi_generator(2), + published=False, + session=cls.private_session, + ) + cls.unowned_ps = PublishedState.objects.create( + id=3, + doi=doi_generator(3), + published=True, + session=cls.unowned_session, + ) + cls.auth_client1 = APIClient() + cls.auth_client2 = APIClient() + cls.auth_client1.force_authenticate(cls.user1) + cls.auth_client2.force_authenticate(cls.user2) + + # Test listing published states including those of owned private sessions + def test_list_published_states_private(self): + request = self.auth_client1.get("/v1/data/published/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + }, + 2: { + "title": "Private Session", + "published": False, + "doi": doi_generator(2), + }, + 3: { + "title": "Unowned Session", + "published": True, + "doi": doi_generator(3), + }, + } + }, + ) + + # Test listing published states of public sessions + def test_list_published_states_public(self): + request = self.auth_client2.get("/v1/data/published/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + }, + 3: { + "title": "Unowned Session", + "published": True, + "doi": doi_generator(3), + }, + } + }, + ) + + # Test listing published states including sessions with access granted + def test_list_published_states_shared(self): + self.private_session.users.add(self.user2) + request = self.auth_client2.get("/v1/data/published/") + self.private_session.users.remove(self.user2) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + }, + 2: { + "title": "Private Session", + "published": False, + "doi": doi_generator(2), + }, + 3: { + "title": "Unowned Session", + "published": True, + "doi": doi_generator(3), + }, + } + }, + ) + + # Test listing published states while unauthenticated + def test_list_published_states_unauthenticated(self): + request = self.client.get("/v1/data/published/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + }, + 3: { + "title": "Unowned Session", + "published": True, + "doi": doi_generator(3), + }, + } + }, + ) + + # Test listing a user's own published states + def test_list_user_published_states_private(self): + request = self.auth_client1.get( + "/v1/data/published/", data={"username": "testUser1"} + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + }, + 2: { + "title": "Private Session", + "published": False, + "doi": doi_generator(2), + }, + } + }, + ) + + # Test listing another user's published states + def test_list_user_published_states_public(self): + request = self.auth_client2.get( + "/v1/data/published/", data={"username": "testUser1"} + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + } + } + }, + ) + + # Test listing another user's published states with access granted + def test_list_user_published_states_shared(self): + self.private_session.users.add(self.user2) + request = self.auth_client2.get( + "/v1/data/published/", data={"username": "testUser1"} + ) + self.private_session.users.remove(self.user2) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + }, + 2: { + "title": "Private Session", + "published": False, + "doi": doi_generator(2), + }, + } + }, + ) + + # Test listing a user's published states while unauthenticated + def test_list_user_published_states_unauthenticated(self): + request = self.client.get("/v1/data/published/", data={"username": "testUser1"}) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_ids": { + 1: { + "title": "Public Session", + "published": True, + "doi": doi_generator(1), + } + } + }, + ) + + # Test creating a published state for a private session + def test_published_state_created_private(self): + self.unpublished_session.is_public = False + self.unpublished_session.save() + published_state = {"published": True, "session": 4} + request = self.auth_client1.post("/v1/data/published/", data=published_state) + max_id = PublishedState.objects.aggregate(Max("id"))["id__max"] + new_ps = PublishedState.objects.get(id=max_id) + self.publishable_session = Session.objects.get(id=4) + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "published_state_id": max_id, + "session_id": 4, + "title": "Publishable Session", + "doi": doi_generator(4), + "published": True, + "current_user": "testUser1", + "is_public": False, + }, + ) + self.assertEqual(self.publishable_session.published_state, new_ps) + self.assertEqual(new_ps.session, self.publishable_session) + new_ps.delete() + self.unpublished_session.is_public = True + self.unpublished_session.save() + + # Test creating a published state for a public session + def test_published_state_created_public(self): + published_state = {"published": False, "session": 4} + request = self.auth_client1.post("/v1/data/published/", data=published_state) + max_id = PublishedState.objects.aggregate(Max("id"))["id__max"] + new_ps = PublishedState.objects.get(id=max_id) + self.publishable_session = Session.objects.get(id=4) + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "published_state_id": max_id, + "session_id": 4, + "title": "Publishable Session", + "doi": doi_generator(4), + "published": False, + "current_user": "testUser1", + "is_public": True, + }, + ) + self.assertEqual(self.publishable_session.published_state, new_ps) + self.assertEqual(new_ps.session, self.publishable_session) + new_ps.delete() + + # Test that you can't create a published state for an unowned session + def test_published_state_created_unowned(self): + self.unpublished_session.current_user = None + self.unpublished_session.save() + published_state = {"published": True, "session": 4} + request = self.auth_client1.post("/v1/data/published/", data=published_state) + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(len(PublishedState.objects.all()), 3) + self.unpublished_session.current_user = self.user1 + self.unpublished_session.save() + + # Test that an unauthenticated user cannot create a published state + def test_published_state_created_unauthenticated(self): + published_state = {"published": True, "session": 4} + request = self.client.post("/v1/data/published/", data=published_state) + self.assertEqual(request.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(len(PublishedState.objects.all()), 3) + + # Test that a user cannot create a published state for a session they don't own + def test_published_state_created_unauthorized(self): + published_state = {"published": True, "session": 4} + request = self.auth_client2.post("/v1/data/published/", data=published_state) + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(len(PublishedState.objects.all()), 3) + + # Test that only one published state can be created per session + def test_no_duplicate_published_states(self): + published_state = {"published": True, "session": 1} + request = self.auth_client1.post("/v1/data/published/", data=published_state) + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + + @classmethod + def tearDownClass(cls): + cls.public_session.delete() + cls.private_session.delete() + cls.unowned_session.delete() + cls.user1.delete() + cls.user2.delete() + + +class TestSinglePublishedState(APITestCase): + """Test HTTP methods of SinglePublishedStateView.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user( + id=1, username="testUser1", password="secret" + ) + cls.user2 = User.objects.create_user( + id=2, username="testUser2", password="secret" + ) + cls.public_session = Session.objects.create( + id=1, current_user=cls.user1, title="Public Session", is_public=True + ) + cls.private_session = Session.objects.create( + id=2, current_user=cls.user1, title="Private Session", is_public=False + ) + cls.unowned_session = Session.objects.create( + id=3, title="Unowned Session", is_public=True + ) + cls.public_ps = PublishedState.objects.create( + id=1, + doi=doi_generator(1), + published=True, + session=cls.public_session, + ) + cls.private_ps = PublishedState.objects.create( + id=2, + doi=doi_generator(2), + published=False, + session=cls.private_session, + ) + cls.unowned_ps = PublishedState.objects.create( + id=3, + doi=doi_generator(3), + published=True, + session=cls.unowned_session, + ) + cls.auth_client1 = APIClient() + cls.auth_client2 = APIClient() + cls.auth_client1.force_authenticate(cls.user1) + cls.auth_client2.force_authenticate(cls.user2) + + # Test viewing a published state of a public session + def test_get_public_published_state(self): + request1 = self.auth_client2.get("/v1/data/published/1/") + request2 = self.client.get("/v1/data/published/1/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + { + "id": 1, + "doi": doi_generator(1), + "published": True, + "session": 1, + "title": "Public Session", + "current_user": "testUser1", + "is_public": True, + }, + ) + self.assertEqual(request1.data, request2.data) + + # Test viewing a published state of a private session + def test_get_private_published_state(self): + request = self.auth_client1.get("/v1/data/published/2/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "id": 2, + "doi": doi_generator(2), + "published": False, + "session": 2, + "title": "Private Session", + "current_user": "testUser1", + "is_public": False, + }, + ) + + # Test viewing a published state of an unowned session + def test_get_unowned_published_state(self): + request = self.auth_client1.get("/v1/data/published/3/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "id": 3, + "doi": doi_generator(3), + "published": True, + "session": 3, + "title": "Unowned Session", + "current_user": "", + "is_public": True, + }, + ) + + # Test viewing a published state of a session with access granted + def test_get_shared_published_state(self): + self.private_session.users.add(self.user2) + request = self.auth_client2.get("/v1/data/published/2/") + self.private_session.users.remove(self.user2) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "id": 2, + "doi": doi_generator(2), + "published": False, + "session": 2, + "title": "Private Session", + "current_user": "testUser1", + "is_public": False, + }, + ) + + # Test a user can't view a published state of a private session they don't own + def test_get_private_published_state_unauthorized(self): + request1 = self.client.get("/v1/data/published/2/") + request2 = self.auth_client2.get("/v1/data/published/2/") + self.assertEqual(request1.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + + # Test updating a published state of a public session + def test_update_public_published_state(self): + request = self.auth_client1.put( + "/v1/data/published/1/", data={"published": False} + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_id": 1, + "session_id": 1, + "title": "Public Session", + "published": False, + "is_public": True, + }, + ) + self.assertFalse(PublishedState.objects.get(id=1).published) + self.public_ps.save() + + # Test updating a published state of a private session + def test_update_private_published_state(self): + request = self.auth_client1.put( + "/v1/data/published/2/", data={"published": True} + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "published_state_id": 2, + "session_id": 2, + "title": "Private Session", + "published": True, + "is_public": False, + }, + ) + self.assertTrue(PublishedState.objects.get(id=2).published) + self.private_ps.save() + + # Test a user can't update the published state of an unowned session + def test_update_unowned_published_state(self): + request1 = self.auth_client1.put( + "/v1/data/published/3/", data={"published": False} + ) + request2 = self.client.put("/v1/data/published/3/", data={"published": False}) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertTrue(PublishedState.objects.get(id=3).published) + + # Test a user can't update a public published state unauthorized + def test_update_public_published_state_unauthorized(self): + request1 = self.auth_client2.put( + "/v1/data/published/1/", data={"published": False} + ) + self.public_session.users.add(self.user2) + request2 = self.auth_client2.put( + "/v1/data/published/1/", data={"published": False} + ) + self.public_session.users.remove(self.user2) + request3 = self.client.put("/v1/data/published/1/", data={"published": False}) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request3.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertTrue(PublishedState.objects.get(id=1).published) + + # Test a user can't update a private published state unauthorized + def test_update_private_published_state_unauthorized(self): + request1 = self.auth_client2.put( + "/v1/data/published/2/", data={"published": True} + ) + self.public_session.users.add(self.user2) + request2 = self.auth_client2.put( + "/v1/data/published/2/", data={"published": True} + ) + self.public_session.users.remove(self.user2) + request3 = self.client.put("/v1/data/published/2/", data={"published": True}) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request3.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertFalse(PublishedState.objects.get(id=2).published) + + # Test deleting a published state of a private session + def test_delete_private_published_state(self): + request = self.auth_client1.delete("/v1/data/published/2/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(len(PublishedState.objects.all()), 2) + self.assertEqual(len(Session.objects.all()), 3) + self.assertRaises(PublishedState.DoesNotExist, PublishedState.objects.get, id=2) + self.private_ps = PublishedState.objects.create( + id=2, + doi=doi_generator(2), + published=False, + session=self.private_session, + ) + + # Test a user can't delete a private published state unauthorized + def test_delete_private_published_state_unauthorized(self): + request1 = self.auth_client2.delete("/v1/data/published/2/") + self.private_session.users.add(self.user2) + request2 = self.auth_client2.delete("/v1/data/published/2/") + self.private_session.users.remove(self.user2) + request3 = self.client.delete("/v1/data/published/2/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request3.status_code, status.HTTP_401_UNAUTHORIZED) + + # Test a user can't delete a published state of a public + def test_cant_delete_public_published_state(self): + request = self.auth_client1.delete("/v1/data/published/1/") + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + + # Test a user can't delete an unowned published state + def test_delete_unowned_published_state(self): + request = self.auth_client1.delete("/v1/data/published/3/") + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + + @classmethod + def tearDownClass(cls): + cls.public_session.delete() + cls.private_session.delete() + cls.unowned_session.delete() + cls.user1.delete() + cls.user2.delete() diff --git a/sasdata/fair_database/data/test/test_session.py b/sasdata/fair_database/data/test/test_session.py new file mode 100644 index 000000000..fc185f8fd --- /dev/null +++ b/sasdata/fair_database/data/test/test_session.py @@ -0,0 +1,700 @@ +from data.models import DataSet, PublishedState, Session +from django.contrib.auth.models import User +from django.db.models import Max +from rest_framework import status +from rest_framework.test import APIClient, APITestCase + + +class TestSession(APITestCase): + """Test HTTP methods of SessionView.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user( + id=1, username="testUser1", password="secret" + ) + cls.user2 = User.objects.create_user( + id=2, username="testUser2", password="secret" + ) + cls.public_session = Session.objects.create( + id=1, current_user=cls.user1, title="Public Session", is_public=True + ) + cls.private_session = Session.objects.create( + id=2, current_user=cls.user1, title="Private Session", is_public=False + ) + cls.unowned_session = Session.objects.create( + id=3, title="Unowned Session", is_public=True + ) + cls.auth_client1 = APIClient() + cls.auth_client2 = APIClient() + cls.auth_client1.force_authenticate(cls.user1) + cls.auth_client2.force_authenticate(cls.user2) + + # Test listing sessions + def test_list_private(self): + request = self.auth_client1.get("/v1/data/session/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "session_ids": { + 1: "Public Session", + 2: "Private Session", + 3: "Unowned Session", + } + }, + ) + + # Test listing public sessions + def test_list_public(self): + request = self.auth_client2.get("/v1/data/session/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, {"session_ids": {1: "Public Session", 3: "Unowned Session"}} + ) + + # Test listing sessions while unauthenticated + def test_list_unauthenticated(self): + request = self.client.get("/v1/data/session/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, {"session_ids": {1: "Public Session", 3: "Unowned Session"}} + ) + + # Test listing a session with access granted + def test_list_granted_access(self): + self.private_session.users.add(self.user2) + request = self.auth_client2.get("/v1/data/session/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "session_ids": { + 1: "Public Session", + 2: "Private Session", + 3: "Unowned Session", + } + }, + ) + self.private_session.users.remove(self.user2) + + # Test listing by username + def test_list_username(self): + request = self.auth_client1.get( + "/v1/data/session/", data={"username": "testUser1"} + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, {"session_ids": {1: "Public Session", 2: "Private Session"}} + ) + + # Test listing by another user's username + def test_list_other_username(self): + request = self.auth_client2.get( + "/v1/data/session/", data={"username": "testUser1"} + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual(request.data, {"session_ids": {1: "Public Session"}}) + + # Test creating a public session + def test_session_created(self): + session = { + "title": "New session", + "datasets": [ + { + "name": "New dataset", + "metadata": { + "title": "New metadata", + "run": 0, + "description": "test", + "instrument": {}, + "process": {}, + "sample": {}, + }, + "data_contents": [], + } + ], + "is_public": True, + "published_state": {"published": False}, + } + request = self.auth_client1.post( + "/v1/data/session/", data=session, format="json" + ) + max_id = Session.objects.aggregate(Max("id"))["id__max"] + new_session = Session.objects.get(id=max_id) + new_dataset = new_session.datasets.get() + new_metadata = new_dataset.metadata + new_published_state = new_session.published_state + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "session_id": max_id, + "title": "New session", + "authenticated": True, + "current_user": "testUser1", + "is_public": True, + }, + ) + self.assertEqual(new_session.title, "New session") + self.assertEqual(new_dataset.name, "New dataset") + self.assertEqual(new_metadata.title, "New metadata") + self.assertEqual(new_session.current_user, self.user1) + self.assertEqual(new_dataset.current_user, self.user1) + self.assertTrue(all([new_session.is_public, new_dataset.is_public])) + self.assertFalse(new_published_state.published) + new_session.delete() + + # Test creating a private session + def test_session_created_private(self): + session = { + "title": "New session", + "datasets": [ + { + "name": "New dataset", + "metadata": { + "title": "New metadata", + "run": 0, + "description": "test", + "instrument": {}, + "process": {}, + "sample": {}, + }, + "data_contents": [], + } + ], + "is_public": False, + } + request = self.auth_client1.post( + "/v1/data/session/", data=session, format="json" + ) + max_id = Session.objects.aggregate(Max("id"))["id__max"] + new_session = Session.objects.get(id=max_id) + new_dataset = new_session.datasets.get() + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "session_id": max_id, + "title": "New session", + "authenticated": True, + "current_user": "testUser1", + "is_public": False, + }, + ) + self.assertEqual(new_session.current_user, self.user1) + self.assertEqual(new_dataset.current_user, self.user1) + self.assertFalse(any([new_session.is_public, new_dataset.is_public])) + new_session.delete() + + # Test creating a session while unauthenticated + def test_session_created_unauthenticated(self): + session = { + "title": "New session", + "datasets": [ + { + "name": "New dataset", + "metadata": { + "title": "New metadata", + "run": 0, + "description": "test", + "instrument": {}, + "process": {}, + "sample": {}, + }, + "data_contents": [], + } + ], + "is_public": True, + } + request = self.client.post("/v1/data/session/", data=session, format="json") + max_id = Session.objects.aggregate(Max("id"))["id__max"] + new_session = Session.objects.get(id=max_id) + new_dataset = new_session.datasets.get() + self.assertEqual(request.status_code, status.HTTP_201_CREATED) + self.assertEqual( + request.data, + { + "session_id": max_id, + "title": "New session", + "authenticated": False, + "current_user": "", + "is_public": True, + }, + ) + self.assertIsNone(new_session.current_user) + self.assertIsNone(new_dataset.current_user) + self.assertTrue(all([new_session.is_public, new_dataset.is_public])) + new_session.delete() + + # Test that a private session must have an owner + def test_no_private_unowned_session(self): + session = {"title": "New session", "datasets": [], "is_public": False} + request = self.client.post("/v1/data/session/", data=session, format="json") + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + + # Test post fails with dataset validation issue + def test_no_session_invalid_dataset(self): + session = { + "title": "New session", + "datasets": [ + { + "metadata": { + "title": "New metadata", + "run": 0, + "description": "test", + "instrument": {}, + "process": {}, + "sample": {}, + }, + "data_contents": [], + } + ], + "is_public": True, + } + request = self.auth_client1.post( + "/v1/data/session/", data=session, format="json" + ) + self.assertEqual(request.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(len(Session.objects.all()), 3) + self.assertEqual(len(DataSet.objects.all()), 0) + + @classmethod + def tearDownClass(cls): + cls.public_session.delete() + cls.private_session.delete() + cls.unowned_session.delete() + cls.user1.delete() + cls.user2.delete() + + +class TestSingleSession(APITestCase): + """Test HTTP methods of SingleSessionView.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user( + id=1, username="testUser1", password="secret" + ) + cls.user2 = User.objects.create_user( + id=2, username="testUser2", password="secret" + ) + cls.public_session = Session.objects.create( + id=1, current_user=cls.user1, title="Public Session", is_public=True + ) + cls.private_session = Session.objects.create( + id=2, current_user=cls.user1, title="Private Session", is_public=False + ) + cls.unowned_session = Session.objects.create( + id=3, title="Unowned Session", is_public=True + ) + cls.public_dataset = DataSet.objects.create( + id=1, + current_user=cls.user1, + is_public=True, + name="Public Dataset", + session=cls.public_session, + ) + cls.private_dataset = DataSet.objects.create( + id=2, + current_user=cls.user1, + name="Private Dataset", + session=cls.private_session, + ) + cls.unowned_dataset = DataSet.objects.create( + id=3, is_public=True, name="Unowned Dataset", session=cls.unowned_session + ) + cls.private_published_state = PublishedState.objects.create( + id=2, + session=cls.private_session, + published=False, + doi="http://localhost:8000/v1/data/session/2/", + ) + cls.auth_client1 = APIClient() + cls.auth_client2 = APIClient() + cls.auth_client1.force_authenticate(cls.user1) + cls.auth_client2.force_authenticate(cls.user2) + + # Test loading another user's public session + def test_get_public_session(self): + request = self.auth_client2.get("/v1/data/session/1/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "id": 1, + "current_user": "testUser1", + "users": [], + "is_public": True, + "title": "Public Session", + "datasets": [ + { + "id": 1, + "current_user": 1, + "users": [], + "is_public": True, + "name": "Public Dataset", + "files": [], + "metadata": None, + "data_contents": [], + } + ], + "published_state": None, + }, + ) + + # Test loading a private session as the owner + def test_get_private_session(self): + request = self.auth_client1.get("/v1/data/session/2/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "id": 2, + "current_user": "testUser1", + "users": [], + "is_public": False, + "title": "Private Session", + "published_state": { + "id": 2, + "published": False, + "doi": "http://localhost:8000/v1/data/session/2/", + "session": 2, + }, + "datasets": [ + { + "id": 2, + "current_user": 1, + "users": [], + "is_public": False, + "name": "Private Dataset", + "files": [], + "metadata": None, + "data_contents": [], + } + ], + }, + ) + + # Test loading a private session as a user with granted access + def test_get_private_session_access_granted(self): + self.private_session.users.add(self.user2) + request = self.auth_client2.get("/v1/data/session/2/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.private_session.users.remove(self.user2) + + # Test loading an unowned session + def test_get_unowned_session(self): + request = self.auth_client1.get("/v1/data/session/3/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "id": 3, + "current_user": None, + "users": [], + "is_public": True, + "title": "Unowned Session", + "published_state": None, + "datasets": [ + { + "id": 3, + "current_user": None, + "users": [], + "is_public": True, + "name": "Unowned Dataset", + "files": [], + "metadata": None, + "data_contents": [], + } + ], + }, + ) + + # Test loading another user's private session + def test_get_private_session_unauthorized(self): + request1 = self.auth_client2.get("/v1/data/session/2/") + request2 = self.client.get("/v1/data/session/2/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + + # Test updating a public session + def test_update_public_session(self): + request = self.auth_client1.put( + "/v1/data/session/1/", data={"is_public": False} + ) + session = Session.objects.get(id=1) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + {"session_id": 1, "title": "Public Session", "is_public": False}, + ) + self.assertFalse(session.is_public) + session.is_public = False + session.save() + + # Test creating a published state by updating a session + def test_update_session_new_published_state(self): + request = self.auth_client1.put( + "/v1/data/session/1/", + data={"published_state": {"published": False}}, + format="json", + ) + new_published_state = Session.objects.get(id=1).published_state + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertFalse(new_published_state.published) + new_published_state.delete() + + # Test that another user's public session cannot be updated + def test_update_public_session_unauthorized(self): + request1 = self.auth_client2.put( + "/v1/data/session/1/", data={"is_public": False} + ) + request2 = self.client.put("/v1/data/session/1/", data={"is_public": False}) + session = Session.objects.get(id=1) + session.users.add(self.user2) + request3 = self.auth_client2.put( + "/v1/data/session/1/", data={"is_public": False} + ) + session.users.remove(self.user2) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(request3.status_code, status.HTTP_403_FORBIDDEN) + self.assertTrue(Session.objects.get(id=1).is_public) + + # Test updating a private session + def test_update_private_session(self): + request1 = self.auth_client1.put( + "/v1/data/session/2/", data={"is_public": True} + ) + session = Session.objects.get(id=2) + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + {"session_id": 2, "title": "Private Session", "is_public": True}, + ) + self.assertTrue(session.is_public) + self.assertTrue(session.datasets.get().is_public) + session.is_public = False + session.save() + + # Test updating a published state through its session + def test_update_session_published_state(self): + request = self.auth_client1.put( + "/v1/data/session/2/", + data={"published_state": {"published": True}}, + format="json", + ) + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertTrue(PublishedState.objects.get(id=2).published) + self.private_published_state.save() + + # Test that another user's private session cannot be updated + def test_update_private_session_unauthorized(self): + request1 = self.auth_client2.put( + "/v1/data/session/2/", data={"is_public": True} + ) + request2 = self.client.put("/v1/data/session/2/", data={"is_public": True}) + session = Session.objects.get(id=2) + session.users.add(self.user2) + request3 = self.auth_client2.put( + "/v1/data/session/2/", data={"is_public": True} + ) + session.users.remove(self.user2) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(request3.status_code, status.HTTP_403_FORBIDDEN) + self.assertFalse(Session.objects.get(id=2).is_public) + + # Test that an unowned session cannot be updated + def test_update_unowned_session(self): + request = self.auth_client1.put( + "/v1/data/session/3/", data={"is_public": False} + ) + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + self.assertTrue(Session.objects.get(id=3).is_public) + + # Test deleting a private session + def test_delete_private_session(self): + request = self.auth_client1.delete("/v1/data/session/2/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertRaises(Session.DoesNotExist, Session.objects.get, id=2) + self.assertRaises(DataSet.DoesNotExist, DataSet.objects.get, id=2) + self.assertRaises(PublishedState.DoesNotExist, PublishedState.objects.get, id=2) + self.private_session = Session.objects.create( + id=2, current_user=self.user1, title="Private Session", is_public=False + ) + self.private_dataset = DataSet.objects.create( + id=2, + current_user=self.user1, + name="Private Dataset", + session=self.private_session, + ) + self.private_published_state = PublishedState.objects.create( + id=2, + session=self.private_session, + published=False, + doi="http://localhost:8000/v1/data/session/2/", + ) + + # Test that another user's private session cannot be deleted + def test_delete_private_session_unauthorized(self): + request1 = self.auth_client2.delete("/v1/data/session/2/") + request2 = self.client.delete("/v1/data/session/2/") + self.private_session.users.add(self.user2) + request3 = self.auth_client2.delete("/v1/data/session/2/") + self.private_session.users.remove(self.user2) + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(request3.status_code, status.HTTP_403_FORBIDDEN) + + # Test that a public session cannot be deleted + def test_delete_public_session(self): + request = self.auth_client1.delete("/v1/data/session/1/") + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + + # Test that an unowned session cannot be deleted + def test_delete_unowned_session(self): + request = self.auth_client1.delete("/v1/data/session/3/") + self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN) + + @classmethod + def tearDownClass(cls): + cls.public_session.delete() + cls.private_session.delete() + cls.unowned_session.delete() + cls.user1.delete() + cls.user2.delete() + + +class TestSessionAccessManagement(APITestCase): + """Test HTTP methods of SessionUsersView.""" + + @classmethod + def setUpTestData(cls): + cls.user1 = User.objects.create_user(username="testUser1", password="secret") + cls.user2 = User.objects.create_user(username="testUser2", password="secret") + cls.private_session = Session.objects.create( + id=1, current_user=cls.user1, title="Private Session", is_public=False + ) + cls.shared_session = Session.objects.create( + id=2, current_user=cls.user1, title="Shared Session", is_public=False + ) + cls.private_dataset = DataSet.objects.create( + id=1, + current_user=cls.user1, + name="Private Dataset", + session=cls.private_session, + ) + cls.shared_dataset = DataSet.objects.create( + id=2, + current_user=cls.user1, + name="Shared Dataset", + session=cls.shared_session, + ) + cls.shared_session.users.add(cls.user2) + cls.shared_dataset.users.add(cls.user2) + cls.client_owner = APIClient() + cls.client_other = APIClient() + cls.client_owner.force_authenticate(cls.user1) + cls.client_other.force_authenticate(cls.user2) + + # Test listing access to an unshared session + def test_list_access_private(self): + request = self.client_owner.get("/v1/data/session/1/users/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "session_id": 1, + "title": "Private Session", + "is_public": False, + "users": [], + }, + ) + + # Test listing access to a shared session + def test_list_access_shared(self): + request = self.client_owner.get("/v1/data/session/2/users/") + self.assertEqual(request.status_code, status.HTTP_200_OK) + self.assertEqual( + request.data, + { + "session_id": 2, + "title": "Shared Session", + "is_public": False, + "users": ["testUser2"], + }, + ) + + # Test that only the owner can view access + def test_list_access_unauthorized(self): + request1 = self.client_other.get("/v1/data/session/1/users/") + request2 = self.client_other.get("/v1/data/session/2/users/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + + # Test granting access to a session + def test_grant_access(self): + request1 = self.client_owner.put( + "/v1/data/session/1/users/", {"username": "testUser2", "access": True} + ) + request2 = self.client_other.get("/v1/data/session/1/") + request3 = self.client_other.get("/v1/data/set/1/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual( + request1.data, + { + "username": "testUser2", + "session_id": 1, + "title": "Private Session", + "access": True, + }, + ) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertEqual(request3.status_code, status.HTTP_200_OK) + self.assertIn(self.user2, self.private_session.users.all()) # codespell:ignore + self.assertIn(self.user2, self.private_dataset.users.all()) # codespell:ignore + self.private_session.users.remove(self.user2) + self.private_dataset.users.remove(self.user2) + + # Test revoking access to a session + def test_revoke_access(self): + request1 = self.client_owner.put( + "/v1/data/session/2/users/", {"username": "testUser2", "access": False} + ) + request2 = self.client_other.get("/v1/data/session/2/") + request3 = self.client_other.get("/v1/data/session/2/") + self.assertEqual(request1.status_code, status.HTTP_200_OK) + self.assertEqual(request2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request3.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + request1.data, + { + "username": "testUser2", + "session_id": 2, + "title": "Shared Session", + "access": False, + }, + ) + self.assertNotIn(self.user2, self.shared_session.users.all()) + self.assertNotIn(self.user2, self.shared_dataset.users.all()) + self.shared_session.users.add(self.user2) + self.shared_dataset.users.add(self.user2) + + # Test that only the owner can change access + def test_revoke_access_unauthorized(self): + request1 = self.client_other.put( + "/v1/data/session/2/users/", {"username": "testUser2", "access": False} + ) + request2 = self.client_other.get("/v1/data/session/2/") + self.assertEqual(request1.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(request2.status_code, status.HTTP_200_OK) + self.assertIn(self.user2, self.shared_session.users.all()) # codespell:ignore + + @classmethod + def tearDownClass(cls): + cls.private_session.delete() + cls.shared_session.delete() + cls.user1.delete() + cls.user2.delete() diff --git a/sasdata/fair_database/data/urls.py b/sasdata/fair_database/data/urls.py new file mode 100644 index 000000000..0e94f60c7 --- /dev/null +++ b/sasdata/fair_database/data/urls.py @@ -0,0 +1,49 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path("file/", views.DataFileView.as_view(), name="view and create files"), + path( + "file//", + views.SingleDataFileView.as_view(), + name="view, download, modify, delete files", + ), + path( + "file//users/", + views.DataFileUsersView.as_view(), + name="manage access to files", + ), + path("set/", views.DataSetView.as_view(), name="view and create datasets"), + path( + "set//", + views.SingleDataSetView.as_view(), + name="load, modify, delete datasets", + ), + path( + "set//users/", + views.DataSetUsersView.as_view(), + name="manage access to datasets", + ), + path("session/", views.SessionView.as_view(), name="view and create sessions"), + path( + "session//", + views.SingleSessionView.as_view(), + name="load, modify, delete sessions", + ), + path( + "session//users/", + views.SessionUsersView.as_view(), + name="manage access to sessions", + ), + path( + "published/", + views.PublishedStateView.as_view(), + name="view and create published states", + ), + path( + "published//", + views.SinglePublishedStateView.as_view(), + name="load, modify, delete published states", + ), +] diff --git a/sasdata/fair_database/data/views.py b/sasdata/fair_database/data/views.py new file mode 100644 index 000000000..fc1c547c1 --- /dev/null +++ b/sasdata/fair_database/data/views.py @@ -0,0 +1,707 @@ +import json +import os + +from data.forms import DataFileForm +from data.models import DataFile, DataSet, PublishedState, Session +from data.serializers import ( + AccessManagementSerializer, + DataFileSerializer, + DataSetSerializer, + PublishedStateSerializer, + PublishedStateUpdateSerializer, + SessionSerializer, +) +from django.contrib.auth.models import User +from django.http import ( + FileResponse, + Http404, + HttpResponse, + HttpResponseBadRequest, + HttpResponseForbidden, +) +from django.shortcuts import get_object_or_404 +from drf_spectacular.utils import extend_schema +from fair_database import permissions +from fair_database.permissions import DataPermission +from rest_framework import status +from rest_framework.response import Response +from rest_framework.views import APIView + +from sasdata.dataloader.loader import Loader + + +class DataFileView(APIView): + """ + View associated with the DataFile model. + + Functionality for viewing a list of files and uploading a new file. + """ + + # List of datafiles + @extend_schema( + description="Retrieve a list of accessible data files by id and filename." + ) + def get(self, request, version=None): + if "username" in request.GET: + search_user = get_object_or_404(User, username=request.GET["username"]) + data_list = {"user_data_ids": {}} + private_data = DataFile.objects.filter(current_user=search_user) + for x in private_data: + if permissions.check_permissions(request, x): + data_list["user_data_ids"][x.id] = x.file_name + else: + public_data = DataFile.objects.all() + data_list = {"public_data_ids": {}} + for x in public_data: + if permissions.check_permissions(request, x): + data_list["public_data_ids"][x.id] = x.file_name + return Response(data_list) + + # Create a datafile + @extend_schema(description="Upload a data file.") + def post(self, request, version=None): + form = DataFileForm(request.data, request.FILES) + if form.is_valid(): + form.save() + db = DataFile.objects.get(pk=form.instance.pk) + serializer = DataFileSerializer( + db, + data={ + "file_name": os.path.basename(form.instance.file.path), + "current_user": None, + "users": [], + }, + context={"is_public": db.is_public}, + ) + if request.user.is_authenticated: + serializer.initial_data["current_user"] = request.user.id + + if serializer.is_valid(raise_exception=True): + serializer.save() + return_data = { + "current_user": request.user.username, + "authenticated": request.user.is_authenticated, + "file_id": db.id, + "file_alternative_name": serializer.data["file_name"], + "is_public": serializer.data["is_public"], + } + return Response(return_data, status=status.HTTP_201_CREATED) + + # Create a datafile + @extend_schema(description="Upload a data file.") + def put(self, request, version=None): + return self.post(request, version) + + +class SingleDataFileView(APIView): + """ + View associated with a single DataFile. + + Functionality for viewing, modifying, or deleting a DataFile. + """ + + # Load the contents of a datafile or download the file to a device + @extend_schema( + description="Retrieve the contents of a data file or download a file." + ) + def get(self, request, data_id, version=None): + data = get_object_or_404(DataFile, id=data_id) + if "download" in request.GET and request.GET["download"]: + if not permissions.check_permissions(request, data): + if not request.user.is_authenticated: + return HttpResponse("Must be authenticated to download", status=401) + return HttpResponseForbidden("data is private") + try: + file = open(data.file.path, "rb") + except Exception as e: + return HttpResponseBadRequest(str(e)) + if file is None: + raise Http404("File not found.") + return FileResponse(file, as_attachment=True) + else: + loader = Loader() + if not permissions.check_permissions(request, data): + if not request.user.is_authenticated: + return HttpResponse("Must be authenticated to view", status=401) + return HttpResponseForbidden( + "Data is either not public or wrong auth token" + ) + data_list = loader.load(data.file.path) + contents = [str(data) for data in data_list] + return_data = {data.file_name: contents} + return Response(return_data) + + # Modify a datafile + @extend_schema(description="Make changes to a data file that you own.") + def put(self, request, data_id, version=None): + db = get_object_or_404(DataFile, id=data_id) + if not permissions.check_permissions(request, db): + if not request.user.is_authenticated: + return HttpResponse("must be authenticated to modify", status=401) + return HttpResponseForbidden("must be the data owner to modify") + form = DataFileForm(request.data, request.FILES, instance=db) + if form.is_valid(): + form.save() + serializer = DataFileSerializer( + db, + data={ + "file_name": os.path.basename(form.instance.file.path), + "current_user": request.user.id, + }, + context={"is_public": db.is_public}, + partial=True, + ) + if serializer.is_valid(raise_exception=True): + serializer.save() + return_data = { + "current_user": request.user.username, + "authenticated": request.user.is_authenticated, + "file_id": db.id, + "file_alternative_name": serializer.data["file_name"], + "is_public": serializer.data["is_public"], + } + return Response(return_data) + + # Delete a datafile + @extend_schema(description="Delete a data file that you own.") + def delete(self, request, data_id, version=None): + db = get_object_or_404(DataFile, id=data_id) + if not permissions.is_owner(request, db): + if not request.user.is_authenticated: + return HttpResponse("Must be authenticated to delete", status=401) + return HttpResponseForbidden("Must be the data owner to delete") + db.delete() + return Response(data={"success": True}) + + +class DataFileUsersView(APIView): + """ + View for the users that have access to a datafile. + + Functionality for accessing a list of users with access and granting or + revoking access. + """ + + # View users with access to a datafile + @extend_schema( + description="Retrieve a list of users that have been granted access to" + " a data file and the file's publicity status." + ) + def get(self, request, data_id, version=None): + db = get_object_or_404(DataFile, id=data_id) + if not permissions.is_owner(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to manage access", status=401 + ) + return HttpResponseForbidden("Must be the data owner to manage access") + response_data = { + "file": db.pk, + "file_name": db.file_name, + "is_public": db.is_public, + "users": [user.username for user in db.users.all()], + } + return Response(response_data) + + # Grant or revoke access to a datafile + @extend_schema(description="Grant or revoke a user's access to a data file.") + def put(self, request, data_id, version=None): + db = get_object_or_404(DataFile, id=data_id) + if not permissions.is_owner(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to manage access", status=401 + ) + return HttpResponseForbidden("Must be the data owner to manage access") + serializer = AccessManagementSerializer(data=request.data) + serializer.is_valid() + user = get_object_or_404(User, username=serializer.data["username"]) + if serializer.data["access"]: + db.users.add(user) + else: + db.users.remove(user) + response_data = { + "username": user.username, + "file": db.pk, + "file_name": db.file_name, + "access": (serializer.data["access"] or user == db.current_user), + } + return Response(response_data) + + +class DataSetView(APIView): + """ + View associated with the DataSet model. + + Functionality for viewing a list of datasets and creating a dataset. + """ + + permission_classes = [DataPermission] + + # get a list of accessible datasets + @extend_schema(description="Retrieve a list of accessible datasets by id and name.") + def get(self, request, version=None): + data_list = {"dataset_ids": {}} + data = DataSet.objects.all() + if "username" in request.GET: + user = get_object_or_404(User, username=request.GET["username"]) + data = DataSet.objects.filter(current_user=user) + for dataset in data: + if permissions.check_permissions(request, dataset): + data_list["dataset_ids"][dataset.id] = dataset.name + return Response(data=data_list) + + # TODO: enable uploading files as part of dataset creation, not just associating dataset with existing files + # create a dataset + @extend_schema(description="Upload a dataset.") + def post(self, request, version=None): + # TODO: revisit request data format + if isinstance(request.data, str): + serializer = DataSetSerializer( + data=json.loads(request.data), context={"request": request} + ) + else: + serializer = DataSetSerializer( + data=request.data, context={"request": request} + ) + if serializer.is_valid(raise_exception=True): + serializer.save() + db = serializer.instance + response = { + "dataset_id": db.id, + "name": db.name, + "authenticated": request.user.is_authenticated, + "current_user": request.user.username, + "is_public": db.is_public, + } + return Response(data=response, status=status.HTTP_201_CREATED) + + # create a dataset + @extend_schema(description="Upload a dataset.") + def put(self, request, version=None): + return self.post(request, version) + + +class SingleDataSetView(APIView): + """ + View associated with single datasets. + + Functionality for accessing a dataset in a format intended to be loaded + into SasView, modifying a dataset, or deleting a dataset. + """ + + permission_classes = [DataPermission] + + # get a specific dataset + @extend_schema(description="Retrieve a dataset.") + def get(self, request, data_id, version=None): + db = get_object_or_404(DataSet, id=data_id) + if not permissions.check_permissions(request, db): + if not request.user.is_authenticated: + return HttpResponse("Must be authenticated to view dataset", status=401) + return HttpResponseForbidden( + "You do not have permission to view this dataset." + ) + serializer = DataSetSerializer(db, context={"request": request}) + response_data = serializer.data + if db.current_user: + response_data["current_user"] = db.current_user.username + return Response(response_data) + + # edit a specific dataset + @extend_schema(description="Make changes to a dataset that you own.") + def put(self, request, data_id, version=None): + db = get_object_or_404(DataSet, id=data_id) + if not permissions.check_permissions(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to modify dataset", status=401 + ) + return HttpResponseForbidden("Cannot modify a dataset you do not own") + serializer = DataSetSerializer( + db, request.data, context={"request": request}, partial=True + ) + clear_files = "files" in request.data and not request.data["files"] + if clear_files: + data_copy = request.data.copy() + data_copy.pop("files") + serializer = DataSetSerializer( + db, data_copy, context={"request": request}, partial=True + ) + if serializer.is_valid(raise_exception=True): + serializer.save() + if clear_files: + db.files.clear() + db.save() + data = {"data_id": db.id, "name": db.name, "is_public": db.is_public} + return Response(data) + + # delete a dataset + @extend_schema(description="Delete a dataset that you own.") + def delete(self, request, data_id, version=None): + db = get_object_or_404(DataSet, id=data_id) + if not permissions.check_permissions(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to delete a dataset", status=401 + ) + return HttpResponseForbidden("Not authorized to delete") + db.delete() + return Response({"success": True}) + + +class DataSetUsersView(APIView): + """ + View for the users that have access to a dataset. + + Functionality for accessing a list of users with access and granting or + revoking access. + """ + + permission_classes = [DataPermission] + + # get a list of users with access to dataset data_id + @extend_schema( + description="Retrieve a list of users that have been granted access to" + " a dataset and the dataset's publicity status." + ) + def get(self, request, data_id, version=None): + db = get_object_or_404(DataSet, id=data_id) + if not permissions.is_owner(request, db): + if not request.user.is_authenticated: + return HttpResponse("Must be authenticated to view access", status=401) + return HttpResponseForbidden("Must be the dataset owner to view access") + response_data = { + "data_id": db.id, + "name": db.name, + "is_public": db.is_public, + "users": [user.username for user in db.users.all()], + } + return Response(response_data) + + # grant or revoke a user's access to dataset data_id + @extend_schema(description="Grant or revoke a user's access to a dataset.") + def put(self, request, data_id, version=None): + db = get_object_or_404(DataSet, id=data_id) + if not permissions.is_owner(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to manage access", status=401 + ) + return HttpResponseForbidden("Must be the dataset owner to manage access") + serializer = AccessManagementSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = get_object_or_404(User, username=serializer.data["username"]) + if serializer.data["access"]: + db.users.add(user) + else: + db.users.remove(user) + response_data = { + "username": user.username, + "data_id": db.id, + "name": db.name, + "access": serializer.data["access"], + } + return Response(response_data) + + +class SessionView(APIView): + """ + View associated with the Session model. + + Functionality for viewing a list of sessions and for creating a session. + """ + + # View a list of accessible sessions + @extend_schema( + description="Retrieve a list of accessible sessions by name and title." + ) + def get(self, request, version=None): + session_list = {"session_ids": {}} + sessions = Session.objects.all() + if "username" in request.GET: + user = get_object_or_404(User, username=request.GET["username"]) + sessions = Session.objects.filter(current_user=user) + for session in sessions: + if permissions.check_permissions(request, session): + session_list["session_ids"][session.id] = session.title + return Response(data=session_list) + + # Create a session + # TODO: revisit response data + @extend_schema(description="Upload a session.") + def post(self, request, version=None): + if isinstance(request.data, str): + serializer = SessionSerializer( + data=json.loads(request.data), context={"request": request} + ) + else: + serializer = SessionSerializer( + data=request.data, context={"request": request} + ) + if serializer.is_valid(raise_exception=True): + serializer.save() + db = serializer.instance + response = { + "session_id": db.id, + "title": db.title, + "authenticated": request.user.is_authenticated, + "current_user": request.user.username, + "is_public": db.is_public, + } + return Response(data=response, status=status.HTTP_201_CREATED) + + # Create a session + @extend_schema(description="Upload a session.") + def put(self, request, version=None): + return self.post(request, version) + + +class SingleSessionView(APIView): + """ + View associated with single sessions. + + Functionality for viewing, modifying, and deleting individual sessions. + """ + + # get a specific session + @extend_schema(description="Retrieve a session.") + def get(self, request, data_id, version=None): + db = get_object_or_404(Session, id=data_id) + if not permissions.check_permissions(request, db): + if not request.user.is_authenticated: + return HttpResponse("Must be authenticated to view session", status=401) + return HttpResponseForbidden( + "You do not have permission to view this session." + ) + serializer = SessionSerializer(db) + response_data = serializer.data + if db.current_user: + response_data["current_user"] = db.current_user.username + return Response(response_data) + + # modify a session + @extend_schema(description="Make changes to a session that you own.") + def put(self, request, data_id, version=None): + db = get_object_or_404(Session, id=data_id) + if not permissions.check_permissions(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to modify session", status=401 + ) + return HttpResponseForbidden("Cannot modify a session you do not own") + serializer = SessionSerializer( + db, request.data, context={"request": request}, partial=True + ) + if serializer.is_valid(raise_exception=True): + serializer.save() + data = {"session_id": db.id, "title": db.title, "is_public": db.is_public} + return Response(data) + + # delete a session + @extend_schema(description="Delete a session that you own.") + def delete(self, request, data_id, version=None): + db = get_object_or_404(Session, id=data_id) + if not permissions.check_permissions(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to delete a session", status=401 + ) + return HttpResponseForbidden("Not authorized to delete") + db.delete() + return Response({"success": True}) + + +class SessionUsersView(APIView): + """ + View for the users that have access to a session. + + Functionality for accessing a list of users with access and granting or + revoking access. + """ + + # view the users that have access to a specific session + @extend_schema( + description="Retrieve a list of users that have been granted access to" + " a session and the session's publicity status." + ) + def get(self, request, data_id, version=None): + db = get_object_or_404(Session, id=data_id) + if not permissions.is_owner(request, db): + if not request.user.is_authenticated: + return HttpResponse("Must be authenticated to view access", status=401) + return HttpResponseForbidden("Must be the session owner to view access") + response_data = { + "session_id": db.id, + "title": db.title, + "is_public": db.is_public, + "users": [user.username for user in db.users.all()], + } + return Response(response_data) + + # grant or revoke access to a session + @extend_schema(description="Grant or revoke a user's access to a data file.") + def put(self, request, data_id, version=None): + db = get_object_or_404(Session, id=data_id) + if not permissions.is_owner(request, db): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to manage access", status=401 + ) + return HttpResponseForbidden("Must be the dataset owner to manage access") + serializer = AccessManagementSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + user = get_object_or_404(User, username=serializer.data["username"]) + if serializer.data["access"]: + db.users.add(user) + for dataset in db.datasets.all(): + dataset.users.add(user) + else: + db.users.remove(user) + for dataset in db.datasets.all(): + dataset.users.remove(user) + response_data = { + "username": user.username, + "session_id": db.id, + "title": db.title, + "access": serializer.data["access"], + } + return Response(response_data) + + +class PublishedStateView(APIView): + """ + View associated with the PublishedState model. + + Functionality for viewing a list of session published states and for + creating a published state. + """ + + # View a list of accessible sessions' published states + @extend_schema( + description="Retrieve a list of published states of accessible sessions." + ) + def get(self, request, version=None): + ps_list = {"published_state_ids": {}} + published_states = PublishedState.objects.all() + if "username" in request.GET: + user = get_object_or_404(User, username=request.GET["username"]) + published_states = PublishedState.objects.filter(session__current_user=user) + for ps in published_states: + if permissions.check_permissions(request, ps.session): + ps_list["published_state_ids"][ps.id] = { + "title": ps.session.title, + "published": ps.published, + "doi": ps.doi, + } + return Response(data=ps_list) + + # Create a published state for an existing session + @extend_schema(description="Create a published state for an existing session.") + def post(self, request, version=None): + if isinstance(request.data, str): + serializer = PublishedStateSerializer( + data=json.loads(request.data), context={"request": request} + ) + else: + serializer = PublishedStateSerializer( + data=request.data, context={"request": request} + ) + if serializer.is_valid(raise_exception=True): + if not permissions.is_owner(request, serializer.validated_data["session"]): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to create a published state for a session", + status=401, + ) + return HttpResponseForbidden( + "Must be the session owner to create a published state for a session" + ) + serializer.save() + db = serializer.instance + response = { + "published_state_id": db.id, + "session_id": db.session.id, + "title": db.session.title, + "doi": db.doi, + "published": db.published, + "current_user": request.user.username, + "is_public": db.session.is_public, + } + return Response(data=response, status=status.HTTP_201_CREATED) + + # Create a published state for an existing session + @extend_schema(description="Create a published state for an existing session.") + def put(self, request, version=None): + return self.post(request, version) + + +class SinglePublishedStateView(APIView): + """ + View associated with specific session published states. + + Functionality for viewing, modifying, and deleting individual published states. + """ + + # View a specific published state + @extend_schema(description="Retrieve a published state.") + def get(self, request, ps_id, version=None): + db = get_object_or_404(PublishedState, id=ps_id) + if not permissions.check_permissions(request, db.session): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to view published state", status=401 + ) + return HttpResponseForbidden( + "You do not have permission to view this published state." + ) + serializer = PublishedStateSerializer(db) + response_data = serializer.data + response_data["title"] = db.session.title + if db.session.current_user: + response_data["current_user"] = db.session.current_user.username + else: + response_data["current_user"] = "" + response_data["is_public"] = db.session.is_public + return Response(response_data) + + # Modify a published state + @extend_schema( + description="Make changes to the published state of a session that you own." + ) + def put(self, request, ps_id, version=None): + db = get_object_or_404(PublishedState, id=ps_id) + if not permissions.check_permissions(request, db.session): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to modify published state", status=401 + ) + return HttpResponseForbidden( + "Cannot modify a published state you do not own" + ) + serializer = PublishedStateUpdateSerializer( + db, request.data, context={"request": request}, partial=True + ) + if serializer.is_valid(raise_exception=True): + serializer.save() + data = { + "published_state_id": db.id, + "session_id": db.session.id, + "title": db.session.title, + "published": db.published, + "is_public": db.session.is_public, + } + return Response(data) + + # Delete a published state + @extend_schema(description="Delete the published state of a session that you own.") + def delete(self, request, ps_id, version=None): + db = get_object_or_404(PublishedState, id=ps_id) + if not permissions.check_permissions(request, db.session): + if not request.user.is_authenticated: + return HttpResponse( + "Must be authenticated to delete a published state", status=401 + ) + return HttpResponseForbidden("Not authorized to delete") + db.delete() + return Response({"success": True}) diff --git a/sasdata/fair_database/documentation.yaml b/sasdata/fair_database/documentation.yaml new file mode 100644 index 000000000..22a0488fb --- /dev/null +++ b/sasdata/fair_database/documentation.yaml @@ -0,0 +1,1172 @@ +openapi: 3.0.3 +info: + title: SasView Database + version: 0.1.0 + description: A database following the FAIR data principles for SasView, a small + angle scattering analysis application. +paths: + /{version}/data/file/: + get: + operationId: data_file_list + description: Retrieve a list of accessible data files by id and filename. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: "#components/schemas/DataFileList" + post: + operationId: data_file_create + description: Upload a data file. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: "#components/schemas/DataFileCreate" + responses: + '201': + description: CREATED + content: + application/json: + schema: + $ref: "#components/schemas/DataFileCreated" + put: + operationId: data_file_create_2 + description: Upload a data file. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: "components/schemas/DataFileCreate" + responses: + '201': + description: CREATED + content: + application/json: + schema: + $ref: "#components/schemas/DataFileCreated" + /{version}/data/file/{data_id}/: + get: + operationId: data_file_retrieve + description: Retrieve the contents of a data file or download a file. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + requestBlock: + schema: + $ref: "#components/schemas/DataFileGet" + responses: + '200': + description: OK + content: + application/json: + schema: + oneOf: + - $ref: "#components/schemas/DataFile" + - $ref: "components/schemas/DataFileDownload" + put: + operationId: data_file_update_2 + description: Make changes to a data file that you own. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + requestBody: + required: true + content: + multipart/form-data: + schema: + $ref: "components/schemas/DataFileCreate" + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: "#components/schemas/DataFileCreated" + delete: + operationId: data_file_destroy + description: Delete a data file that you own. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: "#components/schemas/Delete" + /{version}/data/file/{data_id}/users/: + get: + operationId: data_file_users_retrieve + description: Retrieve a list of users that have been granted access to a data + file and the file's publicity status. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + content: + application/json: + schema: + allOf: + - $ref: "#components/schemas/UsersList" + - type: object + properties: + file: + type: integer + file_name: + type: string + put: + operationId: data_file_users_update + description: Grant or revoke a user's access to a data file. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + requestBody: + required: true + content: + application/json: + schema: + $ref: "#components/schemas/ManageAccess" + responses: + '200': + description: OK + content: + application/json: + schema: + allOf: + - $ref: "#components/schemas/ManageAccess" + - type: object + properties: + file: + type: integer + file_name: + type: string + /{version}/data/published/: + get: + operationId: data_published_retrieve + description: Retrieve a list of published states of accessible sessions. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + post: + operationId: data_published_create + description: Create a published state for an existing session. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '201': + description: CREATED + put: + operationId: data_published_update + description: Create a published state for an existing session. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '201': + description: CREATED + /{version}/data/published/{ps_id}/: + get: + operationId: data_published_retrieve_2 + description: Retrieve a published state. + parameters: + - in: path + name: ps_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + put: + operationId: data_published_update_2 + description: Make changes to the published state of a session that you own. + parameters: + - in: path + name: ps_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + delete: + operationId: data_published_destroy + description: Delete the published state of a session that you own. + parameters: + - in: path + name: ps_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + /{version}/data/session/: + get: + operationId: data_session_retrieve + description: Retrieve a list of accessible sessions by name and title. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + post: + operationId: data_session_create + description: Upload a session. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '201': + description: CREATED + put: + operationId: data_session_update + description: Upload a session. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '201': + description: CREATED + /{version}/data/session/{data_id}/: + get: + operationId: data_session_retrieve_2 + description: Retrieve a session. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + put: + operationId: data_session_update_2 + description: Make changes to a session that you own. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + delete: + operationId: data_session_destroy + description: Delete a session that you own. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + /{version}/data/session/{data_id}/users/: + get: + operationId: data_session_users_retrieve + description: Retrieve a list of users that have been granted access to a session + and the session's publicity status. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + put: + operationId: data_session_users_update + description: Grant or revoke a user's access to a data file. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + description: OK + /{version}/data/set/: + get: + operationId: data_set_retrieve + description: Retrieve a list of accessible datasets by id and name. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + description: OK + post: + operationId: data_set_create + description: Upload a dataset. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '201': + description: CREATED + put: + operationId: data_set_update + description: Upload a dataset. + parameters: + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '201': + description: CREATED + /{version}/data/set/{data_id}/: + get: + operationId: data_set_retrieve_2 + description: Retrieve a dataset. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + description: OK + put: + operationId: data_set_update_2 + description: Make changes to a dataset that you own. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + description: OK + delete: + operationId: data_set_destroy + description: Delete a dataset that you own. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + description: OK + /{version}/data/set/{data_id}/users/: + get: + operationId: data_set_users_retrieve + description: Retrieve a list of users that have been granted access to a dataset + and the dataset's publicity status. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + description: OK + put: + operationId: data_set_users_update + description: Grant or revoke a user's access to a dataset. + parameters: + - in: path + name: data_id + schema: + type: integer + required: true + - in: path + name: version + schema: + type: string + pattern: ^(v1)$ + required: true + tags: + - data + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + description: OK + /auth/login/: + post: + operationId: auth_login_create + description: |- + Check the credentials and return the REST Token + if the credentials are valid and authenticated. + Calls Django Auth login method to register User ID + in Django session framework + + Accept the following POST parameters: username, password + Return the REST Framework Token Object's key. + tags: + - auth + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Login' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Login' + multipart/form-data: + schema: + $ref: '#/components/schemas/Login' + required: true + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/Login' + description: '' + /auth/logout/: + post: + operationId: auth_logout_create + description: |- + Calls Django logout method and delete the Token object + assigned to the current User object. + + Accepts/Returns nothing. + tags: + - auth + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RestAuthDetail' + description: '' + /auth/password/change/: + post: + operationId: auth_password_change_create + description: |- + Calls Django Auth SetPasswordForm save method. + + Accepts the following POST parameters: new_password1, new_password2 + Returns the success/fail message. + tags: + - auth + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PasswordChange' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PasswordChange' + multipart/form-data: + schema: + $ref: '#/components/schemas/PasswordChange' + required: true + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/RestAuthDetail' + description: '' + /auth/register/: + post: + operationId: auth_register_create + description: |- + Registers a new user. + + Accepts the following POST parameters: username, email, password1, password2. + tags: + - auth + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/Register' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/Register' + multipart/form-data: + schema: + $ref: '#/components/schemas/Register' + required: true + security: + - knoxApiToken: [] + - cookieAuth: [] + - {} + responses: + '201': + content: + application/json: + schema: + $ref: '#/components/schemas/Register' + description: '' + /auth/user/: + get: + operationId: auth_user_retrieve + description: |- + Reads and updates UserModel fields + Accepts GET, PUT, PATCH methods. + + Default accepted fields: username, first_name, last_name + Default display fields: pk, username, email, first_name, last_name + Read-only fields: pk, email + + Returns UserModel fields. + tags: + - auth + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetails' + description: '' + put: + operationId: auth_user_update + description: |- + Reads and updates UserModel fields + Accepts GET, PUT, PATCH methods. + + Default accepted fields: username, first_name, last_name + Default display fields: pk, username, email, first_name, last_name + Read-only fields: pk, email + + Returns UserModel fields. + tags: + - auth + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetails' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/UserDetails' + multipart/form-data: + schema: + $ref: '#/components/schemas/UserDetails' + required: true + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetails' + description: '' + patch: + operationId: auth_user_partial_update + description: |- + Reads and updates UserModel fields + Accepts GET, PUT, PATCH methods. + + Default accepted fields: username, first_name, last_name + Default display fields: pk, username, email, first_name, last_name + Read-only fields: pk, email + + Returns UserModel fields. + tags: + - auth + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PatchedUserDetails' + application/x-www-form-urlencoded: + schema: + $ref: '#/components/schemas/PatchedUserDetails' + multipart/form-data: + schema: + $ref: '#/components/schemas/PatchedUserDetails' + security: + - knoxApiToken: [] + - cookieAuth: [] + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/UserDetails' + description: '' +components: + schemas: + Delete: + type: object + properties: + success: + type: boolean + UsersList: + type: object + properties: + is_public: + type: boolean + users: + type: array + items: + type: string + ManageAccess: + type: object + properties: + username: + type: string + access: + type: boolean + DataFileList: + type: object + properties: + data_ids: + type: object + additionalProperties: + filename: + type: string + DataFileCreate: + type: object + properties: + filename: + type: string + file: + type: string + format: binary + DataFileCreated: + type: object + properties: + current_user: + type: string + authenticated: + type: boolean + file_id: + type: integer + file_alternative_name: + type: string + is_public: + type: boolean + DataFileGet: + type: object + properties: + download: + type: boolean + DataFile: + type: object + properties: + filename: + type: object + additionalProperties: + type: array + items: + type: string + DataFileDownload: + type: string + format: binary + Login: + type: object + properties: + username: + type: string + email: + type: string + format: email + password: + type: string + required: + - password + DataSetList: + type: object + properties: + dataset_ids: + type: object + additionalProperties: + name: + type: string + DataSetCreate: + type: object + properties: + name: + type: string + is_public: + type: boolean + data_contents: + type: array + items: + type: object + properties: + label: + type: string + value: + type: object + additionalProperties: true + PasswordChange: + type: object + properties: + new_password1: + type: string + maxLength: 128 + new_password2: + type: string + maxLength: 128 + required: + - new_password1 + - new_password2 + PatchedUserDetails: + type: object + description: User model w/o password + properties: + pk: + type: integer + readOnly: true + title: ID + username: + type: string + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + email: + type: string + format: email + readOnly: true + title: Email address + first_name: + type: string + maxLength: 150 + last_name: + type: string + maxLength: 150 + Register: + type: object + properties: + username: + type: string + maxLength: 150 + minLength: 1 + email: + type: string + format: email + password1: + type: string + writeOnly: true + password2: + type: string + writeOnly: true + required: + - password1 + - password2 + - username + RestAuthDetail: + type: object + properties: + detail: + type: string + readOnly: true + required: + - detail + UserDetails: + type: object + description: User model w/o password + properties: + pk: + type: integer + readOnly: true + title: ID + username: + type: string + description: Required. 150 characters or fewer. Letters, digits and @/./+/-/_ + only. + pattern: ^[\w.@+-]+$ + maxLength: 150 + email: + type: string + format: email + readOnly: true + title: Email address + first_name: + type: string + maxLength: 150 + last_name: + type: string + maxLength: 150 + required: + - email + - pk + - username + securitySchemes: + cookieAuth: + type: apiKey + in: cookie + name: sessionid + knoxApiToken: + type: apiKey + in: header + name: Authorization + description: Token-based authentication with required prefix "Token" diff --git a/sasdata/fair_database/fair_database/__init__.py b/sasdata/fair_database/fair_database/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/fair_database/fair_database/asgi.py b/sasdata/fair_database/fair_database/asgi.py new file mode 100644 index 000000000..a10c9b212 --- /dev/null +++ b/sasdata/fair_database/fair_database/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for fair_database project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fair_database.settings") + +application = get_asgi_application() diff --git a/sasdata/fair_database/fair_database/create_example_session.py b/sasdata/fair_database/fair_database/create_example_session.py new file mode 100644 index 000000000..6c10d9905 --- /dev/null +++ b/sasdata/fair_database/fair_database/create_example_session.py @@ -0,0 +1,97 @@ +import requests + +session = { + "title": "Example Session", + "datasets": [ + { + "name": "Dataset 1", + "metadata": { + "title": "Metadata 1", + "run": 1, + "description": "test", + "instrument": {}, + "process": {}, + "sample": {}, + }, + "data_contents": [ + { + "value": 0, + "variance": 0, + "units": "no", + "hash": 0, + "label": "Quantity 1", + "history": {"operation_tree": {}, "references": []}, + } + ], + }, + { + "name": "Dataset 2", + "metadata": { + "title": "Metadata 2", + "run": 2, + "description": "test", + "instrument": {}, + "process": {}, + "sample": {}, + }, + "data_contents": [ + { + "label": "Quantity 2", + "value": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "variance": {"array_contents": [0, 0, 0, 0], "shape": (2, 2)}, + "units": "none", + "hash": 0, + "history": { + "operation_tree": { + "operation": "neg", + "parameters": { + "a": { + "operation": "mul", + "parameters": { + "a": { + "operation": "constant", + "parameters": { + "value": {"type": "int", "value": 7} + }, + }, + "b": { + "operation": "variable", + "parameters": { + "hash_value": 111, + "name": "x", + }, + }, + }, + }, + }, + }, + "references": [ + { + "value": 5, + "variance": 0, + "units": "none", + "hash": 111, + "history": {}, + } + ], + }, + } + ], + }, + ], + "is_public": False, +} + +url = "http://127.0.0.1:8000/v1/data/session/" +login_data = {"email": "test@test.org", "username": "testUser", "password": "sasview!"} +response = requests.post("http://127.0.0.1:8000/auth/login/", data=login_data) +if response.status_code != 200: + register_data = { + "email": "test@test.org", + "username": "testUser", + "password1": "sasview!", + "password2": "sasview!", + } + response = requests.post("http://127.0.0.1:8000/auth/register/", data=register_data) +token = response.json()["token"] +requests.request("POST", url, json=session, headers={"Authorization": "Token " + token}) diff --git a/sasdata/fair_database/fair_database/permissions.py b/sasdata/fair_database/fair_database/permissions.py new file mode 100644 index 000000000..74be5f33a --- /dev/null +++ b/sasdata/fair_database/fair_database/permissions.py @@ -0,0 +1,29 @@ +from rest_framework.permissions import BasePermission + + +# check if a request is made by an object's owner +def is_owner(request, obj): + return request.user.is_authenticated and request.user == obj.current_user + + +# check if a request is made by a user with read access +def has_access(request, obj): + return is_owner(request, obj) or ( + request.user.is_authenticated and request.user in obj.users.all() + ) + + +class DataPermission(BasePermission): + # check if a request has the correct permissions for a specific object + def has_object_permission(self, request, view, obj): + if request.method == "GET": + return obj.is_public or has_access(request, obj) + elif request.method == "DELETE": + return not obj.is_public and is_owner(request, obj) + else: + return is_owner(request, obj) + + +# check if a request has the correct permissions for a specific object +def check_permissions(request, obj): + return DataPermission().has_object_permission(request, None, obj) diff --git a/sasdata/fair_database/fair_database/settings.py b/sasdata/fair_database/fair_database/settings.py new file mode 100644 index 000000000..f3ec69ed9 --- /dev/null +++ b/sasdata/fair_database/fair_database/settings.py @@ -0,0 +1,202 @@ +""" +Django settings for fair_database project. + +Generated by 'django-admin startproject' using Django 5.1.5. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +import os +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure--f-t5!pdhq&4)^&xenr^k0e8n%-h06jx9d0&2kft(!+1$xzig)" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "data.apps.DataConfig", + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.sites", + "rest_framework", + "rest_framework.authtoken", + "allauth", + "allauth.account", + "allauth.socialaccount", + "allauth.socialaccount.providers.orcid", + "dj_rest_auth", + "dj_rest_auth.registration", + "knox", + "user_app.apps.UserAppConfig", + "drf_spectacular", +] + +SITE_ID = 1 + +MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "allauth.account.middleware.AccountMiddleware", +] + +ROOT_URLCONF = "fair_database.urls" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +WSGI_APPLICATION = "fair_database.wsgi.application" + +# Authentication +AUTHENTICATION_BACKENDS = ( + "django.contrib.auth.backends.ModelBackend", + "allauth.account.auth_backends.AuthenticationBackend", +) + +REST_FRAMEWORK = { + "DEFAULT_AUTHENTICATION_CLASSES": [ + "knox.auth.TokenAuthentication", + "rest_framework.authentication.SessionAuthentication", + ], + "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", +} + +REST_AUTH = { + "TOKEN_SERIALIZER": "user_app.serializers.KnoxSerializer", + "USER_DETAILS_SERIALIZER": "dj_rest_auth.serializers.UserDetailsSerializer", + "TOKEN_MODEL": "knox.models.AuthToken", + "TOKEN_CREATOR": "user_app.util.create_knox_token", +} + +SPECTACULAR_SETTINGS = { + "TITLE": "SasView Database", + "DESCRIPTION": "A database following the FAIR data principles for SasView," + " a small angle scattering analysis application.", + "VERSION": "0.1.0", + "SERVE_INCLUDE_SCHEMA": False, +} + +# allauth settings +HEADLESS_ONLY = True +ACCOUNT_EMAIL_VERIFICATION = "none" + +# to enable ORCID, register for credentials through ORCID and fill out client_id and secret +# https://info.orcid.org/documentation/integration-guide/ +# https://docs.allauth.org/en/latest/socialaccount/index.html +SOCIALACCOUNT_PROVIDERS = { + "orcid": { + "APPS": [ + { + "client_id": "", + "secret": "", + "key": "", + } + ], + "SCOPE": [ + "profile", + "email", + ], + "AUTH_PARAMETERS": {"access_type": "online"}, + # Base domain of the API. Default value: 'orcid.org', for the production API + "BASE_DOMAIN": "sandbox.orcid.org", # for the sandbox API + # Member API or Public API? Default: False (for the public API) + "MEMBER_API": False, + } +} + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", + }, + { + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = "en-us" + +TIME_ZONE = "UTC" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/4.2/howto/static-files/ + + +STATIC_ROOT = os.path.join(BASE_DIR, "static") +STATIC_URL = "/static/" + +# instead of doing this, create a create a new media_root +MEDIA_ROOT = os.path.join(BASE_DIR, "media") +MEDIA_URL = "/media/" + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/sasdata/fair_database/fair_database/test_permissions.py b/sasdata/fair_database/fair_database/test_permissions.py new file mode 100644 index 000000000..ffb55dbd7 --- /dev/null +++ b/sasdata/fair_database/fair_database/test_permissions.py @@ -0,0 +1,292 @@ +import os +import shutil + +from data.models import DataFile +from django.conf import settings +from django.contrib.auth.models import User +from rest_framework import status +from rest_framework.test import APITestCase + + +def find(filename): + return os.path.join( + os.path.dirname(__file__), "../../example_data/1d_data", filename + ) + + +def auth_header(response): + return {"Authorization": "Token " + response.data["token"]} + + +class DataListPermissionsTests(APITestCase): + """Test permissions of data views using user_app for authentication.""" + + @classmethod + def setUpTestData(cls): + cls.user = User.objects.create_user( + username="testUser", password="secret", id=1, email="email@domain.com" + ) + cls.user2 = User.objects.create_user( + username="testUser2", password="secret", id=2, email="email2@domain.com" + ) + cls.unowned_test_data = DataFile.objects.create( + id=1, file_name="cyl_400_40.txt", is_public=True + ) + cls.unowned_test_data.file.save( + "cyl_400_40.txt", open(find("cyl_400_40.txt"), "rb") + ) + cls.private_test_data = DataFile.objects.create( + id=2, current_user=cls.user, file_name="cyl_400_20.txt", is_public=False + ) + cls.private_test_data.file.save( + "cyl_400_20.txt", open(find("cyl_400_20.txt"), "rb") + ) + cls.public_test_data = DataFile.objects.create( + id=3, current_user=cls.user, file_name="cyl_testdata.txt", is_public=True + ) + cls.public_test_data.file.save( + "cyl_testdata.txt", open(find("cyl_testdata.txt"), "rb") + ) + cls.login_data_1 = { + "username": "testUser", + "password": "secret", + "email": "email@domain.com", + } + cls.login_data_2 = { + "username": "testUser2", + "password": "secret", + "email": "email2@domain.com", + } + + # Authenticated user can view list of data + def test_list_authenticated(self): + token = self.client.post("/auth/login/", data=self.login_data_1) + response = self.client.get("/v1/data/file/", headers=auth_header(token)) + response2 = self.client.get( + "/v1/data/file/", data={"username": "testUser"}, headers=auth_header(token) + ) + self.assertEqual( + response.data, + { + "public_data_ids": { + 1: "cyl_400_40.txt", + 2: "cyl_400_20.txt", + 3: "cyl_testdata.txt", + } + }, + ) + self.assertEqual( + response2.data, + {"user_data_ids": {2: "cyl_400_20.txt", 3: "cyl_testdata.txt"}}, + ) + + # Authenticated user cannot view other users' private data on list + def test_list_authenticated_2(self): + token = self.client.post("/auth/login/", data=self.login_data_2) + response = self.client.get("/v1/data/file/", headers=auth_header(token)) + response2 = self.client.get( + "/v1/data/file/", data={"username": "testUser"}, headers=auth_header(token) + ) + response3 = self.client.get( + "/v1/data/file/", data={"username": "testUser2"}, headers=auth_header(token) + ) + self.assertEqual( + response.data, + {"public_data_ids": {1: "cyl_400_40.txt", 3: "cyl_testdata.txt"}}, + ) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response2.data, {"user_data_ids": {3: "cyl_testdata.txt"}}) + self.assertEqual(response3.data, {"user_data_ids": {}}) + + # Unauthenticated user can view list of public data + def test_list_unauthenticated(self): + response = self.client.get("/v1/data/file/") + response2 = self.client.get("/v1/data/file/", data={"username": "testUser"}) + self.assertEqual( + response.data, + {"public_data_ids": {1: "cyl_400_40.txt", 3: "cyl_testdata.txt"}}, + ) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response2.data, {"user_data_ids": {3: "cyl_testdata.txt"}}) + + # Authenticated user can load public data and owned private data + def test_load_authenticated(self): + token = self.client.post("/auth/login/", data=self.login_data_1) + response = self.client.get("/v1/data/file/1/", headers=auth_header(token)) + response2 = self.client.get("/v1/data/file/2/", headers=auth_header(token)) + response3 = self.client.get("/v1/data/file/3/", headers=auth_header(token)) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response3.status_code, status.HTTP_200_OK) + + # Authenticated user cannot load others' private data + def test_load_unauthorized(self): + token = self.client.post("/auth/login/", data=self.login_data_2) + response = self.client.get("/v1/data/file/2/", headers=auth_header(token)) + response2 = self.client.get("/v1/data/file/3/", headers=auth_header(token)) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + + # Unauthenticated user can load public data only + def test_load_unauthenticated(self): + response = self.client.get("/v1/data/file/1/") + response2 = self.client.get("/v1/data/file/2/") + response3 = self.client.get("/v1/data/file/3/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response2.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(response3.status_code, status.HTTP_200_OK) + + # Authenticated user can upload data + def test_upload_authenticated(self): + token = self.client.post("/auth/login/", data=self.login_data_1) + file = open(find("cyl_testdata1.txt"), "rb") + data = {"file": file, "is_public": False} + response = self.client.post( + "/v1/data/file/", data=data, headers=auth_header(token) + ) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual( + response.data, + { + "current_user": "testUser", + "authenticated": True, + "file_id": 4, + "file_alternative_name": "cyl_testdata1.txt", + "is_public": False, + }, + ) + DataFile.objects.get(id=4).delete() + + # Unauthenticated user can upload public data only + def test_upload_unauthenticated(self): + file = open(find("cyl_testdata2.txt"), "rb") + file2 = open(find("cyl_testdata2.txt"), "rb") + data = {"file": file, "is_public": True} + data2 = {"file": file2, "is_public": False} + response = self.client.post("/v1/data/file/", data=data) + response2 = self.client.post("/v1/data/file/", data=data2) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual( + response.data, + { + "current_user": "", + "authenticated": False, + "file_id": 4, + "file_alternative_name": "cyl_testdata2.txt", + "is_public": True, + }, + ) + self.assertEqual(response2.status_code, status.HTTP_400_BAD_REQUEST) + + # Authenticated user can update own data + def test_upload_put_authenticated(self): + token = self.client.post("/auth/login/", data=self.login_data_1) + data = {"is_public": False} + response = self.client.put( + "/v1/data/file/2/", data=data, headers=auth_header(token) + ) + response2 = self.client.put( + "/v1/data/file/3/", data=data, headers=auth_header(token) + ) + self.assertEqual( + response.data, + { + "current_user": "testUser", + "authenticated": True, + "file_id": 2, + "file_alternative_name": "cyl_400_20.txt", + "is_public": False, + }, + ) + self.assertEqual( + response2.data, + { + "current_user": "testUser", + "authenticated": True, + "file_id": 3, + "file_alternative_name": "cyl_testdata.txt", + "is_public": False, + }, + ) + DataFile.objects.get(id=3).is_public = True + + # Authenticated user cannot update unowned data + def test_upload_put_unauthorized(self): + token = self.client.post("/auth/login/", data=self.login_data_2) + file = open(find("cyl_400_40.txt")) + data = {"file": file, "is_public": False} + response = self.client.put( + "/v1/data/file/1/", data=data, headers=auth_header(token) + ) + response2 = self.client.put( + "/v1/data/file/2/", data=data, headers=auth_header(token) + ) + response3 = self.client.put( + "/v1/data/file/3/", data=data, headers=auth_header(token) + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response2.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response3.status_code, status.HTTP_403_FORBIDDEN) + + # Unauthenticated user cannot update data + def test_upload_put_unauthenticated(self): + file = open(find("cyl_400_40.txt")) + data = {"file": file, "is_public": False} + response = self.client.put("/v1/data/file/1/", data=data) + response2 = self.client.put("/v1/data/file/2/", data=data) + response3 = self.client.put("/v1/data/file/3/", data=data) + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(response2.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(response3.status_code, status.HTTP_401_UNAUTHORIZED) + + # Authenticated user can download public and own data + def test_download_authenticated(self): + token = self.client.post("/auth/login/", data=self.login_data_1) + response = self.client.get( + "/v1/data/file/1/", data={"download": True}, headers=auth_header(token) + ) + response2 = self.client.get( + "/v1/data/file/2/", data={"download": True}, headers=auth_header(token) + ) + response3 = self.client.get( + "/v1/data/file/3/", data={"download": True}, headers=auth_header(token) + ) + b"".join(response.streaming_content) + b"".join(response2.streaming_content) + b"".join(response3.streaming_content) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response3.status_code, status.HTTP_200_OK) + + # Authenticated user cannot download others' data + def test_download_unauthorized(self): + token = self.client.post("/auth/login/", data=self.login_data_2) + response = self.client.get( + "/v1/data/file/2/", data={"download": True}, headers=auth_header(token) + ) + response2 = self.client.get( + "/v1/data/file/3/", data={"download": True}, headers=auth_header(token) + ) + b"".join(response2.streaming_content) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + + # Unauthenticated user cannot download private data + def test_download_unauthenticated(self): + response = self.client.get("/v1/data/file/1/", data={"download": True}) + response2 = self.client.get("/v1/data/file/2/", data={"download": True}) + response3 = self.client.get("/v1/data/file/3/", data={"download": True}) + b"".join(response.streaming_content) + b"".join(response3.streaming_content) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response2.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual(response3.status_code, status.HTTP_200_OK) + + @classmethod + def tearDownClass(cls): + cls.user.delete() + cls.user2.delete() + cls.public_test_data.delete() + cls.private_test_data.delete() + cls.unowned_test_data.delete() + shutil.rmtree(settings.MEDIA_ROOT) diff --git a/sasdata/fair_database/fair_database/upload_example_data.py b/sasdata/fair_database/fair_database/upload_example_data.py new file mode 100644 index 000000000..79de203d4 --- /dev/null +++ b/sasdata/fair_database/fair_database/upload_example_data.py @@ -0,0 +1,46 @@ +import logging +import os +from glob import glob + +import requests + +EXAMPLE_DATA_DIR = os.environ.get("EXAMPLE_DATA_DIR", "../../example_data") + + +def parse_1D(): + dir_1d = os.path.join(EXAMPLE_DATA_DIR, "1d_data") + if not os.path.isdir(dir_1d): + logging.error(f"1D Data directory not found at: {dir_1d}") + return + for file_path in glob(os.path.join(dir_1d, "*")): + upload_file(file_path) + + +def parse_2D(): + dir_2d = os.path.join(EXAMPLE_DATA_DIR, "2d_data") + if not os.path.isdir(dir_2d): + logging.error(f"2D Data directory not found at: {dir_2d}") + return + for file_path in glob(os.path.join(dir_2d, "*")): + upload_file(file_path) + + +def parse_sesans(): + sesans_dir = os.path.join(EXAMPLE_DATA_DIR, "sesans_data") + if not os.path.isdir(sesans_dir): + logging.error(f"Sesans Data directory not found at: {sesans_dir}") + return + for file_path in glob(os.path.join(sesans_dir, "*")): + upload_file(file_path) + + +def upload_file(file_path): + url = "http://localhost:8000/v1/data/file/" + file = open(file_path, "rb") + requests.request("POST", url, data={"is_public": True}, files={"file": file}) + + +if __name__ == "__main__": + parse_1D() + parse_2D() + parse_sesans() diff --git a/sasdata/fair_database/fair_database/urls.py b/sasdata/fair_database/fair_database/urls.py new file mode 100644 index 000000000..56c88ce21 --- /dev/null +++ b/sasdata/fair_database/fair_database/urls.py @@ -0,0 +1,42 @@ +""" +URL configuration for fair_database project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" + +from django.contrib import admin +from django.urls import include, path, re_path +from drf_spectacular.views import ( + SpectacularAPIView, + SpectacularRedocView, + SpectacularSwaggerView, +) + +urlpatterns = [ + re_path(r"^(?P(v1))/data/", include("data.urls")), + path("admin/", admin.site.urls), + path("accounts/", include("allauth.urls")), # needed for social auth + path("auth/", include("user_app.urls")), + path("api/schema/", SpectacularAPIView.as_view(), name="schema"), + path( + "api/schema/swagger-ui/", + SpectacularSwaggerView.as_view(url_name="schema"), + name="swagger-ui", + ), + path( + "api/schema/redoc/", + SpectacularRedocView.as_view(url_name="schema"), + name="redoc", + ), +] diff --git a/sasdata/fair_database/fair_database/wsgi.py b/sasdata/fair_database/fair_database/wsgi.py new file mode 100644 index 000000000..5dfc4819c --- /dev/null +++ b/sasdata/fair_database/fair_database/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for fair_database project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fair_database.settings") + +application = get_wsgi_application() diff --git a/sasdata/fair_database/manage.py b/sasdata/fair_database/manage.py new file mode 100755 index 000000000..7d7e97246 --- /dev/null +++ b/sasdata/fair_database/manage.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" + +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "fair_database.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == "__main__": + main() diff --git a/sasdata/fair_database/requirements.txt b/sasdata/fair_database/requirements.txt new file mode 100644 index 000000000..22b32934b --- /dev/null +++ b/sasdata/fair_database/requirements.txt @@ -0,0 +1,8 @@ +#this requirements extends the base sasview requirements files +#to get both you will need to run this after base requirements files +django +djangorestframework +dj-rest-auth +django-allauth +django-rest-knox +drf-spectacular diff --git a/sasdata/fair_database/user_app/__init__.py b/sasdata/fair_database/user_app/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/fair_database/user_app/admin.py b/sasdata/fair_database/user_app/admin.py new file mode 100644 index 000000000..846f6b406 --- /dev/null +++ b/sasdata/fair_database/user_app/admin.py @@ -0,0 +1 @@ +# Register your models here. diff --git a/sasdata/fair_database/user_app/apps.py b/sasdata/fair_database/user_app/apps.py new file mode 100644 index 000000000..83a29decf --- /dev/null +++ b/sasdata/fair_database/user_app/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class UserAppConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "user_app" diff --git a/sasdata/fair_database/user_app/migrations/__init__.py b/sasdata/fair_database/user_app/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/fair_database/user_app/models.py b/sasdata/fair_database/user_app/models.py new file mode 100644 index 000000000..6b2021999 --- /dev/null +++ b/sasdata/fair_database/user_app/models.py @@ -0,0 +1 @@ +# Create your models here. diff --git a/sasdata/fair_database/user_app/serializers.py b/sasdata/fair_database/user_app/serializers.py new file mode 100644 index 000000000..4993a7ab3 --- /dev/null +++ b/sasdata/fair_database/user_app/serializers.py @@ -0,0 +1,14 @@ +from dj_rest_auth.serializers import UserDetailsSerializer +from rest_framework import serializers + + +class KnoxSerializer(serializers.Serializer): + """ + Serializer for Knox authentication. + """ + + token = serializers.SerializerMethodField() + user = UserDetailsSerializer() + + def get_token(self, obj): + return obj["token"][1] diff --git a/sasdata/fair_database/user_app/tests.py b/sasdata/fair_database/user_app/tests.py new file mode 100644 index 000000000..8943ab40e --- /dev/null +++ b/sasdata/fair_database/user_app/tests.py @@ -0,0 +1,169 @@ +from django.contrib.auth.models import User +from django.test import TestCase +from rest_framework import status +from rest_framework.test import APIClient + + +# Create your tests here. +class AuthTests(TestCase): + """Tests for authentication endpoints.""" + + @classmethod + def setUpTestData(cls): + cls.client1 = APIClient() + cls.client2 = APIClient() + cls.register_data = { + "email": "email@domain.org", + "username": "testUser", + "password1": "sasview!", + "password2": "sasview!", + } + cls.login_data = { + "username": "testUser", + "email": "email@domain.org", + "password": "sasview!", + } + cls.login_data_2 = { + "username": "testUser2", + "email": "email2@domain.org", + "password": "sasview!", + } + cls.user = User.objects.create_user( + id=1, username="testUser2", password="sasview!", email="email2@domain.org" + ) + cls.client_authenticated = APIClient() + cls.client_authenticated.force_authenticate(user=cls.user) + + # Create an authentication header for a given token + def auth_header(self, response): + return {"Authorization": "Token " + response.data["token"]} + + # Test if registration successfully creates a new user and logs in + def test_register(self): + response = self.client1.post("/auth/register/", data=self.register_data) + user = User.objects.get(username="testUser") + response2 = self.client1.get("/auth/user/", headers=self.auth_header(response)) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual(user.email, self.register_data["email"]) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + user.delete() + + # Test if login successful + def test_login(self): + response = self.client1.post("/auth/login/", data=self.login_data_2) + response2 = self.client1.get("/auth/user/", headers=self.auth_header(response)) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + + # Test simultaneous login by multiple clients + def test_multiple_login(self): + response = self.client1.post("/auth/login/", data=self.login_data_2) + response2 = self.client2.post("/auth/login/", data=self.login_data_2) + response3 = self.client1.get("/auth/user/", headers=self.auth_header(response)) + response4 = self.client2.get("/auth/user/", headers=self.auth_header(response2)) + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response3.status_code, status.HTTP_200_OK) + self.assertEqual(response4.status_code, status.HTTP_200_OK) + self.assertNotEqual(response.content, response2.content) + + # Test get user information + def test_user_get(self): + response = self.client_authenticated.get("/auth/user/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + response.content, + b'{"pk":1,"username":"testUser2","email":"email2@domain.org","first_name":"","last_name":""}', + ) + + # Test changing username + def test_user_put_username(self): + data = {"username": "newName"} + response = self.client_authenticated.put("/auth/user/", data=data) + self.user.username = "testUser2" + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + response.content, + b'{"pk":1,"username":"newName","email":"email2@domain.org","first_name":"","last_name":""}', + ) + + # Test changing username and first and last name + def test_user_put_name(self): + data = {"username": "newName", "first_name": "Clark", "last_name": "Kent"} + response = self.client_authenticated.put("/auth/user/", data=data) + self.user.first_name = "" + self.user.last_name = "" + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + response.content, + b'{"pk":1,"username":"newName","email":"email2@domain.org","first_name":"Clark","last_name":"Kent"}', + ) + + # Test user info inaccessible when unauthenticated + def test_user_unauthenticated(self): + response = self.client1.get("/auth/user/") + self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) + self.assertEqual( + response.content, + b'{"detail":"Authentication credentials were not provided."}', + ) + + # Test logout is successful after login + def test_login_logout(self): + self.client1.post("/auth/login/", data=self.login_data_2) + response = self.client1.post("/auth/logout/") + response2 = self.client1.get("/auth/user/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.content, b'{"detail":"Successfully logged out."}') + self.assertEqual(response2.status_code, status.HTTP_401_UNAUTHORIZED) + + # Test logout is successful after registration + def test_register_logout(self): + self.client1.post("/auth/register/", data=self.register_data) + response = self.client1.post("/auth/logout/") + response2 = self.client1.get("/auth/user/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response.content, b'{"detail":"Successfully logged out."}') + self.assertEqual(response2.status_code, status.HTTP_401_UNAUTHORIZED) + User.objects.get(username="testUser").delete() + + # Test multiple logins for the same account log out independently + def test_multiple_logout(self): + self.client1.post("/auth/login/", data=self.login_data_2) + token = self.client2.post("/auth/login/", data=self.login_data_2) + response = self.client1.post("/auth/logout/") + response2 = self.client2.get("/auth/user/", headers=self.auth_header(token)) + response3 = self.client2.post("/auth/logout/") + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(response2.status_code, status.HTTP_200_OK) + self.assertEqual(response3.status_code, status.HTTP_200_OK) + + # Test login is successful after registering then logging out + def test_register_login(self): + register_response = self.client1.post( + "/auth/register/", data=self.register_data + ) + logout_response = self.client1.post("/auth/logout/") + login_response = self.client1.post("/auth/login/", data=self.login_data) + self.assertEqual(register_response.status_code, status.HTTP_201_CREATED) + self.assertEqual(logout_response.status_code, status.HTTP_200_OK) + self.assertEqual(login_response.status_code, status.HTTP_200_OK) + User.objects.get(username="testUser").delete() + + # Test password is successfully changed + def test_password_change(self): + data = { + "new_password1": "sasview?", + "new_password2": "sasview?", + "old_password": "sasview!", + } + self.login_data_2["password"] = "sasview?" + response = self.client_authenticated.post("/auth/password/change/", data=data) + login_response = self.client1.post("/auth/login/", data=self.login_data_2) + self.login_data_2["password"] = "sasview!" + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual(login_response.status_code, status.HTTP_200_OK) + + @classmethod + def tearDownClass(cls): + cls.user.delete() diff --git a/sasdata/fair_database/user_app/urls.py b/sasdata/fair_database/user_app/urls.py new file mode 100644 index 000000000..e393cb4b6 --- /dev/null +++ b/sasdata/fair_database/user_app/urls.py @@ -0,0 +1,15 @@ +from dj_rest_auth.views import LogoutView, PasswordChangeView, UserDetailsView +from django.urls import path + +from .views import KnoxLoginView, KnoxRegisterView + +"""Urls for authentication. Orcid login not functional. See settings.py for ORCID activation.""" + +urlpatterns = [ + path("register/", KnoxRegisterView.as_view(), name="register"), + path("login/", KnoxLoginView.as_view(), name="login"), + path("logout/", LogoutView.as_view(), name="logout"), + path("user/", UserDetailsView.as_view(), name="view user information"), + path("password/change/", PasswordChangeView.as_view(), name="change password"), + # path("login/orcid/", OrcidLoginView.as_view(), name="orcid login"), +] diff --git a/sasdata/fair_database/user_app/util.py b/sasdata/fair_database/user_app/util.py new file mode 100644 index 000000000..dc7b35026 --- /dev/null +++ b/sasdata/fair_database/user_app/util.py @@ -0,0 +1,7 @@ +from knox.models import AuthToken + + +# create an authentication token +def create_knox_token(token_model, user, serializer): + token = AuthToken.objects.create(user=user) + return token diff --git a/sasdata/fair_database/user_app/views.py b/sasdata/fair_database/user_app/views.py new file mode 100644 index 000000000..3a033add4 --- /dev/null +++ b/sasdata/fair_database/user_app/views.py @@ -0,0 +1,39 @@ +from allauth.account import app_settings as allauth_settings +from allauth.account.utils import complete_signup +from allauth.socialaccount.providers.orcid.views import OrcidOAuth2Adapter +from dj_rest_auth.registration.views import RegisterView, SocialLoginView +from dj_rest_auth.views import LoginView +from rest_framework.response import Response +from user_app.serializers import KnoxSerializer +from user_app.util import create_knox_token + +# Login using knox tokens rather than django-rest-framework tokens. + + +class KnoxLoginView(LoginView): + def get_response(self): + serializer_class = self.get_response_serializer() + + data = {"user": self.user, "token": self.token} + serializer = serializer_class(instance=data, context={"request": self.request}) + + return Response(serializer.data, status=200) + + +# Registration using knox tokens rather than django-rest-framework tokens. +class KnoxRegisterView(RegisterView): + def get_response_data(self, user): + return KnoxSerializer({"user": user, "token": self.token}).data + + def perform_create(self, serializer): + user = serializer.save(self.request) + self.token = create_knox_token(None, user, None) + complete_signup( + self.request._request, user, allauth_settings.EMAIL_VERIFICATION, None + ) + return user + + +# For ORCID login +class OrcidLoginView(SocialLoginView): + adapter_class = OrcidOAuth2Adapter diff --git a/sasdata/guess.py b/sasdata/guess.py index 9bc0a7ddd..93b0b3dd8 100644 --- a/sasdata/guess.py +++ b/sasdata/guess.py @@ -17,16 +17,8 @@ def guess_columns(col_count: int, dataset_type: DatasetType) -> list[str]: # Ideally we want an exact match but if the ordering is bigger than the col # count then we can accept that as well. for order_list in dataset_type.expected_orders: - if ( - len(order_list) >= col_count - or order_list == dataset_type.expected_orders[-1] - ): - return_value = order_list[:] - # If we have any extra columns than expected, then we'll just ignore them. - excess = col_count - len(order_list) - for _ in range(excess): - return_value.append("") - return return_value + if len(order_list) >= col_count: + return order_list return dataset_type.expected_orders[-1] diff --git a/sasdata/manual_tests/__init__.py b/sasdata/manual_tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/manual_tests/interpolation.py b/sasdata/manual_tests/interpolation.py new file mode 100644 index 000000000..59d53815c --- /dev/null +++ b/sasdata/manual_tests/interpolation.py @@ -0,0 +1,43 @@ +import matplotlib.pyplot as plt +import numpy as np + +from sasdata.quantities import units +from sasdata.quantities.plotting import quantity_plot +from sasdata.quantities.quantity import NamedQuantity +from sasdata.transforms.rebinning import InterpolationOptions, calculate_interpolation_matrix_1d + + +def linear_interpolation_check(): + + for from_bins in [(-10, 10, 10), + (-10, 10, 1000), + (-15, 5, 10), + (15,5, 10)]: + for to_bins in [ + (-15, 0, 10), + (-15, 15, 10), + (0, 20, 100)]: + + plt.figure() + + x = NamedQuantity("x", np.linspace(*from_bins), units=units.meters) + y = x**2 + + quantity_plot(x, y) + + new_x = NamedQuantity("x_new", np.linspace(*to_bins), units=units.meters) + + rebin_mat = calculate_interpolation_matrix_1d(x, new_x, order=InterpolationOptions.LINEAR) + + new_y = y @ rebin_mat + + quantity_plot(new_x, new_y) + + print(new_y.history.summary()) + + plt.show() + + + + +linear_interpolation_check() diff --git a/sasdata/metadata.py b/sasdata/metadata.py index 588a4de76..da0ed9c7e 100644 --- a/sasdata/metadata.py +++ b/sasdata/metadata.py @@ -1,248 +1,159 @@ -""" -Contains classes describing the metadata for a scattering run - -The metadata is structures around the CANSas format version 1.1, found at -https://www.cansas.org/formats/canSAS1d/1.1/doc/specification.html -Metadata from other file formats should be massaged to fit into the data classes presented here. -Any useful metadata which cannot be included in these classes represent a bug in the CANSas format. - -""" - -import base64 -import json -import re -from dataclasses import dataclass, field, fields, is_dataclass -from typing import Any - -import h5py import numpy as np -from numpy import ndarray - -from sasdata.quantities.quantity import Quantity -from sasdata.quantities.unit_parser import parse_unit -from sasdata.quantities.units import NamedUnit - - -def from_json_quantity(obj: dict) -> Quantity | None: - if obj is None: - return None - - return Quantity(obj["value"], parse_unit(obj["units"])) - - -@dataclass(kw_only=True) -class Vec3: - """A three-vector of measured quantities""" - - x: Quantity[float] | None - y: Quantity[float] | None - z: Quantity[float] | None - - @staticmethod - def from_json(obj: dict) -> Quantity | None: - if obj is None: - return None - return Vec3( - x=from_json_quantity(obj["x"]), - y=from_json_quantity(obj["y"]), - z=from_json_quantity(obj["z"]), - ) +from numpy.typing import ArrayLike - def as_h5(self, f: h5py.Group): - """Export data onto an HDF5 group""" - if self.x: - self.x.as_h5(f, "x") - if self.y: - self.y.as_h5(f, "y") - if self.z: - self.z.as_h5(f, "z") +import sasdata.quantities.units as units +from sasdata.quantities.absolute_temperature import AbsoluteTemperatureAccessor +from sasdata.quantities.accessors import ( + AccessorTarget, + AngleAccessor, + FloatAccessor, + LengthAccessor, + QuantityAccessor, + StringAccessor, +) -@dataclass(kw_only=True) -class Rot3: - """A measured rotation in 3-space""" - - roll: Quantity[float] | None - pitch: Quantity[float] | None - yaw: Quantity[float] | None - - @staticmethod - def from_json(obj: dict) -> Quantity | None: - if obj is None: - return None - return Rot3( - roll=from_json_quantity(obj["roll"]), - pitch=from_json_quantity(obj["pitch"]), - yaw=from_json_quantity(obj["yaw"]), - ) - - def as_h5(self, f: h5py.Group): - """Export data onto an HDF5 group""" - if self.roll: - self.roll.as_h5(f, "roll") - if self.pitch: - self.pitch.as_h5(f, "pitch") - if self.yaw: - self.yaw.as_h5(f, "yaw") - - -@dataclass(kw_only=True) class Detector: """ Detector information """ - name: str | None - distance: Quantity[float] | None - offset: Vec3 | None - orientation: Rot3 | None - beam_center: Vec3 | None - pixel_size: Vec3 | None - slit_length: Quantity[float] | None + def __init__(self, target_object: AccessorTarget): + + # Name of the instrument [string] + self.name = StringAccessor(target_object, "name") + + # Sample to detector distance [float] [mm] + self.distance = LengthAccessor[float](target_object, + "distance", + "distance.units", + default_unit=units.millimeters) + + # Offset of this detector position in X, Y, + # (and Z if necessary) [Vector] [mm] + self.offset = LengthAccessor[ArrayLike](target_object, + "offset", + "offset.units", + default_unit=units.millimeters) + + self.orientation = AngleAccessor[ArrayLike](target_object, + "orientation", + "orientation.units", + default_unit=units.degrees) + + self.beam_center = LengthAccessor[ArrayLike](target_object, + "beam_center", + "beam_center.units", + default_unit=units.millimeters) + + # Pixel size in X, Y, (and Z if necessary) [Vector] [mm] + self.pixel_size = LengthAccessor[ArrayLike](target_object, + "pixel_size", + "pixel_size.units", + default_unit=units.millimeters) + + # Slit length of the instrument for this detector.[float] [mm] + self.slit_length = LengthAccessor[float](target_object, + "slit_length", + "slit_length.units", + default_unit=units.millimeters) def summary(self): - return ( - f"Detector:\n" - f" Name: {self.name}\n" - f" Distance: {self.distance}\n" - f" Offset: {self.offset}\n" - f" Orientation: {self.orientation}\n" - f" Beam center: {self.beam_center}\n" - f" Pixel size: {self.pixel_size}\n" - f" Slit length: {self.slit_length}\n" - ) + return (f"Detector:\n" + f" Name: {self.name.value}\n" + f" Distance: {self.distance.value}\n" + f" Offset: {self.offset.value}\n" + f" Orientation: {self.orientation.value}\n" + f" Beam center: {self.beam_center.value}\n" + f" Pixel size: {self.pixel_size.value}\n" + f" Slit length: {self.slit_length.value}\n") - @staticmethod - def from_json(obj): - return Detector( - name=obj["name"], - distance=from_json_quantity(obj["distance"]), - offset=Vec3.from_json(obj["offset"]), - orientation=Rot3.from_json(obj["orientation"]), - beam_center=Vec3.from_json(obj["beam_center"]), - pixel_size=Vec3.from_json(obj["pixel_size"]), - slit_length=from_json_quantity(obj["slit_length"]), - ) +class Aperture: - def as_h5(self, group: h5py.Group): - """Export data onto an HDF5 group""" - if self.name is not None: - group.create_dataset("name", data=[self.name]) - if self.distance: - self.distance.as_h5(group, "SDD") - if self.offset: - self.offset.as_h5(group.create_group("offset")) - if self.orientation: - self.orientation.as_h5(group.create_group("orientation")) - if self.beam_center: - self.beam_center.as_h5(group.create_group("beam_center")) - if self.pixel_size: - self.pixel_size.as_h5(group.create_group("pixel_size")) - if self.slit_length: - self.slit_length.as_h5(group, "slit_length") + def __init__(self, target_object: AccessorTarget): -@dataclass(kw_only=True) -class Aperture: - distance: Quantity[float] | None - size: Vec3 | None - size_name: str | None - name: str | None - type_: str | None + # Name + self.name = StringAccessor(target_object, "name") - def summary(self): - return ( - f" Aperture:\n" - f" Name: {self.name}\n" - f" Aperture size: {self.size}\n" - f" Aperture distance: {self.distance}\n" - ) + # Type + self.type = StringAccessor(target_object, "type") - @staticmethod - def from_json(obj): - return Aperture( - distance=from_json_quantity(obj["distance"]), - size=Vec3.from_json(obj["size"]), - size_name=obj["size_name"], - name=obj["name"], - type_=obj["type"], - ) + # Size name - TODO: What is the name of a size + self.size_name = StringAccessor(target_object, "size_name") + # Aperture size [Vector] # TODO: Wat!?! + self.size = QuantityAccessor[ArrayLike](target_object, + "size", + "size.units", + default_unit=units.millimeters) - def as_h5(self, group: h5py.Group): - """Export data onto an HDF5 group""" - if self.distance is not None: - self.distance.as_h5(group, "distance") - if self.name is not None: - group.attrs["name"] = self.name - if self.type_ is not None: - group.attrs["type"] = self.type_ - if self.size: - size_group = group.create_group("size") - self.size.as_h5(size_group) - if self.size_name is not None: - size_group.attrs["name"] = self.size_name + # Aperture distance [float] + self.distance = LengthAccessor[float](target_object, + "distance", + "distance.units", + default_unit=units.millimeters) + def summary(self): + return (f"Aperture:\n" + f" Name: {self.name.value}\n" + f" Aperture size: {self.size.value}\n" + f" Aperture distance: {self.distance.value}\n") -@dataclass(kw_only=True) class Collimation: """ Class to hold collimation information """ - length: Quantity[float] | None - apertures: list[Aperture] - - def summary(self): - return f"Collimation:\n Length: {self.length}\n" + "".join([a.summary() for a in self.apertures]) + def __init__(self, target_object: AccessorTarget): - @staticmethod - def from_json(obj): - return Collimation( - length=from_json_quantity(obj["length"]) if obj["length"] else None, - apertures=list(map(Aperture.from_json, obj["apertures"])), - ) + # Name + self.name = StringAccessor(target_object, "name") + # Length [float] [mm] + self.length = LengthAccessor[float](target_object, + "length", + "length.units", + default_unit=units.millimeters) - def as_h5(self, group: h5py.Group): - """Export data onto an HDF5 group""" - if self.length: - self.length.as_h5(group, "length") - for idx, a in enumerate(self.apertures): - a.as_h5(group.create_group(f"sasaperture{idx:02d}")) + # Todo - how do we handle this + # self.collimator = Collimation(target_object) -@dataclass(kw_only=True) -class BeamSize: - name: str | None - size: Vec3 | None + def summary(self): - @staticmethod - def from_json(obj): - return BeamSize(name=obj["name"], size=Vec3.from_json(obj["size"])) + #TODO collimation stuff + return ( + f"Collimation:\n" + f" Length: {self.length.value}\n") - def as_h5(self, group: h5py.Group): - """Export data onto an HDF5 group""" - if self.name: - group.attrs["name"] = self.name - if self.size: - self.size.as_h5(group) +@dataclass +class BeamSize: + name: Optional[str] + x: Optional[Quantity[float]] + y: Optional[Quantity[float]] + z: Optional[Quantity[float]] -@dataclass(kw_only=True) +@dataclass class Source: - radiation: str | None - beam_shape: str | None - beam_size: BeamSize | None - wavelength: Quantity[float] | None - wavelength_min: Quantity[float] | None - wavelength_max: Quantity[float] | None - wavelength_spread: Quantity[float] | None + radiation: str + beam_shape: str + beam_size: Optional[BeamSize] + wavelength : Quantity[float] + wavelength_min : Quantity[float] + wavelength_max : Quantity[float] + wavelength_spread : Quantity[float] def summary(self) -> str: + if self.radiation is None and self.type.value and self.probe_particle.value: + radiation = f"{self.type.value} {self.probe_particle.value}" + else: + radiation = f"{self.radiation}" + return ( f"Source:\n" - f" Radiation: {self.radiation}\n" + f" Radiation: {radiation}\n" f" Shape: {self.beam_shape}\n" f" Wavelength: {self.wavelength}\n" f" Min. Wavelength: {self.wavelength_min}\n" @@ -251,591 +162,177 @@ def summary(self) -> str: f" Beam Size: {self.beam_size}\n" ) - @staticmethod - def from_json(obj): - return Source( - radiation=obj["radiation"], - beam_shape=obj["beam_shape"], - beam_size=BeamSize.from_json(obj["beam_size"]) if obj["beam_size"] else None, - wavelength=obj["wavelength"], - wavelength_min=obj["wavelength_min"], - wavelength_max=obj["wavelength_max"], - wavelength_spread=obj["wavelength_spread"], - ) - - def as_h5(self, group: h5py.Group): - """Export data onto an HDF5 group""" - if self.radiation: - group.create_dataset("radiation", data=[self.radiation]) - if self.beam_shape: - group.create_dataset("beam_shape", data=[self.beam_shape]) - if self.beam_size: - self.beam_size.as_h5(group.create_group("beam_size")) - if self.wavelength: - self.wavelength.as_h5(group, "wavelength") - if self.wavelength_min: - self.wavelength_min.as_h5(group, "wavelength_min") - if self.wavelength_max: - self.wavelength_max.as_h5(group, "wavelength_max") - if self.wavelength_spread: - self.wavelength_spread.as_h5(group, "wavelength_spread") - - +""" +Definitions of radiation types +""" +NEUTRON = 'neutron' +XRAY = 'x-ray' +MUON = 'muon' +ELECTRON = 'electron' -@dataclass(kw_only=True) class Sample: """ Class to hold the sample description """ + def __init__(self, target_object: AccessorTarget): - name: str | None - sample_id: str | None - thickness: Quantity[float] | None - transmission: float | None - temperature: Quantity[float] | None - position: Vec3 | None - orientation: Rot3 | None - details: list[str] + # Short name for sample + self.name = StringAccessor(target_object, "name") + # ID - def summary(self) -> str: - return ( - f"Sample:\n" - f" ID: {self.sample_id}\n" - f" Transmission: {self.transmission}\n" - f" Thickness: {self.thickness}\n" - f" Temperature: {self.temperature}\n" - f" Position: {self.position}\n" - f" Orientation: {self.orientation}\n" - ) + self.sample_id = StringAccessor(target_object, "id") - @staticmethod - def from_json(obj): - return Sample( - name=obj["name"], - sample_id=obj["sample_id"], - thickness=obj["thickness"], - transmission=obj["transmission"], - temperature=obj["temperature"], - position=obj["position"], - orientation=obj["orientation"], - details=obj["details"], - ) + # Thickness [float] [mm] + self.thickness = LengthAccessor(target_object, + "thickness", + "thickness.units", + default_unit=units.millimeters) - def as_h5(self, f: h5py.Group): - """Export data onto an HDF5 group""" - if self.name is not None: - f.attrs["name"] = self.name - if self.sample_id is not None: - f.create_dataset("ID", data=[self.sample_id]) - if self.thickness: - self.thickness.as_h5(f, "thickness") - if self.transmission is not None: - f.create_dataset("transmission", data=[self.transmission]) - if self.temperature: - self.temperature.as_h5(f, "temperature") - if self.position: - self.position.as_h5(f.create_group("position")) - if self.orientation: - self.orientation.as_h5(f.create_group("orientation")) - if self.details: - f.create_dataset("details", data=self.details) + # Transmission [float] [fraction] + self.transmission = FloatAccessor(target_object,"transmission") + + # Temperature [float] [No Default] + self.temperature = AbsoluteTemperatureAccessor(target_object, + "temperature", + "temperature.unit", + default_unit=units.kelvin) + # Position [Vector] [mm] + self.position = LengthAccessor[ArrayLike](target_object, + "position", + "position.unit", + default_unit=units.millimeters) + + # Orientation [Vector] [degrees] + self.orientation = AngleAccessor[ArrayLike](target_object, + "orientation", + "orientation.unit", + default_unit=units.degrees) + + # Details + self.details = StringAccessor(target_object, "details") + + + # SESANS zacceptance + zacceptance = (0,"") + yacceptance = (0,"") + + def summary(self) -> str: + return (f"Sample:\n" + f" ID: {self.sample_id.value}\n" + f" Transmission: {self.transmission.value}\n" + f" Thickness: {self.thickness.value}\n" + f" Temperature: {self.temperature.value}\n" + f" Position: {self.position.value}\n" + f" Orientation: {self.orientation.value}\n") + # + # _str += " Details:\n" + # for item in self.details: + # _str += " %s\n" % item + # + # return _str -@dataclass(kw_only=True) class Process: """ Class that holds information about the processes performed on the data. """ + def __init__(self, target_object: AccessorTarget): + self.name = StringAccessor(target_object, "name") + self.date = StringAccessor(target_object, "date") + self.description = StringAccessor(target_object, "description") + + #TODO: It seems like these might be lists of strings, this should be checked - name: str | None - date: str | None - description: str | None - terms: dict[str, str | Quantity[float]] - notes: list[str] + self.term = StringAccessor(target_object, "term") + self.notes = StringAccessor(target_object, "notes") def single_line_desc(self): """ - Return a single line string representing the process + Return a single line string representing the process """ return f"{self.name.value} {self.date.value} {self.description.value}" def summary(self): - if self.terms: - termInfo = " Terms:\n" + "\n".join([f" {k}: {v}" for k, v in self.terms.items()]) + "\n" - else: - termInfo = "" - - if self.notes: - noteInfo = " Notes:\n" + "\n".join([f" {note}" for note in self.notes]) + "\n" - else: - noteInfo = "" - - return ( - f"Process:\n" - f" Name: {self.name}\n" - f" Date: {self.date}\n" - f" Description: {self.description}\n" - f"{termInfo}" - f"{noteInfo}" - ) - - @staticmethod - def from_json(obj): - return Process( - name=obj["name"], - date=obj["date"], - description=obj["description"], - terms=obj["terms"], - notes=obj["notes"], - ) - - def as_h5(self, group: h5py.Group): - """Export data onto an HDF5 group""" - if self.name is not None: - group.create_dataset("name", data=[self.name]) - if self.date is not None: - group.create_dataset("date", data=[self.date]) - if self.description is not None: - group.create_dataset("description", data=[self.description]) - if self.terms: - for idx, (term, value) in enumerate(self.terms.items()): - node = group.create_group(f"term{idx:02d}") - node.attrs["name"] = term - if type(value) is Quantity: - node.attrs["value"] = value.value - node.attrs["unit"] = value.units.symbol - else: - node.attrs["value"] = value - for idx, note in enumerate(self.notes): - group.create_dataset(f"note{idx:02d}", data=[note]) + return (f"Process:\n" + f" Name: {self.name.value}\n" + f" Date: {self.date.value}\n" + f" Description: {self.description.value}\n" + f" Term: {self.term.value}\n" + f" Notes: {self.notes.value}\n" + ) @dataclass class Instrument: - collimations: list[Collimation] - source: Source | None - detector: list[Detector] + collimations : list[Collimation] + source : Source + detector : list[Detector] def summary(self): return ( - "\n".join([c.summary() for c in self.collimations]) - + "".join([d.summary() for d in self.detector]) - + (self.source.summary() if self.source is not None else "") - ) + self.aperture.summary() + + self.collimation.summary() + + self.detector.summary() + + self.source.summary()) - @staticmethod - def from_json(obj): - return Instrument( - collimations=list(map(Collimation.from_json, obj["collimations"])), - source=Source.from_json(obj["source"]), - detector=list(map(Detector.from_json, obj["detector"])), - ) +def decode_string(data): + """ This is some crazy stuff""" - def as_h5(self, group: h5py.Group): - """Export data onto an HDF5 group""" - if self.source: - self.source.as_h5(group.create_group("sassource")) - for idx, c in enumerate(self.collimations): - c.as_h5(group.create_group(f"sascollimation{idx:02d}")) - for idx, d in enumerate(self.detector): - d.as_h5(group.create_group(f"sasdetector{idx:02d}")) + if isinstance(data, str): + return data + elif isinstance(data, np.ndarray): -@dataclass(kw_only=True) -class MetaNode: - name: str - attrs: dict[str, str] - contents: str | Quantity | ndarray | list["MetaNode"] - - def to_string(self, header=""): - """Convert node to pretty printer string""" - if self.attrs: - attributes = f"\n{header} Attributes:\n" + "\n".join( - [f"{header} {k}: {v}" for k, v in self.attrs.items()] - ) - else: - attributes = "" - if self.contents: - if type(self.contents) is str: - children = f"\n{header} {self.contents}" - else: - children = "".join([n.to_string(header + " ") for n in self.contents]) - else: - children = "" - - return f"\n{header}{self.name}:{attributes}{children}" - - def filter(self, name: str) -> list[ndarray | Quantity | str]: - match self.contents: - case str() | ndarray() | Quantity(): - if name == self.name: - return [self.contents] - case list(): - return [y for x in self.contents for y in x.filter(name)] - case _: - raise RuntimeError(f"Cannot filter contents of type {type(self.contents)}: {self.contents}") - return [] - - def __eq__(self, other) -> bool: - """Custom equality overload needed since numpy arrays don't - play nicely with equality""" - match self.contents: - case ndarray(): - if not np.all(self.contents == other.contents): - return False - case Quantity(): - result = self.contents == other.contents - if type(result) is ndarray and not np.all(result): - return False - if type(result) is bool and not result: - return False - case _: - if self.contents != other.contents: - return False - for k, v in self.attrs.items(): - if k not in other.attrs: - return False - if type(v) is np.ndarray and np.any(v != other.attrs[k]): - return False - if type(v) is not np.ndarray and v != other.attrs[k]: - return False - return self.name == other.name - - @staticmethod - def from_json(obj): - def from_content(con): - match con: - case list(): - return list(map(MetaNode.from_json, con)) - case { - "type": "ndarray", - "dtype": dtype, - "encoding": "base64", - "contents": contents, - "shape": shape, - }: - return np.frombuffer(base64.b64decode(contents), dtype=dtype).reshape(shape) - case {"value": value, "units": units}: - return from_json_quantity({"value": from_content(value), "units": from_content(units)}) - case _: - return con - - return MetaNode( - name=obj["name"], - attrs={k: from_content(v) for k, v in obj["attrs"].items()}, - contents=from_content(obj["contents"]), - ) + if data.dtype == object: + data = data.reshape(-1) + data = data[0] -@dataclass(kw_only=True, eq=True) -class Metadata: - title: str | None - run: list[str] - definition: str | None - process: list[Process] - sample: Sample | None - instrument: Instrument | None - raw: MetaNode - - def summary(self): - run_string = str(self.run[0] if len(self.run) == 1 else self.run) - return ( - f" {self.title}, Run: {run_string}\n" - + " " - + "=" * len(str(self.title)) - + "=======" - + "=" * len(run_string) - + "\n\n" - + f"Definition: {self.title}\n" - + "".join([p.summary() for p in self.process]) - + (self.sample.summary() if self.sample else "") - + (self.instrument.summary() if self.instrument else "") - ) - - @staticmethod - def from_json(obj): - return Metadata( - title=obj["title"] if obj["title"] else None, - run=obj["run"], - definition=obj["definition"] if obj["definition"] else None, - process=[Process.from_json(p) for p in obj["process"]], - sample=Sample.from_json(obj["sample"]) if obj["sample"] else None, - instrument=Instrument.from_json(obj["instrument"]) if obj["instrument"] else None, - raw=MetaNode.from_json(obj["raw"]), - ) + if isinstance(data, bytes): + return data.decode("utf-8") - def as_h5(self, f: h5py.Group): - """Export data onto an HDF5 group""" - for idx, run in enumerate(self.run): - f.create_dataset(f"run{idx:02d}", data=[run]) - if self.title is not None: - f.create_dataset("title", data=[self.title]) - if self.definition is not None: - f.create_dataset("definition", data=[self.definition]) - if self.process: - for idx, process in enumerate(self.process): - name = f"sasprocess{idx:02d}" - process.as_h5(f.create_group(name)) - if self.sample: - self.sample.as_h5(f.create_group("sassample")) - if self.instrument: - self.instrument.as_h5(f.create_group("sasinstrument")) - # self.raw.as_h5(meta) if self.raw else None - - -class MetadataEncoder(json.JSONEncoder): - def default(self, obj): - match obj: - case None: - return None - case bytes(): - return obj.decode("utf-8") - case NamedUnit(): - return obj.name - case Quantity(): - return {"value": obj.value, "units": obj.units.ascii_symbol} - case ndarray(): - return { - "type": "ndarray", - "encoding": "base64", - "contents": base64.b64encode(obj.tobytes()).decode("utf-8"), - "dtype": obj.dtype.str, - "shape": obj.shape, - } - case Vec3(): - return { - "x": obj.x, - "y": obj.y, - "z": obj.z, - } - case Rot3(): - return { - "roll": obj.roll, - "pitch": obj.pitch, - "yaw": obj.yaw, - } - case Sample(): - return { - "name": obj.name, - "sample_id": obj.sample_id, - "thickness": obj.thickness, - "transmission": obj.transmission, - "temperature": obj.temperature, - "position": obj.position, - "orientation": obj.orientation, - "details": obj.details, - } - case Process(): - return { - "name": obj.name, - "date": obj.date, - "description": obj.description, - "terms": {k: obj.terms[k] for k in obj.terms}, - "notes": obj.notes, - } - case Aperture(): - return { - "distance": obj.distance, - "size": obj.size, - "size_name": obj.size_name, - "name": obj.name, - "type": obj.type_, - } - case Collimation(): - return { - "length": obj.length, - "apertures": [a for a in obj.apertures], - } - case BeamSize(): - return {"name": obj.name, "size": obj.size} - case Source(): - return { - "radiation": obj.radiation, - "beam_shape": obj.beam_shape, - "beam_size": obj.beam_size, - "wavelength": obj.wavelength, - "wavelength_min": obj.wavelength_min, - "wavelength_max": obj.wavelength_max, - "wavelength_spread": obj.wavelength_spread, - } - case Detector(): - return { - "name": obj.name, - "distance": obj.distance, - "offset": obj.offset, - "orientation": obj.orientation, - "beam_center": obj.beam_center, - "pixel_size": obj.pixel_size, - "slit_length": obj.slit_length, - } - case Instrument(): - return { - "collimations": [c for c in obj.collimations], - "source": obj.source, - "detector": [d for d in obj.detector], - } - case MetaNode(): - return {"name": obj.name, "attrs": obj.attrs, "contents": obj.contents} - case Metadata(): - return { - "title": obj.title, - "run": obj.run, - "definition": obj.definition, - "process": [p for p in obj.process], - "sample": obj.sample, - "instrument": obj.instrument, - "raw": obj.raw, - } - case _: - return super().default(obj) - - -def access_meta(obj: dataclass, key: str) -> Any | None: - """Use a string accessor to locate a key from within the data - object. - - The basic grammar of these accessors explicitly match the python - syntax for accessing the data. For example, to access the `name` - field within the object `person`, you would call - `access_meta(person, ".name")`. Similarly, lists and dicts are - access with square brackets. - - > assert access_meta(person, '.name') == person.name - > assert access_meta(person, '.phone.home') == person.phone.home - > assert access_meta(person, '.addresses[0].postal_code') == person.address[0].postal_code - > assert access_meta(person, '.children["Taylor"]') == person.children["Taylor"] - - Obviously, when the accessor is know ahead of time, `access_meta` - provides no benefit over directly retrieving the data. However, - when a data structure is loaded at runtime (e.g. the metadata of a - neutron scattering file), then it isn't possible to know in - advance the location of the specific value that the user desires. - `access_meta` allows the user to provide the location at runtime. - - This function returns `None` when the key is not a valid address - for any data within the structure. Since the leaf could be any - type that is not a list, dict, or dataclass, the return type of - the function is `Any | None`. - - The list of locations within a structure is given by the - `meta_tags` function. + return str(data) - """ - result = obj - while key != "": - match key: - case accessor if accessor.startswith("."): - for fld in fields(result): - field_string = f".{fld.name}" - if accessor.startswith(field_string): - key = accessor[len(field_string) :] - result = getattr(result, fld.name) - break - case index if (type(result) is list) and (matches := re.match(r"\[(\d+?)\](.*)", index)): - result = result[int(matches[1])] - key = matches[2] - case name if (type(result) is dict) and (matches := re.match(r'\["(.+)"\](.*)', name)): - result = result[matches[1]] - key = matches[2] - case _: - return None - return result - - -def meta_tags(obj: dataclass) -> list[str]: - """Find all leaf accessors from a data object. - - The function treats the passed in object as a tree. Lists, dicts, - and dataclasses are all treated as branches on the tree and any - other type is treated as a leaf. The function then returns a list - of strings, where each string is a "path" from the root of the - tree to one leaf. The structure of the path is designed to mimic - the python code to access that specific leaf value. - - These accessors allow us to treat accessing entries within a - structure as first class values. This list can then be presented - to the user to allow them to select specific information within - the larger structure. This is particularly important when plotting - against a specific date value within the structure. - - Example: - - >@dataclass - class Thermometer: - temperature: float - units: str - params: list - > item = Example() - > item.temperature = 273 - > item.units = "K" - > item.old_values = [{'date': '2025-08-12', 'temperature': 300'}] - > assert meta_tags(item) = ['.temperature', '.units', '.old_values[0]["date"]', '.old_values[0]["temperature"]'] - - The actual value of the leaf object specified by a path can be - retrieved with the `access_meta` function. - - """ - result = [] - items = [("", obj)] - while items: - path, item = items.pop() - match item: - case list(xs): - for idx, x in enumerate(xs): - items.append((f"{path}[{idx}]", x)) - case dict(xs): - for k, v in xs.items(): - items.append((f'{path}["{k}"]', v)) - case n if is_dataclass(n): - for fld in fields(item): - items.append((f"{path}.{fld.name}", getattr(item, fld.name))) - case _: - result.append(path) - return result + else: + return data.tobytes().decode("utf-8") + else: + return str(data) @dataclass(kw_only=True) -class TagCollection: - """The collected tags and their variability.""" - - singular: set[str] = field(default_factory=set) - variable: set[str] = field(default_factory=set) - - -def collect_tags(objs: list[dataclass]) -> TagCollection: - """Identify uniform and varying data within a groups of data objects - - The resulting TagCollection contains every accessor string that is - valid for every object in the `objs` list. For example, if - `obj.name` is a string for every `obj` in `objs`, then the string - ".name" will be present in one of the two sets in the tags - collection. - - To be more specific, if `obj.name` exists and has the same value - for every `obj` in `objs`, the string ".name" will be included in - the `singular` set. If there are at least two distinct values for - `obj.name`, then ".name" will be in the `variable` set. - - """ - if not objs: - return ([], []) - first = objs.pop() - terms = set(meta_tags(first)) - for obj in objs: - terms = terms.intersection(set(meta_tags(obj))) - - objs.append(first) - - result = TagCollection() - - for term in terms: - values = set([access_meta(obj, term) for obj in objs]) - if len(values) == 1: - result.singular.add(term) - else: - result.variable.add(term) +class Metadata: + def __init__(self, target: AccessorTarget): + self._target = target + + self.instrument = Instrument(target.with_path_prefix("sasinstrument|instrument")) + self.process = Process(target.with_path_prefix("sasprocess|process")) + self.sample = Sample(target.with_path_prefix("sassample|sample")) + self.transmission_spectrum = TransmissionSpectrum(target.with_path_prefix("sastransmission_spectrum|transmission_spectrum")) + + self._title = StringAccessor(target, "title") + self._run = StringAccessor(target, "run") + self._definition = StringAccessor(target, "definition") + + self.title: str = decode_string(self._title.value) + self.run: str = decode_string(self._run.value) + self.definition: str = decode_string(self._definition.value) + title: Optional[str] + run: list[str] + definition: Optional[str] + process: list[str] + sample: Optional[Sample] + instrument: Optional[Instrument] - return result + def summary(self): + return ( + f" {self.title}, Run: {self.run}\n" + + " " + "="*len(self.title) + + "=======" + + "="*len(self.run) + "\n\n" + + f"Definition: {self.title}\n" + + self.process.summary() + + self.sample.summary() + + (self.instrument.summary() if self.instrument else "")) diff --git a/sasdata/model_requirements.py b/sasdata/model_requirements.py index 3773c86ee..262f662e8 100644 --- a/sasdata/model_requirements.py +++ b/sasdata/model_requirements.py @@ -1,581 +1,23 @@ -from abc import ABC, abstractmethod -from functools import singledispatch -from typing import Self +from dataclasses import dataclass import numpy as np -from scipy.special import erf, j0 +from transforms.operation import Operation -from sasdata import dataset_types -from sasdata.data import SasData -from sasdata.quantities import units -from sasdata.quantities.quantity import Operation, Quantity +from sasdata.metadata import Metadata -class ModellingRequirements(ABC): - """Requirements that need to be passed to any modelling step""" - +@dataclass +class ModellingRequirements: + """ Requirements that need to be passed to any modelling step """ dimensionality: int operation: Operation - def __add__(self, other: Self) -> Self: - return self.compose(other) - - @singledispatch - def compose(self, other: Self) -> Self: - # Compose uses the reversed order - return compose(other, self) - - @abstractmethod - def preprocess_q(self, data: np.ndarray, full_data: SasData) -> np.ndarray: - """Transform the Q values before processing in the model""" - pass - - @abstractmethod - def postprocess_iq(self, data: np.ndarray, full_data: SasData) -> np.ndarray: - """Transform the I(Q) values after running the model""" + def from_qi_transformation(self, data: np.ndarray, metadata: Metadata) -> np.ndarray: + """ Transformation for going from qi to this data""" pass -class ComposeRequirements(ModellingRequirements): - """Composition of two models""" - - first: ModellingRequirements - second: ModellingRequirements - - def __init__(self, fst, snd): - self.first = fst - self.second = snd - - def preprocess_q(self, data: np.ndarray, full_data: SasData) -> np.ndarray: - """Perform both transformations in order""" - return self.second.preprocess_q( - self.first.preprocess_q(data, full_data), full_data - ) - - def postprocess_iq(self, data: np.ndarray, full_data: SasData) -> np.ndarray: - """Perform both transformations in order""" - return self.second.postprocess_iq( - self.first.postprocess_iq(data, full_data), full_data - ) - - -class SesansModel(ModellingRequirements): - """Perform Hankel transform for SESANS""" - - def preprocess_q( - self, spin_echo_length: np.ndarray, full_data: SasData - ) -> np.ndarray: - """Calculate the q values needed to perform the Hankel transform - - Note: this is undefined for the case when spin_echo_lengths contains - exactly one element and that values is zero. - - """ - if len(spin_echo_length) == 1: - q_min, q_max = ( - 0.01 * 2 * np.pi / spin_echo_length[-1], - 10 * 2 * np.pi / spin_echo_length[0], - ) - else: - # TODO: Why does q_min depend on the number of correlation lengths? - # TODO: Why does q_max depend on the correlation step size? - q_min = 0.1 * 2 * np.pi / (np.size(spin_echo_length) * spin_echo_length[-1]) - q_max = 2 * np.pi / (spin_echo_length[1] - spin_echo_length[0]) - - # TODO: Possibly make this adjustable - log_spacing = 1.0003 - self.q = np.exp(np.arange(np.log(q_min), np.log(q_max), np.log(log_spacing))) - - dq = np.diff(self.q) - dq = np.insert(dq, 0, dq[0]) - - self.H0 = dq / (2 * np.pi) * self.q - - self.H = np.outer(self.q, spin_echo_length) - j0(self.H, out=self.H) - self.H *= (dq * self.q / (2 * np.pi)).reshape((-1, 1)) - - reptheta = np.outer( - self.q, - full_data._data_contents["Wavelength"].in_units_of(units.angstroms) - / (2 * np.pi), - ) - # Note: Using inplace update with reptheta => arcsin(reptheta). - # When q L / 2 pi > 1 that means wavelength is too large to - # reach that q value at any angle. These should produce theta = NaN - # without any warnings. - # - # Reverse the condition to protect against NaN. We can't use - # theta > zaccept since all comparisons with NaN return False. - zaccept = [ - x.terms["zmax"] for x in full_data.metadata.process if "zmax" in x.terms - ][0] - with np.errstate(invalid="ignore"): - mask = ~(np.arcsin(reptheta) <= zaccept.in_units_of(units.radians)) - self.H[mask] = 0 - - return self.q - - def postprocess_iq(self, data: np.ndarray, full_data: SasData) -> np.ndarray: - """ - Apply the SESANS transform to the computed I(q) - """ - G0 = self.H0 @ data - G = self.H.T @ data - P = G - G0 - - return P - - -MINIMUM_RESOLUTION = 1e-8 -MINIMUM_ABSOLUTE_Q = 0.02 # relative to the minimum q in the data -# According to (Barker & Pedersen 1995 JAC), 2.5 sigma is a good limit. -# According to simulations with github.com:scattering/sansresolution.git -# it is better to use asymmetric bounds (2.5, 3.0) -PINHOLE_N_SIGMA = (2.5, 3.0) - - -class PinholeModel(ModellingRequirements): - """Perform a pin hole smearing""" - - def __init__(self, q_width: np.ndarray, nsigma: (float, float) = PINHOLE_N_SIGMA): - self.q_width = q_width - self.nsigma_low, self.nsigma_high = nsigma - - def preprocess_q(self, q: np.ndarray, full_data: SasData) -> np.ndarray: - """Perform smearing transform""" - self.q = q - q_min = np.min(self.q - self.nsigma_low * self.q_width) - q_max = np.max(self.q + self.nsigma_high * self.q_width) - - self.q_calc = linear_extrapolation(self.q, q_min, q_max) - - # Protect against models which are not defined for very low q. Limit - # the smallest q value evaluated (in absolute) to 0.02*min - cutoff = MINIMUM_ABSOLUTE_Q * np.min(self.q) - self.q_calc = self.q_calc[abs(self.q_calc) >= cutoff] - - # Build weight matrix from calculated q values - self.weight_matrix = pinhole_resolution( - self.q_calc, - self.q, - np.maximum(self.q_width, MINIMUM_RESOLUTION), - nsigma=(self.nsigma_low, self.nsigma_high), - ) - - return np.abs(self.q_calc) - - def postprocess_iq(self, data: np.ndarray, full_data: SasData) -> np.ndarray: - """Perform smearing transform""" - return self.weight_matrix.T @ data - - -class SlitModel(ModellingRequirements): - """Perform a slit smearing""" - - def __init__( - self, - q_length: np.ndarray, - q_width: np.ndarray, - nsigma: (float, float) = PINHOLE_N_SIGMA, - ): - self.q_length = q_length - self.q_width = q_width - self.nsigma_low, self.nsigma_high = nsigma - - def preprocess_q(self, q: np.ndarray, full_data: SasData) -> np.ndarray: - """Perform smearing transform""" - self.q = q - q_min = np.min(self.q - self.nsigma_low * self.q_width) - q_max = np.max(self.q + self.nsigma_high * self.q_width) - - self.q_calc = slit_extend_q(self.q, self.q_width, self.q_length) - - # Protect against models which are not defined for very low q. Limit - # the smallest q value evaluated (in absolute) to 0.02*min - cutoff = MINIMUM_ABSOLUTE_Q * np.min(self.q) - self.q_calc = self.q_calc[abs(self.q_calc) >= cutoff] - - # Build weight matrix from calculated q values - self.weight_matrix = slit_resolution( - self.q_calc, self.q, self.q_length, self.q_width - ) - - return np.abs(self.q_calc) - - def postprocess_iq(self, data: np.ndarray, full_data: SasData) -> np.ndarray: - """Perform smearing transform""" - return self.weight_matrix.T @ data - - -class NullModel(ModellingRequirements): - """A model that does nothing""" - - def compose(self, other: ModellingRequirements) -> ModellingRequirements: - return other - - def preprocess_q( - self, data: Quantity[np.ndarray], _full_data: SasData - ) -> np.ndarray: - """Do nothing""" - return data - - def postprocess_iq(self, data: np.ndarray, _full_data: SasData) -> np.ndarray: - """Do nothing""" - return data - - -def guess_requirements(data: SasData) -> ModellingRequirements: - """Use names of axes and units to guess what kind of processing needs to be done""" - if data.dataset_type == dataset_types.sesans: - return SesansModel() - pass - - -@singledispatch -def compose( - second: ModellingRequirements, first: ModellingRequirements -) -> ModellingRequirements: - """Compose to models together - - This function uses a reverse order so that it can perform dispatch on - the *second* term, since the classes already had a chance to dispatch - on the first parameter - - """ - return ComposeRequirements(first, second) - - -@compose.register -def _(second: NullModel, first: ModellingRequirements) -> ModellingRequirements: - """Null model is the identity element of composition""" - return first - - -@compose.register -def _(second: SesansModel, first: ModellingRequirements) -> ModellingRequirements: - match first: - case PinholeModel() | SlitModel(): - # To the first approximation, there is no slit smearing in SESANS data - return second - case _: - return ComposeRequirements(first, second) - - -def linear_extrapolation(q, q_min, q_max): - """ - Extrapolate *q* out to [*q_min*, *q_max*] using the step size in *q* as - a guide. Extrapolation below uses about the same size as the first - interval. Extrapolation above uses about the same size as the final - interval. - - Note that extrapolated values may be negative. - """ - q = np.sort(q) - delta_low = q[1] - q[0] if len(q) > 1 else 0 - n_low = int(np.ceil((q[0] - q_min) / delta_low)) if delta_low > 0 else 15 - q_low = np.linspace(q_min, q[0], n_low + 1)[:-1] if q_min + 2 * MINIMUM_RESOLUTION >= q[0] else [] - - delta_high = q[-1] - q[-2] if len(q) > 1 else 0 - n_high = int(np.ceil((q_max - q[-1]) / delta_high)) if delta_high > 0 else 15 - q_high = np.linspace(q[-1], q_max, n_high + 1)[1:] if q_max - 2 * MINIMUM_RESOLUTION <= q[-1] else [] - return np.concatenate([q_low, q, q_high]) - - -def pinhole_resolution( - q_calc: np.ndarray, q: np.ndarray, q_width: np.ndarray, nsigma=PINHOLE_N_SIGMA -) -> np.ndarray: - r""" - Compute the convolution matrix *W* for pinhole resolution 1-D data. - - Each row *W[i]* determines the normalized weight that the corresponding - points *q_calc* contribute to the resolution smeared point *q[i]*. Given - *W*, the resolution smearing can be computed using *dot(W,q)*. - - Note that resolution is limited to $\pm 2.5 \sigma$.[1] The true resolution - function is a broadened triangle, and does not extend over the entire - range $(-\infty, +\infty)$. It is important to impose this limitation - since some models fall so steeply that the weighted value in gaussian - tails would otherwise dominate the integral. - - *q_calc* must be increasing. *q_width* must be greater than zero. - - [1] Barker, J. G., and J. S. Pedersen. 1995. Instrumental Smearing Effects - in Radially Symmetric Small-Angle Neutron Scattering by Numerical and - Analytical Methods. Journal of Applied Crystallography 28 (2): 105--14. - https://doi.org/10.1107/S0021889894010095. - """ - # The current algorithm is a midpoint rectangle rule. In the test case, - # neither trapezoid nor Simpson's rule improved the accuracy. - edges = bin_edges(q_calc) - # edges[edges < 0.0] = 0.0 # clip edges below zero - cdf = erf((edges[:, None] - q[None, :]) / (np.sqrt(2.0) * q_width)[None, :]) - weights = cdf[1:] - cdf[:-1] - # Limit q range to (-2.5,+3) sigma - try: - nsigma_low, nsigma_high = nsigma - except TypeError: - nsigma_low = nsigma_high = nsigma - qhigh = q + nsigma_high * q_width - qlow = q - nsigma_low * q_width # linear limits - ##qlow = q*q/qhigh # log limits - weights[q_calc[:, None] < qlow[None, :]] = 0.0 - weights[q_calc[:, None] > qhigh[None, :]] = 0.0 - weights /= np.sum(weights, axis=0)[None, :] - return weights - - -def bin_edges(x): - """ - Determine bin edges from bin centers, assuming that edges are centered - between the bins. - - Note: this uses the arithmetic mean, which may not be appropriate for - log-scaled data. - """ - if len(x) < 2 or (np.diff(x) < 0).any(): - raise ValueError("Expected bins to be an increasing set") - edges = np.hstack( - [ - x[0] - 0.5 * (x[1] - x[0]), # first point minus half first interval - 0.5 * (x[1:] + x[:-1]), # mid points of all central intervals - x[-1] + 0.5 * (x[-1] - x[-2]), # last point plus half last interval - ] - ) - return edges - - -def slit_resolution(q_calc, q, width, length, n_length=30): - r""" - Build a weight matrix to compute *I_s(q)* from *I(q_calc)*, given - $q_\perp$ = *width* (in the high-resolution axis) and $q_\parallel$ - = *length* (in the low resolution axis). *n_length* is the number - of steps to use in the integration over $q_\parallel$ when both - $q_\perp$ and $q_\parallel$ are non-zero. - - Each $q$ can have an independent width and length value even though - current instruments use the same slit setting for all measured points. - - If slit length is large relative to width, use: - - .. math:: - - I_s(q_i) = \frac{1}{\Delta q_\perp} - \int_0^{\Delta q_\perp} - I\left(\sqrt{q_i^2 + q_\perp^2}\right) \,dq_\perp - - If slit width is large relative to length, use: - - .. math:: - - I_s(q_i) = \frac{1}{2 \Delta q_\parallel} - \int_{-\Delta q_\parallel}^{\Delta q_\parallel} - I\left(|q_i + q_\parallel|\right) \,dq_\parallel - - For a mixture of slit width and length use: - - .. math:: - - I_s(q_i) = \frac{1}{2 \Delta q_\parallel \Delta q_\perp} - \int_{-\Delta q_\parallel}^{\Delta q_\parallel} - \int_0^{\Delta q_\perp} - I\left(\sqrt{(q_i + q_\parallel)^2 + q_\perp^2}\right) - \,dq_\perp dq_\parallel - - **Definition** - - We are using the mid-point integration rule to assign weights to each - element of a weight matrix $W$ so that - - .. math:: - - I_s(q) = W\,I(q_\text{calc}) - - If *q_calc* is at the mid-point, we can infer the bin edges from the - pairwise averages of *q_calc*, adding the missing edges before - *q_calc[0]* and after *q_calc[-1]*. - - For $q_\parallel = 0$, the smeared value can be computed numerically - using the $u$ substitution - - .. math:: - - u_j = \sqrt{q_j^2 - q^2} - - This gives - - .. math:: - - I_s(q) \approx \sum_j I(u_j) \Delta u_j - - where $I(u_j)$ is the value at the mid-point, and $\Delta u_j$ is the - difference between consecutive edges which have been first converted - to $u$. Only $u_j \in [0, \Delta q_\perp]$ are used, which corresponds - to $q_j \in \left[q, \sqrt{q^2 + \Delta q_\perp}\right]$, so - - .. math:: - - W_{ij} = \frac{1}{\Delta q_\perp} \Delta u_j - = \frac{1}{\Delta q_\perp} \left( - \sqrt{q_{j+1}^2 - q_i^2} - \sqrt{q_j^2 - q_i^2} \right) - \ \text{if}\ q_j \in \left[q_i, \sqrt{q_i^2 + q_\perp^2}\right] - - where $I_s(q_i)$ is the theory function being computed and $q_j$ are the - mid-points between the calculated values in *q_calc*. We tweak the - edges of the initial and final intervals so that they lie on integration - limits. - - (To be precise, the transformed midpoint $u(q_j)$ is not necessarily the - midpoint of the edges $u((q_{j-1}+q_j)/2)$ and $u((q_j + q_{j+1})/2)$, - but it is at least in the interval, so the approximation is going to be - a little better than the left or right Riemann sum, and should be - good enough for our purposes.) - - For $q_\perp = 0$, the $u$ substitution is simpler: - - .. math:: - - u_j = \left|q_j - q\right| - - so - - .. math:: - - W_{ij} = \frac{1}{2 \Delta q_\parallel} \Delta u_j - = \frac{1}{2 \Delta q_\parallel} (q_{j+1} - q_j) - \ \text{if}\ q_j \in - \left[q-\Delta q_\parallel, q+\Delta q_\parallel\right] - - However, we need to support cases were $u_j < 0$, which means using - $2 (q_{j+1} - q_j)$ when $q_j \in \left[0, q_\parallel-q_i\right]$. - This is not an issue for $q_i > q_\parallel$. - - For both $q_\perp > 0$ and $q_\parallel > 0$ we perform a 2 dimensional - integration with - - .. math:: - - u_{jk} = \sqrt{q_j^2 - (q + (k\Delta q_\parallel/L))^2} - \ \text{for}\ k = -L \ldots L - - for $L$ = *n_length*. This gives - - .. math:: - - W_{ij} = \frac{1}{2 \Delta q_\perp q_\parallel} - \sum_{k=-L}^L \Delta u_{jk} - \left(\frac{\Delta q_\parallel}{2 L + 1}\right) - - - """ - - # The current algorithm is a midpoint rectangle rule. - q_edges = bin_edges(q_calc) # Note: requires q > 0 - weights = np.zeros((len(q), len(q_calc)), "d") - - for i, (qi, w, l) in enumerate(zip(q, width, length)): - if w == 0.0 and l == 0.0: - # Perfect resolution, so return the theory value directly. - # Note: assumes that q is a subset of q_calc. If qi need not be - # in q_calc, then we can do a weighted interpolation by looking - # up qi in q_calc, then weighting the result by the relative - # distance to the neighbouring points. - weights[i, :] = q_calc == qi - elif l == 0: - weights[i, :] = _q_perp_weights(q_edges, qi, w) - elif w == 0 and qi >= l: - in_x = 1.0 * ((q_calc >= qi - l) & (q_calc <= qi + l)) - weights[i, :] = in_x * np.diff(q_edges) / (2 * l) - elif w == 0: - in_x = 1.0 * ((q_calc >= qi - l) & (q_calc <= qi + l)) - abs_x = 1.0 * (q_calc < abs(qi - l)) - weights[i, :] = (in_x + abs_x) * np.diff(q_edges) / (2 * l) - else: - weights[i, :] = _q_perp_weights( - q_edges, qi + np.arange(-n_length, n_length + 1) * l / n_length, w - ) - weights[i, :] /= 2 * n_length + 1 - - return weights.T - - -def _q_perp_weights(q_edges, qi, w): - q_edges = np.reshape(q_edges, (1, -1)) - qi = np.reshape(qi, (-1, 1)) - # Convert bin edges from q to u - u_limit = np.sqrt(qi**2 + w**2) - u_edges = q_edges**2 - qi**2 - u_edges[q_edges < abs(qi)] = 0.0 - u_edges[q_edges > u_limit] = np.repeat( - u_limit**2 - qi**2, u_edges.shape[1], axis=1 - )[q_edges > u_limit] - return (np.diff(np.sqrt(u_edges), axis=1) / w).sum(axis=0) - - -def slit_extend_q(q, width, length): - """ - Given *q*, *width* and *length*, find a set of sampling points *q_calc* so - that each point I(q) has sufficient support from the underlying - function. - """ - q_min, q_max = np.min(q - length), np.max(np.sqrt((q + length) ** 2 + width**2)) - - return geometric_extrapolation(q, q_min, q_max) - - -def geometric_extrapolation(q, q_min, q_max, points_per_decade=None): - r""" - Extrapolate *q* to [*q_min*, *q_max*] using geometric steps, with the - average geometric step size in *q* as the step size. - - if *q_min* is zero or less then *q[0]/10* is used instead. - - *points_per_decade* sets the ratio between consecutive steps such - that there will be $n$ points used for every factor of 10 increase - in *q*. - - If *points_per_decade* is not given, it will be estimated as follows. - Starting at $q_1$ and stepping geometrically by $\Delta q$ to $q_n$ - in $n$ points gives a geometric average of: - - .. math:: - - \log \Delta q = (\log q_n - \log q_1) / (n - 1) - - From this we can compute the number of steps required to extend $q$ - from $q_n$ to $q_\text{max}$ by $\Delta q$ as: - - .. math:: - - n_\text{extend} = (\log q_\text{max} - \log q_n) / \log \Delta q - - Substituting: - .. math:: - n_\text{extend} = (n-1) (\log q_\text{max} - \log q_n) - / (\log q_n - \log q_1) - """ - DEFAULT_POINTS_PER_DECADE = 10 - q = np.sort(q) - data_min, data_max = q[0], q[-1] - if points_per_decade is None: - if data_max > data_min: - log_delta_q = (len(q) - 1) / (np.log(data_max) - np.log(data_min)) - else: - log_delta_q = np.log(10.0) / DEFAULT_POINTS_PER_DECADE - else: - log_delta_q = np.log(10.0) / points_per_decade - if q_min <= 0: - q_min = data_min * MINIMUM_ABSOLUTE_Q - if q_min < data_min: - n_low = int(np.ceil(log_delta_q * (np.log(data_min) - np.log(q_min)))) - q_low = np.logspace(np.log10(q_min), np.log10(data_min), n_low + 1)[:-1] - else: - q_low = [] - if q_max > data_max: - n_high = int(np.ceil(log_delta_q * (np.log(q_max) - np.log(data_max)))) - q_high = np.logspace(np.log10(data_max), np.log10(q_max), n_high + 1)[1:] - else: - q_high = [] - return np.concatenate([q_low, q, q_high]) +def guess_requirements(abscissae, ordinate) -> ModellingRequirements: + """ Use names of axes and units to guess what kind of processing needs to be done """ diff --git a/sasdata/postprocess.py b/sasdata/postprocess.py new file mode 100644 index 000000000..82ce61420 --- /dev/null +++ b/sasdata/postprocess.py @@ -0,0 +1,16 @@ +""" + +Post processing for loaded files + +""" + +def fix_mantid_units_error(data: SasData) -> SasData: + pass + + + +def apply_fixes(data: SasData, mantid_unit_error=True): + if mantid_unit_error: + data = fix_mantid_units_error(data) + + return data diff --git a/sasdata/quantities/_accessor_base.py b/sasdata/quantities/_accessor_base.py new file mode 100644 index 000000000..09a1b6e01 --- /dev/null +++ b/sasdata/quantities/_accessor_base.py @@ -0,0 +1,152 @@ +from typing import TypeVar + +import sasdata.quantities.units as units +from sasdata.data_backing import Dataset, Group +from sasdata.quantities.quantity import Quantity +from sasdata.quantities.unit_parser import parse_unit +from sasdata.quantities.units import Unit + + +# logger = logging.getLogger("Accessors") +class LoggerDummy: + def info(self, data): + print(data) +logger = LoggerDummy() + +DataType = TypeVar("DataType") +OutputType = TypeVar("OutputType") + + +class AccessorTarget: + def __init__(self, data: Group, verbose=False, prefix_tokens: tuple=()): + self._data = data + self.verbose = verbose + + self.prefix_tokens = list(prefix_tokens) + + def with_path_prefix(self, path_prexix: str): + """ Get an accessor that looks at a subtree of the metadata with the supplied prefix + + For example, accessors aiming at a.b, when the target it c.d will look at c.d.a.b + """ + return AccessorTarget(self._data, + verbose=self.verbose, + prefix_tokens=tuple(self.prefix_tokens + [path_prexix])) + + def get_value(self, path: str): + + tokens = self.prefix_tokens + path.split(".") + + if self.verbose: + logger.info(f"Finding: {path}") + logger.info(f"Full path: {tokens}") + + # Navigate the tree from the entry we need + + current_tree_position: Group | Dataset = self._data + + for token in tokens: + + options = token.split("|") + + if isinstance(current_tree_position, Group): + + found = False + for option in options: + if option in current_tree_position.children: + current_tree_position = current_tree_position.children[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on group {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.children])) + return None + + elif isinstance(current_tree_position, Dataset): + + found = False + for option in options: + if option in current_tree_position.attributes: + current_tree_position = current_tree_position.attributes[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on attribute {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.attributes])) + return None + + if self.verbose: + logger.info(f"Found value: {current_tree_position}") + + return current_tree_position.data + + + +class Accessor[DataType, OutputType]: + """ Base class """ + def __init__(self, target_object: AccessorTarget, value_target: str): + self.target_object = target_object + self.value_target = value_target + + @property + def value(self) -> OutputType | None: + return self.target_object.get_value(self.value_target) + +class StringAccessor(Accessor[str, str]): + """ String based fields """ + @property + def value(self) -> str | None: + return self.target_object.get_value(self.value_target) + +class FloatAccessor(Accessor[float, float]): + """ Float based fields """ + @property + def value(self) -> float | None: + return self.target_object.get_value(self.value_target) + + + + +class QuantityAccessor[DataType](Accessor[DataType, Quantity[DataType]]): + """ Base class for accessors that work with quantities that have units """ + def __init__(self, target_object: AccessorTarget, value_target: str, unit_target: str, default_unit=units.none): + super().__init__(target_object, value_target) + self._unit_target = unit_target + self.default_unit = default_unit + + def _numerical_part(self) -> DataType | None: + """ Numerical part of the data """ + return self.target_object.get_value(self.value_target) + + def _unit_part(self) -> str | None: + """ String form of units for the data """ + return self.target_object.get_value(self._unit_target) + + @property + def unit(self) -> Unit: + u = self._unit_part() + if u is None: + return self.default_unit + else: + return parse_unit(u) + + @property + def value(self) -> Quantity[DataType] | None: + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + + @property + def quantity(self): + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + diff --git a/sasdata/quantities/_autogen_warning.py b/sasdata/quantities/_autogen_warning.py index 9a8c9372e..fc8be67dc 100644 --- a/sasdata/quantities/_autogen_warning.py +++ b/sasdata/quantities/_autogen_warning.py @@ -5,75 +5,75 @@ Do not edit by hand, instead edit the files that build it (%s) - - -DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt -D::::::::::::DDD N:::::::N N::::::N ttt:::t -D:::::::::::::::DD N::::::::N N::::::N t:::::t -DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t - D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt - D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t - D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t - D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt - D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t - D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t - D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t - D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt -DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t -D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t -D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt -DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt - - - - - - - - - dddddddd -EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB -E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B -E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B -EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy - E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y - E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y - E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y - E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y - E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y - E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y - E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y -EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y -E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y -E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y -EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y - y:::::y - y:::::y - y:::::y - y:::::y - yyyyyyy - - - - dddddddd -HHHHHHHHH HHHHHHHHH d::::::d -H:::::::H H:::::::H d::::::d -H:::::::H H:::::::H d::::::d -HH::::::H H::::::HH d:::::d - H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d - H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d - H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d - H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d - H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d - H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d - H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d - H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d -HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd -H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d -H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d -HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd - + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + """ diff --git a/sasdata/quantities/_build_tables.py b/sasdata/quantities/_build_tables.py index ba07aee80..5af6a92bb 100644 --- a/sasdata/quantities/_build_tables.py +++ b/sasdata/quantities/_build_tables.py @@ -61,14 +61,12 @@ non_si_dimensioned_units: list[tuple[str, str | None, str, str, float, int, int, int, int, int, int, int, list]] = [ UnitData("Ang", "Å", r"\AA", "angstrom", "angstroms", 1e-10, 1, 0, 0, 0, 0, 0, 0, []), - UnitData("micron", None, None, "micron", "microns", 1e-6, 1, 0, 0, 0, 0, 0, 0, []), UnitData("min", None, None, "minute", "minutes", 60, 0, 1, 0, 0, 0, 0, 0, []), - UnitData("h", None, None, "hour", "hours", 3600, 0, 1, 0, 0, 0, 0, 0, []), - UnitData("d", None, None, "day", "days", 3600*24, 0, 1, 0, 0, 0, 0, 0, []), - UnitData("y", None, None, "year", "years", 3600*24*365.2425, 0, 1, 0, 0, 0, 0, 0, []), + UnitData("h", None, None, "hour", "hours", 360, 0, 1, 0, 0, 0, 0, 0, []), + UnitData("d", None, None, "day", "days", 360*24, 0, 1, 0, 0, 0, 0, 0, []), + UnitData("y", None, None, "year", "years", 360*24*365.2425, 0, 1, 0, 0, 0, 0, 0, []), UnitData("deg", None, None, "degree", "degrees", 180/np.pi, 0, 0, 0, 0, 0, 0, 1, []), UnitData("rad", None, None, "radian", "radians", 1, 0, 0, 0, 0, 0, 0, 1, []), - UnitData("rot", None, None, "rotation", "rotations", 2*np.pi, 0, 0, 0, 0, 0, 0, 1, []), UnitData("sr", None, None, "stradian", "stradians", 1, 0, 0, 0, 0, 0, 0, 2, []), UnitData("l", None, None, "litre", "litres", 1e-3, 3, 0, 0, 0, 0, 0, 0, []), UnitData("eV", None, None, "electronvolt", "electronvolts", 1.602176634e-19, 2, -2, 1, 0, 0, 0, 0, all_magnitudes), @@ -111,7 +109,7 @@ "Ang": ["A", "Å"], "au": ["amu"], "percent": ["%"], - "deg": ["degr", "Deg", "degree", "degrees", "Degrees"], + "deg": ["degr", "Deg", "degrees", "Degrees"], "none": ["Counts", "counts", "cnts", "Cnts", "a.u.", "fraction", "Fraction"], "K": ["C"] # Ugh, cansas } @@ -150,7 +148,7 @@ def format_name(name: str): # Write in unit definitions fid.write("\n\n" "#\n" - "# Specific units \n" + "# Specific units\n" "#\n\n") symbol_lookup = {} @@ -374,14 +372,14 @@ def format_name(name: str): ("concentration", Dimensions(length=-3, moles_hint=1)), ] - fid.write("\n#\n# Units by type \n#\n\n") + fid.write("\n#\n# Units by type\n#\n\n") for dimension_name, dimensions in dimension_names: fid.write(f"\n" f"{dimension_name} = UnitGroup(\n" - f" name = '{dimension_name}', \n" + f" name = '{dimension_name}',\n" f" units = [\n") for unit_name in unit_types[hash(dimensions)]: @@ -419,7 +417,7 @@ def format_name(name: str): fid.write(f"\n" f"class {accessor_name}[T](QuantityAccessor[T]):\n" f" dimension_name = '{dimension_name}'\n" - f" \n") + f"\n") for unit_name in unit_types[hash(dimensions)]: fid.write(f" @property\n" @@ -432,7 +430,6 @@ def format_name(name: str): f"\n") fid.write("\n") - with open("si.py", 'w') as fid: fid.write('"""'+(warning_text%"_build_tables.py")+'"""\n\n') @@ -441,7 +438,6 @@ def format_name(name: str): for name in si_unit_names: fid.write(f"from sasdata.quantities.units import {name}\n") - fid.write("\nall_si = [\n") for name in si_unit_names: fid.write(f" {name},\n") diff --git a/sasdata/quantities/_units_base.py b/sasdata/quantities/_units_base.py index 9e6401b53..d8ec39b45 100644 --- a/sasdata/quantities/_units_base.py +++ b/sasdata/quantities/_units_base.py @@ -72,7 +72,7 @@ def __truediv__(self: Self, other: Self): def __pow__(self, power: int | float): - if not isinstance(power, (int | float)): + if not isinstance(power, (int, float)): return NotImplemented frac = Fraction(power).limit_denominator(500) # Probably way bigger than needed, 10 would probably be fine @@ -214,24 +214,21 @@ def _components(self, tokens: Sequence["UnitToken"]): pass def __mul__(self: Self, other: "Unit"): - if isinstance(other, Unit): - return Unit(self.scale * other.scale, self.dimensions * other.dimensions) - elif isinstance(other, (int, float)): - return Unit(other * self.scale, self.dimensions) - return NotImplemented + if not isinstance(other, Unit): + return NotImplemented + + return Unit(self.scale * other.scale, self.dimensions * other.dimensions) def __truediv__(self: Self, other: "Unit"): - if isinstance(other, Unit): - return Unit(self.scale / other.scale, self.dimensions / other.dimensions) - elif isinstance(other, (int, float)): - return Unit(self.scale / other, self.dimensions) - else: + if not isinstance(other, Unit): return NotImplemented + return Unit(self.scale / other.scale, self.dimensions / other.dimensions) + def __rtruediv__(self: Self, other: "Unit"): if isinstance(other, Unit): return Unit(other.scale / self.scale, other.dimensions / self.dimensions) - elif isinstance(other, (int | float)): + elif isinstance(other, (int, float)): return Unit(other / self.scale, self.dimensions ** -1) else: return NotImplemented @@ -295,27 +292,6 @@ def __init__(self, def __repr__(self): return self.name - def __eq__(self, other): - """Match other units exactly or match strings against ANY of our names""" - match other: - case str(): - return self.name == other or self.name == f"{other}s" or self.ascii_symbol == other or self.symbol == other - case NamedUnit(): - return self.name == other.name \ - and self.ascii_symbol == other.ascii_symbol and self.symbol == other.symbol - case Unit(): - return self.equivalent(other) and np.abs(np.log(self.scale/other.scale)) < 1e-5 - case _: - return False - - - def startswith(self, prefix: str) -> bool: - """Check if any representation of the unit begins with the prefix string""" - prefix = prefix.lower() - return (self.name is not None and self.name.lower().startswith(prefix)) \ - or (self.ascii_symbol is not None and self.ascii_symbol.lower().startswith(prefix)) \ - or (self.symbol is not None and self.symbol.lower().startswith(prefix)) - # # Parsing plan: # Require unknown amounts of units to be explicitly positive or negative? @@ -348,7 +324,6 @@ def apply(self, scale, dimensions) -> tuple[float, Dimensions, ProcessedUnitToke token = ProcessedUnitToken(self.unit, self.power) return new_scale, new_dimensions, token - class GreedyAbsDimensionUnitFormatProcessor(UnitFormatProcessor): """ This processor minimises the dimensionality of the unit by multiplying by as many units of the specified type as needed """ @@ -358,6 +333,9 @@ def __init__(self, unit: Unit): def apply(self, scale, dimensions) -> tuple[ProcessedUnitToken, float, Dimensions]: pass +class GreedyAbsDimensionUnitFormatProcessor(UnitFormatProcessor): + pass + class UnitGroup: """ A group of units that all have the same dimensionality """ def __init__(self, name: str, units: list[NamedUnit]): diff --git a/sasdata/quantities/absolute_temperature.py b/sasdata/quantities/absolute_temperature.py index 045c7de97..108f30760 100644 --- a/sasdata/quantities/absolute_temperature.py +++ b/sasdata/quantities/absolute_temperature.py @@ -1,14 +1,14 @@ -from typing import TypeVar - -from sasdata.quantities.accessors import TemperatureAccessor -from sasdata.quantities.quantity import Quantity - -DataType = TypeVar("DataType") -class AbsoluteTemperatureAccessor(TemperatureAccessor[DataType]): - """ Parsing for absolute temperatures """ - @property - def value(self) -> Quantity[DataType] | None: - if self._numerical_part() is None: - return None - else: - return Quantity.parse(self._numerical_part(), self._unit_part(), absolute_temperature=True) +from typing import TypeVar + +from sasdata.quantities.accessors import TemperatureAccessor +from sasdata.quantities.quantity import Quantity + +DataType = TypeVar("DataType") +class AbsoluteTemperatureAccessor(TemperatureAccessor[DataType]): + """ Parsing for absolute temperatures """ + @property + def value(self) -> Quantity[DataType] | None: + if self._numerical_part() is None: + return None + else: + return Quantity.parse(self._numerical_part(), self._unit_part(), absolute_temperature=True) diff --git a/sasdata/quantities/accessors.py b/sasdata/quantities/accessors.py new file mode 100644 index 000000000..a7d23fd27 --- /dev/null +++ b/sasdata/quantities/accessors.py @@ -0,0 +1,10321 @@ +""" + +This file is autogenerated! + +Do not edit by hand, instead edit the files that build it (_build_tables.py, _accessor_base.py) + + + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + + + +""" + +from typing import TypeVar + +import sasdata.quantities.units as units +from sasdata.data_backing import Dataset, Group +from sasdata.quantities.quantity import Quantity +from sasdata.quantities.unit_parser import parse_unit +from sasdata.quantities.units import Unit + + +# logger = logging.getLogger("Accessors") +class LoggerDummy: + def info(self, data): + print(data) +logger = LoggerDummy() + +DataType = TypeVar("DataType") +OutputType = TypeVar("OutputType") + + +class AccessorTarget: + def __init__(self, data: Group, verbose=False, prefix_tokens: tuple=()): + self._data = data + self.verbose = verbose + + self.prefix_tokens = list(prefix_tokens) + + def with_path_prefix(self, path_prexix: str): + """ Get an accessor that looks at a subtree of the metadata with the supplied prefix + + For example, accessors aiming at a.b, when the target it c.d will look at c.d.a.b + """ + return AccessorTarget(self._data, + verbose=self.verbose, + prefix_tokens=tuple(self.prefix_tokens + [path_prexix])) + + def get_value(self, path: str): + + tokens = self.prefix_tokens + path.split(".") + + if self.verbose: + logger.info(f"Finding: {path}") + logger.info(f"Full path: {tokens}") + + # Navigate the tree from the entry we need + + current_tree_position: Group | Dataset = self._data + + for token in tokens: + + options = token.split("|") + + if isinstance(current_tree_position, Group): + + found = False + for option in options: + if option in current_tree_position.children: + current_tree_position = current_tree_position.children[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on group {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.children])) + return None + + elif isinstance(current_tree_position, Dataset): + + found = False + for option in options: + if option in current_tree_position.attributes: + current_tree_position = current_tree_position.attributes[option] + found = True + + if self.verbose: + logger.info(f"Found option: {option}") + + if not found: + if self.verbose: + logger.info(f"Failed to find any of {options} on attribute {current_tree_position.name}. Options: " + + ",".join([key for key in current_tree_position.attributes])) + return None + + if self.verbose: + logger.info(f"Found value: {current_tree_position}") + + return current_tree_position.data + + + +class Accessor[DataType, OutputType]: + """ Base class """ + def __init__(self, target_object: AccessorTarget, value_target: str): + self.target_object = target_object + self.value_target = value_target + + @property + def value(self) -> OutputType | None: + return self.target_object.get_value(self.value_target) + +class StringAccessor(Accessor[str, str]): + """ String based fields """ + @property + def value(self) -> str | None: + return self.target_object.get_value(self.value_target) + +class FloatAccessor(Accessor[float, float]): + """ Float based fields """ + @property + def value(self) -> float | None: + return self.target_object.get_value(self.value_target) + + + + +class QuantityAccessor[DataType](Accessor[DataType, Quantity[DataType]]): + """ Base class for accessors that work with quantities that have units """ + def __init__(self, target_object: AccessorTarget, value_target: str, unit_target: str, default_unit=units.none): + super().__init__(target_object, value_target) + self._unit_target = unit_target + self.default_unit = default_unit + + def _numerical_part(self) -> DataType | None: + """ Numerical part of the data """ + return self.target_object.get_value(self.value_target) + + def _unit_part(self) -> str | None: + """ String form of units for the data """ + return self.target_object.get_value(self._unit_target) + + @property + def unit(self) -> Unit: + u = self._unit_part() + if u is None: + return self.default_unit + else: + return parse_unit(u) + + @property + def value(self) -> Quantity[DataType] | None: + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + + @property + def quantity(self): + if self._unit_part() is not None and self._numerical_part() is not None: + return Quantity(self._numerical_part(), self.unit) + return None + + +class LengthAccessor[T](QuantityAccessor[T]): + dimension_name = 'length' + + @property + def meters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters) + + @property + def exameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters) + + @property + def petameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters) + + @property + def terameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters) + + @property + def gigameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters) + + @property + def megameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters) + + @property + def kilometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers) + + @property + def millimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters) + + @property + def micrometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers) + + @property + def nanometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers) + + @property + def picometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers) + + @property + def femtometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers) + + @property + def attometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers) + + @property + def decimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters) + + @property + def centimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters) + + @property + def angstroms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms) + + @property + def miles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles) + + @property + def yards(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards) + + @property + def feet(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet) + + @property + def inches(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches) + + + +class AreaAccessor[T](QuantityAccessor[T]): + dimension_name = 'area' + + @property + def square_meters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_meters) + + @property + def square_exameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_exameters) + + @property + def square_petameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_petameters) + + @property + def square_terameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_terameters) + + @property + def square_gigameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_gigameters) + + @property + def square_megameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_megameters) + + @property + def square_kilometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_kilometers) + + @property + def square_millimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_millimeters) + + @property + def square_micrometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_micrometers) + + @property + def square_nanometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_nanometers) + + @property + def square_picometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_picometers) + + @property + def square_femtometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_femtometers) + + @property + def square_attometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_attometers) + + @property + def square_decimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_decimeters) + + @property + def square_centimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_centimeters) + + @property + def square_angstroms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_angstroms) + + @property + def square_miles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_miles) + + @property + def square_yards(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_yards) + + @property + def square_feet(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_feet) + + @property + def square_inches(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.square_inches) + + + +class VolumeAccessor[T](QuantityAccessor[T]): + dimension_name = 'volume' + + @property + def litres(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.litres) + + @property + def cubic_meters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_meters) + + @property + def cubic_exameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_exameters) + + @property + def cubic_petameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_petameters) + + @property + def cubic_terameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_terameters) + + @property + def cubic_gigameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_gigameters) + + @property + def cubic_megameters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_megameters) + + @property + def cubic_kilometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_kilometers) + + @property + def cubic_millimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_millimeters) + + @property + def cubic_micrometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_micrometers) + + @property + def cubic_nanometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_nanometers) + + @property + def cubic_picometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_picometers) + + @property + def cubic_femtometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_femtometers) + + @property + def cubic_attometers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_attometers) + + @property + def cubic_decimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_decimeters) + + @property + def cubic_centimeters(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_centimeters) + + @property + def cubic_angstroms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_angstroms) + + @property + def cubic_miles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_miles) + + @property + def cubic_yards(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_yards) + + @property + def cubic_feet(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_feet) + + @property + def cubic_inches(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.cubic_inches) + + + +class InverselengthAccessor[T](QuantityAccessor[T]): + dimension_name = 'inverse_length' + + @property + def per_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_meter) + + @property + def per_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_exameter) + + @property + def per_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_petameter) + + @property + def per_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_terameter) + + @property + def per_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_gigameter) + + @property + def per_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_megameter) + + @property + def per_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_kilometer) + + @property + def per_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_millimeter) + + @property + def per_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_micrometer) + + @property + def per_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_nanometer) + + @property + def per_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_picometer) + + @property + def per_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_femtometer) + + @property + def per_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_attometer) + + @property + def per_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_decimeter) + + @property + def per_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_centimeter) + + @property + def per_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_angstrom) + + @property + def per_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_mile) + + @property + def per_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_yard) + + @property + def per_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_foot) + + @property + def per_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_inch) + + + +class InverseareaAccessor[T](QuantityAccessor[T]): + dimension_name = 'inverse_area' + + @property + def per_square_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_meter) + + @property + def per_square_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_exameter) + + @property + def per_square_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_petameter) + + @property + def per_square_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_terameter) + + @property + def per_square_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_gigameter) + + @property + def per_square_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_megameter) + + @property + def per_square_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_kilometer) + + @property + def per_square_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_millimeter) + + @property + def per_square_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_micrometer) + + @property + def per_square_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_nanometer) + + @property + def per_square_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_picometer) + + @property + def per_square_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_femtometer) + + @property + def per_square_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_attometer) + + @property + def per_square_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_decimeter) + + @property + def per_square_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_centimeter) + + @property + def per_square_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_angstrom) + + @property + def per_square_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_mile) + + @property + def per_square_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_yard) + + @property + def per_square_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_foot) + + @property + def per_square_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_square_inch) + + + +class InversevolumeAccessor[T](QuantityAccessor[T]): + dimension_name = 'inverse_volume' + + @property + def per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_meter) + + @property + def per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_exameter) + + @property + def per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_petameter) + + @property + def per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_terameter) + + @property + def per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_gigameter) + + @property + def per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_megameter) + + @property + def per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_kilometer) + + @property + def per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_millimeter) + + @property + def per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_micrometer) + + @property + def per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_nanometer) + + @property + def per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_picometer) + + @property + def per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_femtometer) + + @property + def per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_attometer) + + @property + def per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_decimeter) + + @property + def per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_centimeter) + + @property + def per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_angstrom) + + @property + def per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_mile) + + @property + def per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_yard) + + @property + def per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_foot) + + @property + def per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.per_cubic_inch) + + + +class TimeAccessor[T](QuantityAccessor[T]): + dimension_name = 'time' + + @property + def seconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.seconds) + + @property + def milliseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliseconds) + + @property + def microseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microseconds) + + @property + def nanoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanoseconds) + + @property + def picoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picoseconds) + + @property + def femtoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtoseconds) + + @property + def attoseconds(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attoseconds) + + @property + def minutes(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.minutes) + + @property + def hours(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.hours) + + @property + def days(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.days) + + @property + def years(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.years) + + + +class RateAccessor[T](QuantityAccessor[T]): + dimension_name = 'rate' + + @property + def hertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.hertz) + + @property + def exahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exahertz) + + @property + def petahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petahertz) + + @property + def terahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terahertz) + + @property + def gigahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigahertz) + + @property + def megahertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megahertz) + + @property + def kilohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilohertz) + + @property + def millihertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millihertz) + + @property + def microhertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microhertz) + + @property + def nanohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanohertz) + + @property + def picohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picohertz) + + @property + def femtohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtohertz) + + @property + def attohertz(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attohertz) + + + +class SpeedAccessor[T](QuantityAccessor[T]): + dimension_name = 'speed' + + @property + def meters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_second) + + @property + def meters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_millisecond) + + @property + def meters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_microsecond) + + @property + def meters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_nanosecond) + + @property + def meters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_picosecond) + + @property + def meters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_femtosecond) + + @property + def meters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_attosecond) + + @property + def meters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_minute) + + @property + def meters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_hour) + + @property + def meters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_day) + + @property + def meters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_year) + + @property + def exameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_second) + + @property + def exameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_millisecond) + + @property + def exameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_microsecond) + + @property + def exameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_nanosecond) + + @property + def exameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_picosecond) + + @property + def exameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_femtosecond) + + @property + def exameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_attosecond) + + @property + def exameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_minute) + + @property + def exameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_hour) + + @property + def exameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_day) + + @property + def exameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_year) + + @property + def petameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_second) + + @property + def petameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_millisecond) + + @property + def petameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_microsecond) + + @property + def petameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_nanosecond) + + @property + def petameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_picosecond) + + @property + def petameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_femtosecond) + + @property + def petameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_attosecond) + + @property + def petameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_minute) + + @property + def petameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_hour) + + @property + def petameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_day) + + @property + def petameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_year) + + @property + def terameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_second) + + @property + def terameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_millisecond) + + @property + def terameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_microsecond) + + @property + def terameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_nanosecond) + + @property + def terameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_picosecond) + + @property + def terameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_femtosecond) + + @property + def terameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_attosecond) + + @property + def terameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_minute) + + @property + def terameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_hour) + + @property + def terameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_day) + + @property + def terameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_year) + + @property + def gigameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_second) + + @property + def gigameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_millisecond) + + @property + def gigameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_microsecond) + + @property + def gigameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_nanosecond) + + @property + def gigameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_picosecond) + + @property + def gigameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_femtosecond) + + @property + def gigameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_attosecond) + + @property + def gigameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_minute) + + @property + def gigameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_hour) + + @property + def gigameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_day) + + @property + def gigameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_year) + + @property + def megameters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_second) + + @property + def megameters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_millisecond) + + @property + def megameters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_microsecond) + + @property + def megameters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_nanosecond) + + @property + def megameters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_picosecond) + + @property + def megameters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_femtosecond) + + @property + def megameters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_attosecond) + + @property + def megameters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_minute) + + @property + def megameters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_hour) + + @property + def megameters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_day) + + @property + def megameters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_year) + + @property + def kilometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_second) + + @property + def kilometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_millisecond) + + @property + def kilometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_microsecond) + + @property + def kilometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_nanosecond) + + @property + def kilometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_picosecond) + + @property + def kilometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_femtosecond) + + @property + def kilometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_attosecond) + + @property + def kilometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_minute) + + @property + def kilometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_hour) + + @property + def kilometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_day) + + @property + def kilometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_year) + + @property + def millimeters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_second) + + @property + def millimeters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_millisecond) + + @property + def millimeters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_microsecond) + + @property + def millimeters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_nanosecond) + + @property + def millimeters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_picosecond) + + @property + def millimeters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_femtosecond) + + @property + def millimeters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_attosecond) + + @property + def millimeters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_minute) + + @property + def millimeters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_hour) + + @property + def millimeters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_day) + + @property + def millimeters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_year) + + @property + def micrometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_second) + + @property + def micrometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_millisecond) + + @property + def micrometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_microsecond) + + @property + def micrometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_nanosecond) + + @property + def micrometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_picosecond) + + @property + def micrometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_femtosecond) + + @property + def micrometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_attosecond) + + @property + def micrometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_minute) + + @property + def micrometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_hour) + + @property + def micrometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_day) + + @property + def micrometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_year) + + @property + def nanometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_second) + + @property + def nanometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_millisecond) + + @property + def nanometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_microsecond) + + @property + def nanometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_nanosecond) + + @property + def nanometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_picosecond) + + @property + def nanometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_femtosecond) + + @property + def nanometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_attosecond) + + @property + def nanometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_minute) + + @property + def nanometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_hour) + + @property + def nanometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_day) + + @property + def nanometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_year) + + @property + def picometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_second) + + @property + def picometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_millisecond) + + @property + def picometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_microsecond) + + @property + def picometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_nanosecond) + + @property + def picometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_picosecond) + + @property + def picometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_femtosecond) + + @property + def picometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_attosecond) + + @property + def picometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_minute) + + @property + def picometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_hour) + + @property + def picometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_day) + + @property + def picometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_year) + + @property + def femtometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_second) + + @property + def femtometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_millisecond) + + @property + def femtometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_microsecond) + + @property + def femtometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_nanosecond) + + @property + def femtometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_picosecond) + + @property + def femtometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_femtosecond) + + @property + def femtometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_attosecond) + + @property + def femtometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_minute) + + @property + def femtometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_hour) + + @property + def femtometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_day) + + @property + def femtometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_year) + + @property + def attometers_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_second) + + @property + def attometers_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_millisecond) + + @property + def attometers_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_microsecond) + + @property + def attometers_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_nanosecond) + + @property + def attometers_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_picosecond) + + @property + def attometers_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_femtosecond) + + @property + def attometers_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_attosecond) + + @property + def attometers_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_minute) + + @property + def attometers_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_hour) + + @property + def attometers_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_day) + + @property + def attometers_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_year) + + @property + def decimeters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_second) + + @property + def decimeters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_millisecond) + + @property + def decimeters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_microsecond) + + @property + def decimeters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_nanosecond) + + @property + def decimeters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_picosecond) + + @property + def decimeters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_femtosecond) + + @property + def decimeters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_attosecond) + + @property + def decimeters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_minute) + + @property + def decimeters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_hour) + + @property + def decimeters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_day) + + @property + def decimeters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_year) + + @property + def centimeters_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_second) + + @property + def centimeters_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_millisecond) + + @property + def centimeters_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_microsecond) + + @property + def centimeters_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_nanosecond) + + @property + def centimeters_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_picosecond) + + @property + def centimeters_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_femtosecond) + + @property + def centimeters_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_attosecond) + + @property + def centimeters_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_minute) + + @property + def centimeters_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_hour) + + @property + def centimeters_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_day) + + @property + def centimeters_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_year) + + @property + def angstroms_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_second) + + @property + def angstroms_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_millisecond) + + @property + def angstroms_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_microsecond) + + @property + def angstroms_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_nanosecond) + + @property + def angstroms_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_picosecond) + + @property + def angstroms_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_femtosecond) + + @property + def angstroms_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_attosecond) + + @property + def angstroms_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_minute) + + @property + def angstroms_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_hour) + + @property + def angstroms_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_day) + + @property + def angstroms_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_year) + + @property + def miles_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_second) + + @property + def miles_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_millisecond) + + @property + def miles_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_microsecond) + + @property + def miles_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_nanosecond) + + @property + def miles_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_picosecond) + + @property + def miles_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_femtosecond) + + @property + def miles_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_attosecond) + + @property + def miles_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_minute) + + @property + def miles_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_hour) + + @property + def miles_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_day) + + @property + def miles_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_year) + + @property + def yards_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_second) + + @property + def yards_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_millisecond) + + @property + def yards_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_microsecond) + + @property + def yards_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_nanosecond) + + @property + def yards_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_picosecond) + + @property + def yards_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_femtosecond) + + @property + def yards_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_attosecond) + + @property + def yards_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_minute) + + @property + def yards_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_hour) + + @property + def yards_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_day) + + @property + def yards_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_year) + + @property + def feet_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_second) + + @property + def feet_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_millisecond) + + @property + def feet_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_microsecond) + + @property + def feet_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_nanosecond) + + @property + def feet_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_picosecond) + + @property + def feet_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_femtosecond) + + @property + def feet_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_attosecond) + + @property + def feet_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_minute) + + @property + def feet_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_hour) + + @property + def feet_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_day) + + @property + def feet_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_year) + + @property + def inches_per_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_second) + + @property + def inches_per_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_millisecond) + + @property + def inches_per_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_microsecond) + + @property + def inches_per_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_nanosecond) + + @property + def inches_per_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_picosecond) + + @property + def inches_per_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_femtosecond) + + @property + def inches_per_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_attosecond) + + @property + def inches_per_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_minute) + + @property + def inches_per_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_hour) + + @property + def inches_per_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_day) + + @property + def inches_per_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_year) + + + +class AccelerationAccessor[T](QuantityAccessor[T]): + dimension_name = 'acceleration' + + @property + def meters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_second) + + @property + def meters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_millisecond) + + @property + def meters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_microsecond) + + @property + def meters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_nanosecond) + + @property + def meters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_picosecond) + + @property + def meters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_femtosecond) + + @property + def meters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_attosecond) + + @property + def meters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_minute) + + @property + def meters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_hour) + + @property + def meters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_day) + + @property + def meters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meters_per_square_year) + + @property + def exameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_second) + + @property + def exameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_millisecond) + + @property + def exameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_microsecond) + + @property + def exameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_nanosecond) + + @property + def exameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_picosecond) + + @property + def exameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_femtosecond) + + @property + def exameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_attosecond) + + @property + def exameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_minute) + + @property + def exameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_hour) + + @property + def exameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_day) + + @property + def exameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exameters_per_square_year) + + @property + def petameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_second) + + @property + def petameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_millisecond) + + @property + def petameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_microsecond) + + @property + def petameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_nanosecond) + + @property + def petameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_picosecond) + + @property + def petameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_femtosecond) + + @property + def petameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_attosecond) + + @property + def petameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_minute) + + @property + def petameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_hour) + + @property + def petameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_day) + + @property + def petameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petameters_per_square_year) + + @property + def terameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_second) + + @property + def terameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_millisecond) + + @property + def terameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_microsecond) + + @property + def terameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_nanosecond) + + @property + def terameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_picosecond) + + @property + def terameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_femtosecond) + + @property + def terameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_attosecond) + + @property + def terameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_minute) + + @property + def terameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_hour) + + @property + def terameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_day) + + @property + def terameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terameters_per_square_year) + + @property + def gigameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_second) + + @property + def gigameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_millisecond) + + @property + def gigameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_microsecond) + + @property + def gigameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_nanosecond) + + @property + def gigameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_picosecond) + + @property + def gigameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_femtosecond) + + @property + def gigameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_attosecond) + + @property + def gigameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_minute) + + @property + def gigameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_hour) + + @property + def gigameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_day) + + @property + def gigameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigameters_per_square_year) + + @property + def megameters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_second) + + @property + def megameters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_millisecond) + + @property + def megameters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_microsecond) + + @property + def megameters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_nanosecond) + + @property + def megameters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_picosecond) + + @property + def megameters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_femtosecond) + + @property + def megameters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_attosecond) + + @property + def megameters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_minute) + + @property + def megameters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_hour) + + @property + def megameters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_day) + + @property + def megameters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megameters_per_square_year) + + @property + def kilometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_second) + + @property + def kilometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_millisecond) + + @property + def kilometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_microsecond) + + @property + def kilometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_nanosecond) + + @property + def kilometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_picosecond) + + @property + def kilometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_femtosecond) + + @property + def kilometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_attosecond) + + @property + def kilometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_minute) + + @property + def kilometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_hour) + + @property + def kilometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_day) + + @property + def kilometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilometers_per_square_year) + + @property + def millimeters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_second) + + @property + def millimeters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_millisecond) + + @property + def millimeters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_microsecond) + + @property + def millimeters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_nanosecond) + + @property + def millimeters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_picosecond) + + @property + def millimeters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_femtosecond) + + @property + def millimeters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_attosecond) + + @property + def millimeters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_minute) + + @property + def millimeters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_hour) + + @property + def millimeters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_day) + + @property + def millimeters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimeters_per_square_year) + + @property + def micrometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_second) + + @property + def micrometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_millisecond) + + @property + def micrometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_microsecond) + + @property + def micrometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_nanosecond) + + @property + def micrometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_picosecond) + + @property + def micrometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_femtosecond) + + @property + def micrometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_attosecond) + + @property + def micrometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_minute) + + @property + def micrometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_hour) + + @property + def micrometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_day) + + @property + def micrometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrometers_per_square_year) + + @property + def nanometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_second) + + @property + def nanometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_millisecond) + + @property + def nanometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_microsecond) + + @property + def nanometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_nanosecond) + + @property + def nanometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_picosecond) + + @property + def nanometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_femtosecond) + + @property + def nanometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_attosecond) + + @property + def nanometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_minute) + + @property + def nanometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_hour) + + @property + def nanometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_day) + + @property + def nanometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanometers_per_square_year) + + @property + def picometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_second) + + @property + def picometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_millisecond) + + @property + def picometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_microsecond) + + @property + def picometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_nanosecond) + + @property + def picometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_picosecond) + + @property + def picometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_femtosecond) + + @property + def picometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_attosecond) + + @property + def picometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_minute) + + @property + def picometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_hour) + + @property + def picometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_day) + + @property + def picometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picometers_per_square_year) + + @property + def femtometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_second) + + @property + def femtometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_millisecond) + + @property + def femtometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_microsecond) + + @property + def femtometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_nanosecond) + + @property + def femtometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_picosecond) + + @property + def femtometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_femtosecond) + + @property + def femtometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_attosecond) + + @property + def femtometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_minute) + + @property + def femtometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_hour) + + @property + def femtometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_day) + + @property + def femtometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtometers_per_square_year) + + @property + def attometers_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_second) + + @property + def attometers_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_millisecond) + + @property + def attometers_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_microsecond) + + @property + def attometers_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_nanosecond) + + @property + def attometers_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_picosecond) + + @property + def attometers_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_femtosecond) + + @property + def attometers_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_attosecond) + + @property + def attometers_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_minute) + + @property + def attometers_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_hour) + + @property + def attometers_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_day) + + @property + def attometers_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attometers_per_square_year) + + @property + def decimeters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_second) + + @property + def decimeters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_millisecond) + + @property + def decimeters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_microsecond) + + @property + def decimeters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_nanosecond) + + @property + def decimeters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_picosecond) + + @property + def decimeters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_femtosecond) + + @property + def decimeters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_attosecond) + + @property + def decimeters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_minute) + + @property + def decimeters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_hour) + + @property + def decimeters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_day) + + @property + def decimeters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.decimeters_per_square_year) + + @property + def centimeters_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_second) + + @property + def centimeters_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_millisecond) + + @property + def centimeters_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_microsecond) + + @property + def centimeters_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_nanosecond) + + @property + def centimeters_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_picosecond) + + @property + def centimeters_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_femtosecond) + + @property + def centimeters_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_attosecond) + + @property + def centimeters_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_minute) + + @property + def centimeters_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_hour) + + @property + def centimeters_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_day) + + @property + def centimeters_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.centimeters_per_square_year) + + @property + def angstroms_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_second) + + @property + def angstroms_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_millisecond) + + @property + def angstroms_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_microsecond) + + @property + def angstroms_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_nanosecond) + + @property + def angstroms_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_picosecond) + + @property + def angstroms_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_femtosecond) + + @property + def angstroms_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_attosecond) + + @property + def angstroms_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_minute) + + @property + def angstroms_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_hour) + + @property + def angstroms_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_day) + + @property + def angstroms_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.angstroms_per_square_year) + + @property + def miles_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_second) + + @property + def miles_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_millisecond) + + @property + def miles_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_microsecond) + + @property + def miles_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_nanosecond) + + @property + def miles_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_picosecond) + + @property + def miles_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_femtosecond) + + @property + def miles_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_attosecond) + + @property + def miles_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_minute) + + @property + def miles_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_hour) + + @property + def miles_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_day) + + @property + def miles_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.miles_per_square_year) + + @property + def yards_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_second) + + @property + def yards_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_millisecond) + + @property + def yards_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_microsecond) + + @property + def yards_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_nanosecond) + + @property + def yards_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_picosecond) + + @property + def yards_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_femtosecond) + + @property + def yards_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_attosecond) + + @property + def yards_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_minute) + + @property + def yards_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_hour) + + @property + def yards_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_day) + + @property + def yards_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.yards_per_square_year) + + @property + def feet_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_second) + + @property + def feet_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_millisecond) + + @property + def feet_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_microsecond) + + @property + def feet_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_nanosecond) + + @property + def feet_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_picosecond) + + @property + def feet_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_femtosecond) + + @property + def feet_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_attosecond) + + @property + def feet_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_minute) + + @property + def feet_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_hour) + + @property + def feet_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_day) + + @property + def feet_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.feet_per_square_year) + + @property + def inches_per_square_second(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_second) + + @property + def inches_per_square_millisecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_millisecond) + + @property + def inches_per_square_microsecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_microsecond) + + @property + def inches_per_square_nanosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_nanosecond) + + @property + def inches_per_square_picosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_picosecond) + + @property + def inches_per_square_femtosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_femtosecond) + + @property + def inches_per_square_attosecond(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_attosecond) + + @property + def inches_per_square_minute(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_minute) + + @property + def inches_per_square_hour(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_hour) + + @property + def inches_per_square_day(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_day) + + @property + def inches_per_square_year(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.inches_per_square_year) + + + +class DensityAccessor[T](QuantityAccessor[T]): + dimension_name = 'density' + + @property + def grams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_meter) + + @property + def exagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_meter) + + @property + def petagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_meter) + + @property + def teragrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_meter) + + @property + def gigagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_meter) + + @property + def megagrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_meter) + + @property + def kilograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_meter) + + @property + def milligrams_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_meter) + + @property + def micrograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_meter) + + @property + def nanograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_meter) + + @property + def picograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_meter) + + @property + def femtograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_meter) + + @property + def attograms_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_meter) + + @property + def atomic_mass_units_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_meter) + + @property + def pounds_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_meter) + + @property + def ounces_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_meter) + + @property + def grams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_exameter) + + @property + def exagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_exameter) + + @property + def petagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_exameter) + + @property + def teragrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_exameter) + + @property + def gigagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_exameter) + + @property + def megagrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_exameter) + + @property + def kilograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_exameter) + + @property + def milligrams_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_exameter) + + @property + def micrograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_exameter) + + @property + def nanograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_exameter) + + @property + def picograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_exameter) + + @property + def femtograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_exameter) + + @property + def attograms_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_exameter) + + @property + def atomic_mass_units_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_exameter) + + @property + def pounds_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_exameter) + + @property + def ounces_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_exameter) + + @property + def grams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_petameter) + + @property + def exagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_petameter) + + @property + def petagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_petameter) + + @property + def teragrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_petameter) + + @property + def gigagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_petameter) + + @property + def megagrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_petameter) + + @property + def kilograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_petameter) + + @property + def milligrams_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_petameter) + + @property + def micrograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_petameter) + + @property + def nanograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_petameter) + + @property + def picograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_petameter) + + @property + def femtograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_petameter) + + @property + def attograms_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_petameter) + + @property + def atomic_mass_units_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_petameter) + + @property + def pounds_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_petameter) + + @property + def ounces_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_petameter) + + @property + def grams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_terameter) + + @property + def exagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_terameter) + + @property + def petagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_terameter) + + @property + def teragrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_terameter) + + @property + def gigagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_terameter) + + @property + def megagrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_terameter) + + @property + def kilograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_terameter) + + @property + def milligrams_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_terameter) + + @property + def micrograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_terameter) + + @property + def nanograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_terameter) + + @property + def picograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_terameter) + + @property + def femtograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_terameter) + + @property + def attograms_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_terameter) + + @property + def atomic_mass_units_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_terameter) + + @property + def pounds_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_terameter) + + @property + def ounces_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_terameter) + + @property + def grams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_gigameter) + + @property + def exagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_gigameter) + + @property + def petagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_gigameter) + + @property + def teragrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_gigameter) + + @property + def gigagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_gigameter) + + @property + def megagrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_gigameter) + + @property + def kilograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_gigameter) + + @property + def milligrams_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_gigameter) + + @property + def micrograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_gigameter) + + @property + def nanograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_gigameter) + + @property + def picograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_gigameter) + + @property + def femtograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_gigameter) + + @property + def attograms_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_gigameter) + + @property + def atomic_mass_units_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_gigameter) + + @property + def pounds_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_gigameter) + + @property + def ounces_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_gigameter) + + @property + def grams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_megameter) + + @property + def exagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_megameter) + + @property + def petagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_megameter) + + @property + def teragrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_megameter) + + @property + def gigagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_megameter) + + @property + def megagrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_megameter) + + @property + def kilograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_megameter) + + @property + def milligrams_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_megameter) + + @property + def micrograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_megameter) + + @property + def nanograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_megameter) + + @property + def picograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_megameter) + + @property + def femtograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_megameter) + + @property + def attograms_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_megameter) + + @property + def atomic_mass_units_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_megameter) + + @property + def pounds_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_megameter) + + @property + def ounces_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_megameter) + + @property + def grams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_kilometer) + + @property + def exagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_kilometer) + + @property + def petagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_kilometer) + + @property + def teragrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_kilometer) + + @property + def gigagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_kilometer) + + @property + def megagrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_kilometer) + + @property + def kilograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_kilometer) + + @property + def milligrams_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_kilometer) + + @property + def micrograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_kilometer) + + @property + def nanograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_kilometer) + + @property + def picograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_kilometer) + + @property + def femtograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_kilometer) + + @property + def attograms_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_kilometer) + + @property + def atomic_mass_units_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_kilometer) + + @property + def pounds_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_kilometer) + + @property + def ounces_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_kilometer) + + @property + def grams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_millimeter) + + @property + def exagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_millimeter) + + @property + def petagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_millimeter) + + @property + def teragrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_millimeter) + + @property + def gigagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_millimeter) + + @property + def megagrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_millimeter) + + @property + def kilograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_millimeter) + + @property + def milligrams_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_millimeter) + + @property + def micrograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_millimeter) + + @property + def nanograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_millimeter) + + @property + def picograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_millimeter) + + @property + def femtograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_millimeter) + + @property + def attograms_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_millimeter) + + @property + def atomic_mass_units_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_millimeter) + + @property + def pounds_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_millimeter) + + @property + def ounces_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_millimeter) + + @property + def grams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_micrometer) + + @property + def exagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_micrometer) + + @property + def petagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_micrometer) + + @property + def teragrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_micrometer) + + @property + def gigagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_micrometer) + + @property + def megagrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_micrometer) + + @property + def kilograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_micrometer) + + @property + def milligrams_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_micrometer) + + @property + def micrograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_micrometer) + + @property + def nanograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_micrometer) + + @property + def picograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_micrometer) + + @property + def femtograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_micrometer) + + @property + def attograms_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_micrometer) + + @property + def atomic_mass_units_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_micrometer) + + @property + def pounds_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_micrometer) + + @property + def ounces_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_micrometer) + + @property + def grams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_nanometer) + + @property + def exagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_nanometer) + + @property + def petagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_nanometer) + + @property + def teragrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_nanometer) + + @property + def gigagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_nanometer) + + @property + def megagrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_nanometer) + + @property + def kilograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_nanometer) + + @property + def milligrams_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_nanometer) + + @property + def micrograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_nanometer) + + @property + def nanograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_nanometer) + + @property + def picograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_nanometer) + + @property + def femtograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_nanometer) + + @property + def attograms_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_nanometer) + + @property + def atomic_mass_units_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_nanometer) + + @property + def pounds_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_nanometer) + + @property + def ounces_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_nanometer) + + @property + def grams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_picometer) + + @property + def exagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_picometer) + + @property + def petagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_picometer) + + @property + def teragrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_picometer) + + @property + def gigagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_picometer) + + @property + def megagrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_picometer) + + @property + def kilograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_picometer) + + @property + def milligrams_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_picometer) + + @property + def micrograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_picometer) + + @property + def nanograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_picometer) + + @property + def picograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_picometer) + + @property + def femtograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_picometer) + + @property + def attograms_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_picometer) + + @property + def atomic_mass_units_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_picometer) + + @property + def pounds_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_picometer) + + @property + def ounces_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_picometer) + + @property + def grams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_femtometer) + + @property + def exagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_femtometer) + + @property + def petagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_femtometer) + + @property + def teragrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_femtometer) + + @property + def gigagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_femtometer) + + @property + def megagrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_femtometer) + + @property + def kilograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_femtometer) + + @property + def milligrams_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_femtometer) + + @property + def micrograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_femtometer) + + @property + def nanograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_femtometer) + + @property + def picograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_femtometer) + + @property + def femtograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_femtometer) + + @property + def attograms_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_femtometer) + + @property + def atomic_mass_units_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_femtometer) + + @property + def pounds_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_femtometer) + + @property + def ounces_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_femtometer) + + @property + def grams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_attometer) + + @property + def exagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_attometer) + + @property + def petagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_attometer) + + @property + def teragrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_attometer) + + @property + def gigagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_attometer) + + @property + def megagrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_attometer) + + @property + def kilograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_attometer) + + @property + def milligrams_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_attometer) + + @property + def micrograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_attometer) + + @property + def nanograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_attometer) + + @property + def picograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_attometer) + + @property + def femtograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_attometer) + + @property + def attograms_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_attometer) + + @property + def atomic_mass_units_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_attometer) + + @property + def pounds_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_attometer) + + @property + def ounces_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_attometer) + + @property + def grams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_decimeter) + + @property + def exagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_decimeter) + + @property + def petagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_decimeter) + + @property + def teragrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_decimeter) + + @property + def gigagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_decimeter) + + @property + def megagrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_decimeter) + + @property + def kilograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_decimeter) + + @property + def milligrams_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_decimeter) + + @property + def micrograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_decimeter) + + @property + def nanograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_decimeter) + + @property + def picograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_decimeter) + + @property + def femtograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_decimeter) + + @property + def attograms_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_decimeter) + + @property + def atomic_mass_units_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_decimeter) + + @property + def pounds_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_decimeter) + + @property + def ounces_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_decimeter) + + @property + def grams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_centimeter) + + @property + def exagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_centimeter) + + @property + def petagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_centimeter) + + @property + def teragrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_centimeter) + + @property + def gigagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_centimeter) + + @property + def megagrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_centimeter) + + @property + def kilograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_centimeter) + + @property + def milligrams_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_centimeter) + + @property + def micrograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_centimeter) + + @property + def nanograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_centimeter) + + @property + def picograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_centimeter) + + @property + def femtograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_centimeter) + + @property + def attograms_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_centimeter) + + @property + def atomic_mass_units_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_centimeter) + + @property + def pounds_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_centimeter) + + @property + def ounces_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_centimeter) + + @property + def grams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_angstrom) + + @property + def exagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_angstrom) + + @property + def petagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_angstrom) + + @property + def teragrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_angstrom) + + @property + def gigagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_angstrom) + + @property + def megagrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_angstrom) + + @property + def kilograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_angstrom) + + @property + def milligrams_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_angstrom) + + @property + def micrograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_angstrom) + + @property + def nanograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_angstrom) + + @property + def picograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_angstrom) + + @property + def femtograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_angstrom) + + @property + def attograms_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_angstrom) + + @property + def atomic_mass_units_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_angstrom) + + @property + def pounds_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_angstrom) + + @property + def ounces_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_angstrom) + + @property + def grams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_mile) + + @property + def exagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_mile) + + @property + def petagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_mile) + + @property + def teragrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_mile) + + @property + def gigagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_mile) + + @property + def megagrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_mile) + + @property + def kilograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_mile) + + @property + def milligrams_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_mile) + + @property + def micrograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_mile) + + @property + def nanograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_mile) + + @property + def picograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_mile) + + @property + def femtograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_mile) + + @property + def attograms_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_mile) + + @property + def atomic_mass_units_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_mile) + + @property + def pounds_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_mile) + + @property + def ounces_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_mile) + + @property + def grams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_yard) + + @property + def exagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_yard) + + @property + def petagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_yard) + + @property + def teragrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_yard) + + @property + def gigagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_yard) + + @property + def megagrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_yard) + + @property + def kilograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_yard) + + @property + def milligrams_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_yard) + + @property + def micrograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_yard) + + @property + def nanograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_yard) + + @property + def picograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_yard) + + @property + def femtograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_yard) + + @property + def attograms_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_yard) + + @property + def atomic_mass_units_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_yard) + + @property + def pounds_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_yard) + + @property + def ounces_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_yard) + + @property + def grams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_foot) + + @property + def exagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_foot) + + @property + def petagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_foot) + + @property + def teragrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_foot) + + @property + def gigagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_foot) + + @property + def megagrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_foot) + + @property + def kilograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_foot) + + @property + def milligrams_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_foot) + + @property + def micrograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_foot) + + @property + def nanograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_foot) + + @property + def picograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_foot) + + @property + def femtograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_foot) + + @property + def attograms_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_foot) + + @property + def atomic_mass_units_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_foot) + + @property + def pounds_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_foot) + + @property + def ounces_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_foot) + + @property + def grams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.grams_per_cubic_inch) + + @property + def exagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exagrams_per_cubic_inch) + + @property + def petagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petagrams_per_cubic_inch) + + @property + def teragrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teragrams_per_cubic_inch) + + @property + def gigagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigagrams_per_cubic_inch) + + @property + def megagrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megagrams_per_cubic_inch) + + @property + def kilograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilograms_per_cubic_inch) + + @property + def milligrams_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milligrams_per_cubic_inch) + + @property + def micrograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micrograms_per_cubic_inch) + + @property + def nanograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanograms_per_cubic_inch) + + @property + def picograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picograms_per_cubic_inch) + + @property + def femtograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtograms_per_cubic_inch) + + @property + def attograms_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attograms_per_cubic_inch) + + @property + def atomic_mass_units_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.atomic_mass_units_per_cubic_inch) + + @property + def pounds_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_per_cubic_inch) + + @property + def ounces_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ounces_per_cubic_inch) + + + +class ForceAccessor[T](QuantityAccessor[T]): + dimension_name = 'force' + + @property + def newtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.newtons) + + @property + def exanewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exanewtons) + + @property + def petanewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petanewtons) + + @property + def teranewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teranewtons) + + @property + def giganewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.giganewtons) + + @property + def meganewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.meganewtons) + + @property + def kilonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilonewtons) + + @property + def millinewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millinewtons) + + @property + def micronewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micronewtons) + + @property + def nanonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanonewtons) + + @property + def piconewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.piconewtons) + + @property + def femtonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtonewtons) + + @property + def attonewtons(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attonewtons) + + @property + def kg_force(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kg_force) + + @property + def pounds_force(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_force) + + + +class PressureAccessor[T](QuantityAccessor[T]): + dimension_name = 'pressure' + + @property + def pascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pascals) + + @property + def exapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exapascals) + + @property + def petapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petapascals) + + @property + def terapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terapascals) + + @property + def gigapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigapascals) + + @property + def megapascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megapascals) + + @property + def kilopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilopascals) + + @property + def millipascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millipascals) + + @property + def micropascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micropascals) + + @property + def nanopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanopascals) + + @property + def picopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picopascals) + + @property + def femtopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtopascals) + + @property + def attopascals(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attopascals) + + @property + def pounds_force_per_square_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.pounds_force_per_square_inch) + + + +class EnergyAccessor[T](QuantityAccessor[T]): + dimension_name = 'energy' + + @property + def joules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.joules) + + @property + def exajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exajoules) + + @property + def petajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petajoules) + + @property + def terajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terajoules) + + @property + def gigajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigajoules) + + @property + def megajoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megajoules) + + @property + def kilojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilojoules) + + @property + def millijoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millijoules) + + @property + def microjoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microjoules) + + @property + def nanojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanojoules) + + @property + def picojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picojoules) + + @property + def femtojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtojoules) + + @property + def attojoules(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attojoules) + + @property + def electronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.electronvolts) + + @property + def exaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exaelectronvolts) + + @property + def petaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petaelectronvolts) + + @property + def teraelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teraelectronvolts) + + @property + def gigaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigaelectronvolts) + + @property + def megaelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megaelectronvolts) + + @property + def kiloelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kiloelectronvolts) + + @property + def millielectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millielectronvolts) + + @property + def microelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microelectronvolts) + + @property + def nanoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanoelectronvolts) + + @property + def picoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picoelectronvolts) + + @property + def femtoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtoelectronvolts) + + @property + def attoelectronvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attoelectronvolts) + + + +class PowerAccessor[T](QuantityAccessor[T]): + dimension_name = 'power' + + @property + def watts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.watts) + + @property + def exawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exawatts) + + @property + def petawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petawatts) + + @property + def terawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terawatts) + + @property + def gigawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigawatts) + + @property + def megawatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megawatts) + + @property + def kilowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilowatts) + + @property + def milliwatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliwatts) + + @property + def microwatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microwatts) + + @property + def nanowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanowatts) + + @property + def picowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picowatts) + + @property + def femtowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtowatts) + + @property + def attowatts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attowatts) + + + +class ChargeAccessor[T](QuantityAccessor[T]): + dimension_name = 'charge' + + @property + def coulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.coulombs) + + @property + def exacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exacoulombs) + + @property + def petacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petacoulombs) + + @property + def teracoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teracoulombs) + + @property + def gigacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigacoulombs) + + @property + def megacoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megacoulombs) + + @property + def kilocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilocoulombs) + + @property + def millicoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millicoulombs) + + @property + def microcoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microcoulombs) + + @property + def nanocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanocoulombs) + + @property + def picocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picocoulombs) + + @property + def femtocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtocoulombs) + + @property + def attocoulombs(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attocoulombs) + + + +class PotentialAccessor[T](QuantityAccessor[T]): + dimension_name = 'potential' + + @property + def volts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.volts) + + @property + def exavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exavolts) + + @property + def petavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petavolts) + + @property + def teravolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teravolts) + + @property + def gigavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigavolts) + + @property + def megavolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megavolts) + + @property + def kilovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilovolts) + + @property + def millivolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millivolts) + + @property + def microvolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microvolts) + + @property + def nanovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanovolts) + + @property + def picovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picovolts) + + @property + def femtovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtovolts) + + @property + def attovolts(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attovolts) + + + +class ResistanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'resistance' + + @property + def ohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.ohms) + + @property + def exaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exaohms) + + @property + def petaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petaohms) + + @property + def teraohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teraohms) + + @property + def gigaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigaohms) + + @property + def megaohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megaohms) + + @property + def kiloohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kiloohms) + + @property + def milliohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliohms) + + @property + def microohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microohms) + + @property + def nanoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanoohms) + + @property + def picoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picoohms) + + @property + def femtoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtoohms) + + @property + def attoohms(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attoohms) + + + +class CapacitanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'capacitance' + + @property + def farads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.farads) + + @property + def exafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exafarads) + + @property + def petafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petafarads) + + @property + def terafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terafarads) + + @property + def gigafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigafarads) + + @property + def megafarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megafarads) + + @property + def kilofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilofarads) + + @property + def millifarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millifarads) + + @property + def microfarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microfarads) + + @property + def nanofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanofarads) + + @property + def picofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picofarads) + + @property + def femtofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtofarads) + + @property + def attofarads(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attofarads) + + + +class ConductanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'conductance' + + @property + def siemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.siemens) + + @property + def exasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exasiemens) + + @property + def petasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petasiemens) + + @property + def terasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terasiemens) + + @property + def gigasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigasiemens) + + @property + def megasiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megasiemens) + + @property + def kilosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilosiemens) + + @property + def millisiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millisiemens) + + @property + def microsiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microsiemens) + + @property + def nanosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanosiemens) + + @property + def picosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picosiemens) + + @property + def femtosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtosiemens) + + @property + def attosiemens(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attosiemens) + + + +class MagneticfluxAccessor[T](QuantityAccessor[T]): + dimension_name = 'magnetic_flux' + + @property + def webers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.webers) + + @property + def exawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exawebers) + + @property + def petawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petawebers) + + @property + def terawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terawebers) + + @property + def gigawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigawebers) + + @property + def megawebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megawebers) + + @property + def kilowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilowebers) + + @property + def milliwebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.milliwebers) + + @property + def microwebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microwebers) + + @property + def nanowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanowebers) + + @property + def picowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picowebers) + + @property + def femtowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtowebers) + + @property + def attowebers(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attowebers) + + + +class MagneticfluxdensityAccessor[T](QuantityAccessor[T]): + dimension_name = 'magnetic_flux_density' + + @property + def tesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.tesla) + + @property + def exatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exatesla) + + @property + def petatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petatesla) + + @property + def teratesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.teratesla) + + @property + def gigatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigatesla) + + @property + def megatesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megatesla) + + @property + def kilotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilotesla) + + @property + def millitesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millitesla) + + @property + def microtesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microtesla) + + @property + def nanotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanotesla) + + @property + def picotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picotesla) + + @property + def femtotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtotesla) + + @property + def attotesla(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attotesla) + + + +class InductanceAccessor[T](QuantityAccessor[T]): + dimension_name = 'inductance' + + @property + def henry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.henry) + + @property + def exahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exahenry) + + @property + def petahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petahenry) + + @property + def terahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terahenry) + + @property + def gigahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigahenry) + + @property + def megahenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megahenry) + + @property + def kilohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilohenry) + + @property + def millihenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millihenry) + + @property + def microhenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microhenry) + + @property + def nanohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanohenry) + + @property + def picohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picohenry) + + @property + def femtohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtohenry) + + @property + def attohenry(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attohenry) + + + +class TemperatureAccessor[T](QuantityAccessor[T]): + dimension_name = 'temperature' + + @property + def kelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kelvin) + + @property + def exakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.exakelvin) + + @property + def petakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.petakelvin) + + @property + def terakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.terakelvin) + + @property + def gigakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.gigakelvin) + + @property + def megakelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.megakelvin) + + @property + def kilokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.kilokelvin) + + @property + def millikelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millikelvin) + + @property + def microkelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.microkelvin) + + @property + def nanokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanokelvin) + + @property + def picokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picokelvin) + + @property + def femtokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtokelvin) + + @property + def attokelvin(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attokelvin) + + @property + def degrees_celsius(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.degrees_celsius) + + + +class DimensionlessAccessor[T](QuantityAccessor[T]): + dimension_name = 'dimensionless' + + @property + def none(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.none) + + @property + def percent(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.percent) + + + +class AngleAccessor[T](QuantityAccessor[T]): + dimension_name = 'angle' + + @property + def degrees(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.degrees) + + @property + def radians(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.radians) + + + +class SolidangleAccessor[T](QuantityAccessor[T]): + dimension_name = 'solid_angle' + + @property + def stradians(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.stradians) + + + +class AmountAccessor[T](QuantityAccessor[T]): + dimension_name = 'amount' + + @property + def moles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles) + + @property + def millimoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles) + + @property + def micromoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles) + + @property + def nanomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles) + + @property + def picomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles) + + @property + def femtomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles) + + @property + def attomoles(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles) + + + +class ConcentrationAccessor[T](QuantityAccessor[T]): + dimension_name = 'concentration' + + @property + def moles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_meter) + + @property + def millimoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_meter) + + @property + def micromoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_meter) + + @property + def nanomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_meter) + + @property + def picomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_meter) + + @property + def femtomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_meter) + + @property + def attomoles_per_cubic_meter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_meter) + + @property + def moles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_exameter) + + @property + def millimoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_exameter) + + @property + def micromoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_exameter) + + @property + def nanomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_exameter) + + @property + def picomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_exameter) + + @property + def femtomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_exameter) + + @property + def attomoles_per_cubic_exameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_exameter) + + @property + def moles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_petameter) + + @property + def millimoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_petameter) + + @property + def micromoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_petameter) + + @property + def nanomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_petameter) + + @property + def picomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_petameter) + + @property + def femtomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_petameter) + + @property + def attomoles_per_cubic_petameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_petameter) + + @property + def moles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_terameter) + + @property + def millimoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_terameter) + + @property + def micromoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_terameter) + + @property + def nanomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_terameter) + + @property + def picomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_terameter) + + @property + def femtomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_terameter) + + @property + def attomoles_per_cubic_terameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_terameter) + + @property + def moles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_gigameter) + + @property + def millimoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_gigameter) + + @property + def micromoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_gigameter) + + @property + def nanomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_gigameter) + + @property + def picomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_gigameter) + + @property + def femtomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_gigameter) + + @property + def attomoles_per_cubic_gigameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_gigameter) + + @property + def moles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_megameter) + + @property + def millimoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_megameter) + + @property + def micromoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_megameter) + + @property + def nanomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_megameter) + + @property + def picomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_megameter) + + @property + def femtomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_megameter) + + @property + def attomoles_per_cubic_megameter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_megameter) + + @property + def moles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_kilometer) + + @property + def millimoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_kilometer) + + @property + def micromoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_kilometer) + + @property + def nanomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_kilometer) + + @property + def picomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_kilometer) + + @property + def femtomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_kilometer) + + @property + def attomoles_per_cubic_kilometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_kilometer) + + @property + def moles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_millimeter) + + @property + def millimoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_millimeter) + + @property + def micromoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_millimeter) + + @property + def nanomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_millimeter) + + @property + def picomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_millimeter) + + @property + def femtomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_millimeter) + + @property + def attomoles_per_cubic_millimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_millimeter) + + @property + def moles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_micrometer) + + @property + def millimoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_micrometer) + + @property + def micromoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_micrometer) + + @property + def nanomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_micrometer) + + @property + def picomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_micrometer) + + @property + def femtomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_micrometer) + + @property + def attomoles_per_cubic_micrometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_micrometer) + + @property + def moles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_nanometer) + + @property + def millimoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_nanometer) + + @property + def micromoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_nanometer) + + @property + def nanomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_nanometer) + + @property + def picomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_nanometer) + + @property + def femtomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_nanometer) + + @property + def attomoles_per_cubic_nanometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_nanometer) + + @property + def moles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_picometer) + + @property + def millimoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_picometer) + + @property + def micromoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_picometer) + + @property + def nanomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_picometer) + + @property + def picomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_picometer) + + @property + def femtomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_picometer) + + @property + def attomoles_per_cubic_picometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_picometer) + + @property + def moles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_femtometer) + + @property + def millimoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_femtometer) + + @property + def micromoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_femtometer) + + @property + def nanomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_femtometer) + + @property + def picomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_femtometer) + + @property + def femtomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_femtometer) + + @property + def attomoles_per_cubic_femtometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_femtometer) + + @property + def moles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_attometer) + + @property + def millimoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_attometer) + + @property + def micromoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_attometer) + + @property + def nanomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_attometer) + + @property + def picomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_attometer) + + @property + def femtomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_attometer) + + @property + def attomoles_per_cubic_attometer(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_attometer) + + @property + def moles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_decimeter) + + @property + def millimoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_decimeter) + + @property + def micromoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_decimeter) + + @property + def nanomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_decimeter) + + @property + def picomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_decimeter) + + @property + def femtomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_decimeter) + + @property + def attomoles_per_cubic_decimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_decimeter) + + @property + def moles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_centimeter) + + @property + def millimoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_centimeter) + + @property + def micromoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_centimeter) + + @property + def nanomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_centimeter) + + @property + def picomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_centimeter) + + @property + def femtomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_centimeter) + + @property + def attomoles_per_cubic_centimeter(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_centimeter) + + @property + def moles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_angstrom) + + @property + def millimoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_angstrom) + + @property + def micromoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_angstrom) + + @property + def nanomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_angstrom) + + @property + def picomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_angstrom) + + @property + def femtomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_angstrom) + + @property + def attomoles_per_cubic_angstrom(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_angstrom) + + @property + def moles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_mile) + + @property + def millimoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_mile) + + @property + def micromoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_mile) + + @property + def nanomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_mile) + + @property + def picomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_mile) + + @property + def femtomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_mile) + + @property + def attomoles_per_cubic_mile(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_mile) + + @property + def moles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_yard) + + @property + def millimoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_yard) + + @property + def micromoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_yard) + + @property + def nanomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_yard) + + @property + def picomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_yard) + + @property + def femtomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_yard) + + @property + def attomoles_per_cubic_yard(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_yard) + + @property + def moles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_foot) + + @property + def millimoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_foot) + + @property + def micromoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_foot) + + @property + def nanomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_foot) + + @property + def picomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_foot) + + @property + def femtomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_foot) + + @property + def attomoles_per_cubic_foot(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_foot) + + @property + def moles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.moles_per_cubic_inch) + + @property + def millimoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.millimoles_per_cubic_inch) + + @property + def micromoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.micromoles_per_cubic_inch) + + @property + def nanomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.nanomoles_per_cubic_inch) + + @property + def picomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.picomoles_per_cubic_inch) + + @property + def femtomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.femtomoles_per_cubic_inch) + + @property + def attomoles_per_cubic_inch(self) -> T: + quantity = self.quantity + if quantity is None: + return None + else: + return quantity.in_units_of(units.attomoles_per_cubic_inch) + + diff --git a/sasdata/quantities/numerical_encoding.py b/sasdata/quantities/numerical_encoding.py index cab930d55..64264aab7 100644 --- a/sasdata/quantities/numerical_encoding.py +++ b/sasdata/quantities/numerical_encoding.py @@ -1,72 +1,74 @@ -import base64 -import struct - -import numpy as np -from scipy.sparse import coo_array, coo_matrix, csc_array, csc_matrix, csr_array, csr_matrix - - -def numerical_encode(obj: int | float | np.ndarray | coo_matrix | coo_array | csr_matrix | csr_array | csc_matrix | csc_array): - - if isinstance(obj, int): - return {"type": "int", - "value": obj} - - elif isinstance(obj, float): - return {"type": "float", - "value": base64.b64encode(bytearray(struct.pack('d', obj))).decode("utf-8")} - - elif isinstance(obj, np.ndarray): - return { - "type": "numpy", - "value": base64.b64encode(obj.tobytes()).decode("utf-8"), - "dtype": obj.dtype.str, - "shape": list(obj.shape) - } - - elif isinstance(obj, (coo_matrix | coo_array | csr_matrix | csr_array | csc_matrix | csc_array)): - - output = { - "type": obj.__class__.__name__, # not robust to name changes, but more concise - "dtype": obj.dtype.str, - "shape": list(obj.shape) - } - - if isinstance(obj, (coo_array | coo_matrix)): - - output["data"] = numerical_encode(obj.data) - output["coords"] = [numerical_encode(coord) for coord in obj.coords] - - - elif isinstance(obj, (csr_array | csr_matrix)): - pass - - - elif isinstance(obj, (csc_array | csc_matrix)): - - pass - - - return output - - else: - raise TypeError(f"Cannot serialise object of type: {type(obj)}") - -def numerical_decode(data: dict[str, str | int | list[int]]) -> int | float | np.ndarray | coo_matrix | coo_array | csr_matrix | csr_array | csc_matrix | csc_array: - obj_type = data["type"] - - match obj_type: - case "int": - return int(data["value"]) - - case "float": - return struct.unpack('d', base64.b64decode(data["value"]))[0] - - case "numpy": - value = base64.b64decode(data["value"]) - dtype = np.dtype(data["dtype"]) - shape = tuple(data["shape"]) - return np.frombuffer(value, dtype=dtype).reshape(*shape) - - case _: - raise ValueError(f"Cannot decode objects of type '{obj_type}'") - + + +import base64 +import struct + +import numpy as np +from scipy.sparse import coo_array, coo_matrix, csc_array, csc_matrix, csr_array, csr_matrix + + +def numerical_encode(obj: int | float | np.ndarray | coo_matrix | coo_array | csr_matrix | csr_array | csc_matrix | csc_array): + + if isinstance(obj, int): + return {"type": "int", + "value": obj} + + elif isinstance(obj, float): + return {"type": "float", + "value": base64.b64encode(bytearray(struct.pack('d', obj))).decode("utf-8")} + + elif isinstance(obj, np.ndarray): + return { + "type": "numpy", + "value": base64.b64encode(obj.tobytes()).decode("utf-8"), + "dtype": obj.dtype.str, + "shape": list(obj.shape) + } + + elif isinstance(obj, (coo_matrix, coo_array, csr_matrix, csr_array, csc_matrix, csc_array)): + + output = { + "type": obj.__class__.__name__, # not robust to name changes, but more concise + "dtype": obj.dtype.str, + "shape": list(obj.shape) + } + + if isinstance(obj, (coo_array, coo_matrix)): + + output["data"] = numerical_encode(obj.data) + output["coords"] = [numerical_encode(coord) for coord in obj.coords] + + + elif isinstance(obj, (csr_array, csr_matrix)): + pass + + + elif isinstance(obj, (csc_array, csc_matrix)): + + pass + + + return output + + else: + raise TypeError(f"Cannot serialise object of type: {type(obj)}") + +def numerical_decode(data: dict[str, str | int | list[int]]) -> int | float | np.ndarray | coo_matrix | coo_array | csr_matrix | csr_array | csc_matrix | csc_array: + obj_type = data["type"] + + match obj_type: + case "int": + return int(data["value"]) + + case "float": + return struct.unpack('d', base64.b64decode(data["value"]))[0] + + case "numpy": + value = base64.b64decode(data["value"]) + dtype = np.dtype(data["dtype"]) + shape = tuple(data["shape"]) + return np.frombuffer(value, dtype=dtype).reshape(*shape) + + case _: + raise ValueError(f"Cannot decode objects of type '{obj_type}'") + diff --git a/sasdata/quantities/operations_examples.py b/sasdata/quantities/operations_examples.py new file mode 100644 index 000000000..29b50ccc0 --- /dev/null +++ b/sasdata/quantities/operations_examples.py @@ -0,0 +1,11 @@ +from sasdata.quantities.operations import Mul, Variable + +x = Variable("x") +y = Variable("y") +z = Variable("z") +f = Mul(Mul(x, y), z) + + +dfdx = f.derivative(x).derivative(y).derivative(z) + +print(dfdx.summary()) diff --git a/sasdata/quantities/plotting.py b/sasdata/quantities/plotting.py index b90f017c2..d4a99295c 100644 --- a/sasdata/quantities/plotting.py +++ b/sasdata/quantities/plotting.py @@ -1,23 +1,23 @@ -import matplotlib.pyplot as plt -from numpy.typing import ArrayLike - -from sasdata.quantities.quantity import NamedQuantity, Quantity - - -def quantity_plot(x: Quantity[ArrayLike], y: Quantity[ArrayLike], *args, **kwargs): - plt.plot(x.value, y.value, *args, **kwargs) - - x_name = x.name if isinstance(x, NamedQuantity) else "x" - y_name = y.name if isinstance(y, NamedQuantity) else "y" - - plt.xlabel(f"{x_name} / {x.units}") - plt.ylabel(f"{y_name} / {y.units}") - -def quantity_scatter(x: Quantity[ArrayLike], y: Quantity[ArrayLike], *args, **kwargs): - plt.scatter(x.value, y.value, *args, **kwargs) - - x_name = x.name if isinstance(x, NamedQuantity) else "x" - y_name = y.name if isinstance(y, NamedQuantity) else "y" - - plt.xlabel(f"{x_name} / {x.units}") - plt.ylabel(f"{y_name} / {y.units}") +import matplotlib.pyplot as plt +from numpy.typing import ArrayLike + +from sasdata.quantities.quantity import NamedQuantity, Quantity + + +def quantity_plot(x: Quantity[ArrayLike], y: Quantity[ArrayLike], *args, **kwargs): + plt.plot(x.value, y.value, *args, **kwargs) + + x_name = x.name if isinstance(x, NamedQuantity) else "x" + y_name = y.name if isinstance(y, NamedQuantity) else "y" + + plt.xlabel(f"{x_name} / {x.units}") + plt.ylabel(f"{y_name} / {y.units}") + +def quantity_scatter(x: Quantity[ArrayLike], y: Quantity[ArrayLike], *args, **kwargs): + plt.scatter(x.value, y.value, *args, **kwargs) + + x_name = x.name if isinstance(x, NamedQuantity) else "x" + y_name = y.name if isinstance(y, NamedQuantity) else "y" + + plt.xlabel(f"{x_name} / {x.units}") + plt.ylabel(f"{y_name} / {y.units}") diff --git a/sasdata/quantities/quantity.py b/sasdata/quantities/quantity.py index 7cc8f853e..5ac546024 100644 --- a/sasdata/quantities/quantity.py +++ b/sasdata/quantities/quantity.py @@ -1,14 +1,15 @@ + + + import hashlib import json from typing import Any, Self, TypeVar, Union -import h5py import numpy as np from numpy._typing import ArrayLike from sasdata.quantities import units from sasdata.quantities.numerical_encoding import numerical_decode, numerical_encode -from sasdata.quantities.unit_parser import parse_unit from sasdata.quantities.units import NamedUnit, Unit T = TypeVar("T") @@ -301,6 +302,9 @@ class Constant(ConstantBase): def __init__(self, value): self.value = value + def summary(self, indent_amount: int = 0, indent: str=" "): + return repr(self.value) + def evaluate(self, variables: dict[int, T]) -> T: return self.value @@ -961,7 +965,7 @@ def _summary_open(self): class UnitError(Exception): - """ Errors caused by unit specification not being correct """ + """Errors caused by unit specification not being correct""" def hash_data_via_numpy(*data: ArrayLike): @@ -1115,9 +1119,9 @@ def __init__(self, # TODO: Adding this method as a temporary measure but we need a single # method that does this. - def with_standard_error(self, standard_error: "Quantity"): + def with_standard_error(self, standard_error: Quantity): if standard_error.units.equivalent(self.units): - return Quantity( + return NamedQuantity( value=self.value, units=self.units, standard_error=standard_error.in_units_of(self.units),) @@ -1182,20 +1186,6 @@ def in_si_with_standard_error(self): else: return self.in_si(), None - def explicitly_formatted(self, unit_string: str) -> str: - """Returns quantity as a string with specific unit formatting - - Performs any necessary unit conversions, but maintains the exact unit - formatting provided by the user. This can be useful if you have a - power expressed in horsepower and you want it expressed as "745.7 N m/s" and not as "745.7 W". """ - unit = parse_unit(unit_string) - quantity = self.in_units_of(unit) - return f"{quantity} {unit_string}" - - def __eq__(self: Self, other: Self) -> bool | np.ndarray: - return self.value == other.in_units_of(self.units) - - def __mul__(self: Self, other: ArrayLike | Self ) -> Self: if isinstance(other, Quantity): return DerivedQuantity( @@ -1349,7 +1339,6 @@ def __pow__(self: Self, other: int | float): @staticmethod def _array_repr_format(arr: np.ndarray): - """ Format the array """ order = len(arr.shape) reshaped = arr.reshape(-1) @@ -1399,12 +1388,6 @@ def parse(number_or_string: str | ArrayLike, unit: str, absolute_temperature: Fa def string_repr(self): return str(self.hash_value) - def as_h5(self, group: h5py.Group, name: str): - """Add this data onto a group as a dataset under the given name""" - boxed = self.value if type(self.value) is np.ndarray else [self.value] - data = group.create_dataset(name, data=boxed) - data.attrs["units"] = self.units.ascii_symbol - class NamedQuantity[QuantityType](Quantity[QuantityType]): def __init__(self, diff --git a/sasdata/quantities/quantity_examples.py b/sasdata/quantities/quantity_examples.py new file mode 100644 index 000000000..cc12640db --- /dev/null +++ b/sasdata/quantities/quantity_examples.py @@ -0,0 +1,8 @@ +from sasdata.quantities import units +from sasdata.quantities.quantity import NamedQuantity + +x = NamedQuantity("x", 1, units.meters, standard_error=1) +y = NamedQuantity("y", 1, units.decimeters, standard_error=1) + +print(x+y) +print((x+y).to_units_of(units.centimeters)) diff --git a/sasdata/quantities/si.py b/sasdata/quantities/si.py index 947cc4a11..6e2b77169 100644 --- a/sasdata/quantities/si.py +++ b/sasdata/quantities/si.py @@ -5,75 +5,75 @@ Do not edit by hand, instead edit the files that build it (_build_tables.py) - - -DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt -D::::::::::::DDD N:::::::N N::::::N ttt:::t -D:::::::::::::::DD N::::::::N N::::::N t:::::t -DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t - D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt - D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t - D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t - D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt - D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t - D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t - D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t - D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt -DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t -D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t -D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt -DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt - - - - - - - - - dddddddd -EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB -E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B -E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B -EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy - E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y - E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y - E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y - E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y - E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y - E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y - E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y -EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y -E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y -E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y -EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y - y:::::y - y:::::y - y:::::y - y:::::y - yyyyyyy - - - - dddddddd -HHHHHHHHH HHHHHHHHH d::::::d -H:::::::H H:::::::H d::::::d -H:::::::H H:::::::H d::::::d -HH::::::H H::::::HH d:::::d - H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d - H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d - H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d - H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d - H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d - H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d - H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d - H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d -HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd -H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d -H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d -HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd - + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + """ diff --git a/sasdata/quantities/test_numerical_encoding.py b/sasdata/quantities/test_numerical_encoding.py new file mode 100644 index 000000000..80cfbad9a --- /dev/null +++ b/sasdata/quantities/test_numerical_encoding.py @@ -0,0 +1,68 @@ +""" Tests for the encoding and decoding of numerical data""" + +import numpy as np +import pytest + +from sasdata.quantities.numerical_encoding import numerical_encode, numerical_decode + + +@pytest.mark.parametrize("value", [-100.0, -10.0, -1.0, 0.0, 0.5, 1.0, 10.0, 100.0, 1e100]) +def test_float_encode_decode(value: float): + + assert isinstance(value, float) # Make sure we have the right inputs + + encoded = numerical_encode(value) + decoded = numerical_decode(encoded) + + assert isinstance(decoded, float) + assert value == decoded + +@pytest.mark.parametrize("value", [-100, -10, -1, 0, 1, 10, 100, 1000000000000000000000000000000000]) +def test_int_encode_decode(value: int): + + assert isinstance(value, int) # Make sure we have the right inputs + + encoded = numerical_encode(value) + decoded = numerical_decode(encoded) + + assert isinstance(decoded, int) + assert value == decoded + +@pytest.mark.parametrize("shape", [ + (2,3,4), + (1,2), + (10,5,10), + (1,), + (4,), + (0, ) ]) +def test_numpy_float_encode_decode(shape): + np.random.seed(1776) + test_matrix = np.random.rand(*shape) + + encoded = numerical_encode(test_matrix) + decoded = numerical_decode(encoded) + + assert decoded.dtype == test_matrix.dtype + assert decoded.shape == test_matrix.shape + assert np.all(decoded == test_matrix) + +@pytest.mark.parametrize("dtype", [int, float, complex]) +def test_numpy_dtypes_encode_decode(dtype): + test_matrix = np.zeros((3,3), dtype=dtype) + + encoded = numerical_encode(test_matrix) + decoded = numerical_decode(encoded) + + assert decoded.dtype == test_matrix.dtype + +@pytest.mark.parametrize("dtype", [int, float, complex]) +@pytest.mark.parametrize("shape, n, m", [ + ((8, 8), (1,3,5),(2,5,7)), + ((6, 8), (1,0,5),(0,5,0)), + ((6, 1), (1, 0, 5), (0, 0, 0)), +]) +def test_coo_matrix_encode_decode(shape, n, m, dtype): + + i_indices = + + values = np.arange(10) \ No newline at end of file diff --git a/sasdata/quantities/unit_formatting.py b/sasdata/quantities/unit_formatting.py index e63921329..904ce801f 100644 --- a/sasdata/quantities/unit_formatting.py +++ b/sasdata/quantities/unit_formatting.py @@ -1,4 +1,7 @@ + + + import numpy as np diff --git a/sasdata/quantities/unit_parser.py b/sasdata/quantities/unit_parser.py index a264489d6..26def035d 100644 --- a/sasdata/quantities/unit_parser.py +++ b/sasdata/quantities/unit_parser.py @@ -10,21 +10,16 @@ for group in all_units_groups: all_units.extend(group) - def split_unit_str(unit_str: str) -> list[str]: """Separate the letters from the numbers in unit_str""" - return findall(r"[A-Za-zΩ%Å]+|[-\d]+|/", unit_str) - + return findall(r'[A-Za-zΩ%Å]+|[-\d]+|/', unit_str) def validate_unit_str(unit_str: str) -> bool: """Validate whether unit_str is valid. This doesn't mean that the unit specified in unit_str exists but rather it only consists of letters, and numbers as a unit string should.""" - return fullmatch(r"[A-Za-zΩµ%Å^1-9⁻¹-⁹\-\+/\ \._]+", unit_str) is not None + return fullmatch(r'[A-Za-zΩ%Å^1-9\-\+/\ \.]+', unit_str) is not None - -def parse_single_unit( - unit_str: str, unit_group: UnitGroup | None = None, longest_unit: bool = True -) -> tuple[Unit | None, str]: +def parse_single_unit(unit_str: str, unit_group: UnitGroup | None = None, longest_unit: bool = True) -> tuple[Unit | None, str]: """Attempts to find a single unit for unit_str. Return this unit, and the remaining string in a tuple. If a unit cannot be parsed, the unit will be None, and the remaining string will be the entire unit_str. @@ -33,7 +28,7 @@ def parse_single_unit( If unit_group is set, it will only try to parse units within that group. This is useful for resolving ambiguities. """ - current_unit = "" + current_unit = '' string_pos = 0 if unit_group is None: lookup_dict = symbol_lookup @@ -41,45 +36,34 @@ def parse_single_unit( lookup_dict = dict([(name, unit) for name, unit in symbol_lookup.items() if unit in unit_group.units]) for next_char in unit_str: potential_unit_str = current_unit + next_char - potential_symbols = [ - symbol - for symbol, unit in lookup_dict.items() - if symbol.startswith(potential_unit_str) or unit.startswith(potential_unit_str) - ] + potential_symbols = [symbol for symbol in lookup_dict.keys() if symbol.startswith(potential_unit_str)] if len(potential_symbols) == 0: break string_pos += 1 current_unit = potential_unit_str - if not longest_unit and current_unit in lookup_dict: + if not longest_unit and current_unit in lookup_dict.keys(): break - if current_unit == "": + if current_unit == '': return None, unit_str - matching_types = [unit for symbol, unit in lookup_dict.items() if symbol == current_unit or unit == current_unit] - if not matching_types: - raise KeyError(f"No known type matching {current_unit}") - final_unit = matching_types[0] remaining_str = unit_str[string_pos::] - return final_unit, remaining_str - + return lookup_dict[current_unit], remaining_str -def parse_unit_strs(unit_str: str, current_units: list[Unit] | None = None, longest_unit: bool = True) -> list[Unit]: +def parse_unit_strs(unit_str: str, current_units: list[Unit] | None=None, longest_unit: bool = True) -> list[Unit]: """Recursively parse units from unit_str until no more characters are present.""" if current_units is None: current_units = [] - if unit_str == "": + if unit_str == '': return current_units parsed_unit, remaining_str = parse_single_unit(unit_str, longest_unit=longest_unit) if parsed_unit is not None: current_units += [parsed_unit] return parse_unit_strs(remaining_str, current_units, longest_unit) else: - raise ValueError(f"Could not interpret {remaining_str}") - + raise ValueError(f'Could not interpret {remaining_str}') # Its probably useful to work out the unit first, and then later work out if a named unit exists for it. Hence why there # are two functions. - def parse_unit_stack(unit_str: str, longest_unit: bool = True) -> list[Unit]: """Split unit_str into a stack of parsed units.""" unit_stack: list[Unit] = [] @@ -87,12 +71,12 @@ def parse_unit_stack(unit_str: str, longest_unit: bool = True) -> list[Unit]: inverse_next_unit = False for token in split_str: try: - if token == "/": + if token == '/': inverse_next_unit = True continue power = int(token) to_modify = unit_stack[-1] - modified = to_modify**power + modified = to_modify ** power # modified = unit_power(to_modify, power) unit_stack[-1] = modified except ValueError: @@ -109,34 +93,19 @@ def parse_unit_stack(unit_str: str, longest_unit: bool = True) -> list[Unit]: pass return unit_stack - -def known_mistake(unit_str: str) -> Unit | None: - """Take known broken units from historical files - and give them a reasonible parse""" - import sasdata.quantities.units as units - - mistakes = {"µm": units.micrometers, "per_centimeter": units.per_centimeter, "per_angstrom": units.per_angstrom} - if unit_str in mistakes: - return mistakes[unit_str] - return None - - def parse_unit(unit_str: str, longest_unit: bool = True) -> Unit: """Parse unit_str into a unit.""" - if result := known_mistake(unit_str): - return result try: if not validate_unit_str(unit_str): - raise ValueError(f"unit_str ({unit_str}) contains forbidden characters.") + raise ValueError('unit_str contains forbidden characters.') parsed_unit = Unit(1, Dimensions()) unit_stack = parse_unit_stack(unit_str, longest_unit) for unit in unit_stack: # parsed_unit = combine_units(parsed_unit, unit) parsed_unit *= unit return parsed_unit - except KeyError as ex: - raise ValueError(f"Unit string contains an unrecognised pattern: {unit_str}") from ex - + except KeyError: + raise ValueError('Unit string contains an unrecognised pattern.') def parse_unit_from_group(unit_str: str, from_group: UnitGroup) -> Unit | None: """Tries to use the given unit group to resolve ambiguities. Parse a unit twice with different options, and returns @@ -150,8 +119,7 @@ def parse_unit_from_group(unit_str: str, from_group: UnitGroup) -> Unit | None: else: return None - -def parse_named_unit(unit_string: str, rtol: float = 1e-14) -> NamedUnit: +def parse_named_unit(unit_string: str, rtol: float=1e-14) -> NamedUnit: """Parses unit into a named unit. Parses unit into a Unit if it is not already, and then finds an equivaelent named unit. Please note that this might not be the expected unit from the string itself. E.g. 'kgm/2' will become newtons. @@ -166,15 +134,14 @@ def parse_named_unit(unit_string: str, rtol: float = 1e-14) -> NamedUnit: else: return named_unit - -def find_named_unit(unit: Unit, rtol: float = 1e-14) -> NamedUnit | None: - """Find a named unit matching the one provided""" +def find_named_unit(unit: Unit, rtol: float=1e-14) -> NamedUnit | None: + """ Find a named unit matching the one provided """ dimension_hash = hash(unit.dimensions) if dimension_hash in unit_groups_by_dimension_hash: unit_group = unit_groups_by_dimension_hash[hash(unit.dimensions)] for named_unit in unit_group.units: - if abs(named_unit.scale - unit.scale) < rtol * named_unit.scale: + if abs(named_unit.scale - unit.scale) < rtol*named_unit.scale: return named_unit return None @@ -185,13 +152,14 @@ def parse_named_unit_from_group(unit_str: str, from_group: UnitGroup) -> NamedUn unit that is present in from_group is returned. This is useful in cases of ambiguities.""" parsed_unit = parse_unit_from_group(unit_str, from_group) if parsed_unit is None: - raise ValueError("That unit cannot be parsed from the specified group.") + raise ValueError('That unit cannot be parsed from the specified group.') return find_named_unit(parsed_unit) +def parse(string: str, + name_lookup: bool = True, + longest_unit: bool = True, + lookup_rtol: float = 1e-14): -def parse(string: str, name_lookup: bool = True, longest_unit: bool = True, lookup_rtol: float = 1e-14): - if type(string) is not str: - string = string.decode("utf-8") unit = parse_unit(string, longest_unit=longest_unit) if name_lookup: named = find_named_unit(unit, rtol=lookup_rtol) @@ -202,11 +170,11 @@ def parse(string: str, name_lookup: bool = True, longest_unit: bool = True, look if __name__ == "__main__": - to_parse = input("Enter a unit to parse: ") + to_parse = input('Enter a unit to parse: ') try: generic_unit = parse_unit(to_parse) - print(f"Generic Unit: {generic_unit}") + print(f'Generic Unit: {generic_unit}') named_unit = find_named_unit(generic_unit) - print(f"Named Unit: {named_unit}") + print(f'Named Unit: {named_unit}') except ValueError: - print("There is no named unit available.") + print('There is no named unit available.') diff --git a/sasdata/quantities/units.py b/sasdata/quantities/units.py index 7d03abda0..7c2698bcd 100644 --- a/sasdata/quantities/units.py +++ b/sasdata/quantities/units.py @@ -5,75 +5,75 @@ Do not edit by hand, instead edit the files that build it (_build_tables.py, _units_base.py) - - -DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt -D::::::::::::DDD N:::::::N N::::::N ttt:::t -D:::::::::::::::DD N::::::::N N::::::N t:::::t -DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t - D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt - D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t - D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t - D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt - D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t - D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t - D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t - D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt -DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t -D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t -D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt -DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt - - - - - - - - - dddddddd -EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB -E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B -E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B -EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B + + +DDDDDDDDDDDDD NNNNNNNN NNNNNNNN tttt +D::::::::::::DDD N:::::::N N::::::N ttt:::t +D:::::::::::::::DD N::::::::N N::::::N t:::::t +DDD:::::DDDDD:::::D N:::::::::N N::::::N t:::::t + D:::::D D:::::D ooooooooooo N::::::::::N N::::::N ooooooooooo ttttttt:::::ttttttt + D:::::D D:::::D oo:::::::::::oo N:::::::::::N N::::::N oo:::::::::::oo t:::::::::::::::::t + D:::::D D:::::Do:::::::::::::::o N:::::::N::::N N::::::No:::::::::::::::ot:::::::::::::::::t + D:::::D D:::::Do:::::ooooo:::::o N::::::N N::::N N::::::No:::::ooooo:::::otttttt:::::::tttttt + D:::::D D:::::Do::::o o::::o N::::::N N::::N:::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N:::::::::::No::::o o::::o t:::::t + D:::::D D:::::Do::::o o::::o N::::::N N::::::::::No::::o o::::o t:::::t + D:::::D D:::::D o::::o o::::o N::::::N N:::::::::No::::o o::::o t:::::t tttttt +DDD:::::DDDDD:::::D o:::::ooooo:::::o N::::::N N::::::::No:::::ooooo:::::o t::::::tttt:::::t +D:::::::::::::::DD o:::::::::::::::o N::::::N N:::::::No:::::::::::::::o tt::::::::::::::t +D::::::::::::DDD oo:::::::::::oo N::::::N N::::::N oo:::::::::::oo tt:::::::::::tt +DDDDDDDDDDDDD ooooooooooo NNNNNNNN NNNNNNN ooooooooooo ttttttttttt + + + + + + + + + dddddddd +EEEEEEEEEEEEEEEEEEEEEE d::::::d iiii tttt BBBBBBBBBBBBBBBBB +E::::::::::::::::::::E d::::::d i::::i ttt:::t B::::::::::::::::B +E::::::::::::::::::::E d::::::d iiii t:::::t B::::::BBBBBB:::::B +EE::::::EEEEEEEEE::::E d:::::d t:::::t BB:::::B B:::::B E:::::E EEEEEE ddddddddd:::::d iiiiiiittttttt:::::ttttttt B::::B B:::::Byyyyyyy yyyyyyy - E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y - E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y - E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y - E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y - E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y - E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y - E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y -EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y -E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y -E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y -EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y - y:::::y - y:::::y - y:::::y - y:::::y - yyyyyyy - - - - dddddddd -HHHHHHHHH HHHHHHHHH d::::::d -H:::::::H H:::::::H d::::::d -H:::::::H H:::::::H d::::::d -HH::::::H H::::::HH d:::::d - H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d - H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d - H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d - H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d - H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d - H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d - H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d - H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d -HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd -H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d -H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d -HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd - + E:::::E dd::::::::::::::d i:::::it:::::::::::::::::t B::::B B:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d::::::::::::::::d i::::it:::::::::::::::::t B::::BBBBBB:::::B y:::::y y:::::y + E:::::::::::::::E d:::::::ddddd:::::d i::::itttttt:::::::tttttt B:::::::::::::BB y:::::y y:::::y + E:::::::::::::::E d::::::d d:::::d i::::i t:::::t B::::BBBBBB:::::B y:::::y y:::::y + E::::::EEEEEEEEEE d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y y:::::y + E:::::E d:::::d d:::::d i::::i t:::::t B::::B B:::::B y:::::y:::::y + E:::::E EEEEEEd:::::d d:::::d i::::i t:::::t tttttt B::::B B:::::B y:::::::::y +EE::::::EEEEEEEE:::::Ed::::::ddddd::::::ddi::::::i t::::::tttt:::::t BB:::::BBBBBB::::::B y:::::::y +E::::::::::::::::::::E d:::::::::::::::::di::::::i tt::::::::::::::t B:::::::::::::::::B y:::::y +E::::::::::::::::::::E d:::::::::ddd::::di::::::i tt:::::::::::tt B::::::::::::::::B y:::::y +EEEEEEEEEEEEEEEEEEEEEE ddddddddd dddddiiiiiiii ttttttttttt BBBBBBBBBBBBBBBBB y:::::y + y:::::y + y:::::y + y:::::y + y:::::y + yyyyyyy + + + + dddddddd +HHHHHHHHH HHHHHHHHH d::::::d +H:::::::H H:::::::H d::::::d +H:::::::H H:::::::H d::::::d +HH::::::H H::::::HH d:::::d + H:::::H H:::::H aaaaaaaaaaaaa nnnn nnnnnnnn ddddddddd:::::d + H:::::H H:::::H a::::::::::::a n:::nn::::::::nn dd::::::::::::::d + H::::::HHHHH::::::H aaaaaaaaa:::::an::::::::::::::nn d::::::::::::::::d + H:::::::::::::::::H a::::ann:::::::::::::::nd:::::::ddddd:::::d + H:::::::::::::::::H aaaaaaa:::::a n:::::nnnn:::::nd::::::d d:::::d + H::::::HHHHH::::::H aa::::::::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::aaaa::::::a n::::n n::::nd:::::d d:::::d + H:::::H H:::::H a::::a a:::::a n::::n n::::nd:::::d d:::::d +HH::::::H H::::::HHa::::a a:::::a n::::n n::::nd::::::ddddd::::::dd +H:::::::H H:::::::Ha:::::aaaa::::::a n::::n n::::n d:::::::::::::::::d +H:::::::H H:::::::H a::::::::::aa:::a n::::n n::::n d:::::::::ddd::::d +HHHHHHHHH HHHHHHHHH aaaaaaaaaa aaaa nnnnnn nnnnnn ddddddddd ddddd + """ @@ -299,20 +299,17 @@ def _components(self, tokens: Sequence["UnitToken"]): pass def __mul__(self: Self, other: "Unit"): - if isinstance(other, Unit): - return Unit(self.scale * other.scale, self.dimensions * other.dimensions) - elif isinstance(other, (int, float)): - return Unit(other * self.scale, self.dimensions) - return NotImplemented + if not isinstance(other, Unit): + return NotImplemented + + return Unit(self.scale * other.scale, self.dimensions * other.dimensions) def __truediv__(self: Self, other: "Unit"): - if isinstance(other, Unit): - return Unit(self.scale / other.scale, self.dimensions / other.dimensions) - elif isinstance(other, (int, float)): - return Unit(self.scale / other, self.dimensions) - else: + if not isinstance(other, Unit): return NotImplemented + return Unit(self.scale / other.scale, self.dimensions / other.dimensions) + def __rtruediv__(self: Self, other: "Unit"): if isinstance(other, Unit): return Unit(other.scale / self.scale, other.dimensions / self.dimensions) @@ -380,27 +377,6 @@ def __init__(self, def __repr__(self): return self.name - def __eq__(self, other): - """Match other units exactly or match strings against ANY of our names""" - match other: - case str(): - return self.name == other or self.name == f"{other}s" or self.ascii_symbol == other or self.symbol == other - case NamedUnit(): - return self.name == other.name \ - and self.ascii_symbol == other.ascii_symbol and self.symbol == other.symbol - case Unit(): - return self.equivalent(other) and np.abs(np.log(self.scale/other.scale)) < 1e-5 - case _: - return False - - - def startswith(self, prefix: str) -> bool: - """Check if any representation of the unit begins with the prefix string""" - prefix = prefix.lower() - return (self.name is not None and self.name.lower().startswith(prefix)) \ - or (self.ascii_symbol is not None and self.ascii_symbol.lower().startswith(prefix)) \ - or (self.symbol is not None and self.symbol.lower().startswith(prefix)) - # # Parsing plan: # Require unknown amounts of units to be explicitly positive or negative? @@ -688,14 +664,12 @@ def __init__(self, name: str, units: list[NamedUnit]): femtohenry = NamedUnit(1e-15, Dimensions(2, -2, 1, -2, 0, 0, 0),name='femtohenry',ascii_symbol='fH',symbol='fH') attohenry = NamedUnit(1e-18, Dimensions(2, -2, 1, -2, 0, 0, 0),name='attohenry',ascii_symbol='aH',symbol='aH') angstroms = NamedUnit(1e-10, Dimensions(1, 0, 0, 0, 0, 0, 0),name='angstroms',ascii_symbol='Ang',latex_symbol=r'\AA',symbol='Å') -microns = NamedUnit(1e-06, Dimensions(1, 0, 0, 0, 0, 0, 0),name='microns',ascii_symbol='micron',symbol='micron') minutes = NamedUnit(60, Dimensions(0, 1, 0, 0, 0, 0, 0),name='minutes',ascii_symbol='min',symbol='min') -hours = NamedUnit(3600, Dimensions(0, 1, 0, 0, 0, 0, 0),name='hours',ascii_symbol='h',symbol='h') -days = NamedUnit(86400, Dimensions(0, 1, 0, 0, 0, 0, 0),name='days',ascii_symbol='d',symbol='d') -years = NamedUnit(31556952.0, Dimensions(0, 1, 0, 0, 0, 0, 0),name='years',ascii_symbol='y',symbol='y') +hours = NamedUnit(360, Dimensions(0, 1, 0, 0, 0, 0, 0),name='hours',ascii_symbol='h',symbol='h') +days = NamedUnit(8640, Dimensions(0, 1, 0, 0, 0, 0, 0),name='days',ascii_symbol='d',symbol='d') +years = NamedUnit(3155695.2, Dimensions(0, 1, 0, 0, 0, 0, 0),name='years',ascii_symbol='y',symbol='y') degrees = NamedUnit(57.29577951308232, Dimensions(0, 0, 0, 0, 0, 0, 1),name='degrees',ascii_symbol='deg',symbol='deg') radians = NamedUnit(1, Dimensions(0, 0, 0, 0, 0, 0, 1),name='radians',ascii_symbol='rad',symbol='rad') -rotations = NamedUnit(6.283185307179586, Dimensions(0, 0, 0, 0, 0, 0, 1),name='rotations',ascii_symbol='rot',symbol='rot') stradians = NamedUnit(1, Dimensions(0, 0, 0, 0, 0, 0, 2),name='stradians',ascii_symbol='sr',symbol='sr') litres = NamedUnit(0.001, Dimensions(3, 0, 0, 0, 0, 0, 0),name='litres',ascii_symbol='l',symbol='l') electronvolts = NamedUnit(1.602176634e-19, Dimensions(2, -2, 1, 0, 0, 0, 0),name='electronvolts',ascii_symbol='eV',symbol='eV') @@ -811,11 +785,6 @@ def __init__(self, name: str, units: list[NamedUnit]): per_angstrom = NamedUnit(10000000000.0, Dimensions(length=-1), name='per_angstrom', ascii_symbol='Ang^-1', symbol='Å⁻¹') per_square_angstrom = NamedUnit(1e+20, Dimensions(length=-2), name='per_square_angstrom', ascii_symbol='Ang^-2', symbol='Å⁻²') per_cubic_angstrom = NamedUnit(9.999999999999999e+29, Dimensions(length=-3), name='per_cubic_angstrom', ascii_symbol='Ang^-3', symbol='Å⁻³') -square_microns = NamedUnit(1e-12, Dimensions(length=2), name='square_microns', ascii_symbol='micron^2', symbol='micron²') -cubic_microns = NamedUnit(9.999999999999999e-19, Dimensions(length=3), name='cubic_microns', ascii_symbol='micron^3', symbol='micron³') -per_micron = NamedUnit(1000000.0, Dimensions(length=-1), name='per_micron', ascii_symbol='micron^-1', symbol='micron⁻¹') -per_square_micron = NamedUnit(1000000000000.0001, Dimensions(length=-2), name='per_square_micron', ascii_symbol='micron^-2', symbol='micron⁻²') -per_cubic_micron = NamedUnit(1.0000000000000001e+18, Dimensions(length=-3), name='per_cubic_micron', ascii_symbol='micron^-3', symbol='micron⁻³') square_miles = NamedUnit(2589988.110336, Dimensions(length=2), name='square_miles', ascii_symbol='miles^2', symbol='miles²') cubic_miles = NamedUnit(4168181825.44058, Dimensions(length=3), name='cubic_miles', ascii_symbol='miles^3', symbol='miles³') per_mile = NamedUnit(0.0006213711922373339, Dimensions(length=-1), name='per_mile', ascii_symbol='miles^-1', symbol='miles⁻¹') @@ -852,12 +821,12 @@ def __init__(self, name: str, units: list[NamedUnit]): meters_per_square_attosecond = NamedUnit(9.999999999999999e+35, Dimensions(length=1, time=-2), name='meters_per_square_attosecond', ascii_symbol='m/as^2', symbol='mas⁻²') meters_per_minute = NamedUnit(0.016666666666666666, Dimensions(length=1, time=-1), name='meters_per_minute', ascii_symbol='m/min', symbol='mmin⁻¹') meters_per_square_minute = NamedUnit(0.0002777777777777778, Dimensions(length=1, time=-2), name='meters_per_square_minute', ascii_symbol='m/min^2', symbol='mmin⁻²') -meters_per_hour = NamedUnit(0.0002777777777777778, Dimensions(length=1, time=-1), name='meters_per_hour', ascii_symbol='m/h', symbol='mh⁻¹') -meters_per_square_hour = NamedUnit(7.71604938271605e-08, Dimensions(length=1, time=-2), name='meters_per_square_hour', ascii_symbol='m/h^2', symbol='mh⁻²') -meters_per_day = NamedUnit(1.1574074074074073e-05, Dimensions(length=1, time=-1), name='meters_per_day', ascii_symbol='m/d', symbol='md⁻¹') -meters_per_square_day = NamedUnit(1.3395919067215363e-10, Dimensions(length=1, time=-2), name='meters_per_square_day', ascii_symbol='m/d^2', symbol='md⁻²') -meters_per_year = NamedUnit(3.168873850681143e-08, Dimensions(length=1, time=-1), name='meters_per_year', ascii_symbol='m/y', symbol='my⁻¹') -meters_per_square_year = NamedUnit(1.0041761481530735e-15, Dimensions(length=1, time=-2), name='meters_per_square_year', ascii_symbol='m/y^2', symbol='my⁻²') +meters_per_hour = NamedUnit(0.002777777777777778, Dimensions(length=1, time=-1), name='meters_per_hour', ascii_symbol='m/h', symbol='mh⁻¹') +meters_per_square_hour = NamedUnit(7.71604938271605e-06, Dimensions(length=1, time=-2), name='meters_per_square_hour', ascii_symbol='m/h^2', symbol='mh⁻²') +meters_per_day = NamedUnit(0.00011574074074074075, Dimensions(length=1, time=-1), name='meters_per_day', ascii_symbol='m/d', symbol='md⁻¹') +meters_per_square_day = NamedUnit(1.3395919067215363e-08, Dimensions(length=1, time=-2), name='meters_per_square_day', ascii_symbol='m/d^2', symbol='md⁻²') +meters_per_year = NamedUnit(3.168873850681143e-07, Dimensions(length=1, time=-1), name='meters_per_year', ascii_symbol='m/y', symbol='my⁻¹') +meters_per_square_year = NamedUnit(1.0041761481530735e-13, Dimensions(length=1, time=-2), name='meters_per_square_year', ascii_symbol='m/y^2', symbol='my⁻²') exameters_per_second = NamedUnit(1e+18, Dimensions(length=1, time=-1), name='exameters_per_second', ascii_symbol='Em/s', symbol='Ems⁻¹') exameters_per_square_second = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='exameters_per_square_second', ascii_symbol='Em/s^2', symbol='Ems⁻²') exameters_per_millisecond = NamedUnit(1e+21, Dimensions(length=1, time=-1), name='exameters_per_millisecond', ascii_symbol='Em/ms', symbol='Emms⁻¹') @@ -874,12 +843,12 @@ def __init__(self, name: str, units: list[NamedUnit]): exameters_per_square_attosecond = NamedUnit(9.999999999999999e+53, Dimensions(length=1, time=-2), name='exameters_per_square_attosecond', ascii_symbol='Em/as^2', symbol='Emas⁻²') exameters_per_minute = NamedUnit(1.6666666666666666e+16, Dimensions(length=1, time=-1), name='exameters_per_minute', ascii_symbol='Em/min', symbol='Emmin⁻¹') exameters_per_square_minute = NamedUnit(277777777777777.78, Dimensions(length=1, time=-2), name='exameters_per_square_minute', ascii_symbol='Em/min^2', symbol='Emmin⁻²') -exameters_per_hour = NamedUnit(277777777777777.78, Dimensions(length=1, time=-1), name='exameters_per_hour', ascii_symbol='Em/h', symbol='Emh⁻¹') -exameters_per_square_hour = NamedUnit(77160493827.16049, Dimensions(length=1, time=-2), name='exameters_per_square_hour', ascii_symbol='Em/h^2', symbol='Emh⁻²') -exameters_per_day = NamedUnit(11574074074074.074, Dimensions(length=1, time=-1), name='exameters_per_day', ascii_symbol='Em/d', symbol='Emd⁻¹') -exameters_per_square_day = NamedUnit(133959190.67215364, Dimensions(length=1, time=-2), name='exameters_per_square_day', ascii_symbol='Em/d^2', symbol='Emd⁻²') -exameters_per_year = NamedUnit(31688738506.81143, Dimensions(length=1, time=-1), name='exameters_per_year', ascii_symbol='Em/y', symbol='Emy⁻¹') -exameters_per_square_year = NamedUnit(1004.1761481530735, Dimensions(length=1, time=-2), name='exameters_per_square_year', ascii_symbol='Em/y^2', symbol='Emy⁻²') +exameters_per_hour = NamedUnit(2777777777777778.0, Dimensions(length=1, time=-1), name='exameters_per_hour', ascii_symbol='Em/h', symbol='Emh⁻¹') +exameters_per_square_hour = NamedUnit(7716049382716.05, Dimensions(length=1, time=-2), name='exameters_per_square_hour', ascii_symbol='Em/h^2', symbol='Emh⁻²') +exameters_per_day = NamedUnit(115740740740740.73, Dimensions(length=1, time=-1), name='exameters_per_day', ascii_symbol='Em/d', symbol='Emd⁻¹') +exameters_per_square_day = NamedUnit(13395919067.215364, Dimensions(length=1, time=-2), name='exameters_per_square_day', ascii_symbol='Em/d^2', symbol='Emd⁻²') +exameters_per_year = NamedUnit(316887385068.1143, Dimensions(length=1, time=-1), name='exameters_per_year', ascii_symbol='Em/y', symbol='Emy⁻¹') +exameters_per_square_year = NamedUnit(100417.61481530734, Dimensions(length=1, time=-2), name='exameters_per_square_year', ascii_symbol='Em/y^2', symbol='Emy⁻²') petameters_per_second = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='petameters_per_second', ascii_symbol='Pm/s', symbol='Pms⁻¹') petameters_per_square_second = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-2), name='petameters_per_square_second', ascii_symbol='Pm/s^2', symbol='Pms⁻²') petameters_per_millisecond = NamedUnit(1e+18, Dimensions(length=1, time=-1), name='petameters_per_millisecond', ascii_symbol='Pm/ms', symbol='Pmms⁻¹') @@ -896,12 +865,12 @@ def __init__(self, name: str, units: list[NamedUnit]): petameters_per_square_attosecond = NamedUnit(9.999999999999998e+50, Dimensions(length=1, time=-2), name='petameters_per_square_attosecond', ascii_symbol='Pm/as^2', symbol='Pmas⁻²') petameters_per_minute = NamedUnit(16666666666666.666, Dimensions(length=1, time=-1), name='petameters_per_minute', ascii_symbol='Pm/min', symbol='Pmmin⁻¹') petameters_per_square_minute = NamedUnit(277777777777.7778, Dimensions(length=1, time=-2), name='petameters_per_square_minute', ascii_symbol='Pm/min^2', symbol='Pmmin⁻²') -petameters_per_hour = NamedUnit(277777777777.7778, Dimensions(length=1, time=-1), name='petameters_per_hour', ascii_symbol='Pm/h', symbol='Pmh⁻¹') -petameters_per_square_hour = NamedUnit(77160493.82716049, Dimensions(length=1, time=-2), name='petameters_per_square_hour', ascii_symbol='Pm/h^2', symbol='Pmh⁻²') -petameters_per_day = NamedUnit(11574074074.074074, Dimensions(length=1, time=-1), name='petameters_per_day', ascii_symbol='Pm/d', symbol='Pmd⁻¹') -petameters_per_square_day = NamedUnit(133959.19067215364, Dimensions(length=1, time=-2), name='petameters_per_square_day', ascii_symbol='Pm/d^2', symbol='Pmd⁻²') -petameters_per_year = NamedUnit(31688738.506811433, Dimensions(length=1, time=-1), name='petameters_per_year', ascii_symbol='Pm/y', symbol='Pmy⁻¹') -petameters_per_square_year = NamedUnit(1.0041761481530735, Dimensions(length=1, time=-2), name='petameters_per_square_year', ascii_symbol='Pm/y^2', symbol='Pmy⁻²') +petameters_per_hour = NamedUnit(2777777777777.778, Dimensions(length=1, time=-1), name='petameters_per_hour', ascii_symbol='Pm/h', symbol='Pmh⁻¹') +petameters_per_square_hour = NamedUnit(7716049382.716049, Dimensions(length=1, time=-2), name='petameters_per_square_hour', ascii_symbol='Pm/h^2', symbol='Pmh⁻²') +petameters_per_day = NamedUnit(115740740740.74074, Dimensions(length=1, time=-1), name='petameters_per_day', ascii_symbol='Pm/d', symbol='Pmd⁻¹') +petameters_per_square_day = NamedUnit(13395919.067215364, Dimensions(length=1, time=-2), name='petameters_per_square_day', ascii_symbol='Pm/d^2', symbol='Pmd⁻²') +petameters_per_year = NamedUnit(316887385.0681143, Dimensions(length=1, time=-1), name='petameters_per_year', ascii_symbol='Pm/y', symbol='Pmy⁻¹') +petameters_per_square_year = NamedUnit(100.41761481530735, Dimensions(length=1, time=-2), name='petameters_per_square_year', ascii_symbol='Pm/y^2', symbol='Pmy⁻²') terameters_per_second = NamedUnit(1000000000000.0, Dimensions(length=1, time=-1), name='terameters_per_second', ascii_symbol='Tm/s', symbol='Tms⁻¹') terameters_per_square_second = NamedUnit(1000000000000.0, Dimensions(length=1, time=-2), name='terameters_per_square_second', ascii_symbol='Tm/s^2', symbol='Tms⁻²') terameters_per_millisecond = NamedUnit(1000000000000000.0, Dimensions(length=1, time=-1), name='terameters_per_millisecond', ascii_symbol='Tm/ms', symbol='Tmms⁻¹') @@ -918,12 +887,12 @@ def __init__(self, name: str, units: list[NamedUnit]): terameters_per_square_attosecond = NamedUnit(9.999999999999999e+47, Dimensions(length=1, time=-2), name='terameters_per_square_attosecond', ascii_symbol='Tm/as^2', symbol='Tmas⁻²') terameters_per_minute = NamedUnit(16666666666.666666, Dimensions(length=1, time=-1), name='terameters_per_minute', ascii_symbol='Tm/min', symbol='Tmmin⁻¹') terameters_per_square_minute = NamedUnit(277777777.7777778, Dimensions(length=1, time=-2), name='terameters_per_square_minute', ascii_symbol='Tm/min^2', symbol='Tmmin⁻²') -terameters_per_hour = NamedUnit(277777777.7777778, Dimensions(length=1, time=-1), name='terameters_per_hour', ascii_symbol='Tm/h', symbol='Tmh⁻¹') -terameters_per_square_hour = NamedUnit(77160.49382716049, Dimensions(length=1, time=-2), name='terameters_per_square_hour', ascii_symbol='Tm/h^2', symbol='Tmh⁻²') -terameters_per_day = NamedUnit(11574074.074074075, Dimensions(length=1, time=-1), name='terameters_per_day', ascii_symbol='Tm/d', symbol='Tmd⁻¹') -terameters_per_square_day = NamedUnit(133.95919067215362, Dimensions(length=1, time=-2), name='terameters_per_square_day', ascii_symbol='Tm/d^2', symbol='Tmd⁻²') -terameters_per_year = NamedUnit(31688.73850681143, Dimensions(length=1, time=-1), name='terameters_per_year', ascii_symbol='Tm/y', symbol='Tmy⁻¹') -terameters_per_square_year = NamedUnit(0.0010041761481530736, Dimensions(length=1, time=-2), name='terameters_per_square_year', ascii_symbol='Tm/y^2', symbol='Tmy⁻²') +terameters_per_hour = NamedUnit(2777777777.7777777, Dimensions(length=1, time=-1), name='terameters_per_hour', ascii_symbol='Tm/h', symbol='Tmh⁻¹') +terameters_per_square_hour = NamedUnit(7716049.382716049, Dimensions(length=1, time=-2), name='terameters_per_square_hour', ascii_symbol='Tm/h^2', symbol='Tmh⁻²') +terameters_per_day = NamedUnit(115740740.74074075, Dimensions(length=1, time=-1), name='terameters_per_day', ascii_symbol='Tm/d', symbol='Tmd⁻¹') +terameters_per_square_day = NamedUnit(13395.919067215364, Dimensions(length=1, time=-2), name='terameters_per_square_day', ascii_symbol='Tm/d^2', symbol='Tmd⁻²') +terameters_per_year = NamedUnit(316887.38506811426, Dimensions(length=1, time=-1), name='terameters_per_year', ascii_symbol='Tm/y', symbol='Tmy⁻¹') +terameters_per_square_year = NamedUnit(0.10041761481530735, Dimensions(length=1, time=-2), name='terameters_per_square_year', ascii_symbol='Tm/y^2', symbol='Tmy⁻²') gigameters_per_second = NamedUnit(1000000000.0, Dimensions(length=1, time=-1), name='gigameters_per_second', ascii_symbol='Gm/s', symbol='Gms⁻¹') gigameters_per_square_second = NamedUnit(1000000000.0, Dimensions(length=1, time=-2), name='gigameters_per_square_second', ascii_symbol='Gm/s^2', symbol='Gms⁻²') gigameters_per_millisecond = NamedUnit(1000000000000.0, Dimensions(length=1, time=-1), name='gigameters_per_millisecond', ascii_symbol='Gm/ms', symbol='Gmms⁻¹') @@ -940,12 +909,12 @@ def __init__(self, name: str, units: list[NamedUnit]): gigameters_per_square_attosecond = NamedUnit(1e+45, Dimensions(length=1, time=-2), name='gigameters_per_square_attosecond', ascii_symbol='Gm/as^2', symbol='Gmas⁻²') gigameters_per_minute = NamedUnit(16666666.666666666, Dimensions(length=1, time=-1), name='gigameters_per_minute', ascii_symbol='Gm/min', symbol='Gmmin⁻¹') gigameters_per_square_minute = NamedUnit(277777.77777777775, Dimensions(length=1, time=-2), name='gigameters_per_square_minute', ascii_symbol='Gm/min^2', symbol='Gmmin⁻²') -gigameters_per_hour = NamedUnit(277777.77777777775, Dimensions(length=1, time=-1), name='gigameters_per_hour', ascii_symbol='Gm/h', symbol='Gmh⁻¹') -gigameters_per_square_hour = NamedUnit(77.1604938271605, Dimensions(length=1, time=-2), name='gigameters_per_square_hour', ascii_symbol='Gm/h^2', symbol='Gmh⁻²') -gigameters_per_day = NamedUnit(11574.074074074075, Dimensions(length=1, time=-1), name='gigameters_per_day', ascii_symbol='Gm/d', symbol='Gmd⁻¹') -gigameters_per_square_day = NamedUnit(0.13395919067215364, Dimensions(length=1, time=-2), name='gigameters_per_square_day', ascii_symbol='Gm/d^2', symbol='Gmd⁻²') -gigameters_per_year = NamedUnit(31.688738506811433, Dimensions(length=1, time=-1), name='gigameters_per_year', ascii_symbol='Gm/y', symbol='Gmy⁻¹') -gigameters_per_square_year = NamedUnit(1.0041761481530736e-06, Dimensions(length=1, time=-2), name='gigameters_per_square_year', ascii_symbol='Gm/y^2', symbol='Gmy⁻²') +gigameters_per_hour = NamedUnit(2777777.777777778, Dimensions(length=1, time=-1), name='gigameters_per_hour', ascii_symbol='Gm/h', symbol='Gmh⁻¹') +gigameters_per_square_hour = NamedUnit(7716.049382716049, Dimensions(length=1, time=-2), name='gigameters_per_square_hour', ascii_symbol='Gm/h^2', symbol='Gmh⁻²') +gigameters_per_day = NamedUnit(115740.74074074074, Dimensions(length=1, time=-1), name='gigameters_per_day', ascii_symbol='Gm/d', symbol='Gmd⁻¹') +gigameters_per_square_day = NamedUnit(13.395919067215363, Dimensions(length=1, time=-2), name='gigameters_per_square_day', ascii_symbol='Gm/d^2', symbol='Gmd⁻²') +gigameters_per_year = NamedUnit(316.88738506811427, Dimensions(length=1, time=-1), name='gigameters_per_year', ascii_symbol='Gm/y', symbol='Gmy⁻¹') +gigameters_per_square_year = NamedUnit(0.00010041761481530735, Dimensions(length=1, time=-2), name='gigameters_per_square_year', ascii_symbol='Gm/y^2', symbol='Gmy⁻²') megameters_per_second = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='megameters_per_second', ascii_symbol='Mm/s', symbol='Mms⁻¹') megameters_per_square_second = NamedUnit(1000000.0, Dimensions(length=1, time=-2), name='megameters_per_square_second', ascii_symbol='Mm/s^2', symbol='Mms⁻²') megameters_per_millisecond = NamedUnit(1000000000.0, Dimensions(length=1, time=-1), name='megameters_per_millisecond', ascii_symbol='Mm/ms', symbol='Mmms⁻¹') @@ -962,12 +931,12 @@ def __init__(self, name: str, units: list[NamedUnit]): megameters_per_square_attosecond = NamedUnit(9.999999999999999e+41, Dimensions(length=1, time=-2), name='megameters_per_square_attosecond', ascii_symbol='Mm/as^2', symbol='Mmas⁻²') megameters_per_minute = NamedUnit(16666.666666666668, Dimensions(length=1, time=-1), name='megameters_per_minute', ascii_symbol='Mm/min', symbol='Mmmin⁻¹') megameters_per_square_minute = NamedUnit(277.77777777777777, Dimensions(length=1, time=-2), name='megameters_per_square_minute', ascii_symbol='Mm/min^2', symbol='Mmmin⁻²') -megameters_per_hour = NamedUnit(277.77777777777777, Dimensions(length=1, time=-1), name='megameters_per_hour', ascii_symbol='Mm/h', symbol='Mmh⁻¹') -megameters_per_square_hour = NamedUnit(0.07716049382716049, Dimensions(length=1, time=-2), name='megameters_per_square_hour', ascii_symbol='Mm/h^2', symbol='Mmh⁻²') -megameters_per_day = NamedUnit(11.574074074074074, Dimensions(length=1, time=-1), name='megameters_per_day', ascii_symbol='Mm/d', symbol='Mmd⁻¹') -megameters_per_square_day = NamedUnit(0.00013395919067215364, Dimensions(length=1, time=-2), name='megameters_per_square_day', ascii_symbol='Mm/d^2', symbol='Mmd⁻²') -megameters_per_year = NamedUnit(0.031688738506811434, Dimensions(length=1, time=-1), name='megameters_per_year', ascii_symbol='Mm/y', symbol='Mmy⁻¹') -megameters_per_square_year = NamedUnit(1.0041761481530736e-09, Dimensions(length=1, time=-2), name='megameters_per_square_year', ascii_symbol='Mm/y^2', symbol='Mmy⁻²') +megameters_per_hour = NamedUnit(2777.777777777778, Dimensions(length=1, time=-1), name='megameters_per_hour', ascii_symbol='Mm/h', symbol='Mmh⁻¹') +megameters_per_square_hour = NamedUnit(7.716049382716049, Dimensions(length=1, time=-2), name='megameters_per_square_hour', ascii_symbol='Mm/h^2', symbol='Mmh⁻²') +megameters_per_day = NamedUnit(115.74074074074075, Dimensions(length=1, time=-1), name='megameters_per_day', ascii_symbol='Mm/d', symbol='Mmd⁻¹') +megameters_per_square_day = NamedUnit(0.013395919067215363, Dimensions(length=1, time=-2), name='megameters_per_square_day', ascii_symbol='Mm/d^2', symbol='Mmd⁻²') +megameters_per_year = NamedUnit(0.3168873850681143, Dimensions(length=1, time=-1), name='megameters_per_year', ascii_symbol='Mm/y', symbol='Mmy⁻¹') +megameters_per_square_year = NamedUnit(1.0041761481530735e-07, Dimensions(length=1, time=-2), name='megameters_per_square_year', ascii_symbol='Mm/y^2', symbol='Mmy⁻²') kilometers_per_second = NamedUnit(1000.0, Dimensions(length=1, time=-1), name='kilometers_per_second', ascii_symbol='km/s', symbol='kms⁻¹') kilometers_per_square_second = NamedUnit(1000.0, Dimensions(length=1, time=-2), name='kilometers_per_square_second', ascii_symbol='km/s^2', symbol='kms⁻²') kilometers_per_millisecond = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='kilometers_per_millisecond', ascii_symbol='km/ms', symbol='kmms⁻¹') @@ -984,12 +953,12 @@ def __init__(self, name: str, units: list[NamedUnit]): kilometers_per_square_attosecond = NamedUnit(1e+39, Dimensions(length=1, time=-2), name='kilometers_per_square_attosecond', ascii_symbol='km/as^2', symbol='kmas⁻²') kilometers_per_minute = NamedUnit(16.666666666666668, Dimensions(length=1, time=-1), name='kilometers_per_minute', ascii_symbol='km/min', symbol='kmmin⁻¹') kilometers_per_square_minute = NamedUnit(0.2777777777777778, Dimensions(length=1, time=-2), name='kilometers_per_square_minute', ascii_symbol='km/min^2', symbol='kmmin⁻²') -kilometers_per_hour = NamedUnit(0.2777777777777778, Dimensions(length=1, time=-1), name='kilometers_per_hour', ascii_symbol='km/h', symbol='kmh⁻¹') -kilometers_per_square_hour = NamedUnit(7.716049382716049e-05, Dimensions(length=1, time=-2), name='kilometers_per_square_hour', ascii_symbol='km/h^2', symbol='kmh⁻²') -kilometers_per_day = NamedUnit(0.011574074074074073, Dimensions(length=1, time=-1), name='kilometers_per_day', ascii_symbol='km/d', symbol='kmd⁻¹') -kilometers_per_square_day = NamedUnit(1.3395919067215364e-07, Dimensions(length=1, time=-2), name='kilometers_per_square_day', ascii_symbol='km/d^2', symbol='kmd⁻²') -kilometers_per_year = NamedUnit(3.168873850681143e-05, Dimensions(length=1, time=-1), name='kilometers_per_year', ascii_symbol='km/y', symbol='kmy⁻¹') -kilometers_per_square_year = NamedUnit(1.0041761481530736e-12, Dimensions(length=1, time=-2), name='kilometers_per_square_year', ascii_symbol='km/y^2', symbol='kmy⁻²') +kilometers_per_hour = NamedUnit(2.7777777777777777, Dimensions(length=1, time=-1), name='kilometers_per_hour', ascii_symbol='km/h', symbol='kmh⁻¹') +kilometers_per_square_hour = NamedUnit(0.007716049382716049, Dimensions(length=1, time=-2), name='kilometers_per_square_hour', ascii_symbol='km/h^2', symbol='kmh⁻²') +kilometers_per_day = NamedUnit(0.11574074074074074, Dimensions(length=1, time=-1), name='kilometers_per_day', ascii_symbol='km/d', symbol='kmd⁻¹') +kilometers_per_square_day = NamedUnit(1.3395919067215363e-05, Dimensions(length=1, time=-2), name='kilometers_per_square_day', ascii_symbol='km/d^2', symbol='kmd⁻²') +kilometers_per_year = NamedUnit(0.0003168873850681143, Dimensions(length=1, time=-1), name='kilometers_per_year', ascii_symbol='km/y', symbol='kmy⁻¹') +kilometers_per_square_year = NamedUnit(1.0041761481530735e-10, Dimensions(length=1, time=-2), name='kilometers_per_square_year', ascii_symbol='km/y^2', symbol='kmy⁻²') millimeters_per_second = NamedUnit(0.001, Dimensions(length=1, time=-1), name='millimeters_per_second', ascii_symbol='mm/s', symbol='mms⁻¹') millimeters_per_square_second = NamedUnit(0.001, Dimensions(length=1, time=-2), name='millimeters_per_square_second', ascii_symbol='mm/s^2', symbol='mms⁻²') millimeters_per_millisecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='millimeters_per_millisecond', ascii_symbol='mm/ms', symbol='mmms⁻¹') @@ -1006,12 +975,12 @@ def __init__(self, name: str, units: list[NamedUnit]): millimeters_per_square_attosecond = NamedUnit(1e+33, Dimensions(length=1, time=-2), name='millimeters_per_square_attosecond', ascii_symbol='mm/as^2', symbol='mmas⁻²') millimeters_per_minute = NamedUnit(1.6666666666666667e-05, Dimensions(length=1, time=-1), name='millimeters_per_minute', ascii_symbol='mm/min', symbol='mmmin⁻¹') millimeters_per_square_minute = NamedUnit(2.7777777777777776e-07, Dimensions(length=1, time=-2), name='millimeters_per_square_minute', ascii_symbol='mm/min^2', symbol='mmmin⁻²') -millimeters_per_hour = NamedUnit(2.7777777777777776e-07, Dimensions(length=1, time=-1), name='millimeters_per_hour', ascii_symbol='mm/h', symbol='mmh⁻¹') -millimeters_per_square_hour = NamedUnit(7.716049382716049e-11, Dimensions(length=1, time=-2), name='millimeters_per_square_hour', ascii_symbol='mm/h^2', symbol='mmh⁻²') -millimeters_per_day = NamedUnit(1.1574074074074074e-08, Dimensions(length=1, time=-1), name='millimeters_per_day', ascii_symbol='mm/d', symbol='mmd⁻¹') -millimeters_per_square_day = NamedUnit(1.3395919067215364e-13, Dimensions(length=1, time=-2), name='millimeters_per_square_day', ascii_symbol='mm/d^2', symbol='mmd⁻²') -millimeters_per_year = NamedUnit(3.168873850681143e-11, Dimensions(length=1, time=-1), name='millimeters_per_year', ascii_symbol='mm/y', symbol='mmy⁻¹') -millimeters_per_square_year = NamedUnit(1.0041761481530737e-18, Dimensions(length=1, time=-2), name='millimeters_per_square_year', ascii_symbol='mm/y^2', symbol='mmy⁻²') +millimeters_per_hour = NamedUnit(2.777777777777778e-06, Dimensions(length=1, time=-1), name='millimeters_per_hour', ascii_symbol='mm/h', symbol='mmh⁻¹') +millimeters_per_square_hour = NamedUnit(7.71604938271605e-09, Dimensions(length=1, time=-2), name='millimeters_per_square_hour', ascii_symbol='mm/h^2', symbol='mmh⁻²') +millimeters_per_day = NamedUnit(1.1574074074074074e-07, Dimensions(length=1, time=-1), name='millimeters_per_day', ascii_symbol='mm/d', symbol='mmd⁻¹') +millimeters_per_square_day = NamedUnit(1.3395919067215364e-11, Dimensions(length=1, time=-2), name='millimeters_per_square_day', ascii_symbol='mm/d^2', symbol='mmd⁻²') +millimeters_per_year = NamedUnit(3.168873850681143e-10, Dimensions(length=1, time=-1), name='millimeters_per_year', ascii_symbol='mm/y', symbol='mmy⁻¹') +millimeters_per_square_year = NamedUnit(1.0041761481530735e-16, Dimensions(length=1, time=-2), name='millimeters_per_square_year', ascii_symbol='mm/y^2', symbol='mmy⁻²') micrometers_per_second = NamedUnit(1e-06, Dimensions(length=1, time=-1), name='micrometers_per_second', ascii_symbol='um/s', symbol='µms⁻¹') micrometers_per_square_second = NamedUnit(1e-06, Dimensions(length=1, time=-2), name='micrometers_per_square_second', ascii_symbol='um/s^2', symbol='µms⁻²') micrometers_per_millisecond = NamedUnit(0.001, Dimensions(length=1, time=-1), name='micrometers_per_millisecond', ascii_symbol='um/ms', symbol='µmms⁻¹') @@ -1028,12 +997,12 @@ def __init__(self, name: str, units: list[NamedUnit]): micrometers_per_square_attosecond = NamedUnit(9.999999999999999e+29, Dimensions(length=1, time=-2), name='micrometers_per_square_attosecond', ascii_symbol='um/as^2', symbol='µmas⁻²') micrometers_per_minute = NamedUnit(1.6666666666666667e-08, Dimensions(length=1, time=-1), name='micrometers_per_minute', ascii_symbol='um/min', symbol='µmmin⁻¹') micrometers_per_square_minute = NamedUnit(2.7777777777777777e-10, Dimensions(length=1, time=-2), name='micrometers_per_square_minute', ascii_symbol='um/min^2', symbol='µmmin⁻²') -micrometers_per_hour = NamedUnit(2.7777777777777777e-10, Dimensions(length=1, time=-1), name='micrometers_per_hour', ascii_symbol='um/h', symbol='µmh⁻¹') -micrometers_per_square_hour = NamedUnit(7.71604938271605e-14, Dimensions(length=1, time=-2), name='micrometers_per_square_hour', ascii_symbol='um/h^2', symbol='µmh⁻²') -micrometers_per_day = NamedUnit(1.1574074074074074e-11, Dimensions(length=1, time=-1), name='micrometers_per_day', ascii_symbol='um/d', symbol='µmd⁻¹') -micrometers_per_square_day = NamedUnit(1.3395919067215363e-16, Dimensions(length=1, time=-2), name='micrometers_per_square_day', ascii_symbol='um/d^2', symbol='µmd⁻²') -micrometers_per_year = NamedUnit(3.168873850681143e-14, Dimensions(length=1, time=-1), name='micrometers_per_year', ascii_symbol='um/y', symbol='µmy⁻¹') -micrometers_per_square_year = NamedUnit(1.0041761481530736e-21, Dimensions(length=1, time=-2), name='micrometers_per_square_year', ascii_symbol='um/y^2', symbol='µmy⁻²') +micrometers_per_hour = NamedUnit(2.7777777777777776e-09, Dimensions(length=1, time=-1), name='micrometers_per_hour', ascii_symbol='um/h', symbol='µmh⁻¹') +micrometers_per_square_hour = NamedUnit(7.716049382716049e-12, Dimensions(length=1, time=-2), name='micrometers_per_square_hour', ascii_symbol='um/h^2', symbol='µmh⁻²') +micrometers_per_day = NamedUnit(1.1574074074074074e-10, Dimensions(length=1, time=-1), name='micrometers_per_day', ascii_symbol='um/d', symbol='µmd⁻¹') +micrometers_per_square_day = NamedUnit(1.3395919067215363e-14, Dimensions(length=1, time=-2), name='micrometers_per_square_day', ascii_symbol='um/d^2', symbol='µmd⁻²') +micrometers_per_year = NamedUnit(3.168873850681143e-13, Dimensions(length=1, time=-1), name='micrometers_per_year', ascii_symbol='um/y', symbol='µmy⁻¹') +micrometers_per_square_year = NamedUnit(1.0041761481530734e-19, Dimensions(length=1, time=-2), name='micrometers_per_square_year', ascii_symbol='um/y^2', symbol='µmy⁻²') nanometers_per_second = NamedUnit(1e-09, Dimensions(length=1, time=-1), name='nanometers_per_second', ascii_symbol='nm/s', symbol='nms⁻¹') nanometers_per_square_second = NamedUnit(1e-09, Dimensions(length=1, time=-2), name='nanometers_per_square_second', ascii_symbol='nm/s^2', symbol='nms⁻²') nanometers_per_millisecond = NamedUnit(1e-06, Dimensions(length=1, time=-1), name='nanometers_per_millisecond', ascii_symbol='nm/ms', symbol='nmms⁻¹') @@ -1050,12 +1019,12 @@ def __init__(self, name: str, units: list[NamedUnit]): nanometers_per_square_attosecond = NamedUnit(1e+27, Dimensions(length=1, time=-2), name='nanometers_per_square_attosecond', ascii_symbol='nm/as^2', symbol='nmas⁻²') nanometers_per_minute = NamedUnit(1.6666666666666667e-11, Dimensions(length=1, time=-1), name='nanometers_per_minute', ascii_symbol='nm/min', symbol='nmmin⁻¹') nanometers_per_square_minute = NamedUnit(2.777777777777778e-13, Dimensions(length=1, time=-2), name='nanometers_per_square_minute', ascii_symbol='nm/min^2', symbol='nmmin⁻²') -nanometers_per_hour = NamedUnit(2.777777777777778e-13, Dimensions(length=1, time=-1), name='nanometers_per_hour', ascii_symbol='nm/h', symbol='nmh⁻¹') -nanometers_per_square_hour = NamedUnit(7.71604938271605e-17, Dimensions(length=1, time=-2), name='nanometers_per_square_hour', ascii_symbol='nm/h^2', symbol='nmh⁻²') -nanometers_per_day = NamedUnit(1.1574074074074075e-14, Dimensions(length=1, time=-1), name='nanometers_per_day', ascii_symbol='nm/d', symbol='nmd⁻¹') -nanometers_per_square_day = NamedUnit(1.3395919067215365e-19, Dimensions(length=1, time=-2), name='nanometers_per_square_day', ascii_symbol='nm/d^2', symbol='nmd⁻²') -nanometers_per_year = NamedUnit(3.1688738506811435e-17, Dimensions(length=1, time=-1), name='nanometers_per_year', ascii_symbol='nm/y', symbol='nmy⁻¹') -nanometers_per_square_year = NamedUnit(1.0041761481530737e-24, Dimensions(length=1, time=-2), name='nanometers_per_square_year', ascii_symbol='nm/y^2', symbol='nmy⁻²') +nanometers_per_hour = NamedUnit(2.777777777777778e-12, Dimensions(length=1, time=-1), name='nanometers_per_hour', ascii_symbol='nm/h', symbol='nmh⁻¹') +nanometers_per_square_hour = NamedUnit(7.71604938271605e-15, Dimensions(length=1, time=-2), name='nanometers_per_square_hour', ascii_symbol='nm/h^2', symbol='nmh⁻²') +nanometers_per_day = NamedUnit(1.1574074074074076e-13, Dimensions(length=1, time=-1), name='nanometers_per_day', ascii_symbol='nm/d', symbol='nmd⁻¹') +nanometers_per_square_day = NamedUnit(1.3395919067215365e-17, Dimensions(length=1, time=-2), name='nanometers_per_square_day', ascii_symbol='nm/d^2', symbol='nmd⁻²') +nanometers_per_year = NamedUnit(3.1688738506811433e-16, Dimensions(length=1, time=-1), name='nanometers_per_year', ascii_symbol='nm/y', symbol='nmy⁻¹') +nanometers_per_square_year = NamedUnit(1.0041761481530736e-22, Dimensions(length=1, time=-2), name='nanometers_per_square_year', ascii_symbol='nm/y^2', symbol='nmy⁻²') picometers_per_second = NamedUnit(1e-12, Dimensions(length=1, time=-1), name='picometers_per_second', ascii_symbol='pm/s', symbol='pms⁻¹') picometers_per_square_second = NamedUnit(1e-12, Dimensions(length=1, time=-2), name='picometers_per_square_second', ascii_symbol='pm/s^2', symbol='pms⁻²') picometers_per_millisecond = NamedUnit(1e-09, Dimensions(length=1, time=-1), name='picometers_per_millisecond', ascii_symbol='pm/ms', symbol='pmms⁻¹') @@ -1072,12 +1041,12 @@ def __init__(self, name: str, units: list[NamedUnit]): picometers_per_square_attosecond = NamedUnit(9.999999999999998e+23, Dimensions(length=1, time=-2), name='picometers_per_square_attosecond', ascii_symbol='pm/as^2', symbol='pmas⁻²') picometers_per_minute = NamedUnit(1.6666666666666667e-14, Dimensions(length=1, time=-1), name='picometers_per_minute', ascii_symbol='pm/min', symbol='pmmin⁻¹') picometers_per_square_minute = NamedUnit(2.7777777777777775e-16, Dimensions(length=1, time=-2), name='picometers_per_square_minute', ascii_symbol='pm/min^2', symbol='pmmin⁻²') -picometers_per_hour = NamedUnit(2.7777777777777775e-16, Dimensions(length=1, time=-1), name='picometers_per_hour', ascii_symbol='pm/h', symbol='pmh⁻¹') -picometers_per_square_hour = NamedUnit(7.716049382716049e-20, Dimensions(length=1, time=-2), name='picometers_per_square_hour', ascii_symbol='pm/h^2', symbol='pmh⁻²') -picometers_per_day = NamedUnit(1.1574074074074074e-17, Dimensions(length=1, time=-1), name='picometers_per_day', ascii_symbol='pm/d', symbol='pmd⁻¹') -picometers_per_square_day = NamedUnit(1.3395919067215362e-22, Dimensions(length=1, time=-2), name='picometers_per_square_day', ascii_symbol='pm/d^2', symbol='pmd⁻²') -picometers_per_year = NamedUnit(3.168873850681143e-20, Dimensions(length=1, time=-1), name='picometers_per_year', ascii_symbol='pm/y', symbol='pmy⁻¹') -picometers_per_square_year = NamedUnit(1.0041761481530736e-27, Dimensions(length=1, time=-2), name='picometers_per_square_year', ascii_symbol='pm/y^2', symbol='pmy⁻²') +picometers_per_hour = NamedUnit(2.7777777777777776e-15, Dimensions(length=1, time=-1), name='picometers_per_hour', ascii_symbol='pm/h', symbol='pmh⁻¹') +picometers_per_square_hour = NamedUnit(7.716049382716049e-18, Dimensions(length=1, time=-2), name='picometers_per_square_hour', ascii_symbol='pm/h^2', symbol='pmh⁻²') +picometers_per_day = NamedUnit(1.1574074074074073e-16, Dimensions(length=1, time=-1), name='picometers_per_day', ascii_symbol='pm/d', symbol='pmd⁻¹') +picometers_per_square_day = NamedUnit(1.3395919067215364e-20, Dimensions(length=1, time=-2), name='picometers_per_square_day', ascii_symbol='pm/d^2', symbol='pmd⁻²') +picometers_per_year = NamedUnit(3.168873850681143e-19, Dimensions(length=1, time=-1), name='picometers_per_year', ascii_symbol='pm/y', symbol='pmy⁻¹') +picometers_per_square_year = NamedUnit(1.0041761481530734e-25, Dimensions(length=1, time=-2), name='picometers_per_square_year', ascii_symbol='pm/y^2', symbol='pmy⁻²') femtometers_per_second = NamedUnit(1e-15, Dimensions(length=1, time=-1), name='femtometers_per_second', ascii_symbol='fm/s', symbol='fms⁻¹') femtometers_per_square_second = NamedUnit(1e-15, Dimensions(length=1, time=-2), name='femtometers_per_square_second', ascii_symbol='fm/s^2', symbol='fms⁻²') femtometers_per_millisecond = NamedUnit(1e-12, Dimensions(length=1, time=-1), name='femtometers_per_millisecond', ascii_symbol='fm/ms', symbol='fmms⁻¹') @@ -1094,12 +1063,12 @@ def __init__(self, name: str, units: list[NamedUnit]): femtometers_per_square_attosecond = NamedUnit(1e+21, Dimensions(length=1, time=-2), name='femtometers_per_square_attosecond', ascii_symbol='fm/as^2', symbol='fmas⁻²') femtometers_per_minute = NamedUnit(1.6666666666666667e-17, Dimensions(length=1, time=-1), name='femtometers_per_minute', ascii_symbol='fm/min', symbol='fmmin⁻¹') femtometers_per_square_minute = NamedUnit(2.777777777777778e-19, Dimensions(length=1, time=-2), name='femtometers_per_square_minute', ascii_symbol='fm/min^2', symbol='fmmin⁻²') -femtometers_per_hour = NamedUnit(2.777777777777778e-19, Dimensions(length=1, time=-1), name='femtometers_per_hour', ascii_symbol='fm/h', symbol='fmh⁻¹') -femtometers_per_square_hour = NamedUnit(7.71604938271605e-23, Dimensions(length=1, time=-2), name='femtometers_per_square_hour', ascii_symbol='fm/h^2', symbol='fmh⁻²') -femtometers_per_day = NamedUnit(1.1574074074074075e-20, Dimensions(length=1, time=-1), name='femtometers_per_day', ascii_symbol='fm/d', symbol='fmd⁻¹') -femtometers_per_square_day = NamedUnit(1.3395919067215364e-25, Dimensions(length=1, time=-2), name='femtometers_per_square_day', ascii_symbol='fm/d^2', symbol='fmd⁻²') -femtometers_per_year = NamedUnit(3.1688738506811434e-23, Dimensions(length=1, time=-1), name='femtometers_per_year', ascii_symbol='fm/y', symbol='fmy⁻¹') -femtometers_per_square_year = NamedUnit(1.0041761481530736e-30, Dimensions(length=1, time=-2), name='femtometers_per_square_year', ascii_symbol='fm/y^2', symbol='fmy⁻²') +femtometers_per_hour = NamedUnit(2.777777777777778e-18, Dimensions(length=1, time=-1), name='femtometers_per_hour', ascii_symbol='fm/h', symbol='fmh⁻¹') +femtometers_per_square_hour = NamedUnit(7.71604938271605e-21, Dimensions(length=1, time=-2), name='femtometers_per_square_hour', ascii_symbol='fm/h^2', symbol='fmh⁻²') +femtometers_per_day = NamedUnit(1.1574074074074075e-19, Dimensions(length=1, time=-1), name='femtometers_per_day', ascii_symbol='fm/d', symbol='fmd⁻¹') +femtometers_per_square_day = NamedUnit(1.3395919067215363e-23, Dimensions(length=1, time=-2), name='femtometers_per_square_day', ascii_symbol='fm/d^2', symbol='fmd⁻²') +femtometers_per_year = NamedUnit(3.168873850681143e-22, Dimensions(length=1, time=-1), name='femtometers_per_year', ascii_symbol='fm/y', symbol='fmy⁻¹') +femtometers_per_square_year = NamedUnit(1.0041761481530735e-28, Dimensions(length=1, time=-2), name='femtometers_per_square_year', ascii_symbol='fm/y^2', symbol='fmy⁻²') attometers_per_second = NamedUnit(1e-18, Dimensions(length=1, time=-1), name='attometers_per_second', ascii_symbol='am/s', symbol='ams⁻¹') attometers_per_square_second = NamedUnit(1e-18, Dimensions(length=1, time=-2), name='attometers_per_square_second', ascii_symbol='am/s^2', symbol='ams⁻²') attometers_per_millisecond = NamedUnit(1e-15, Dimensions(length=1, time=-1), name='attometers_per_millisecond', ascii_symbol='am/ms', symbol='amms⁻¹') @@ -1116,12 +1085,12 @@ def __init__(self, name: str, units: list[NamedUnit]): attometers_per_square_attosecond = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='attometers_per_square_attosecond', ascii_symbol='am/as^2', symbol='amas⁻²') attometers_per_minute = NamedUnit(1.6666666666666668e-20, Dimensions(length=1, time=-1), name='attometers_per_minute', ascii_symbol='am/min', symbol='ammin⁻¹') attometers_per_square_minute = NamedUnit(2.777777777777778e-22, Dimensions(length=1, time=-2), name='attometers_per_square_minute', ascii_symbol='am/min^2', symbol='ammin⁻²') -attometers_per_hour = NamedUnit(2.777777777777778e-22, Dimensions(length=1, time=-1), name='attometers_per_hour', ascii_symbol='am/h', symbol='amh⁻¹') -attometers_per_square_hour = NamedUnit(7.71604938271605e-26, Dimensions(length=1, time=-2), name='attometers_per_square_hour', ascii_symbol='am/h^2', symbol='amh⁻²') -attometers_per_day = NamedUnit(1.1574074074074075e-23, Dimensions(length=1, time=-1), name='attometers_per_day', ascii_symbol='am/d', symbol='amd⁻¹') -attometers_per_square_day = NamedUnit(1.3395919067215364e-28, Dimensions(length=1, time=-2), name='attometers_per_square_day', ascii_symbol='am/d^2', symbol='amd⁻²') -attometers_per_year = NamedUnit(3.1688738506811435e-26, Dimensions(length=1, time=-1), name='attometers_per_year', ascii_symbol='am/y', symbol='amy⁻¹') -attometers_per_square_year = NamedUnit(1.0041761481530737e-33, Dimensions(length=1, time=-2), name='attometers_per_square_year', ascii_symbol='am/y^2', symbol='amy⁻²') +attometers_per_hour = NamedUnit(2.7777777777777778e-21, Dimensions(length=1, time=-1), name='attometers_per_hour', ascii_symbol='am/h', symbol='amh⁻¹') +attometers_per_square_hour = NamedUnit(7.71604938271605e-24, Dimensions(length=1, time=-2), name='attometers_per_square_hour', ascii_symbol='am/h^2', symbol='amh⁻²') +attometers_per_day = NamedUnit(1.1574074074074074e-22, Dimensions(length=1, time=-1), name='attometers_per_day', ascii_symbol='am/d', symbol='amd⁻¹') +attometers_per_square_day = NamedUnit(1.3395919067215363e-26, Dimensions(length=1, time=-2), name='attometers_per_square_day', ascii_symbol='am/d^2', symbol='amd⁻²') +attometers_per_year = NamedUnit(3.1688738506811433e-25, Dimensions(length=1, time=-1), name='attometers_per_year', ascii_symbol='am/y', symbol='amy⁻¹') +attometers_per_square_year = NamedUnit(1.0041761481530734e-31, Dimensions(length=1, time=-2), name='attometers_per_square_year', ascii_symbol='am/y^2', symbol='amy⁻²') decimeters_per_second = NamedUnit(0.1, Dimensions(length=1, time=-1), name='decimeters_per_second', ascii_symbol='dm/s', symbol='dms⁻¹') decimeters_per_square_second = NamedUnit(0.1, Dimensions(length=1, time=-2), name='decimeters_per_square_second', ascii_symbol='dm/s^2', symbol='dms⁻²') decimeters_per_millisecond = NamedUnit(100.0, Dimensions(length=1, time=-1), name='decimeters_per_millisecond', ascii_symbol='dm/ms', symbol='dmms⁻¹') @@ -1138,12 +1107,12 @@ def __init__(self, name: str, units: list[NamedUnit]): decimeters_per_square_attosecond = NamedUnit(1e+35, Dimensions(length=1, time=-2), name='decimeters_per_square_attosecond', ascii_symbol='dm/as^2', symbol='dmas⁻²') decimeters_per_minute = NamedUnit(0.0016666666666666668, Dimensions(length=1, time=-1), name='decimeters_per_minute', ascii_symbol='dm/min', symbol='dmmin⁻¹') decimeters_per_square_minute = NamedUnit(2.777777777777778e-05, Dimensions(length=1, time=-2), name='decimeters_per_square_minute', ascii_symbol='dm/min^2', symbol='dmmin⁻²') -decimeters_per_hour = NamedUnit(2.777777777777778e-05, Dimensions(length=1, time=-1), name='decimeters_per_hour', ascii_symbol='dm/h', symbol='dmh⁻¹') -decimeters_per_square_hour = NamedUnit(7.71604938271605e-09, Dimensions(length=1, time=-2), name='decimeters_per_square_hour', ascii_symbol='dm/h^2', symbol='dmh⁻²') -decimeters_per_day = NamedUnit(1.1574074074074074e-06, Dimensions(length=1, time=-1), name='decimeters_per_day', ascii_symbol='dm/d', symbol='dmd⁻¹') -decimeters_per_square_day = NamedUnit(1.3395919067215364e-11, Dimensions(length=1, time=-2), name='decimeters_per_square_day', ascii_symbol='dm/d^2', symbol='dmd⁻²') -decimeters_per_year = NamedUnit(3.168873850681143e-09, Dimensions(length=1, time=-1), name='decimeters_per_year', ascii_symbol='dm/y', symbol='dmy⁻¹') -decimeters_per_square_year = NamedUnit(1.0041761481530736e-16, Dimensions(length=1, time=-2), name='decimeters_per_square_year', ascii_symbol='dm/y^2', symbol='dmy⁻²') +decimeters_per_hour = NamedUnit(0.0002777777777777778, Dimensions(length=1, time=-1), name='decimeters_per_hour', ascii_symbol='dm/h', symbol='dmh⁻¹') +decimeters_per_square_hour = NamedUnit(7.71604938271605e-07, Dimensions(length=1, time=-2), name='decimeters_per_square_hour', ascii_symbol='dm/h^2', symbol='dmh⁻²') +decimeters_per_day = NamedUnit(1.1574074074074075e-05, Dimensions(length=1, time=-1), name='decimeters_per_day', ascii_symbol='dm/d', symbol='dmd⁻¹') +decimeters_per_square_day = NamedUnit(1.3395919067215364e-09, Dimensions(length=1, time=-2), name='decimeters_per_square_day', ascii_symbol='dm/d^2', symbol='dmd⁻²') +decimeters_per_year = NamedUnit(3.168873850681143e-08, Dimensions(length=1, time=-1), name='decimeters_per_year', ascii_symbol='dm/y', symbol='dmy⁻¹') +decimeters_per_square_year = NamedUnit(1.0041761481530735e-14, Dimensions(length=1, time=-2), name='decimeters_per_square_year', ascii_symbol='dm/y^2', symbol='dmy⁻²') centimeters_per_second = NamedUnit(0.01, Dimensions(length=1, time=-1), name='centimeters_per_second', ascii_symbol='cm/s', symbol='cms⁻¹') centimeters_per_square_second = NamedUnit(0.01, Dimensions(length=1, time=-2), name='centimeters_per_square_second', ascii_symbol='cm/s^2', symbol='cms⁻²') centimeters_per_millisecond = NamedUnit(10.0, Dimensions(length=1, time=-1), name='centimeters_per_millisecond', ascii_symbol='cm/ms', symbol='cmms⁻¹') @@ -1160,12 +1129,12 @@ def __init__(self, name: str, units: list[NamedUnit]): centimeters_per_square_attosecond = NamedUnit(1e+34, Dimensions(length=1, time=-2), name='centimeters_per_square_attosecond', ascii_symbol='cm/as^2', symbol='cmas⁻²') centimeters_per_minute = NamedUnit(0.00016666666666666666, Dimensions(length=1, time=-1), name='centimeters_per_minute', ascii_symbol='cm/min', symbol='cmmin⁻¹') centimeters_per_square_minute = NamedUnit(2.777777777777778e-06, Dimensions(length=1, time=-2), name='centimeters_per_square_minute', ascii_symbol='cm/min^2', symbol='cmmin⁻²') -centimeters_per_hour = NamedUnit(2.777777777777778e-06, Dimensions(length=1, time=-1), name='centimeters_per_hour', ascii_symbol='cm/h', symbol='cmh⁻¹') -centimeters_per_square_hour = NamedUnit(7.71604938271605e-10, Dimensions(length=1, time=-2), name='centimeters_per_square_hour', ascii_symbol='cm/h^2', symbol='cmh⁻²') -centimeters_per_day = NamedUnit(1.1574074074074074e-07, Dimensions(length=1, time=-1), name='centimeters_per_day', ascii_symbol='cm/d', symbol='cmd⁻¹') -centimeters_per_square_day = NamedUnit(1.3395919067215364e-12, Dimensions(length=1, time=-2), name='centimeters_per_square_day', ascii_symbol='cm/d^2', symbol='cmd⁻²') -centimeters_per_year = NamedUnit(3.168873850681143e-10, Dimensions(length=1, time=-1), name='centimeters_per_year', ascii_symbol='cm/y', symbol='cmy⁻¹') -centimeters_per_square_year = NamedUnit(1.0041761481530737e-17, Dimensions(length=1, time=-2), name='centimeters_per_square_year', ascii_symbol='cm/y^2', symbol='cmy⁻²') +centimeters_per_hour = NamedUnit(2.777777777777778e-05, Dimensions(length=1, time=-1), name='centimeters_per_hour', ascii_symbol='cm/h', symbol='cmh⁻¹') +centimeters_per_square_hour = NamedUnit(7.71604938271605e-08, Dimensions(length=1, time=-2), name='centimeters_per_square_hour', ascii_symbol='cm/h^2', symbol='cmh⁻²') +centimeters_per_day = NamedUnit(1.1574074074074074e-06, Dimensions(length=1, time=-1), name='centimeters_per_day', ascii_symbol='cm/d', symbol='cmd⁻¹') +centimeters_per_square_day = NamedUnit(1.3395919067215363e-10, Dimensions(length=1, time=-2), name='centimeters_per_square_day', ascii_symbol='cm/d^2', symbol='cmd⁻²') +centimeters_per_year = NamedUnit(3.168873850681143e-09, Dimensions(length=1, time=-1), name='centimeters_per_year', ascii_symbol='cm/y', symbol='cmy⁻¹') +centimeters_per_square_year = NamedUnit(1.0041761481530735e-15, Dimensions(length=1, time=-2), name='centimeters_per_square_year', ascii_symbol='cm/y^2', symbol='cmy⁻²') angstroms_per_second = NamedUnit(1e-10, Dimensions(length=1, time=-1), name='angstroms_per_second', ascii_symbol='Ang/s', symbol='Ås⁻¹') angstroms_per_square_second = NamedUnit(1e-10, Dimensions(length=1, time=-2), name='angstroms_per_square_second', ascii_symbol='Ang/s^2', symbol='Ås⁻²') angstroms_per_millisecond = NamedUnit(1e-07, Dimensions(length=1, time=-1), name='angstroms_per_millisecond', ascii_symbol='Ang/ms', symbol='Åms⁻¹') @@ -1182,34 +1151,12 @@ def __init__(self, name: str, units: list[NamedUnit]): angstroms_per_square_attosecond = NamedUnit(9.999999999999999e+25, Dimensions(length=1, time=-2), name='angstroms_per_square_attosecond', ascii_symbol='Ang/as^2', symbol='Åas⁻²') angstroms_per_minute = NamedUnit(1.6666666666666668e-12, Dimensions(length=1, time=-1), name='angstroms_per_minute', ascii_symbol='Ang/min', symbol='Åmin⁻¹') angstroms_per_square_minute = NamedUnit(2.7777777777777778e-14, Dimensions(length=1, time=-2), name='angstroms_per_square_minute', ascii_symbol='Ang/min^2', symbol='Åmin⁻²') -angstroms_per_hour = NamedUnit(2.7777777777777778e-14, Dimensions(length=1, time=-1), name='angstroms_per_hour', ascii_symbol='Ang/h', symbol='Åh⁻¹') -angstroms_per_square_hour = NamedUnit(7.71604938271605e-18, Dimensions(length=1, time=-2), name='angstroms_per_square_hour', ascii_symbol='Ang/h^2', symbol='Åh⁻²') -angstroms_per_day = NamedUnit(1.1574074074074075e-15, Dimensions(length=1, time=-1), name='angstroms_per_day', ascii_symbol='Ang/d', symbol='Åd⁻¹') -angstroms_per_square_day = NamedUnit(1.3395919067215364e-20, Dimensions(length=1, time=-2), name='angstroms_per_square_day', ascii_symbol='Ang/d^2', symbol='Åd⁻²') -angstroms_per_year = NamedUnit(3.168873850681143e-18, Dimensions(length=1, time=-1), name='angstroms_per_year', ascii_symbol='Ang/y', symbol='Åy⁻¹') -angstroms_per_square_year = NamedUnit(1.0041761481530736e-25, Dimensions(length=1, time=-2), name='angstroms_per_square_year', ascii_symbol='Ang/y^2', symbol='Åy⁻²') -microns_per_second = NamedUnit(1e-06, Dimensions(length=1, time=-1), name='microns_per_second', ascii_symbol='micron/s', symbol='microns⁻¹') -microns_per_square_second = NamedUnit(1e-06, Dimensions(length=1, time=-2), name='microns_per_square_second', ascii_symbol='micron/s^2', symbol='microns⁻²') -microns_per_millisecond = NamedUnit(0.001, Dimensions(length=1, time=-1), name='microns_per_millisecond', ascii_symbol='micron/ms', symbol='micronms⁻¹') -microns_per_square_millisecond = NamedUnit(1.0, Dimensions(length=1, time=-2), name='microns_per_square_millisecond', ascii_symbol='micron/ms^2', symbol='micronms⁻²') -microns_per_microsecond = NamedUnit(1.0, Dimensions(length=1, time=-1), name='microns_per_microsecond', ascii_symbol='micron/us', symbol='micronµs⁻¹') -microns_per_square_microsecond = NamedUnit(1000000.0, Dimensions(length=1, time=-2), name='microns_per_square_microsecond', ascii_symbol='micron/us^2', symbol='micronµs⁻²') -microns_per_nanosecond = NamedUnit(999.9999999999999, Dimensions(length=1, time=-1), name='microns_per_nanosecond', ascii_symbol='micron/ns', symbol='micronns⁻¹') -microns_per_square_nanosecond = NamedUnit(999999999999.9999, Dimensions(length=1, time=-2), name='microns_per_square_nanosecond', ascii_symbol='micron/ns^2', symbol='micronns⁻²') -microns_per_picosecond = NamedUnit(1000000.0, Dimensions(length=1, time=-1), name='microns_per_picosecond', ascii_symbol='micron/ps', symbol='micronps⁻¹') -microns_per_square_picosecond = NamedUnit(1e+18, Dimensions(length=1, time=-2), name='microns_per_square_picosecond', ascii_symbol='micron/ps^2', symbol='micronps⁻²') -microns_per_femtosecond = NamedUnit(999999999.9999999, Dimensions(length=1, time=-1), name='microns_per_femtosecond', ascii_symbol='micron/fs', symbol='micronfs⁻¹') -microns_per_square_femtosecond = NamedUnit(9.999999999999998e+23, Dimensions(length=1, time=-2), name='microns_per_square_femtosecond', ascii_symbol='micron/fs^2', symbol='micronfs⁻²') -microns_per_attosecond = NamedUnit(999999999999.9999, Dimensions(length=1, time=-1), name='microns_per_attosecond', ascii_symbol='micron/as', symbol='micronas⁻¹') -microns_per_square_attosecond = NamedUnit(9.999999999999999e+29, Dimensions(length=1, time=-2), name='microns_per_square_attosecond', ascii_symbol='micron/as^2', symbol='micronas⁻²') -microns_per_minute = NamedUnit(1.6666666666666667e-08, Dimensions(length=1, time=-1), name='microns_per_minute', ascii_symbol='micron/min', symbol='micronmin⁻¹') -microns_per_square_minute = NamedUnit(2.7777777777777777e-10, Dimensions(length=1, time=-2), name='microns_per_square_minute', ascii_symbol='micron/min^2', symbol='micronmin⁻²') -microns_per_hour = NamedUnit(2.7777777777777777e-10, Dimensions(length=1, time=-1), name='microns_per_hour', ascii_symbol='micron/h', symbol='micronh⁻¹') -microns_per_square_hour = NamedUnit(7.71604938271605e-14, Dimensions(length=1, time=-2), name='microns_per_square_hour', ascii_symbol='micron/h^2', symbol='micronh⁻²') -microns_per_day = NamedUnit(1.1574074074074074e-11, Dimensions(length=1, time=-1), name='microns_per_day', ascii_symbol='micron/d', symbol='micrond⁻¹') -microns_per_square_day = NamedUnit(1.3395919067215363e-16, Dimensions(length=1, time=-2), name='microns_per_square_day', ascii_symbol='micron/d^2', symbol='micrond⁻²') -microns_per_year = NamedUnit(3.168873850681143e-14, Dimensions(length=1, time=-1), name='microns_per_year', ascii_symbol='micron/y', symbol='microny⁻¹') -microns_per_square_year = NamedUnit(1.0041761481530736e-21, Dimensions(length=1, time=-2), name='microns_per_square_year', ascii_symbol='micron/y^2', symbol='microny⁻²') +angstroms_per_hour = NamedUnit(2.777777777777778e-13, Dimensions(length=1, time=-1), name='angstroms_per_hour', ascii_symbol='Ang/h', symbol='Åh⁻¹') +angstroms_per_square_hour = NamedUnit(7.716049382716049e-16, Dimensions(length=1, time=-2), name='angstroms_per_square_hour', ascii_symbol='Ang/h^2', symbol='Åh⁻²') +angstroms_per_day = NamedUnit(1.1574074074074074e-14, Dimensions(length=1, time=-1), name='angstroms_per_day', ascii_symbol='Ang/d', symbol='Åd⁻¹') +angstroms_per_square_day = NamedUnit(1.3395919067215363e-18, Dimensions(length=1, time=-2), name='angstroms_per_square_day', ascii_symbol='Ang/d^2', symbol='Åd⁻²') +angstroms_per_year = NamedUnit(3.168873850681143e-17, Dimensions(length=1, time=-1), name='angstroms_per_year', ascii_symbol='Ang/y', symbol='Åy⁻¹') +angstroms_per_square_year = NamedUnit(1.0041761481530734e-23, Dimensions(length=1, time=-2), name='angstroms_per_square_year', ascii_symbol='Ang/y^2', symbol='Åy⁻²') miles_per_second = NamedUnit(1609.344, Dimensions(length=1, time=-1), name='miles_per_second', ascii_symbol='miles/s', symbol='miless⁻¹') miles_per_square_second = NamedUnit(1609.344, Dimensions(length=1, time=-2), name='miles_per_square_second', ascii_symbol='miles/s^2', symbol='miless⁻²') miles_per_millisecond = NamedUnit(1609344.0, Dimensions(length=1, time=-1), name='miles_per_millisecond', ascii_symbol='miles/ms', symbol='milesms⁻¹') @@ -1226,12 +1173,12 @@ def __init__(self, name: str, units: list[NamedUnit]): miles_per_square_attosecond = NamedUnit(1.609344e+39, Dimensions(length=1, time=-2), name='miles_per_square_attosecond', ascii_symbol='miles/as^2', symbol='milesas⁻²') miles_per_minute = NamedUnit(26.822400000000002, Dimensions(length=1, time=-1), name='miles_per_minute', ascii_symbol='miles/min', symbol='milesmin⁻¹') miles_per_square_minute = NamedUnit(0.44704, Dimensions(length=1, time=-2), name='miles_per_square_minute', ascii_symbol='miles/min^2', symbol='milesmin⁻²') -miles_per_hour = NamedUnit(0.44704, Dimensions(length=1, time=-1), name='miles_per_hour', ascii_symbol='miles/h', symbol='milesh⁻¹') -miles_per_square_hour = NamedUnit(0.00012417777777777778, Dimensions(length=1, time=-2), name='miles_per_square_hour', ascii_symbol='miles/h^2', symbol='milesh⁻²') -miles_per_day = NamedUnit(0.018626666666666666, Dimensions(length=1, time=-1), name='miles_per_day', ascii_symbol='miles/d', symbol='milesd⁻¹') -miles_per_square_day = NamedUnit(2.1558641975308643e-07, Dimensions(length=1, time=-2), name='miles_per_square_day', ascii_symbol='miles/d^2', symbol='milesd⁻²') -miles_per_year = NamedUnit(5.099808118350594e-05, Dimensions(length=1, time=-1), name='miles_per_year', ascii_symbol='miles/y', symbol='milesy⁻¹') -miles_per_square_year = NamedUnit(1.61606485897326e-12, Dimensions(length=1, time=-2), name='miles_per_square_year', ascii_symbol='miles/y^2', symbol='milesy⁻²') +miles_per_hour = NamedUnit(4.4704, Dimensions(length=1, time=-1), name='miles_per_hour', ascii_symbol='miles/h', symbol='milesh⁻¹') +miles_per_square_hour = NamedUnit(0.012417777777777778, Dimensions(length=1, time=-2), name='miles_per_square_hour', ascii_symbol='miles/h^2', symbol='milesh⁻²') +miles_per_day = NamedUnit(0.18626666666666666, Dimensions(length=1, time=-1), name='miles_per_day', ascii_symbol='miles/d', symbol='milesd⁻¹') +miles_per_square_day = NamedUnit(2.1558641975308643e-05, Dimensions(length=1, time=-2), name='miles_per_square_day', ascii_symbol='miles/d^2', symbol='milesd⁻²') +miles_per_year = NamedUnit(0.0005099808118350593, Dimensions(length=1, time=-1), name='miles_per_year', ascii_symbol='miles/y', symbol='milesy⁻¹') +miles_per_square_year = NamedUnit(1.61606485897326e-10, Dimensions(length=1, time=-2), name='miles_per_square_year', ascii_symbol='miles/y^2', symbol='milesy⁻²') yards_per_second = NamedUnit(0.9144000000000001, Dimensions(length=1, time=-1), name='yards_per_second', ascii_symbol='yrd/s', symbol='yrds⁻¹') yards_per_square_second = NamedUnit(0.9144000000000001, Dimensions(length=1, time=-2), name='yards_per_square_second', ascii_symbol='yrd/s^2', symbol='yrds⁻²') yards_per_millisecond = NamedUnit(914.4000000000001, Dimensions(length=1, time=-1), name='yards_per_millisecond', ascii_symbol='yrd/ms', symbol='yrdms⁻¹') @@ -1248,12 +1195,12 @@ def __init__(self, name: str, units: list[NamedUnit]): yards_per_square_attosecond = NamedUnit(9.144e+35, Dimensions(length=1, time=-2), name='yards_per_square_attosecond', ascii_symbol='yrd/as^2', symbol='yrdas⁻²') yards_per_minute = NamedUnit(0.015240000000000002, Dimensions(length=1, time=-1), name='yards_per_minute', ascii_symbol='yrd/min', symbol='yrdmin⁻¹') yards_per_square_minute = NamedUnit(0.00025400000000000005, Dimensions(length=1, time=-2), name='yards_per_square_minute', ascii_symbol='yrd/min^2', symbol='yrdmin⁻²') -yards_per_hour = NamedUnit(0.00025400000000000005, Dimensions(length=1, time=-1), name='yards_per_hour', ascii_symbol='yrd/h', symbol='yrdh⁻¹') -yards_per_square_hour = NamedUnit(7.055555555555557e-08, Dimensions(length=1, time=-2), name='yards_per_square_hour', ascii_symbol='yrd/h^2', symbol='yrdh⁻²') -yards_per_day = NamedUnit(1.0583333333333334e-05, Dimensions(length=1, time=-1), name='yards_per_day', ascii_symbol='yrd/d', symbol='yrdd⁻¹') -yards_per_square_day = NamedUnit(1.224922839506173e-10, Dimensions(length=1, time=-2), name='yards_per_square_day', ascii_symbol='yrd/d^2', symbol='yrdd⁻²') -yards_per_year = NamedUnit(2.8976182490628376e-08, Dimensions(length=1, time=-1), name='yards_per_year', ascii_symbol='yrd/y', symbol='yrdy⁻¹') -yards_per_square_year = NamedUnit(9.182186698711705e-16, Dimensions(length=1, time=-2), name='yards_per_square_year', ascii_symbol='yrd/y^2', symbol='yrdy⁻²') +yards_per_hour = NamedUnit(0.00254, Dimensions(length=1, time=-1), name='yards_per_hour', ascii_symbol='yrd/h', symbol='yrdh⁻¹') +yards_per_square_hour = NamedUnit(7.055555555555557e-06, Dimensions(length=1, time=-2), name='yards_per_square_hour', ascii_symbol='yrd/h^2', symbol='yrdh⁻²') +yards_per_day = NamedUnit(0.00010583333333333335, Dimensions(length=1, time=-1), name='yards_per_day', ascii_symbol='yrd/d', symbol='yrdd⁻¹') +yards_per_square_day = NamedUnit(1.224922839506173e-08, Dimensions(length=1, time=-2), name='yards_per_square_day', ascii_symbol='yrd/d^2', symbol='yrdd⁻²') +yards_per_year = NamedUnit(2.897618249062837e-07, Dimensions(length=1, time=-1), name='yards_per_year', ascii_symbol='yrd/y', symbol='yrdy⁻¹') +yards_per_square_year = NamedUnit(9.182186698711705e-14, Dimensions(length=1, time=-2), name='yards_per_square_year', ascii_symbol='yrd/y^2', symbol='yrdy⁻²') feet_per_second = NamedUnit(0.3048, Dimensions(length=1, time=-1), name='feet_per_second', ascii_symbol='ft/s', symbol='fts⁻¹') feet_per_square_second = NamedUnit(0.3048, Dimensions(length=1, time=-2), name='feet_per_square_second', ascii_symbol='ft/s^2', symbol='fts⁻²') feet_per_millisecond = NamedUnit(304.8, Dimensions(length=1, time=-1), name='feet_per_millisecond', ascii_symbol='ft/ms', symbol='ftms⁻¹') @@ -1270,12 +1217,12 @@ def __init__(self, name: str, units: list[NamedUnit]): feet_per_square_attosecond = NamedUnit(3.0479999999999997e+35, Dimensions(length=1, time=-2), name='feet_per_square_attosecond', ascii_symbol='ft/as^2', symbol='ftas⁻²') feet_per_minute = NamedUnit(0.00508, Dimensions(length=1, time=-1), name='feet_per_minute', ascii_symbol='ft/min', symbol='ftmin⁻¹') feet_per_square_minute = NamedUnit(8.466666666666667e-05, Dimensions(length=1, time=-2), name='feet_per_square_minute', ascii_symbol='ft/min^2', symbol='ftmin⁻²') -feet_per_hour = NamedUnit(8.466666666666667e-05, Dimensions(length=1, time=-1), name='feet_per_hour', ascii_symbol='ft/h', symbol='fth⁻¹') -feet_per_square_hour = NamedUnit(2.351851851851852e-08, Dimensions(length=1, time=-2), name='feet_per_square_hour', ascii_symbol='ft/h^2', symbol='fth⁻²') -feet_per_day = NamedUnit(3.527777777777778e-06, Dimensions(length=1, time=-1), name='feet_per_day', ascii_symbol='ft/d', symbol='ftd⁻¹') -feet_per_square_day = NamedUnit(4.083076131687243e-11, Dimensions(length=1, time=-2), name='feet_per_square_day', ascii_symbol='ft/d^2', symbol='ftd⁻²') -feet_per_year = NamedUnit(9.658727496876124e-09, Dimensions(length=1, time=-1), name='feet_per_year', ascii_symbol='ft/y', symbol='fty⁻¹') -feet_per_square_year = NamedUnit(3.060728899570568e-16, Dimensions(length=1, time=-2), name='feet_per_square_year', ascii_symbol='ft/y^2', symbol='fty⁻²') +feet_per_hour = NamedUnit(0.0008466666666666667, Dimensions(length=1, time=-1), name='feet_per_hour', ascii_symbol='ft/h', symbol='fth⁻¹') +feet_per_square_hour = NamedUnit(2.351851851851852e-06, Dimensions(length=1, time=-2), name='feet_per_square_hour', ascii_symbol='ft/h^2', symbol='fth⁻²') +feet_per_day = NamedUnit(3.527777777777778e-05, Dimensions(length=1, time=-1), name='feet_per_day', ascii_symbol='ft/d', symbol='ftd⁻¹') +feet_per_square_day = NamedUnit(4.083076131687243e-09, Dimensions(length=1, time=-2), name='feet_per_square_day', ascii_symbol='ft/d^2', symbol='ftd⁻²') +feet_per_year = NamedUnit(9.658727496876123e-08, Dimensions(length=1, time=-1), name='feet_per_year', ascii_symbol='ft/y', symbol='fty⁻¹') +feet_per_square_year = NamedUnit(3.060728899570568e-14, Dimensions(length=1, time=-2), name='feet_per_square_year', ascii_symbol='ft/y^2', symbol='fty⁻²') inches_per_second = NamedUnit(0.0254, Dimensions(length=1, time=-1), name='inches_per_second', ascii_symbol='in/s', symbol='ins⁻¹') inches_per_square_second = NamedUnit(0.0254, Dimensions(length=1, time=-2), name='inches_per_square_second', ascii_symbol='in/s^2', symbol='ins⁻²') inches_per_millisecond = NamedUnit(25.4, Dimensions(length=1, time=-1), name='inches_per_millisecond', ascii_symbol='in/ms', symbol='inms⁻¹') @@ -1292,12 +1239,12 @@ def __init__(self, name: str, units: list[NamedUnit]): inches_per_square_attosecond = NamedUnit(2.5399999999999998e+34, Dimensions(length=1, time=-2), name='inches_per_square_attosecond', ascii_symbol='in/as^2', symbol='inas⁻²') inches_per_minute = NamedUnit(0.00042333333333333334, Dimensions(length=1, time=-1), name='inches_per_minute', ascii_symbol='in/min', symbol='inmin⁻¹') inches_per_square_minute = NamedUnit(7.055555555555555e-06, Dimensions(length=1, time=-2), name='inches_per_square_minute', ascii_symbol='in/min^2', symbol='inmin⁻²') -inches_per_hour = NamedUnit(7.055555555555555e-06, Dimensions(length=1, time=-1), name='inches_per_hour', ascii_symbol='in/h', symbol='inh⁻¹') -inches_per_square_hour = NamedUnit(1.9598765432098764e-09, Dimensions(length=1, time=-2), name='inches_per_square_hour', ascii_symbol='in/h^2', symbol='inh⁻²') -inches_per_day = NamedUnit(2.939814814814815e-07, Dimensions(length=1, time=-1), name='inches_per_day', ascii_symbol='in/d', symbol='ind⁻¹') -inches_per_square_day = NamedUnit(3.402563443072702e-12, Dimensions(length=1, time=-2), name='inches_per_square_day', ascii_symbol='in/d^2', symbol='ind⁻²') -inches_per_year = NamedUnit(8.048939580730103e-10, Dimensions(length=1, time=-1), name='inches_per_year', ascii_symbol='in/y', symbol='iny⁻¹') -inches_per_square_year = NamedUnit(2.550607416308807e-17, Dimensions(length=1, time=-2), name='inches_per_square_year', ascii_symbol='in/y^2', symbol='iny⁻²') +inches_per_hour = NamedUnit(7.055555555555556e-05, Dimensions(length=1, time=-1), name='inches_per_hour', ascii_symbol='in/h', symbol='inh⁻¹') +inches_per_square_hour = NamedUnit(1.9598765432098765e-07, Dimensions(length=1, time=-2), name='inches_per_square_hour', ascii_symbol='in/h^2', symbol='inh⁻²') +inches_per_day = NamedUnit(2.9398148148148147e-06, Dimensions(length=1, time=-1), name='inches_per_day', ascii_symbol='in/d', symbol='ind⁻¹') +inches_per_square_day = NamedUnit(3.4025634430727023e-10, Dimensions(length=1, time=-2), name='inches_per_square_day', ascii_symbol='in/d^2', symbol='ind⁻²') +inches_per_year = NamedUnit(8.048939580730103e-09, Dimensions(length=1, time=-1), name='inches_per_year', ascii_symbol='in/y', symbol='iny⁻¹') +inches_per_square_year = NamedUnit(2.5506074163088065e-15, Dimensions(length=1, time=-2), name='inches_per_square_year', ascii_symbol='in/y^2', symbol='iny⁻²') grams_per_cubic_meter = NamedUnit(0.001, Dimensions(length=-3, mass=1), name='grams_per_cubic_meter', ascii_symbol='g m^-3', symbol='gm⁻³') exagrams_per_cubic_meter = NamedUnit(1000000000000000.0, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_meter', ascii_symbol='Eg m^-3', symbol='Egm⁻³') petagrams_per_cubic_meter = NamedUnit(1000000000000.0, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_meter', ascii_symbol='Pg m^-3', symbol='Pgm⁻³') @@ -1554,22 +1501,6 @@ def __init__(self, name: str, units: list[NamedUnit]): atomic_mass_units_per_cubic_angstrom = NamedUnit(1660.5389209999996, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_angstrom', ascii_symbol='au Ang^-3', symbol='auÅ⁻³') pounds_per_cubic_angstrom = NamedUnit(4.5359237e+29, Dimensions(length=-3, mass=1), name='pounds_per_cubic_angstrom', ascii_symbol='lb Ang^-3', symbol='lbÅ⁻³') ounces_per_cubic_angstrom = NamedUnit(2.8349523125e+28, Dimensions(length=-3, mass=1), name='ounces_per_cubic_angstrom', ascii_symbol='oz Ang^-3', symbol='ozÅ⁻³') -grams_per_cubic_micron = NamedUnit(1000000000000000.1, Dimensions(length=-3, mass=1), name='grams_per_cubic_micron', ascii_symbol='g micron^-3', symbol='gmicron⁻³') -exagrams_per_cubic_micron = NamedUnit(1.0000000000000001e+33, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_micron', ascii_symbol='Eg micron^-3', symbol='Egmicron⁻³') -petagrams_per_cubic_micron = NamedUnit(1.0000000000000002e+30, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_micron', ascii_symbol='Pg micron^-3', symbol='Pgmicron⁻³') -teragrams_per_cubic_micron = NamedUnit(1.0000000000000002e+27, Dimensions(length=-3, mass=1), name='teragrams_per_cubic_micron', ascii_symbol='Tg micron^-3', symbol='Tgmicron⁻³') -gigagrams_per_cubic_micron = NamedUnit(1.0000000000000001e+24, Dimensions(length=-3, mass=1), name='gigagrams_per_cubic_micron', ascii_symbol='Gg micron^-3', symbol='Ggmicron⁻³') -megagrams_per_cubic_micron = NamedUnit(1.0000000000000001e+21, Dimensions(length=-3, mass=1), name='megagrams_per_cubic_micron', ascii_symbol='Mg micron^-3', symbol='Mgmicron⁻³') -kilograms_per_cubic_micron = NamedUnit(1.0000000000000001e+18, Dimensions(length=-3, mass=1), name='kilograms_per_cubic_micron', ascii_symbol='kg micron^-3', symbol='kgmicron⁻³') -milligrams_per_cubic_micron = NamedUnit(1000000000000.0001, Dimensions(length=-3, mass=1), name='milligrams_per_cubic_micron', ascii_symbol='mg micron^-3', symbol='mgmicron⁻³') -micrograms_per_cubic_micron = NamedUnit(1000000000.0000002, Dimensions(length=-3, mass=1), name='micrograms_per_cubic_micron', ascii_symbol='ug micron^-3', symbol='µgmicron⁻³') -nanograms_per_cubic_micron = NamedUnit(1000000.0000000003, Dimensions(length=-3, mass=1), name='nanograms_per_cubic_micron', ascii_symbol='ng micron^-3', symbol='ngmicron⁻³') -picograms_per_cubic_micron = NamedUnit(1000.0000000000002, Dimensions(length=-3, mass=1), name='picograms_per_cubic_micron', ascii_symbol='pg micron^-3', symbol='pgmicron⁻³') -femtograms_per_cubic_micron = NamedUnit(1.0000000000000002, Dimensions(length=-3, mass=1), name='femtograms_per_cubic_micron', ascii_symbol='fg micron^-3', symbol='fgmicron⁻³') -attograms_per_cubic_micron = NamedUnit(0.0010000000000000002, Dimensions(length=-3, mass=1), name='attograms_per_cubic_micron', ascii_symbol='ag micron^-3', symbol='agmicron⁻³') -atomic_mass_units_per_cubic_micron = NamedUnit(1.660538921e-09, Dimensions(length=-3, mass=1), name='atomic_mass_units_per_cubic_micron', ascii_symbol='au micron^-3', symbol='aumicron⁻³') -pounds_per_cubic_micron = NamedUnit(4.5359237000000006e+17, Dimensions(length=-3, mass=1), name='pounds_per_cubic_micron', ascii_symbol='lb micron^-3', symbol='lbmicron⁻³') -ounces_per_cubic_micron = NamedUnit(2.8349523125000004e+16, Dimensions(length=-3, mass=1), name='ounces_per_cubic_micron', ascii_symbol='oz micron^-3', symbol='ozmicron⁻³') grams_per_cubic_mile = NamedUnit(2.399127585789277e-13, Dimensions(length=-3, mass=1), name='grams_per_cubic_mile', ascii_symbol='g miles^-3', symbol='gmiles⁻³') exagrams_per_cubic_mile = NamedUnit(239912.7585789277, Dimensions(length=-3, mass=1), name='exagrams_per_cubic_mile', ascii_symbol='Eg miles^-3', symbol='Egmiles⁻³') petagrams_per_cubic_mile = NamedUnit(239.9127585789277, Dimensions(length=-3, mass=1), name='petagrams_per_cubic_mile', ascii_symbol='Pg miles^-3', symbol='Pgmiles⁻³') @@ -1746,13 +1677,6 @@ def __init__(self, name: str, units: list[NamedUnit]): picomoles_per_cubic_angstrom = NamedUnit(6.02214076e+41, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_angstrom', ascii_symbol='pmol Ang^-3', symbol='pmolÅ⁻³') femtomoles_per_cubic_angstrom = NamedUnit(6.022140759999999e+38, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_angstrom', ascii_symbol='fmol Ang^-3', symbol='fmolÅ⁻³') attomoles_per_cubic_angstrom = NamedUnit(6.02214076e+35, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_angstrom', ascii_symbol='amol Ang^-3', symbol='amolÅ⁻³') -moles_per_cubic_micron = NamedUnit(6.022140760000001e+41, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_micron', ascii_symbol='mol micron^-3', symbol='molmicron⁻³') -millimoles_per_cubic_micron = NamedUnit(6.022140760000001e+38, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_micron', ascii_symbol='mmol micron^-3', symbol='mmolmicron⁻³') -micromoles_per_cubic_micron = NamedUnit(6.0221407600000004e+35, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_micron', ascii_symbol='umol micron^-3', symbol='µmolmicron⁻³') -nanomoles_per_cubic_micron = NamedUnit(6.022140760000001e+32, Dimensions(length=-3, moles_hint=1), name='nanomoles_per_cubic_micron', ascii_symbol='nmol micron^-3', symbol='nmolmicron⁻³') -picomoles_per_cubic_micron = NamedUnit(6.022140760000001e+29, Dimensions(length=-3, moles_hint=1), name='picomoles_per_cubic_micron', ascii_symbol='pmol micron^-3', symbol='pmolmicron⁻³') -femtomoles_per_cubic_micron = NamedUnit(6.022140760000001e+26, Dimensions(length=-3, moles_hint=1), name='femtomoles_per_cubic_micron', ascii_symbol='fmol micron^-3', symbol='fmolmicron⁻³') -attomoles_per_cubic_micron = NamedUnit(6.0221407600000005e+23, Dimensions(length=-3, moles_hint=1), name='attomoles_per_cubic_micron', ascii_symbol='amol micron^-3', symbol='amolmicron⁻³') moles_per_cubic_mile = NamedUnit(144478840228220.0, Dimensions(length=-3, moles_hint=1), name='moles_per_cubic_mile', ascii_symbol='mol miles^-3', symbol='molmiles⁻³') millimoles_per_cubic_mile = NamedUnit(144478840228.22003, Dimensions(length=-3, moles_hint=1), name='millimoles_per_cubic_mile', ascii_symbol='mmol miles^-3', symbol='mmolmiles⁻³') micromoles_per_cubic_mile = NamedUnit(144478840.22822002, Dimensions(length=-3, moles_hint=1), name='micromoles_per_cubic_mile', ascii_symbol='umol miles^-3', symbol='µmolmiles⁻³') @@ -2049,14 +1973,12 @@ def __init__(self, name: str, units: list[NamedUnit]): "aH": attohenry, "Ang": angstroms, "Å": angstroms, - "micron": microns, "min": minutes, "h": hours, "d": days, "y": years, "deg": degrees, "rad": radians, - "rot": rotations, "sr": stradians, "l": litres, "eV": electronvolts, @@ -2105,7 +2027,6 @@ def __init__(self, name: str, units: list[NamedUnit]): "amu": atomic_mass_units, "degr": degrees, "Deg": degrees, - "degree": degrees, "degrees": degrees, "Degrees": degrees, "Counts": none, @@ -2142,7 +2063,6 @@ def __init__(self, name: str, units: list[NamedUnit]): decimeters, centimeters, angstroms, - microns, miles, yards, feet, @@ -2168,7 +2088,6 @@ def __init__(self, name: str, units: list[NamedUnit]): square_decimeters, square_centimeters, square_angstroms, - square_microns, square_miles, square_yards, square_feet, @@ -2195,7 +2114,6 @@ def __init__(self, name: str, units: list[NamedUnit]): cubic_decimeters, cubic_centimeters, cubic_angstroms, - cubic_microns, cubic_miles, cubic_yards, cubic_feet, @@ -2221,7 +2139,6 @@ def __init__(self, name: str, units: list[NamedUnit]): per_decimeter, per_centimeter, per_angstrom, - per_micron, per_mile, per_yard, per_foot, @@ -2247,7 +2164,6 @@ def __init__(self, name: str, units: list[NamedUnit]): per_square_decimeter, per_square_centimeter, per_square_angstrom, - per_square_micron, per_square_mile, per_square_yard, per_square_foot, @@ -2273,7 +2189,6 @@ def __init__(self, name: str, units: list[NamedUnit]): per_cubic_decimeter, per_cubic_centimeter, per_cubic_angstrom, - per_cubic_micron, per_cubic_mile, per_cubic_yard, per_cubic_foot, @@ -2312,6 +2227,7 @@ def __init__(self, name: str, units: list[NamedUnit]): picohertz, femtohertz, attohertz, + revolutions_per_minute, ]) speed = UnitGroup( @@ -2493,17 +2409,6 @@ def __init__(self, name: str, units: list[NamedUnit]): angstroms_per_hour, angstroms_per_day, angstroms_per_year, - microns_per_second, - microns_per_millisecond, - microns_per_microsecond, - microns_per_nanosecond, - microns_per_picosecond, - microns_per_femtosecond, - microns_per_attosecond, - microns_per_minute, - microns_per_hour, - microns_per_day, - microns_per_year, miles_per_second, miles_per_millisecond, miles_per_microsecond, @@ -2729,17 +2634,6 @@ def __init__(self, name: str, units: list[NamedUnit]): angstroms_per_square_hour, angstroms_per_square_day, angstroms_per_square_year, - microns_per_square_second, - microns_per_square_millisecond, - microns_per_square_microsecond, - microns_per_square_nanosecond, - microns_per_square_picosecond, - microns_per_square_femtosecond, - microns_per_square_attosecond, - microns_per_square_minute, - microns_per_square_hour, - microns_per_square_day, - microns_per_square_year, miles_per_square_second, miles_per_square_millisecond, miles_per_square_microsecond, @@ -3045,22 +2939,6 @@ def __init__(self, name: str, units: list[NamedUnit]): atomic_mass_units_per_cubic_angstrom, pounds_per_cubic_angstrom, ounces_per_cubic_angstrom, - grams_per_cubic_micron, - exagrams_per_cubic_micron, - petagrams_per_cubic_micron, - teragrams_per_cubic_micron, - gigagrams_per_cubic_micron, - megagrams_per_cubic_micron, - kilograms_per_cubic_micron, - milligrams_per_cubic_micron, - micrograms_per_cubic_micron, - nanograms_per_cubic_micron, - picograms_per_cubic_micron, - femtograms_per_cubic_micron, - attograms_per_cubic_micron, - atomic_mass_units_per_cubic_micron, - pounds_per_cubic_micron, - ounces_per_cubic_micron, grams_per_cubic_mile, exagrams_per_cubic_mile, petagrams_per_cubic_mile, @@ -3390,7 +3268,6 @@ def __init__(self, name: str, units: list[NamedUnit]): units = [ degrees, radians, - rotations, ]) solid_angle = UnitGroup( @@ -3526,13 +3403,6 @@ def __init__(self, name: str, units: list[NamedUnit]): picomoles_per_cubic_angstrom, femtomoles_per_cubic_angstrom, attomoles_per_cubic_angstrom, - moles_per_cubic_micron, - millimoles_per_cubic_micron, - micromoles_per_cubic_micron, - nanomoles_per_cubic_micron, - picomoles_per_cubic_micron, - femtomoles_per_cubic_micron, - attomoles_per_cubic_micron, moles_per_cubic_mile, millimoles_per_cubic_mile, micromoles_per_cubic_mile, diff --git a/sasdata/refactor_roadmap.rst b/sasdata/refactor_roadmap.rst new file mode 100644 index 000000000..e74adfb39 --- /dev/null +++ b/sasdata/refactor_roadmap.rst @@ -0,0 +1,91 @@ +* percentages updated last on 6th February 2026 + +SasData Side +============ + +* Load data into memory as SasData objects + + * From different sources + + * Text + * ASCII (95%) + * XML (95%) + * HDF5 (95%) + + * known mistakes (living object) + +* Have calculations of errors and tracking of objects + + * Low level implementation of error prop (95%) + * Linking of data (10%) + * Independent source identification (50%, but see above) + + * Make a decision (0%) + * Carefully document said decision (0%) + + * Units (95%) + + * Unit conversion (100%) + * Unit parsing (95%) + * Big file of useful units and not so useful units (80%) + * Printing units (95%) + + * Operations on Quantities + + * Arithmetic operations (95%) + * Special and not so special functions (90%) + * Linear algebra (30%) + +* Operation on datasets + + * Rebinning (60%) + * Slicing backend [integration] (see above) + * Adding extra annotations (0%) + +* Trends + + * Construct trend (70%) + * Interpolate axes (80%) + +* Save data + + * Into something readable (JSON) (95%) + * Into HDF5 (95%) + +Develop a Rigorous Testing Framework For Critical Objects +========================================================= + +Currently lots of tests, but we should be more systematic. + + + + +SasView Side (Integration) +========================== + +* ASCII loader interface (90%) +* Data explorer refactor (30%) + + * Represent data in GUI (85%) + * Represent plots in GUI (0%) + * Represent links between data in GUI (0%) + * Represent perspectives in GUI (0%) + * Represent trends in GUI (0%) + +* Trends + + * Suggest metadata (65%) + * Present options to user (0%) + +* Perspectives + + * Make them accept new data object (25%) + * Batch stuff should become trend stuff (0%) + +* Slicing + + * Refactor slicers for new backend (0%) + + +`_________|o=o\______` -> this way + diff --git a/sasdata/sasdata_design_decisions.rst b/sasdata/sasdata_design_decisions.rst new file mode 100644 index 000000000..de674ba95 --- /dev/null +++ b/sasdata/sasdata_design_decisions.rst @@ -0,0 +1,57 @@ +SasData Refactor Principles +=========================== + + +Fundamental choices +------------------- + +1: Data is Immutable +==================== + +We want data to be cross referenced and keep track of important information about correlations. Furthermore, to follow +FAIR principles we want a record of this. + +It is very hard to do these things if we allow data to be mutable. This doesn't mean you can't copy the contents +of a data and change the copy, then make a new data object. + +2: Data is tracked +================== + +Again, within the SasData objects, operations are tracked. This allows use to propagate uncertainties correctly +and keep a FAIR record. + +3: Data objects are mostly agnostic to their contents +===================================================== + +To represent more general kinds of data in uniform way, we have data objects that don't specifically have q/I axes. +All axes are however named, and dimensionality is implicit. + +3b: Data types are "duck-typed" +=============================== + +The way whether we tell data is, for example, Q/I data is by checking the axes names, not by the class. + +Note: Some checks of this kind should probably be implemented as utility functions + +3c: Errors are bound to quantities +================================== + +Errors are bound to the quantities they correspond to, so for example, I and dI are held in a single object. + +Note: It is probably incorrect to associate Q and dQ like this, as they don't follow standard error propagation rules, +instead, use supplementary information. + + +4: Relationship to models is specified in the data class +======================================================== + +The processing steps needed to convert model outputs to something comparable to the data is included in the `modelling +requirements` section. Making use of this is optional. + + + +5: Trends +========= + +Have collections of SasData objects that can be treated together, e.g. as functions of some variable, field, concentration + diff --git a/sasdata/slicing/__init__.py b/sasdata/slicing/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/slicing/geometry.py b/sasdata/slicing/geometry.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/slicing/meshes/__init__.py b/sasdata/slicing/meshes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/slicing/meshes/delaunay_mesh.py b/sasdata/slicing/meshes/delaunay_mesh.py new file mode 100644 index 000000000..d0c729a91 --- /dev/null +++ b/sasdata/slicing/meshes/delaunay_mesh.py @@ -0,0 +1,33 @@ +import numpy as np +from scipy.spatial import Delaunay + +from sasdata.slicing.meshes.mesh import Mesh + + +def delaunay_mesh(x, y) -> Mesh: + """ Create a triangulated mesh based on input points """ + + input_data = np.array((x, y)).T + delaunay = Delaunay(input_data) + + return Mesh(points=input_data, cells=delaunay.simplices) + + +if __name__ == "__main__": + import matplotlib.pyplot as plt + + points = np.random.random((100, 2)) + mesh = delaunay_mesh(points[:,0], points[:,1]) + mesh.show(actually_show=False) + + print(mesh.cells[50]) + + # pick random cell to show + for cell in mesh.cells_to_edges[10]: + a, b = mesh.edges[cell] + plt.plot( + [mesh.points[a][0], mesh.points[b][0]], + [mesh.points[a][1], mesh.points[b][1]], + color='r') + + plt.show() diff --git a/sasdata/slicing/meshes/mesh.py b/sasdata/slicing/meshes/mesh.py new file mode 100644 index 000000000..8cfd8a6a0 --- /dev/null +++ b/sasdata/slicing/meshes/mesh.py @@ -0,0 +1,242 @@ +from collections.abc import Sequence + +import matplotlib.pyplot as plt +import numpy as np +from matplotlib import cm +from matplotlib.collections import LineCollection + +from sasdata.slicing.meshes.util import closed_loop_edges + + +class Mesh: + def __init__(self, + points: np.ndarray, + cells: Sequence[Sequence[int]]): + + """ + Object representing a mesh. + + Parameters are the values: + mesh points + map from edge to points + map from cells to edges + + it is done this way to ensure a non-redundant representation of cells and edges, + however there are no checks for the topology of the mesh, this is assumed to be done by + whatever creates it. There are also no checks for ordering of cells. + + :param points: points in 2D forming vertices of the mesh + :param cells: ordered lists of indices of points forming each cell (face) + + """ + + self.points = points + self.cells = cells + + # Get edges + + edges = set() + for cell_index, cell in enumerate(cells): + + for a, b in closed_loop_edges(cell): + # make sure the representation is unique + if a > b: + edges.add((a, b)) + else: + edges.add((b, a)) + + self.edges = list(edges) + + # Associate edges with faces + + edge_lookup = {edge: i for i, edge in enumerate(self.edges)} + self.cells_to_edges = [] + self.cells_to_edges_signs = [] + + for cell in cells: + + this_cell_data = [] + this_sign_data = [] + + for a, b in closed_loop_edges(cell): + # make sure the representation is unique + if a > b: + this_cell_data.append(edge_lookup[(a, b)]) + this_sign_data.append(1) + else: + this_cell_data.append(edge_lookup[(b, a)]) + this_sign_data.append(-1) + + self.cells_to_edges.append(this_cell_data) + self.cells_to_edges_signs.append(this_sign_data) + + # Counts for elements + self.n_points = self.points.shape[0] + self.n_edges = len(self.edges) + self.n_cells = len(self.cells) + + # Areas + self._areas = None + + + @property + def areas(self): + """ Areas of cells """ + + if self._areas is None: + # Calculate areas + areas = [] + for cell in self.cells: + # Use triangle shoelace formula, basically calculate the + # determinant based on of triangles with one point at 0,0 + a_times_2 = 0.0 + for i1, i2 in closed_loop_edges(cell): + p1 = self.points[i1, :] + p2 = self.points[i2, :] + a_times_2 += p1[0]*p2[1] - p1[1]*p2[0] + + areas.append(0.5*np.abs(a_times_2)) + + # Save in cache + self._areas = np.array(areas) + + # Return cache + return self._areas + + + def show(self, actually_show=True, show_labels=False, **kwargs): + """ Show on a plot """ + ax = plt.gca() + segments = [[self.points[edge[0]], self.points[edge[1]]] for edge in self.edges] + line_collection = LineCollection(segments=segments, **kwargs) + ax.add_collection(line_collection) + + if show_labels: + text_color = kwargs["color"] if "color" in kwargs else 'k' + for i, cell in enumerate(self.cells): + xy = np.sum(self.points[cell, :], axis=0)/len(cell) + ax.text(xy[0], xy[1], str(i), horizontalalignment="center", verticalalignment="center", color=text_color) + + x_limits = [np.min(self.points[:,0]), np.max(self.points[:,0])] + y_limits = [np.min(self.points[:,1]), np.max(self.points[:,1])] + + plt.xlim(x_limits) + plt.ylim(y_limits) + + if actually_show: + plt.show() + + def locate_points(self, x: np.ndarray, y: np.ndarray): + """ Find the cells that contain the specified points""" + + x = x.reshape(-1) + y = y.reshape(-1) + + xy = np.concatenate(([x], [y]), axis=1) + + # The most simple implementation is not particularly fast, especially in python + # + # Less obvious, but hopefully faster strategy + # + # Ultimately, checking the inclusion of a point within a polygon + # requires checking the crossings of a half line with the polygon's + # edges. + # + # A fairly efficient thing to do is to check every edge for crossing + # the axis parallel lines x=point_x. + # Then these edges that cross can map back to the polygons they're in + # and a final check for inclusion can be done with the edge sign property + # and some explicit checking of the + # + # Basic idea is: + # 1) build a matrix for each point-edge pair + # True if the edge crosses the half-line above a point + # 2) for each cell get the winding number by evaluating the + # sum of the component edges, weighted 1/-1 according to direction + + + edges = np.array(self.edges) + + edge_xy_1 = self.points[edges[:, 0], :] + edge_xy_2 = self.points[edges[:, 1], :] + + edge_x_1 = edge_xy_1[:, 0] + edge_x_2 = edge_xy_2[:, 0] + + + + # Make an n_edges-by-n_inputs boolean matrix that indicates which of the + # edges cross x=points_x line + crossers = np.logical_xor( + edge_x_1.reshape(-1, 1) < x.reshape(1, -1), + edge_x_2.reshape(-1, 1) < x.reshape(1, -1)) + + # Calculate the gradients, some might be infs, but none that matter will be + # TODO: Disable warnings + gradients = (edge_xy_2[:, 1] - edge_xy_1[:, 1]) / (edge_xy_2[:, 0] - edge_xy_1[:, 0]) + + # Distance to crossing points edge 0 + delta_x = x.reshape(1, -1) - edge_x_1.reshape(-1, 1) + + # Signed distance from point to y (doesn't really matter which sign) + delta_y = gradients.reshape(-1, 1) * delta_x + edge_xy_1[:, 1:] - y.reshape(1, -1) + + score_matrix = np.logical_and(delta_y > 0, crossers) + + output = -np.ones(len(x), dtype=int) + for cell_index, (cell_edges, sign) in enumerate(zip(self.cells_to_edges, self.cells_to_edges_signs)): + cell_score = np.sum(score_matrix[cell_edges, :] * np.array(sign).reshape(-1, 1), axis=0) + points_in_cell = np.abs(cell_score) == 1 + output[points_in_cell] = cell_index + + return output + + def show_data(self, + data: np.ndarray, + cmap='winter', + mesh_color='white', + show_mesh=False, + actually_show=True, + density=False): + + """ Show with data """ + + colormap = cm.get_cmap(cmap, 256) + + data = data.reshape(-1) + + if density: + data = data / self.areas + + cmin = np.min(data) + cmax = np.max(data) + + color_index_map = np.array(255 * (data - cmin) / (cmax - cmin), dtype=int) + + for cell, color_index in zip(self.cells, color_index_map): + + color = colormap(color_index) + + plt.fill(self.points[cell, 0], self.points[cell, 1], color=color, edgecolor=None) + + if show_mesh: + self.show(actually_show=False, color=mesh_color) + + if actually_show: + self.show() + + +if __name__ == "__main__": + from test.slicers.meshes_for_testing import location_test_mesh, location_test_points_x, location_test_points_y + + cell_indices = location_test_mesh.locate_points(location_test_points_x, location_test_points_y) + + print(cell_indices) + + for i in range(location_test_mesh.n_cells): + inds = cell_indices == i + plt.scatter( + location_test_points_x.reshape(-1)[inds], + location_test_points_y.reshape(-1)[inds]) + + location_test_mesh.show() diff --git a/sasdata/slicing/meshes/meshmerge.py b/sasdata/slicing/meshes/meshmerge.py new file mode 100644 index 000000000..ae950803e --- /dev/null +++ b/sasdata/slicing/meshes/meshmerge.py @@ -0,0 +1,155 @@ +import time + +import numpy as np + +from sasdata.slicing.meshes.delaunay_mesh import delaunay_mesh +from sasdata.slicing.meshes.mesh import Mesh + + +def meshmerge(mesh_a: Mesh, mesh_b: Mesh) -> tuple[Mesh, np.ndarray, np.ndarray]: + """ Take two lists of polygons and find their intersections + + Polygons in each of the input variables should not overlap i.e. a point in space should be assignable to + at most one polygon in mesh_a and at most one polygon in mesh_b + + Mesh topology should be sensible, otherwise bad things might happen, also, the cells of the input meshes + must be in order (which is assumed by the mesh class constructor anyway). + + :returns: + 1) A triangulated mesh based on both sets of polygons together + 2) The indices of the mesh_a polygon that corresponds to each triangle, -1 for nothing + 3) The indices of the mesh_b polygon that corresponds to each triangle, -1 for nothing + + """ + + t0 = time.time() + + # Find intersections of all edges in mesh one with edges in mesh two + + # Fastest way might just be to calculate the intersections of all lines on edges, + # see whether we need filtering afterwards + + edges_a = np.array(mesh_a.edges, dtype=int) + edges_b = np.array(mesh_b.edges, dtype=int) + + edge_a_1 = mesh_a.points[edges_a[:, 0], :] + edge_a_2 = mesh_a.points[edges_a[:, 1], :] + edge_b_1 = mesh_b.points[edges_b[:, 0], :] + edge_b_2 = mesh_b.points[edges_b[:, 1], :] + + a_grid, b_grid = np.mgrid[0:mesh_a.n_edges, 0:mesh_b.n_edges] + a_grid = a_grid.reshape(-1) + b_grid = b_grid.reshape(-1) + + p1 = edge_a_1[a_grid, :] + p2 = edge_a_2[a_grid, :] + p3 = edge_b_1[b_grid, :] + p4 = edge_b_2[b_grid, :] + + # + # TODO: Investigate whether adding a bounding box check will help with speed, seems likely as most edges wont cross + # + + # + # Solve the equations + # + # z_a1 + s delta_z_a = z_b1 + t delta_z_b + # + # for z = (x, y) + # + + start_point_diff = p1 - p3 + + delta1 = p2 - p1 + delta3 = p4 - p3 + + deltas = np.concatenate(([-delta1], [delta3]), axis=0) + deltas = np.moveaxis(deltas, 0, 2) + + non_singular = np.linalg.det(deltas) != 0 + + st = np.linalg.solve(deltas[non_singular], start_point_diff[non_singular]) + + # Find the points where s and t are in (0, 1) + + intersection_inds = np.logical_and( + np.logical_and(st[:, 0] > 0, st[:, 0] < 1), + np.logical_and(st[:, 1] > 0, st[:, 1] < 1)) + + start_points_for_intersections = p1[non_singular][intersection_inds, :] + deltas_for_intersections = delta1[non_singular][intersection_inds, :] + + points_to_add = start_points_for_intersections + st[intersection_inds, 0].reshape(-1,1) * deltas_for_intersections + + t1 = time.time() + print("Edge intersections:", t1 - t0) + + # Build list of all input points, in a way that we can check for coincident points + + + points = np.concatenate(( + mesh_a.points, + mesh_b.points, + points_to_add + )) + + + # Remove coincident points + + points = np.unique(points, axis=0) + + # Triangulate based on these intersections + + output_mesh = delaunay_mesh(points[:, 0], points[:, 1]) + + + t2 = time.time() + print("Delaunay:", t2 - t1) + + + # Find centroids of all output triangles, and find which source cells they belong to + + ## step 1) Assign -1 to all cells of original meshes + assignments_a = -np.ones(output_mesh.n_cells, dtype=int) + assignments_b = -np.ones(output_mesh.n_cells, dtype=int) + + ## step 2) Find centroids of triangulated mesh (just needs to be a point inside, but this is a good one) + centroids = [] + for cell in output_mesh.cells: + centroid = np.sum(output_mesh.points[cell, :]/3, axis=0) + centroids.append(centroid) + + centroids = np.array(centroids) + + t3 = time.time() + print("Centroids:", t3 - t2) + + + ## step 3) Find where points belong based on Mesh classes point location algorithm + + assignments_a = mesh_a.locate_points(centroids[:, 0], centroids[:, 1]) + assignments_b = mesh_b.locate_points(centroids[:, 0], centroids[:, 1]) + + t4 = time.time() + print("Assignments:", t4 - t3) + + return output_mesh, assignments_a, assignments_b + + +def main(): + from voronoi_mesh import voronoi_mesh + + n1 = 100 + n2 = 100 + + m1 = voronoi_mesh(np.random.random(n1), np.random.random(n1)) + m2 = voronoi_mesh(np.random.random(n2), np.random.random(n2)) + + + mesh, assignement1, assignement2 = meshmerge(m1, m2) + + mesh.show() + + +if __name__ == "__main__": + main() diff --git a/sasdata/slicing/meshes/util.py b/sasdata/slicing/meshes/util.py new file mode 100644 index 000000000..da5b6e370 --- /dev/null +++ b/sasdata/slicing/meshes/util.py @@ -0,0 +1,11 @@ +from collections.abc import Sequence +from typing import TypeVar + +T = TypeVar("T") + +def closed_loop_edges(values: Sequence[T]) -> tuple[T, T]: + """ Generator for a closed loop of edge pairs """ + for pair in zip(values, values[1:]): + yield pair + + yield values[-1], values[0] diff --git a/sasdata/slicing/meshes/voronoi_mesh.py b/sasdata/slicing/meshes/voronoi_mesh.py new file mode 100644 index 000000000..2f36d3780 --- /dev/null +++ b/sasdata/slicing/meshes/voronoi_mesh.py @@ -0,0 +1,96 @@ +import numpy as np +from scipy.spatial import Voronoi + +from sasdata.slicing.meshes.mesh import Mesh + + +def voronoi_mesh(x, y, debug_plot=False) -> Mesh: + """ Create a mesh based on a voronoi diagram of points """ + + input_data = np.array((x.reshape(-1), y.reshape(-1))).T + + # Need to make sure mesh covers a finite region, probably not important for + # much data stuff, but is important for plotting + # + # * We want the cells at the edge of the mesh to have a reasonable size, definitely not infinite + # * The exact size doesn't matter that much + # * It should work well with a grid, but also + # * ...it should be robust so that if the data isn't on a grid, it doesn't cause any serious problems + # + # Plan: Create a square border of points that are totally around the points, this is + # at the distance it would be if it was an extra row of grid points + # to do this we'll need + # 1) an estimate of the grid spacing + # 2) the bounding box of the grid + # + + + # Use the median area of finite voronoi cells as an estimate + voronoi = Voronoi(input_data) + finite_cells = [region for region in voronoi.regions if -1 not in region and len(region) > 0] + premesh = Mesh(points=voronoi.vertices, cells=finite_cells) + + area_spacing = np.median(premesh.areas) + gap = np.sqrt(area_spacing) + + # Bounding box is easy + x_min, y_min = np.min(input_data, axis=0) + x_max, y_max = np.max(input_data, axis=0) + + # Create a border + n_x = int(np.round((x_max - x_min)/gap)) + n_y = int(np.round((y_max - y_min)/gap)) + + top_bottom_xs = np.linspace(x_min - gap, x_max + gap, n_x + 3) + left_right_ys = np.linspace(y_min, y_max, n_y + 1) + + top = np.array([top_bottom_xs, (y_max + gap) * np.ones_like(top_bottom_xs)]) + bottom = np.array([top_bottom_xs, (y_min - gap) * np.ones_like(top_bottom_xs)]) + left = np.array([(x_min - gap) * np.ones_like(left_right_ys), left_right_ys]) + right = np.array([(x_max + gap) * np.ones_like(left_right_ys), left_right_ys]) + + added_points = np.concatenate((top, bottom, left, right), axis=1).T + + if debug_plot: + import matplotlib.pyplot as plt + plt.scatter(x, y) + plt.scatter(added_points[:, 0], added_points[:, 1]) + plt.show() + + new_points = np.concatenate((input_data, added_points), axis=0) + voronoi = Voronoi(new_points) + + # Remove the cells that correspond to the added edge points, + # Because the points on the edge of the square are (weakly) convex, these + # regions be infinite + + # finite_cells = [region for region in voronoi.regions if -1 not in region and len(region) > 0] + + # ... however, we can just use .region_points + input_regions = voronoi.point_region[:input_data.shape[0]] + cells = [voronoi.regions[region_index] for region_index in input_regions] + + return Mesh(points=voronoi.vertices, cells=cells) + + +def square_grid_check(): + values = np.linspace(-10, 10, 21) + x, y = np.meshgrid(values, values) + + mesh = voronoi_mesh(x, y) + + mesh.show(show_labels=True) + +def random_grid_check(): + import matplotlib.pyplot as plt + points = np.random.random((100, 2)) + mesh = voronoi_mesh(points[:, 0], points[:, 1], True) + mesh.show(actually_show=False) + plt.scatter(points[:, 0], points[:, 1]) + plt.show() + + +if __name__ == "__main__": + square_grid_check() + # random_grid_check() + diff --git a/sasdata/slicing/rebinning.py b/sasdata/slicing/rebinning.py new file mode 100644 index 000000000..060b2e0ca --- /dev/null +++ b/sasdata/slicing/rebinning.py @@ -0,0 +1,148 @@ +import time +from abc import ABC, abstractmethod +from dataclasses import dataclass + +import numpy as np + +from sasdata.slicing.meshes.mesh import Mesh +from sasdata.slicing.meshes.meshmerge import meshmerge +from sasdata.slicing.meshes.voronoi_mesh import voronoi_mesh + + +@dataclass +class CacheData: + """ Data cached for repeated calculations with the same coordinates """ + input_coordinates: np.ndarray # Input data + input_coordinates_mesh: Mesh # Mesh of the input data + merged_mesh_data: tuple[Mesh, np.ndarray, np.ndarray] # mesh information about the merging + + +class Rebinner(ABC): + + + def __init__(self): + """ Base class for rebinning methods""" + + self._bin_mesh_cache: Mesh | None = None # cached version of the output bin mesh + + # Output dependent caching + self._input_cache: CacheData | None = None + + + @abstractmethod + def _bin_coordinates(self) -> np.ndarray: + """ Coordinates for the output bins """ + + @abstractmethod + def _bin_mesh(self) -> Mesh: + """ Get the meshes used for binning """ + + @property + def allowable_orders(self) -> list[int]: + return [-1, 0, 1] + + @property + def bin_mesh(self) -> Mesh: + + if self._bin_mesh_cache is None: + bin_mesh = self._bin_mesh() + self._bin_mesh_cache = bin_mesh + + return self._bin_mesh_cache + + def _post_processing(self, coordinates, values) -> tuple[np.ndarray, np.ndarray]: + """ Perform post-processing on the mesh binned values """ + # Default is to do nothing, override if needed + return coordinates, values + + def _calculate(self, input_coordinates: np.ndarray, input_data: np.ndarray, order: int) -> np.ndarray: + """ Main calculation """ + + if order == -1: + # Construct the input output mapping just based on input points being the output cells, + # Equivalent to the original binning method + + mesh = self.bin_mesh + bin_identities = mesh.locate_points(input_coordinates[:,0], input_coordinates[:, 1]) + output_data = np.zeros(mesh.n_cells, dtype=float) + + for index, bin in enumerate(bin_identities): + if bin >= 0: + output_data[bin] += input_data[index] + + return output_data + + else: + # Use a mapping based on meshes + + # Either create de-cache the appropriate mesh + # Why not use a hash? Hashing takes time, equality checks are pretty fast, need to check equality + # when there is a hit anyway in case of very rare chance of collision, hits are the most common case, + # we want it to work 100% of the time, not 99.9999% + if self._input_cache is not None and np.all(self._input_cache.input_coordinates == input_coordinates): + + input_coordinate_mesh = self._input_cache.input_coordinates_mesh + merge_data = self._input_cache.merged_mesh_data + + else: + # Calculate mesh data + input_coordinate_mesh = voronoi_mesh(input_coordinates[:,0], input_coordinates[:, 1]) + self._data_mesh_cache = input_coordinate_mesh + + merge_data = meshmerge(self.bin_mesh, input_coordinate_mesh) + + # Cache mesh data + self._input_cache = CacheData( + input_coordinates=input_coordinates, + input_coordinates_mesh=input_coordinate_mesh, + merged_mesh_data=merge_data) + + merged_mesh, merged_to_output, merged_to_input = merge_data + + # Calculate values according to the order parameter + t0 = time.time() + if order == 0: + # Based on the overlap of cells only + + input_areas = input_coordinate_mesh.areas + output = np.zeros(self.bin_mesh.n_cells, dtype=float) + + for input_index, output_index, area in zip(merged_to_input, merged_to_output, merged_mesh.areas): + if input_index == -1 or output_index == -1: + # merged region does not correspond to anything of interest + continue + + output[output_index] += input_data[input_index] * area / input_areas[input_index] + + print("Main calc:", time.time() - t0) + + return output + + elif order == 1: + # Linear interpolation requires the following relationship with the data, + # as the input data is the total over the whole input cell, the linear + # interpolation requires continuity at the vertices, and a constraint on the + # integral. + # + # We can take each of the input points, and the associated values, and solve a system + # of linear equations that gives a total value. + + raise NotImplementedError("1st order (linear) interpolation currently not implemented") + + else: + raise ValueError(f"Expected order to be in {self.allowable_orders}, got {order}") + + def sum(self, x: np.ndarray, y: np.ndarray, data: np.ndarray, order: int = 0) -> np.ndarray: + """ Return the summed data in the output bins """ + return self._calculate(np.array((x.reshape(-1), y.reshape(-1))).T, data.reshape(-1), order) + + def error_propagate(self, input_coordinates: np.ndarray, data: np.ndarray, errors) -> np.ndarray: + raise NotImplementedError("Error propagation not implemented yet") + + def resolution_propagate(self, input_coordinates: np.ndarray, data: np.ndarray, errors) -> np.ndarray: + raise NotImplementedError("Resolution propagation not implemented yet") + + def average(self, x: np.ndarray, y: np.ndarray, data: np.ndarray, order: int = 0) -> np.ndarray: + """ Return the averaged data in the output bins """ + return self._calculate(np.array((x, y)).T, data.reshape(-1), order) / self.bin_mesh.areas + diff --git a/sasdata/slicing/sample_polygons.py b/sasdata/slicing/sample_polygons.py new file mode 100644 index 000000000..be54cd0a6 --- /dev/null +++ b/sasdata/slicing/sample_polygons.py @@ -0,0 +1,32 @@ +import numpy as np + + +def wedge(q0, q1, theta0, theta1, clockwise=False, n_points_per_degree=2): + + # Traverse a rectangle in curvilinear coordinates (q0, theta0), (q0, theta1), (q1, theta1), (q1, theta0) + if clockwise: + if theta1 > theta0: + theta0 += 2*np.pi + + else: + if theta0 > theta1: + theta1 += 2*np.pi + + subtended_angle = np.abs(theta1 - theta0) + n_points = int(subtended_angle*180*n_points_per_degree/np.pi)+1 + + angles = np.linspace(theta0, theta1, n_points) + + xs = np.concatenate((q0*np.cos(angles), q1*np.cos(angles[::-1]))) + ys = np.concatenate((q0*np.sin(angles), q1*np.sin(angles[::-1]))) + + return np.array((xs, ys)).T + + +if __name__ == "__main__": + import matplotlib.pyplot as plt + xy = wedge(0.3, 0.6, 2, 3) + + plt.plot(xy[:,0], xy[:,1]) + plt.show() + diff --git a/sasdata/slicing/slicer_demo.py b/sasdata/slicing/slicer_demo.py new file mode 100644 index 000000000..5626ded4d --- /dev/null +++ b/sasdata/slicing/slicer_demo.py @@ -0,0 +1,117 @@ +""" Dev docs: Demo to show the behaviour of the re-binning methods """ + +import matplotlib.pyplot as plt +import numpy as np + +from sasdata.slicing.meshes.voronoi_mesh import voronoi_mesh +from sasdata.slicing.slicers.AnularSector import AnularSector + +if __name__ == "__main__": + q_range = 1.5 + demo1 = True + demo2 = True + + # Demo of sums, annular sector over some not very circular data + + if demo1: + + x = (2 * q_range) * (np.random.random(400) - 0.5) + y = (2 * q_range) * (np.random.random(400) - 0.5) + + display_mesh = voronoi_mesh(x, y) + + + def lobe_test_function(x, y): + return 1 + np.sin(x*np.pi/q_range)*np.sin(y*np.pi/q_range) + + + random_lobe_data = lobe_test_function(x, y) + + plt.figure("Input Dataset 1") + display_mesh.show_data(random_lobe_data, actually_show=False) + + data_order_0 = [] + data_order_neg1 = [] + + sizes = np.linspace(0.1, 1, 100) + + for index, size in enumerate(sizes): + q0 = 0.75 - 0.6*size + q1 = 0.75 + 0.6*size + phi0 = np.pi/2 - size + phi1 = np.pi/2 + size + + rebinner = AnularSector(q0, q1, phi0, phi1) + + data_order_neg1.append(rebinner.sum(x, y, random_lobe_data, order=-1)) + data_order_0.append(rebinner.sum(x, y, random_lobe_data, order=0)) + + if index % 10 == 0: + plt.figure("Regions 1") + rebinner.bin_mesh.show(actually_show=False) + + plt.title("Regions") + + plt.figure("Sum of region, dataset 1") + + plt.plot(sizes, data_order_neg1) + plt.plot(sizes, data_order_0) + + plt.legend(["Order -1", "Order 0"]) + plt.title("Sum over region") + + + # Demo of averaging, annular sector over ring shaped data + + if demo2: + + x, y = np.meshgrid(np.linspace(-q_range, q_range, 41), np.linspace(-q_range, q_range, 41)) + x = x.reshape(-1) + y = y.reshape(-1) + + display_mesh = voronoi_mesh(x, y) + + + def ring_test_function(x, y): + r = np.sqrt(x**2 + y**2) + return np.log(np.sinc(r*1.5)**2) + + + grid_ring_data = ring_test_function(x, y) + + plt.figure("Input Dataset 2") + display_mesh.show_data(grid_ring_data, actually_show=False) + + data_order_0 = [] + data_order_neg1 = [] + + sizes = np.linspace(0.1, 1, 100) + + for index, size in enumerate(sizes): + q0 = 0.25 + q1 = 1.25 + + phi0 = np.pi/2 - size + phi1 = np.pi/2 + size + + rebinner = AnularSector(q0, q1, phi0, phi1) + + data_order_neg1.append(rebinner.average(x, y, grid_ring_data, order=-1)) + data_order_0.append(rebinner.average(x, y, grid_ring_data, order=0)) + + if index % 10 == 0: + plt.figure("Regions 2") + rebinner.bin_mesh.show(actually_show=False) + + plt.title("Regions") + + plt.figure("Average of region 2") + + plt.plot(sizes, data_order_neg1) + plt.plot(sizes, data_order_0) + + plt.legend(["Order -1", "Order 0"]) + plt.title("Sum over region") + + plt.show() + diff --git a/sasdata/slicing/slicers/AnularSector.py b/sasdata/slicing/slicers/AnularSector.py new file mode 100644 index 000000000..56ed5f262 --- /dev/null +++ b/sasdata/slicing/slicers/AnularSector.py @@ -0,0 +1,44 @@ +import numpy as np + +from sasdata.slicing.meshes.mesh import Mesh +from sasdata.slicing.rebinning import Rebinner + + +class AnularSector(Rebinner): + """ A single annular sector (wedge sum)""" + def __init__(self, q0: float, q1: float, phi0: float, phi1: float, points_per_degree: int=2): + super().__init__() + + self.q0 = q0 + self.q1 = q1 + self.phi0 = phi0 + self.phi1 = phi1 + + self.points_per_degree = points_per_degree + + def _bin_mesh(self) -> Mesh: + + n_points = np.max([int(1 + 180*self.points_per_degree*(self.phi1 - self.phi0) / np.pi), 2]) + + angles = np.linspace(self.phi0, self.phi1, n_points) + + row1 = self.q0 * np.array([np.cos(angles), np.sin(angles)]) + row2 = self.q1 * np.array([np.cos(angles), np.sin(angles)])[:, ::-1] + + points = np.concatenate((row1, row2), axis=1).T + + cells = [[i for i in range(2*n_points)]] + + return Mesh(points=points, cells=cells) + + def _bin_coordinates(self) -> np.ndarray: + return np.array([], dtype=float) + + +def main(): + """ Just show a random example""" + AnularSector(1, 2, 1, 2).bin_mesh.show() + + +if __name__ == "__main__": + main() diff --git a/sasdata/slicing/slicers/__init__.py b/sasdata/slicing/slicers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/slicing/transforms.py b/sasdata/slicing/transforms.py new file mode 100644 index 000000000..03ee1968e --- /dev/null +++ b/sasdata/slicing/transforms.py @@ -0,0 +1,57 @@ +import matplotlib.pyplot as plt +import numpy as np +from matplotlib import cm +from scipy.spatial import Voronoi + +# Some test data + +qx_base_values = np.linspace(-10, 10, 21) +qy_base_values = np.linspace(-10, 10, 21) + +qx, qy = np.meshgrid(qx_base_values, qy_base_values) + +include = np.logical_not((np.abs(qx) < 2) & (np.abs(qy) < 2)) + +qx = qx[include] +qy = qy[include] + +r = np.sqrt(qx**2 + qy**2) + +data = np.log((1+np.cos(3*r))*np.exp(-r*r)) + +colormap = cm.get_cmap('winter', 256) + +def get_data_mesh(x, y, data): + + input_data = np.array((x, y)).T + voronoi = Voronoi(input_data) + + # plt.scatter(voronoi.vertices[:,0], voronoi.vertices[:,1]) + # plt.scatter(voronoi.points[:,0], voronoi.points[:,1]) + + cmin = np.min(data) + cmax = np.max(data) + + color_index_map = np.array(255 * (data - cmin) / (cmax - cmin), dtype=int) + + for point_index, points in enumerate(voronoi.points): + + region_index = voronoi.point_region[point_index] + region = voronoi.regions[region_index] + + if len(region) > 0: + + if -1 in region: + + pass + + else: + + color = colormap(color_index_map[point_index]) + + circly = region + [region[0]] + plt.fill(voronoi.vertices[circly, 0], voronoi.vertices[circly, 1], color=color, edgecolor="white") + + plt.show() + +get_data_mesh(qx.reshape(-1), qy.reshape(-1), data) diff --git a/sasdata/temp_ascii_reader.py b/sasdata/temp_ascii_reader.py index d8f726f4f..d1cb9ec7a 100644 --- a/sasdata/temp_ascii_reader.py +++ b/sasdata/temp_ascii_reader.py @@ -1,27 +1,8 @@ -import re -from dataclasses import dataclass, field, replace -from enum import Enum -from os import path +#!/usr/bin/env python -import numpy as np +from enum import Enum -from sasdata.ascii_reader_metadata import ( - AsciiMetadataCategory, - AsciiReaderMetadata, - bidirectional_pairings, - pairings, -) from sasdata.data import SasData -from sasdata.dataset_types import DatasetType, one_dim, unit_kinds -from sasdata.default_units import get_default_unit -from sasdata.guess import ( - guess_column_count, - guess_columns, - guess_dataset_type, - guess_starting_position, -) -from sasdata.metadata import Metadata, MetaNode -from sasdata.quantities.quantity import Quantity from sasdata.quantities.units import NamedUnit @@ -31,192 +12,5 @@ class AsciiSeparator(Enum): Tab = 2 -# TODO: Turn them all of for now so the caller can turn one of them on. But is this the desired behaviour? -def initialise_separator_dict(initial_value: bool = False) -> dict[str, bool]: - return {"Whitespace": initial_value, "Comma": initial_value, "Tab": initial_value} - - -@dataclass -class AsciiReaderParams: - """This object contains the parameters that are used to load a series of - ASCII files. These parameters can be generated by the ASCII Reader Dialog - when using SasView.""" - - # These will be the FULL file path. Will need to convert to basenames for some functions. - filenames: list[str] - # The unit object for the column should only be None if the column is ! - columns: list[tuple[str, NamedUnit | None]] - metadata: AsciiReaderMetadata = field(default_factory=AsciiReaderMetadata) - starting_line: int = 0 - excluded_lines: set[int] = field(default_factory=set) - separator_dict: dict[str, bool] = field(default_factory=initialise_separator_dict) - # Take a copy in case its mutated (which it shouldn't be) - dataset_type: DatasetType = field(default_factory=lambda: replace(one_dim)) - - def __post_init__(self): - self.initialise_metadata() - - def initialise_metadata(self): - for filename in self.filenames: - basename = path.basename(filename) - if basename not in self.metadata.filename_separator: - self.metadata.filename_separator[basename] = "_" - self.metadata.filename_specific_metadata[basename] = {} - - @property - def columns_included(self) -> list[tuple[str, NamedUnit]]: - return [ - column - for column in self.columns - if column[0] != "" and isinstance(column[1], NamedUnit) - ] - - -# TODO: Should I make this work on a list of filenames as well? -def guess_params_from_filename( - filename: str, dataset_type: DatasetType -) -> AsciiReaderParams: - # Lets just assume we want all of the seaprators on. This seems to work for most files. - separator_dict = initialise_separator_dict(True) - with open(filename) as file: - lines = file.readlines() - lines_split = [split_line(separator_dict, line) for line in lines] - startpos = guess_starting_position(lines_split) - colcount = guess_column_count(lines_split, startpos) - columns = [ - (x, get_default_unit(x, unit_kinds[x])) - for x in guess_columns(colcount, dataset_type) - if x in unit_kinds - ] - params = AsciiReaderParams( - [filename], - columns, - starting_line=startpos, - separator_dict=separator_dict, - dataset_type=guess_dataset_type(filename), - ) - return params - - -def split_line(separator_dict: dict[str, bool], line: str) -> list[str]: - """Split a line in a CSV file based on which seperators the user has - selected on the widget. - - """ - expr = "" - for seperator, isenabled in separator_dict.items(): - if isenabled: - if expr != r"": - expr += r"|" - match seperator: - case "Comma": - seperator_text = r"," - case "Whitespace": - seperator_text = r"\s+" - case "Tab": - seperator_text = r"\t" - expr += seperator_text - - return re.split(expr, line.strip()) - - -# TODO: Implement error handling. -def load_quantities(params: AsciiReaderParams, filename: str) -> dict[str, Quantity]: - """Load a list of quantities from the filename based on the params.""" - with open(filename) as ascii_file: - lines = ascii_file.readlines() - arrays: list[np.ndarray] = [] - for _ in params.columns_included: - arrays.append(np.zeros(len(lines) - params.starting_line)) - for i, current_line in enumerate(lines): - if i < params.starting_line or current_line in params.excluded_lines: - continue - line_split = split_line(params.separator_dict, current_line) - try: - for j, token in enumerate(line_split): - # Sometimes in the split, there might be an extra column that doesn't need to be there (e.g. an empty - # string.) This won't convert to a float so we need to ignore it. - if j >= len(params.columns_included): - continue - # TODO: Data might not be floats. Maybe don't hard code this. - arrays[j][i - params.starting_line] = float(token) - except ValueError: - # If any of the lines contain non-numerical data, then this line can't be read in as a quantity so it - # should be ignored entirely. - print(f"Line {i + 1} skipped.") - continue - file_quantities = { - name: Quantity(arrays[i], unit) - for i, (name, unit) in enumerate(params.columns_included) - } - return file_quantities - - -def import_metadata(metadata: dict[str, AsciiMetadataCategory[str]]) -> MetaNode: - root_contents = [] - for top_level_key, top_level_item in metadata.items(): - children = [] - for metadatum_name, metadatum in top_level_item.values.items(): - children.append(MetaNode(name=metadatum_name, attrs={}, contents=metadatum)) - if top_level_key == "other": - root_contents.extend(children) - else: - group = MetaNode(name=top_level_key, attrs={}, contents=children) - root_contents.append(group) - return MetaNode(name="root", attrs={}, contents=root_contents) - - -def merge_uncertainties(quantities: dict[str, Quantity]) -> dict[str, Quantity]: - """Data in the ASCII files will have the uncertainties in a separate column. - This function will merge columns of data with the columns containing their - uncertainties so that both are in one Quantity object.""" - new_quantities: dict[str, Quantity] = {} - error_quantity_names = pairings.values() - for name, quantity in quantities.items(): - if name in error_quantity_names: - continue - pairing = bidirectional_pairings.get(name, "") - error_quantity = None - for other_name, other_quantity in quantities.items(): - if other_name == pairing: - error_quantity = other_quantity - if error_quantity is not None: - to_add = quantity.with_standard_error(error_quantity) - else: - to_add = quantity - new_quantities[name] = to_add - return new_quantities - - -def load_data(params: AsciiReaderParams) -> list[SasData]: - """This loads a series of SasData objects based on the params. The amount of - SasData objects loaded will depend on how many filenames are present in the - list contained in the params.""" - loaded_data: list[SasData] = [] - for filename in params.filenames: - quantities = load_quantities(params, filename) - raw_metadata = import_metadata( - params.metadata.all_file_metadata(path.basename(filename)) - ) - metadata = Metadata( - title=None, - run=[], - definition=None, - sample=None, - instrument=None, - process=None, - raw=raw_metadata, - ) - data = SasData( - path.basename(filename), - merge_uncertainties(quantities), - params.dataset_type, - metadata, - ) - loaded_data.append(data) - return loaded_data - - -def load_data_default_params(filename: str) -> list[SasData]: - params = guess_params_from_filename(filename, guess_dataset_type(filename)) - return load_data(params) +def load_data(filename: str, starting_line: int, columns: list[tuple[str, NamedUnit]], separators: list[AsciiSeparator]) -> list[SasData]: + raise NotImplementedError() diff --git a/sasdata/temp_hdf5_reader.py b/sasdata/temp_hdf5_reader.py index 37a868d89..435f597ad 100644 --- a/sasdata/temp_hdf5_reader.py +++ b/sasdata/temp_hdf5_reader.py @@ -1,5 +1,4 @@ import logging -from collections.abc import Callable import h5py import numpy as np @@ -9,29 +8,15 @@ from sasdata.data import SasData from sasdata.data_backing import Dataset as SASDataDataset from sasdata.data_backing import Group as SASDataGroup -from sasdata.dataset_types import one_dim, two_dim -from sasdata.metadata import ( - Aperture, - BeamSize, - Collimation, - Detector, - Instrument, - Metadata, - MetaNode, - Process, - Rot3, - Sample, - Source, - Vec3, -) +from sasdata.metadata import Aperture, Collimation, Instrument, Source from sasdata.quantities import units -from sasdata.quantities.quantity import NamedQuantity, Quantity +from sasdata.quantities.quantity import NamedQuantity from sasdata.quantities.unit_parser import parse # test_file = "./example_data/1d_data/33837rear_1D_1.75_16.5_NXcanSAS_v3.h5" # test_file = "./example_data/1d_data/33837rear_1D_1.75_16.5_NXcanSAS.h5" -test_file = "./example_data/2d_data/BAM_2D.h5" -# test_file = "./example_data/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5" +# test_file = "./example_data/2d_data/BAM_2D.h5" +test_file = "./example_data/2d_data/14250_2D_NoDetInfo_NXcanSAS_v3.h5" # test_file = "./example_data/2d_data/33837rear_2D_1.75_16.5_NXcanSAS_v3.h5" logger = logging.getLogger(__name__) @@ -39,9 +24,6 @@ def recurse_hdf5(hdf5_entry): if isinstance(hdf5_entry, HDF5Dataset): - # - # print(hdf5_entry.dtype) - # print(type(hdf5_entry.dtype)) attributes = {name: hdf5_entry.attrs[name] for name in hdf5_entry.attrs} @@ -62,7 +44,7 @@ def recurse_hdf5(hdf5_entry): elif isinstance(hdf5_entry, HDF5Group): return SASDataGroup( name=hdf5_entry.name, - children={key: recurse_hdf5(hdf5_entry[key]) for key in hdf5_entry}, + children={key: recurse_hdf5(hdf5_entry[key]) for key in hdf5_entry.keys()}, ) else: @@ -74,7 +56,7 @@ def recurse_hdf5(hdf5_entry): GET_UNITS_FROM_ELSEWHERE = units.meters -def connected_data(node: SASDataGroup, name_prefix="") -> dict[str, Quantity]: +def connected_data(node: SASDataGroup, name_prefix="") -> list[NamedQuantity]: """In the context of NeXus files, load a group of data entries that are organised together match up the units and errors with their values""" # Gather together data with its error terms @@ -86,7 +68,7 @@ def connected_data(node: SASDataGroup, name_prefix="") -> dict[str, Quantity]: for name in node.children: child = node.children[name] - if "units" in child.attributes and child.attributes["units"]: + if "units" in child.attributes: units = parse(child.attributes["units"]) else: units = GET_UNITS_FROM_ELSEWHERE @@ -106,71 +88,61 @@ def connected_data(node: SASDataGroup, name_prefix="") -> dict[str, Quantity]: entries[name] = quantity - output : dict[str, Quantity] = {} + output = [] for name, entry in entries.items(): if name not in uncertainties: if name in uncertainty_map: uncertainty = entries[uncertainty_map[name]] new_entry = entry.with_standard_error(uncertainty) - output[name] = new_entry + output.append(new_entry) else: - output[name] = entry + output.append(entry) return output -### Begin metadata parsing code - -def parse_quantity(node : HDF5Group) -> Quantity[float]: - """Pull a single quantity with length units out of an HDF5 node""" - magnitude = node.astype(float)[0] - unit = node.attrs["units"] - return Quantity(magnitude, parse(unit)) - -def parse_string(node : HDF5Group) -> str: - """Access string data from a node""" - return node.asstr()[0] - -def opt_parse[T](node: HDF5Group, key: str, subparser: Callable[[HDF5Group], T]) -> T | None: - """Parse a subnode if it is present""" - if key in node: - return subparser(node[key]) - return None - -def attr_parse(node: HDF5Group, key: str) -> str | None: - """Parse an attribute if it is present""" - if key in node.attrs: - return node.attrs[key] - return None - - -def parse_apterture(node : HDF5Group) -> Aperture: - distance = opt_parse(node, "distance", parse_quantity) - name = attr_parse(node, "name") - size = opt_parse(node, "size", parse_vec3) - size_name = None - type_ = attr_parse(node, "type") - if size: - size_name = attr_parse(node["size"], "name") - else: - size_name = None - return Aperture(distance=distance, size=size, size_name=size_name, name=name, type_=type_) - -def parse_beam_size(node : HDF5Group) -> BeamSize: - name = attr_parse(node, "name") - size = parse_vec3(node) - return BeamSize(name=name, size=size) - -def parse_source(node : HDF5Group) -> Source: - radiation = opt_parse(node, "radiation", parse_string) - beam_shape = opt_parse(node, "beam_shape", parse_string) - beam_size = opt_parse(node, "beam_size", parse_beam_size) - wavelength = opt_parse(node, "wavelength", parse_quantity) - wavelength_min = opt_parse(node, "wavelength_min", parse_quantity) - wavelength_max = opt_parse(node, "wavelength_max", parse_quantity) - wavelength_spread = opt_parse(node, "wavelength_spread", parse_quantity) + +def parse_apertures(node) -> list[Aperture]: + result = [] + aps = [a for a in node if "aperture" in a] + for ap in aps: + distance = None + size = None + if "distance" in node[ap]: + distance = node[ap]["distance"] + if "size" in node[ap]: + x = y = z = None + if "x" in node[ap]: + x = node[ap]["size"]["x"] + if "y" in node[ap]: + y = node[ap]["size"]["y"] + if "z" in node[ap]: + z = node[ap]["size"]["z"] + if x is not None or y is not None or z is not None: + size = (x, y, z) + result.append(Aperture(distance=distance, size=size, size_name=size_name, name=name, apType=apType)) + return result + + +def parse_source(node) -> Source: + beam_shape = None + beam_size = None + wavelength = None + wavelength_min = None + wavelength_max = None + wavelength_spread = None + if "beam_shape" in node: + beam_shape = node["beam_shape"] + if "wavelength" in node: + wavelength = node["wavelength"] + if "wavelength_min" in node: + wavelength = node["wavelength_min"] + if "wavelength_max" in node: + wavelength = node["wavelength_max"] + if "wavelength_spread" in node: + wavelength = node["wavelength_spread"] return Source( - radiation=radiation, + radiation=node["radiation"].asstr()[0], beam_shape=beam_shape, beam_size=beam_size, wavelength=wavelength, @@ -179,173 +151,75 @@ def parse_source(node : HDF5Group) -> Source: wavelength_spread=wavelength_spread, ) -def parse_vec3(node : HDF5Group) -> Vec3: - """Parse a measured 3-vector""" - x = opt_parse(node, "x", parse_quantity) - y = opt_parse(node, "y", parse_quantity) - z = opt_parse(node, "z", parse_quantity) - return Vec3(x=x, y=y, z=z) - -def parse_rot3(node : HDF5Group) -> Rot3: - """Parse a measured rotation""" - roll = opt_parse(node, "roll", parse_quantity) - pitch = opt_parse(node, "pitch", parse_quantity) - yaw = opt_parse(node, "yaw", parse_quantity) - return Rot3(roll=roll, pitch=pitch, yaw=yaw) - -def parse_detector(node : HDF5Group) -> Detector: - name = opt_parse(node, "name", parse_string) - distance = opt_parse(node, "SDD", parse_quantity) - offset = opt_parse(node, "offset", parse_vec3) - orientation = opt_parse(node, "orientation", parse_rot3) - beam_center = opt_parse(node, "beam_center", parse_vec3) - pixel_size = opt_parse(node, "pixel_size", parse_vec3) - slit_length = opt_parse(node, "slit_length", parse_quantity) - - return Detector(name=name, - distance=distance, - offset=offset, - orientation=orientation, - beam_center=beam_center, - pixel_size=pixel_size, - slit_length=slit_length) - - - -def parse_collimation(node : HDF5Group) -> Collimation: - length = opt_parse(node, "length", parse_quantity) - return Collimation(length=length, apertures=[parse_apterture(node[ap]) - for ap in node if "aperture" in ap]) - - -def parse_instrument(node : HDF5Group) -> Instrument: + +def parse_collimation(node) -> Collimation: + if "length" in node: + length = node["length"] + else: + length = None + return Collimation(length=length, apertures=parse_apertures(node)) + + +def parse_instrument(raw, node) -> Instrument: return Instrument( collimations= [parse_collimation(node[x]) for x in node if "collimation" in x], - detector=[parse_detector(node[d]) for d in node if "detector" in d], source=parse_source(node["sassource"]), ) -def parse_sample(node : HDF5Group) -> Sample: - name = attr_parse(node, "name") - sample_id = opt_parse(node, "ID", parse_string) - thickness = opt_parse(node, "thickness", parse_quantity) - transmission = opt_parse(node, "transmission", lambda n: float(n[0].astype(str))) - temperature = opt_parse(node, "temperature", parse_quantity) - position = opt_parse(node, "position", parse_vec3) - orientation = opt_parse(node, "orientation", parse_rot3) - details : list[str] = sum([list(node[d].asstr()[()]) for d in node if "details" in d], []) - return Sample(name=name, - sample_id=sample_id, - thickness=thickness, - transmission=transmission, - temperature=temperature, - position=position, - orientation=orientation, - details=details) - -def parse_term(node : HDF5Group) -> tuple[str, str | Quantity[float]] | None: - name = attr_parse(node, "name") - unit = attr_parse(node, "unit") - value = attr_parse(node, "value") - if name is None or value is None: - return None - if unit and unit.strip(): - return (name, Quantity(float(value), units.symbol_lookup[unit])) - return (name, value) - - -def parse_process(node : HDF5Group) -> Process: - name = opt_parse(node, "name", parse_string) - date = opt_parse(node, "date", parse_string) - description = opt_parse(node, "description", parse_string) - term_values = [parse_term(node[n]) for n in node if "term" in n] - terms = {tup[0]: tup[1] for tup in term_values if tup is not None} - notes = [parse_string(node[n]) for n in node if "note" in n] - return Process(name=name, date=date, description=description, terms=terms, notes=notes) - -def load_raw(node: HDF5Group | HDF5Dataset) -> MetaNode: - name = node.name.split("/")[-1] - match node: - case HDF5Group(): - attrib = {a: node.attrs[a] for a in node.attrs} - contents = [load_raw(node[v]) for v in node] - return MetaNode(name=name, attrs=attrib, contents=contents) - case HDF5Dataset(dtype=dt): - attrib = {a: node.attrs[a] for a in node.attrs} - if (str(dt).startswith("|S")): - if "units" in attrib: - contents = Quantity(float(node.asstr()[0]), parse(attrib["units"])) - else: - contents = node.asstr()[0] - else: - if "units" in attrib and attrib["units"]: - contents = Quantity(node[:], parse(attrib["units"])) - else: - contents = node[:] - return MetaNode(name=name, attrs=attrib, contents=contents) - case _: - raise RuntimeError(f"Cannot load raw data of type {type(node)}") - -def parse_metadata(node : HDF5Group) -> Metadata: - instrument = opt_parse(node, "sasinstrument", parse_instrument) - sample = opt_parse(node, "sassample", parse_sample) - process = [parse_process(node[p]) for p in node if "sasprocess" in p] - title = opt_parse(node, "title", parse_string) - run = [parse_string(node[r]) for r in node if "run" in r] - definition = opt_parse(node, "definition", parse_string) - raw = load_raw(node) - return Metadata(process=process, - instrument=instrument, - sample=sample, - title=title, - run=run, - raw=raw, - definition=definition) -### End Metadata parsing code +def load_data(filename) -> list[SasData]: + with h5py.File(filename, 'r') as f: + loaded_data: list[SasData] = [] -def load_data(filename: str) -> dict[str, SasData]: - with h5py.File(filename, "r") as f: - loaded_data: dict[str, SasData] = {} + for root_key in f.keys(): - for root_key in f: entry = f[root_key] - data_contents : dict[str, Quantity] = {} + data_contents = [] + raw_metadata = {} - entry_keys = entry + entry_keys = [key for key in entry.keys()] - if not [k for k in entry if k.startswith("sasdata") or k.startswith("data")]: + if "sasdata" not in entry_keys and "data" not in entry_keys: logger.warning("No sasdata or data key") - logger.warning(f"Known keys: {[k for k in entry_keys]}") for key in entry_keys: component = entry[key] lower_key = key.lower() - if lower_key.startswith("sasdata") or lower_key.startswith("data"): + if lower_key == "sasdata" or lower_key == "data": datum = recurse_hdf5(component) - data_contents = connected_data(datum, str(filename)) + # TODO: Use named identifier + data_contents = connected_data(datum, "FILE_ID_HERE") - metadata = parse_metadata(f[root_key]) + else: + raw_metadata[key] = recurse_hdf5(component) - dataset_type = two_dim if "Qy" in data_contents else one_dim + instrument = opt_parse(f["sasentry01"], "sasinstrument", parse_instrument) + sample = opt_parse(f["sasentry01"], "sassample", parse_sample) + process = [parse_process(f["sasentry01"][p]) for p in f["sasentry01"] if "sasprocess" in p] + title = opt_parse(f["sasentry01"], "title", parse_string) + run = [parse_string(f["sasentry01"][r]) for r in f["sasentry01"] if "run" in r] + definition = opt_parse(f["sasentry01"], "definition", parse_string) - entry_key = entry.attrs["sasview_key"] if "sasview_key" in entry.attrs else root_key + metadata = Metadata(process=process, instrument=instrument, sample=sample, title=title, run=run, definition=definition) - loaded_data[entry_key] = SasData( + loaded_data.append( + SasData( name=root_key, - dataset_type=dataset_type, data_contents=data_contents, - metadata=metadata, + raw_metadata=SASDataGroup("root", raw_metadata), + instrument=instrument, verbose=False, ) + ) return loaded_data + if __name__ == "__main__": data = load_data(test_file) - for dataset in data.values(): - print(dataset.summary()) + for dataset in data: + print(dataset.summary(include_raw=False)) diff --git a/sasdata/temp_sesans_reader.py b/sasdata/temp_sesans_reader.py index fd480e40c..b6cfb6861 100644 --- a/sasdata/temp_sesans_reader.py +++ b/sasdata/temp_sesans_reader.py @@ -3,67 +3,37 @@ """ import re -from collections import defaultdict from itertools import groupby -import numpy as np - from sasdata.data import SasData from sasdata.data_util.loader_exceptions import FileContentsException -from sasdata.dataset_types import sesans +from sasdata.dataset_types import one_dim from sasdata.metadata import ( Metadata, MetaNode, Process, Sample, ) -from sasdata.quantities import unit_parser, units +from sasdata.quantities import unit_parser from sasdata.quantities.quantity import Quantity def parse_version(lines: list[str]) -> tuple[str, list[str]]: + import re + header = lines[0] m = re.search(r"FileFormatVersion\s+(\S+)", header) if m is None: - raise FileContentsException( - "Sesans file does not contain File Format Version header" - ) + raise FileContentsException("Alleged Sesans file does not contain File Format Version header") return (m.group(0), lines[1:]) - -def parse_title(kvs: dict[str, str]) -> str: - """Get the title from the key value store""" - if "Title" in kvs: - return kvs["Title"] - elif "DataFileTitle" in kvs: - return kvs["DataFileTitle"] - for k, v in kvs.items(): - if "Title" in k: - return v - return "" - - -def parse_kvs_quantity(key: str, kvs: dict[str, str]) -> Quantity | None: - if key not in kvs or key + "_unit" not in kvs: - return None - return Quantity(value=float(kvs[key]), units=unit_parser.parse(kvs[key + "_unit"])) - - -def parse_sample(kvs: dict[str, str]) -> Sample: - """Get the sample info from the key value store""" - - thickness = parse_kvs_quantity("Thickness", kvs) - if thickness is None: - raise FileContentsException( - "SES format must include sample thickness to normalise calculations" - ) - - return Sample( - name=kvs.get("Sample"), +def parse_metadata(lines: list[str]) -> tuple[Metadata, list[str]]: + sample = Sample( + name=None, sample_id=None, - thickness=thickness, + thickness=None, transmission=None, temperature=None, position=None, @@ -75,7 +45,7 @@ def parse_sample(kvs: dict[str, str]) -> Sample: def parse_process(kvs: dict[str, str]) -> Process: ymax = parse_kvs_quantity("Theta_ymax", kvs) zmax = parse_kvs_quantity("Theta_zmax", kvs) - orientation = kvs.get("Orientation") + orientation = parse_kvs_text("Orientation", kvs) if ymax is None: raise FileContentsException("SES file must specify Theta_ymax") @@ -84,7 +54,7 @@ def parse_process(kvs: dict[str, str]) -> Process: if orientation is None: raise FileContentsException("SES file must include encoding orientation") - terms: dict[str, str | Quantity] = { + terms: dict[str, str | Quantity[float]] = { "ymax": ymax, "zmax": zmax, "orientation": orientation, @@ -136,7 +106,7 @@ def parse_metadata(lines: list[str]) -> tuple[Metadata, dict[str, str], list[str # Parse key value store kvs: dict[str, str] = {} for line in parts[0]: - m = re.search(r"(\S+)\s+(.+)\n", line) + m = re.search("(\\S+)\\s+(.+)\n", line) if not m: continue kvs[m.group(1)] = m.group(2) @@ -149,55 +119,23 @@ def parse_metadata(lines: list[str]) -> tuple[Metadata, dict[str, str], list[str title=parse_title(kvs), run=[], definition=None, - raw=parse_metanode(kvs), ), - kvs, - parts[2], + lines, ) -def parse_data(lines: list[str], kvs: dict[str, str]) -> dict[str, Quantity]: - +def parse_data(lines: list[str]) -> dict[str, Quantity]: data_contents: dict[str, Quantity] = {} - headers = lines[0].split() - points = defaultdict(list) - for line in lines[1:]: - values = line.split() - for idx, v in enumerate(values): - points[headers[idx]].append(float(v)) - - for h in points: - if h.endswith("_error") and h[:-6] in headers: - # This was an error line - continue - unit = units.none - if h + "_unit" in kvs: - unit = unit_parser.parse(kvs[h + "_unit"]) - - error = None - if h + "_error" in headers: - error = np.asarray(points[h + "_error"]) - - data_contents[h] = Quantity( - value=np.asarray(points[h]), - units=unit, - standard_error=error, - ) - - for required in ["SpinEchoLength", "Depolarisation", "Wavelength"]: - if required not in data_contents: - raise FileContentsException(f"SES file missing {required}") - return data_contents def parse_sesans(lines: list[str]) -> SasData: version, lines = parse_version(lines) - metadata, kvs, lines = parse_metadata(lines) - data_contents = parse_data(lines, kvs) + metadata, lines = parse_metadata(lines) + data_contents = parse_data(lines) return SasData( name="Sesans", - dataset_type=sesans, + dataset_type=one_dim, data_contents=data_contents, metadata=metadata, verbose=False, diff --git a/sasdata/temp_xml_reader.py b/sasdata/temp_xml_reader.py index 2a15c251a..b6ea5f2cb 100644 --- a/sasdata/temp_xml_reader.py +++ b/sasdata/temp_xml_reader.py @@ -21,7 +21,7 @@ Source, Vec3, ) -from sasdata.quantities.quantity import Quantity +from sasdata.quantities.quantity import NamedQuantity, Quantity from sasdata.quantities.units import Unit from sasdata.quantities.units import none as unitless @@ -205,7 +205,7 @@ def parse_sample(node: etree._Element, version: str) -> Sample: ) -def parse_data(node: etree._Element, version: str) -> dict[str, Quantity]: +def parse_data(node: etree._Element, version: str, metadata: Metadata) -> dict[str, Quantity]: """Parse scattering data""" aos = [] keys = set() @@ -215,7 +215,7 @@ def parse_data(node: etree._Element, version: str) -> dict[str, Quantity]: struct = {} for value in idata.getchildren(): name = etree.QName(value).localname - if value.text is None or parse_string(value, version).strip() == "": + if value.text is None or value.text.strip() == "": continue if name not in us: unit = ( @@ -244,7 +244,7 @@ def parse_data(node: etree._Element, version: str) -> dict[str, Quantity]: result: dict[str, Quantity] = {} for k in keys: - result[k] = Quantity(np.array(soa[k]), us[k]) + result[k] = NamedQuantity(k, np.array(soa[k]), us[k], id_header=metadata.id_header) if k + "dev" in uncertainties: result[k] = result[k].with_standard_error( Quantity(np.array(soa[k + "dev"]), us[k + "dev"]) @@ -267,17 +267,18 @@ def load_raw(node: etree._Element, version: str) -> MetaNode: contents: Quantity[float] | str | list[MetaNode] = "" if nodes: contents = [load_raw(n, version) for n in nodes] - elif "unit" in attrib and attrib["unit"]: - value = parse_string(node, version) - if value: - try: - contents = Quantity(float(value), unit_parser.parse(attrib["unit"])) - except ValueError: + else: + if "unit" in attrib and attrib["unit"]: + value = parse_string(node, version) + if value: + try: + contents = Quantity(float(value), unit_parser.parse(attrib["unit"])) + except ValueError: + contents = value + else: contents = value else: - contents = value - else: - contents = parse_string(node, version) + contents = parse_string(node, version) return MetaNode(name=etree.QName(node).localname, attrs=attrib, contents=contents) @@ -322,7 +323,7 @@ def load_data(filename: str) -> dict[str, SasData]: datacount = 0 for n in entry.findall(f"{version}:SASdata", ns): datacount += 1 - data_set = parse_data(n, version) + data_set = parse_data(n, version, metadata) data = data_set break diff --git a/sasdata/transforms/NDrebin.py b/sasdata/transforms/NDrebin.py new file mode 100644 index 000000000..e5091a8e1 --- /dev/null +++ b/sasdata/transforms/NDrebin.py @@ -0,0 +1,522 @@ + + +import numpy as np +from numpy._typing import ArrayLike + +from sasdata.quantities.quantity import Quantity + + +class NDRebin: + """ + N-dimensional rebinning of data into regular bins, with optional + fractional binning and error propagation. + + Provide values at points with ND coordinates. + The coordinates may not be in a nice grid. + The data can be in any array shape. + + The coordinates are in the same shape plus one dimension, + preferably the first dimension, which is the ND coordinate + position + + Rebin that data into a regular grid. + + Note that this does lose some information from the underlying data, + as you are essentially averaging multiple measurements into one bin. + + Note that once can use this function to perform integrations over + one or more dimensions by setting the num_bins to 1 or the + step_size to infinity for one or more axes. The integration will + be performed from the lower to upper bound of that axis. + + Parameters + ---------- + data : Quantity[ArrayLike] + Data values in an Nd array. + coords : Quantity[ArrayLike] + The coordinates corresponding to each data point, same size of data + plus one more dimension with the same length as the + dimensionality of the space (Ndim) + data_errs : Quantity[ArrayLike], optional + Errors on data. Optional, the same size as data. + axes : ArrayLike | None = None + The axes of the coordinate system we are binning + into. Defaults to diagonal (e.g. (1,0,0), (0,1,0), and + (0,0,1) for 3D data). A list of Ndim element vectors + upper : ArrayLike | None = None + The upper limits along each axis. Defaults to the largest + values in the data if no limits are provided. + A 1D list of Ndims values. + lower : ArrayLike | None = None + The lower limits along each axis. Defaults to the smallest + values in the data if no limits are provided. + A 1D list of Ndims values. + step_size : ArrayLike | None = None + The size of steps along each axis. Supercedes + num_bins. A list of length Ndim. + num_bins : ArrayLike | None = None + The number of bins along each axis. Superceded by + step_size if step_size is provided. At least one of step_size + or num_bins must be provided. + fractional : bool = False + Whether to perform fractional binning or not. Defaults + to false. + -If false, measurements are binned into one bin, + the one they fall within. Roughly a "nearest neighbor" + approach. + -If true, fractional binning will be applied, where + the value of a measurement is distributed to its 2^Ndim + nearest neighbors weighted by proximity. For example, if + a point falls exactly between two bins, its value will be + given to both bins with 50% weight. This is roughly a + "linear interpolation" approach. Tends to do better at + reducing sharp peaks and edges if data is sampled unevenly. + However, this is roughly 2^Ndim times slower since you have + to address each bin 2^Ndim more times. + normalization : bool = True + Whether to normalize (average) the data or not. If false, + the data are just summed into each bin. If true, the weighted + average of all points added to a bin is computed. + + Attributes + ---------- + binned_data : + has size num_bins and is NDimensional, contains + the binned data + bin_centers_list : + is a list of 1D vectors, contains the + axes of the binned data. The coordinates of bin [i,j,k] + is given by + bin_centers_list[0][i]*axes[i]+bin_centers_list[1][j]*axes[j]+ + bin_centers_list[0][k]*axes[k] + binned_data_errs : + has size num_bins and is NDimensional, contains + the propagated errors of the binned_data + bins_list : + is a list of 1D vectors, is similar to bin_centers_list, + but instead contains the edges of the bins, so it is 1 longer + in each dimension + step_size : + is a list of Ndims numbers, contains the step size + along each dimension + num_bins : + is a list of Ndims numbers, contains the number + of bins along each dimension + + Methods + ------- + run(self): + Bin the data into the defined bins. + + Typical usage + ------------- + .. code-block:: + # test syntax 1 + Ndims = 4 + Nvals = int(1e4) + qmat = np.random.rand(Ndims, Nvals) + Imat = np.random.rand(Nvals) + + rebin = NDRebin(Imat, qmat, + step_size=0.1*np.random.rand(Ndims)+0.05, + lower=0.1*np.random.rand(Ndims)+0.0, + upper=0.1*np.random.rand(Ndims)+0.9) + rebin.run() + + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + + + # test syntax 2 + Ndims = 2 + Nvals = int(1e4) + qmat = np.random.rand(Ndims, 100, Nvals) + Imat = np.random.rand(100, Nvals) + Imat_errs = np.random.rand(100, Nvals) + + rebin = NDRebin(Imat, qmat, + data_errs = Imat_errs, + num_bins=[10,20], + axes = np.eye(2), + fractional=True) + rebin.run() + + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + Ibin_errs = rebin.binned_data_errs + bins_list = rebin.bins_list + step_size = rebin.step_size + num_bins = rebin.num_bins + """ + + def __init__( + self, + data: Quantity[ArrayLike], + coords: Quantity[ArrayLike], + data_errs: Quantity[ArrayLike] | None = None, + axes: ArrayLike | None = None, + upper: ArrayLike | None = None, + lower: ArrayLike | None = None, + step_size: ArrayLike | None = None, + num_bins: ArrayLike | None = None, + fractional: bool = False, + normalize: bool = True, + ): + self.data = data + self.coords = coords + self.data_errs = data_errs + self.axes = axes + self.upper = upper + self.lower = lower + self.step_size = step_size + self.num_bins = num_bins + self.fractional = fractional + self.normalize = normalize + + # Internal attributes initialised later + self.Nvals: int | None = None + self.Ndims: int | None = None + self.data_flat = None + self.errors_flat = None + self.coords_flat = None + self.bins_list = None + self.bin_centers_list = None + self.bin_inds = None + self.binned_data = None + self.binned_data_errs = None + self.n_samples = None + + self._prepared = False # flag to avoid double-prepare + + def __call__(self): + self.run() + + def run(self) -> None: + """Bin the data into the defined bins.""" + if not self._prepared: + self._prepare() + + if self.fractional: + self._calculate_fractional_bins() + else: + self._calculate_bins() + + self._norm_data() + + def _prepare(self) -> None: + """Compute derived quantities: shapes, flattened data, bins, indices.""" + if self._prepared: + return + + # check the size of the data and coords inputs + # and define Ndims and Nvals + self._check_data_coords() + + # flatten the input data and errors + self._check_data_errs() + + # flatten the coords + self._flatten_coords() + + # handle optional axes + if self.axes is None: + # make axes if not provided + self._make_axes() + else: + # project into specified axes + self._project_axes() + + # build the limits + self._build_limits() + + # make the bins + self._make_bins() + + # make the bin indices + self._create_bin_inds() + + self._prepared = True + + def _check_data_coords(self): + """Compute Nvals and Ndims and validate shapes.""" + # Identify number of points + self.Nvals = int(self.data.size) + + # Identify number of dimensions + Ndims = self.coords.size / self.Nvals + + # if Ndims is not an integer value we have a problem + if not float(Ndims).is_integer(): + raise ValueError("The coords have to have the same shape as " + "the data, plus one more dimension which is " + "length Ndims") + self.Ndims = int(Ndims) + + def _check_data_errs(self): + # flatten input data to 1D of length Nvals + self.data_flat = self.data.reshape(-1) + if self.data_errs is None: + self.errors_flat = 0*self.data_flat # no errors + else: + self.errors_flat = self.data_errs.reshape(-1) + + if self.errors_flat.shape != self.data_flat.shape: + raise ValueError("Data and errors have to have the same shape.") + + def _flatten_coords(self): + # if 1D, need to add a size 1 dimension index to coords + if self.Ndims == 1: + self.coords = self.coords.reshape(-1, 1) + + # check if the first axis of coords is the dimensions axis + if self.coords.shape[0] == self.Ndims: + # first check if it is the first axis + self.dim_axis = 0 + elif self.coords.shape[-1] == self.Ndims: + # now check if it is the last axis + self.dim_axis = -1 + else: + # search if any axis is size Ndims + self.dim_axis = next(i for i, s in enumerate(self.coords.shape) if s == self.Ndims) + + if not self.coords.shape[self.dim_axis] == self.Ndims: + raise ValueError("The coords have to have one dimension which is " + "the dimensionality of the space") + + # flatten coords to size Nvals x Ndims + moved = np.moveaxis(self.coords, self.dim_axis, 0) + self.coords_flat = moved.reshape(self.Ndims, -1).T + + def _make_axes(self): + # if axes are not provided, default to identity + if self.axes is None: + self.axes = np.eye(self.Ndims) + + def _project_axes(self): + # now project the data into the axes + self.axes_inv = np.linalg.inv(self.axes) + self.coords_flat = np.tensordot(self.coords_flat, self.axes_inv, axes=([1], [0])) + + def _build_limits(self): + # if limits were not provided, default to the min and max + # coord in each dimension + coords = self.coords_flat + mins = np.min(coords, axis=0) + maxs = np.max(coords, axis=0) + lower = mins if self.lower is None else self.lower + upper = maxs if self.upper is None else self.upper + + # if provided just one limit for 1D as a scalar, make it a list + # for formatting purposes + self.lower = np.atleast_1d(self.lower) + self.upper = np.atleast_1d(self.upper) + lower = np.atleast_1d(lower).astype(float, copy=True) + upper = np.atleast_1d(upper).astype(float, copy=True) + + # validate limits sizes + if lower.size != self.Ndims: + raise ValueError("Lower limits must be None or a 1D iterable of length Ndims.") + if upper.size != self.Ndims: + raise ValueError("Upper limits must be None or a 1D iterable of length Ndims.") + + # if individual limits are nan, inf, none, etc, replace with min/max + finite_lower = np.isfinite(lower) + finite_upper = np.isfinite(upper) + lower = np.where(finite_lower, lower, mins) + upper = np.where(finite_upper, upper, maxs) + + # if any of the limits are in the wrong order, flip them + self.lower = np.minimum(lower, upper) + self.upper = np.maximum(lower, upper) + + def _make_bins(self): + # bins_list is a Ndims long list of vectors which are the edges of + # each bin. Each vector is num_bins[i]+1 long + self.bins_list = [] + + # bin_centers_list is a Ndims long list of vectors which are the centers of + # each bin. Each vector is num_bins[i] long + self.bin_centers_list = [] + + # create the bins in each dimension + if self.step_size is None: + self._step_size_from_num_bins() + else: + self._num_bins_from_step_size() + + def _step_size_from_num_bins(self): + # if step_size was not specified, derive from num_bins + self.step_size = [] + # if provided just one num_bin for 1D as a scalar, make it a list + # for formatting purposes + self.num_bins = np.atleast_1d(self.num_bins) + if self.num_bins.size != self.Ndims: + raise ValueError("num_bins must be None or a 1D iterable of length Ndims.") + for ind in range(self.Ndims): + these_bins = np.linspace(self.lower[ind], self.upper[ind], self.num_bins[ind]+1) + these_centers = (these_bins[:-1] + these_bins[1:]) / 2.0 + this_step_size = these_bins[1] - these_bins[0] + + self.bins_list.append(these_bins) + self.bin_centers_list.append(these_centers) + self.step_size.append(this_step_size) + + def _num_bins_from_step_size(self): + # if num_bins was not specified, derive from step_size + self.num_bins = [] + # if provided just one step_size for 1D as a scalar, make it a list + # for formatting purposes + self.step_size = np.atleast_1d(self.step_size) + if self.step_size.size != self.Ndims: + raise ValueError("step_size must be None or a 1D iterable of length Ndims.") + for ind in range(self.Ndims): + if self.lower[ind] == self.upper[ind]: + # min and max of limits are the same, i.e. data has to be exactly this + these_bins = np.array([self.lower[ind], self.lower[ind]]) + else: + these_bins = np.arange(self.lower[ind], self.upper[ind], self.step_size[ind]) + if these_bins[-1] != self.upper[ind]: + these_bins = np.append(these_bins, self.upper[ind]) + these_centers = (these_bins[:-1] + these_bins[1:]) / 2.0 + this_num_bins = these_bins.size-1 + + self.bins_list.append(these_bins) + self.bin_centers_list.append(these_centers) + self.num_bins.append(this_num_bins) + + def _create_bin_inds(self): + # create the bin inds for each data point as a Nvals x Ndims long vector + self.bin_inds = np.zeros((self.Nvals, self.Ndims)) + for ind in range(self.Ndims): + this_min = self.bins_list[ind][0] + this_step = self.step_size[ind] + self.bin_inds[:, ind] = (self.coords_flat[:,ind] - this_min) / this_step + # any that are outside the bin limits should be removed + self.bin_inds[self.coords_flat[:, ind]< self.bins_list[ind][0], ind] = np.nan + self.bin_inds[self.coords_flat[:, ind]==self.bins_list[ind][-1], ind] = self.num_bins[ind]-1 + self.bin_inds[self.coords_flat[:, ind]> self.bins_list[ind][-1], ind] = np.nan + + def _calculate_bins(self): + # For readibility, this is a non-vector way of binning the data + # which in the following will be vectorized for efficiency: + # for ind in range(Nvals): + # this_bin_ind = bin_inds[ind,:] + # if not np.isnan(this_bin_ind).any(): + # this_bin_ind = this_bin_ind.astype(int) + # binned_data[*this_bin_ind] = binned_data[*this_bin_ind] + data_flat[ind] + # binned_data_errs[*this_bin_ind] = binned_data_errs[*this_bin_ind] + errors_flat[ind]**2 + # n_samples[*this_bin_ind] = n_samples[*this_bin_ind] + 1 + + + # and here is a vector equivalent + # ------------------------------------------------------------- + # Inputs: + # bin_inds : (Nvals, Ndims) array of indices, some rows may contain NaN + # data_flat : (Nvals,) values to accumulate + # errors_flat : (Nvals,) errors to accumulate (squared) + # binned_data : Ndims-dimensional array (output) + # binned_data_errs : Ndims-dimensional array (output) + # n_samples : Ndims-dimensional array (output) + # ------------------------------------------------------------- + + # 1. Identify valid rows (no NaNs) + valid = ~np.isnan(self.bin_inds).any(axis=1) + + # 2. Convert valid bins to integer indices + inds_int = self.bin_inds[valid].astype(int) + + # 3. Map multidimensional indices → flat indices + flat_idx = np.ravel_multi_index(inds_int.T, dims=self.num_bins) + + # 4. Use bincount to accumulate in a vectorized way + size = np.prod(self.num_bins) + + bd_sum = np.bincount(flat_idx, weights=self.data_flat[valid], minlength=size) + err_sum = np.bincount(flat_idx, weights=self.errors_flat[valid]**2, minlength=size) + ns_sum = np.bincount(flat_idx, minlength=size) + + # 5. Reshape and add into the original arrays + self.binned_data = bd_sum.reshape(self.num_bins) + self.binned_data_errs = err_sum.reshape(self.num_bins) + self.n_samples = ns_sum.reshape(self.num_bins) + + def _calculate_fractional_bins(self): + + # more convenient to work with half shifted inds + # bin_inds_frac for bin i is between i-0.5 and i+0.5 and the bin center + # is at i. + bin_inds_frac = self.bin_inds - 0.5 + + # 1. Identify valid rows (no NaNs) + valid = ~np.isnan(bin_inds_frac).any(axis=1) + valid_inds = bin_inds_frac[valid] + partial_weights = 1.-np.mod(valid_inds, 1) + data_valid = self.data_flat[valid] + errs_valid = self.errors_flat[valid] + + # In 1D, for a point at x between bin centers at x_i and x_{i+1}, + # wx_{i+1}=(x-x_i)/dx partial weight goes to bin i+1 + # and wx_i=1-w_{i+1} partial weight goes to bin i. + # bin_inds = (x-(x_1-dx/2))/dx = (x-x_1)/dx+0.5. Therefore + # bin_inds_frac = (x-x_1)/dx, so wx_{i+1} = mod(idx,1) and + # wx_i = 1-mod(idx,1) + + # for each dimension, double the amount of subpoints + for ind in range(self.Ndims): + # bins on the edge only go in one bin on that axis + edge_mask = np.logical_not( + np.logical_or(valid_inds[:, ind]<0, + valid_inds[:, ind]>self.num_bins[ind]-1) + ) + partial_weights[~edge_mask, ind] = 1.0 + # will be where the bin goes + arr_mod = valid_inds[edge_mask] + arr_mod[:, ind] += 1. + valid_inds = np.vstack([valid_inds, arr_mod]) + # how close it is to that bin + arr_mod = partial_weights[edge_mask] + arr_mod[:, ind] = 1. - arr_mod[:, ind] + partial_weights = np.vstack([partial_weights, arr_mod]) + # the value and uncertainty + data_valid = np.concatenate([data_valid, data_valid[edge_mask]]) + errs_valid = np.concatenate([errs_valid, errs_valid[edge_mask]]) + + # any bins that ended up outside just get clamped + for ind in range(self.Ndims): + valid_inds[valid_inds[:, ind]<0, ind] = 0 + valid_inds[valid_inds[:, ind]>self.num_bins[ind]-1, ind] = self.num_bins[ind]-1 + + # weights are the product of partial weights + weights = np.prod(partial_weights, axis=1) + + # 2. Convert valid bins to integer indices + inds_int = valid_inds.astype(int) + + # 3. Map multidimensional indices → flat indices + flat_idx = np.ravel_multi_index(inds_int.T, dims=self.num_bins) + + # 4. Use bincount to accumulate in a vectorized way + size = np.prod(self.num_bins) + + bd_sum = np.bincount(flat_idx, weights=weights*data_valid, minlength=size) + err_sum = np.bincount(flat_idx, weights=(weights**2)*(errs_valid**2), minlength=size) + ns_sum = np.bincount(flat_idx, weights=weights, minlength=size) + + # 5. Reshape and add into the original arrays + self.binned_data = bd_sum.reshape(self.num_bins) + self.binned_data_errs = err_sum.reshape(self.num_bins) + self.n_samples = ns_sum.reshape(self.num_bins) + + def _norm_data(self): + # normalize binned_data by the number of times sampled + with np.errstate(divide='ignore', invalid='ignore'): + if self.normalize: + self.binned_data = np.divide(self.binned_data, self.n_samples) + self.binned_data_errs = np.divide(np.sqrt(self.binned_data_errs), self.n_samples) + else: + self.binned_data_errs = np.sqrt(self.binned_data_errs) + + # any bins with no samples is nan + mask = self.n_samples == 0 + self.binned_data[mask] = np.nan + self.binned_data_errs[mask] = np.nan diff --git a/sasdata/transforms/post_process.py b/sasdata/transforms/post_process.py new file mode 100644 index 000000000..e69de29bb diff --git a/sasdata/transforms/rebinning.py b/sasdata/transforms/rebinning.py index 0e8c07e0d..e5f48b18c 100644 --- a/sasdata/transforms/rebinning.py +++ b/sasdata/transforms/rebinning.py @@ -1,261 +1,204 @@ -""" Algorithms for interpolation and rebinning """ - -from enum import Enum - -import numpy as np -from numpy._typing import ArrayLike -from scipy.sparse import coo_matrix - -from sasdata.quantities.quantity import Quantity - - -class InterpolationOptions(Enum): - NEAREST_NEIGHBOUR = 0 - LINEAR = 1 - CUBIC = 3 - -class InterpolationError(Exception): - """ We probably want to raise exceptions because interpolation is not appropriate/well-defined, - not the same as numerical issues that will raise ValueErrors""" - - -def calculate_interpolation_matrix_1d(input_axis: Quantity[ArrayLike], - output_axis: Quantity[ArrayLike], - mask: ArrayLike | None = None, - order: InterpolationOptions = InterpolationOptions.LINEAR, - is_density=False): - - """ Calculate the matrix that converts values recorded at points specified by input_axis to - values recorded at points specified by output_axis""" - - # We want the input values in terms of the output units, will implicitly check compatability - # TODO: incorporate mask - - working_units = output_axis.units - - input_x = input_axis.in_units_of(working_units) - output_x = output_axis.in_units_of(working_units) - - # Get the array indices that will map the array to a sorted one - input_sort = np.argsort(input_x) - output_sort = np.argsort(output_x) - - input_unsort = np.arange(len(input_x), dtype=int)[input_sort] - output_unsort = np.arange(len(output_x), dtype=int)[output_sort] - - sorted_in = input_x[input_sort] - sorted_out = output_x[output_sort] - - n_in = len(sorted_in) - n_out = len(sorted_out) - - conversion_matrix = None # output - - match order: - case InterpolationOptions.NEAREST_NEIGHBOUR: - - # COO Sparse matrix definition data - i_entries = [] - j_entries = [] - - crossing_points = 0.5*(sorted_out[1:] + sorted_out[:-1]) - - # Find the output values nearest to each of the input values - i=0 - for k, crossing_point in enumerate(crossing_points): - while i < n_in and sorted_in[i] < crossing_point: - i_entries.append(i) - j_entries.append(k) - i += 1 - - # All the rest in the last bin - while i < n_in: - i_entries.append(i) - j_entries.append(n_out-1) - i += 1 - - i_entries = input_unsort[np.array(i_entries, dtype=int)] - j_entries = output_unsort[np.array(j_entries, dtype=int)] - values = np.ones_like(i_entries, dtype=float) - - conversion_matrix = coo_matrix((values, (i_entries, j_entries)), shape=(n_in, n_out)) - - case InterpolationOptions.LINEAR: - - # Leverage existing linear interpolation methods to get the mapping - # do a linear interpolation on indices - # the floor should give the left bin - # the ceil should give the right bin - # the fractional part should give the relative weightings - - input_indices = np.arange(n_in, dtype=int) - output_indices = np.arange(n_out, dtype=int) - - fractional = np.interp(x=sorted_out, xp=sorted_in, fp=input_indices, left=0, right=n_in-1) - - left_bins = np.floor(fractional).astype(int) - right_bins = np.ceil(fractional).astype(int) - - right_weight = fractional % 1 - left_weight = 1 - right_weight - - # There *should* be no repeated entries for both i and j in the main part, but maybe at the ends - # If left bin is the same as right bin, then we only want one entry, and the weight should be 1 - - same = left_bins == right_bins - not_same = ~same - - same_bins = left_bins[same] # could equally be right bins, they're the same - - same_indices = output_indices[same] - not_same_indices = output_indices[not_same] - - j_entries_sorted = np.concatenate((same_indices, not_same_indices, not_same_indices)) - i_entries_sorted = np.concatenate((same_bins, left_bins[not_same], right_bins[not_same])) - - i_entries = input_unsort[i_entries_sorted] - j_entries = output_unsort[j_entries_sorted] - - # weights don't need to be unsorted # TODO: check this is right, it should become obvious if we use unsorted data - weights = np.concatenate((np.ones_like(same_bins, dtype=float), left_weight[not_same], right_weight[not_same])) - - conversion_matrix = coo_matrix((weights, (i_entries, j_entries)), shape=(n_in, n_out)) - - case InterpolationOptions.CUBIC: - # Cubic interpolation, much harder to implement because we can't just cheat and use numpy - - input_indices = np.arange(n_in, dtype=int) - output_indices = np.arange(n_out, dtype=int) - - # Find the location of the largest value in sorted_in that - # is less than every value of sorted_out - lower_bound = ( - np.sum(np.where(np.less.outer(sorted_in, sorted_out), 1, 0), axis=0) - 1 - ) - - # We're using the Finite Difference Cubic Hermite spline - # https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Interpolation_on_an_arbitrary_interval - # https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Finite_difference - - x1 = sorted_in[lower_bound] # xₖ on the wiki - x2 = sorted_in[lower_bound + 1] # xₖ₊₁ on the wiki - - x0 = sorted_in[lower_bound[lower_bound - 1 >= 0] - 1] # xpₖ₋₁ on the wiki - x0 = np.hstack([np.zeros(x1.size - x0.size), x0]) - - x3 = sorted_in[ - lower_bound[lower_bound + 2 < sorted_in.size] + 2 - ] # xₖ₊₂ on the wiki - x3 = np.hstack([x3, np.zeros(x2.size - x3.size)]) - - t = (sorted_out - x1) / (x2 - x1) # t on the wiki - - y0 = ( - -t * (x1 - x2) * (t**2 - 2 * t + 1) / (2 * x0 - 2 * x1) - ) # The coefficient to pₖ₋₁ on the wiki - y1 = ( - -t * (t**2 - 2 * t + 1) * (x0 - 2 * x1 + x2) - + (x0 - x1) * (3 * t**3 - 5 * t**2 + 2) - ) / (2 * (x0 - x1)) # The coefficient to pₖ - y2 = ( - t - * ( - -t * (t - 1) * (x1 - 2 * x2 + x3) - + (x2 - x3) * (-3 * t**2 + 4 * t + 1) - ) - / (2 * (x2 - x3)) - ) # The coefficient to pₗ₊₁ - y3 = t**2 * (t - 1) * (x1 - x2) / (2 * (x2 - x3)) # The coefficient to pₖ₊₂ - - conversion_matrix = np.zeros((n_in, n_out)) - - (row, column) = np.indices(conversion_matrix.shape) - - mask1 = row == lower_bound[column] - - conversion_matrix[np.roll(mask1, -1, axis=0)] = y0 - conversion_matrix[mask1] = y1 - conversion_matrix[np.roll(mask1, 1, axis=0)] = y2 - - # Special boundary condition for y3 - pick = np.roll(mask1, 2, axis=0) - pick[0:1, :] = 0 - if pick.any(): - conversion_matrix[pick] = y3 - - case _: - raise InterpolationError(f"Unsupported interpolation order: {order}") - - if mask is None: - return conversion_matrix, None - - else: - # Create a new mask - - # Convert to numerical values - # Conservative masking: anything touched by the previous mask is now masked - new_mask = (np.array(mask, dtype=float) @ conversion_matrix) != 0.0 - - return conversion_matrix, new_mask - - -def calculate_interpolation_matrix_2d_axis_axis(input_1: Quantity[ArrayLike], - input_2: Quantity[ArrayLike], - output_1: Quantity[ArrayLike], - output_2: Quantity[ArrayLike], - mask, - order: InterpolationOptions = InterpolationOptions.LINEAR, - is_density: bool = False): - - # This is just the same 1D matrices things - - match order: - case InterpolationOptions.NEAREST_NEIGHBOUR: - pass - - case InterpolationOptions.LINEAR: - pass - - case InterpolationOptions.CUBIC: - pass - - case _: - pass - - -def calculate_interpolation_matrix(input_axes: list[Quantity[ArrayLike]], - output_axes: list[Quantity[ArrayLike]], - data: ArrayLike | None = None, - mask: ArrayLike | None = None): - - # TODO: We probably should delete this, but lets keep it for now - - if len(input_axes) not in (1, 2): - raise InterpolationError("Interpolation is only supported for 1D and 2D data") - - if len(input_axes) == 1 and len(output_axes) == 1: - # Check for dimensionality - input_axis = input_axes[0] - output_axis = output_axes[0] - - if len(input_axis.value.shape) == 1: - if len(output_axis.value.shape) == 1: - calculate_interpolation_matrix_1d() - - if len(output_axes) != len(input_axes): - # Input or output axes might be 2D matrices - pass - - - -def rebin(data: Quantity[ArrayLike], - axes: list[Quantity[ArrayLike]], - new_axes: list[Quantity[ArrayLike]], - mask: ArrayLike | None = None, - interpolation_order: int = 1): - - """ This algorithm is only for operations that preserve dimensionality, - i.e. non-projective rebinning. - """ - - pass +""" Algorithms for interpolation and rebinning """ + +from enum import Enum + +import numpy as np +from numpy._typing import ArrayLike +from scipy.sparse import coo_matrix + +from sasdata.quantities.quantity import Quantity + + +class InterpolationOptions(Enum): + NEAREST_NEIGHBOUR = 0 + LINEAR = 1 + CUBIC = 3 + +class InterpolationError(Exception): + """ We probably want to raise exceptions because interpolation is not appropriate/well-defined, + not the same as numerical issues that will raise ValueErrors""" + + +def calculate_interpolation_matrix_1d(input_axis: Quantity[ArrayLike], + output_axis: Quantity[ArrayLike], + mask: ArrayLike | None = None, + order: InterpolationOptions = InterpolationOptions.LINEAR, + is_density=False): + + """ Calculate the matrix that converts values recorded at points specified by input_axis to + values recorded at points specified by output_axis""" + + # We want the input values in terms of the output units, will implicitly check compatability + # TODO: incorporate mask + + working_units = output_axis.units + + input_x = input_axis.in_units_of(working_units) + output_x = output_axis.in_units_of(working_units) + + # Get the array indices that will map the array to a sorted one + input_sort = np.argsort(input_x) + output_sort = np.argsort(output_x) + + input_unsort = np.arange(len(input_x), dtype=int)[input_sort] + output_unsort = np.arange(len(output_x), dtype=int)[output_sort] + + sorted_in = input_x[input_sort] + sorted_out = output_x[output_sort] + + n_in = len(sorted_in) + n_out = len(sorted_out) + + conversion_matrix = None # output + + match order: + case InterpolationOptions.NEAREST_NEIGHBOUR: + + # COO Sparse matrix definition data + i_entries = [] + j_entries = [] + + crossing_points = 0.5*(sorted_out[1:] + sorted_out[:-1]) + + # Find the output values nearest to each of the input values + i=0 + for k, crossing_point in enumerate(crossing_points): + while i < n_in and sorted_in[i] < crossing_point: + i_entries.append(i) + j_entries.append(k) + i += 1 + + # All the rest in the last bin + while i < n_in: + i_entries.append(i) + j_entries.append(n_out-1) + i += 1 + + i_entries = input_unsort[np.array(i_entries, dtype=int)] + j_entries = output_unsort[np.array(j_entries, dtype=int)] + values = np.ones_like(i_entries, dtype=float) + + conversion_matrix = coo_matrix((values, (i_entries, j_entries)), shape=(n_in, n_out)) + + case InterpolationOptions.LINEAR: + + # Leverage existing linear interpolation methods to get the mapping + # do a linear interpolation on indices + # the floor should give the left bin + # the ceil should give the right bin + # the fractional part should give the relative weightings + + input_indices = np.arange(n_in, dtype=int) + output_indices = np.arange(n_out, dtype=int) + + fractional = np.interp(x=sorted_out, xp=sorted_in, fp=input_indices, left=0, right=n_in-1) + + left_bins = np.floor(fractional).astype(int) + right_bins = np.ceil(fractional).astype(int) + + right_weight = fractional % 1 + left_weight = 1 - right_weight + + # There *should* be no repeated entries for both i and j in the main part, but maybe at the ends + # If left bin is the same as right bin, then we only want one entry, and the weight should be 1 + + same = left_bins == right_bins + not_same = ~same + + same_bins = left_bins[same] # could equally be right bins, they're the same + + same_indices = output_indices[same] + not_same_indices = output_indices[not_same] + + j_entries_sorted = np.concatenate((same_indices, not_same_indices, not_same_indices)) + i_entries_sorted = np.concatenate((same_bins, left_bins[not_same], right_bins[not_same])) + + i_entries = input_unsort[i_entries_sorted] + j_entries = output_unsort[j_entries_sorted] + + # weights don't need to be unsorted # TODO: check this is right, it should become obvious if we use unsorted data + weights = np.concatenate((np.ones_like(same_bins, dtype=float), left_weight[not_same], right_weight[not_same])) + + conversion_matrix = coo_matrix((weights, (i_entries, j_entries)), shape=(n_in, n_out)) + + case InterpolationOptions.CUBIC: + # Cubic interpolation, much harder to implement because we can't just cheat and use numpy + raise NotImplementedError("Cubic interpolation not implemented yet") + + case _: + raise InterpolationError(f"Unsupported interpolation order: {order}") + + + if mask is None: + return conversion_matrix, None + + else: + # Create a new mask + + # Convert to numerical values + # Conservative masking: anything touched by the previous mask is now masked + new_mask = (np.array(mask, dtype=float) @ conversion_matrix) != 0.0 + + return conversion_matrix, new_mask + + +def calculate_interpolation_matrix_2d_axis_axis(input_1: Quantity[ArrayLike], + input_2: Quantity[ArrayLike], + output_1: Quantity[ArrayLike], + output_2: Quantity[ArrayLike], + mask, + order: InterpolationOptions = InterpolationOptions.LINEAR, + is_density: bool = False): + + # This is just the same 1D matrices things + + match order: + case InterpolationOptions.NEAREST_NEIGHBOUR: + pass + + case InterpolationOptions.LINEAR: + pass + + case InterpolationOptions.CUBIC: + pass + + case _: + pass + + +def calculate_interpolation_matrix(input_axes: list[Quantity[ArrayLike]], + output_axes: list[Quantity[ArrayLike]], + data: ArrayLike | None = None, + mask: ArrayLike | None = None): + + # TODO: We probably should delete this, but lets keep it for now + + if len(input_axes) not in (1, 2): + raise InterpolationError("Interpolation is only supported for 1D and 2D data") + + if len(input_axes) == 1 and len(output_axes) == 1: + # Check for dimensionality + input_axis = input_axes[0] + output_axis = output_axes[0] + + if len(input_axis.value.shape) == 1: + if len(output_axis.value.shape) == 1: + calculate_interpolation_matrix_1d() + + if len(output_axes) != len(input_axes): + # Input or output axes might be 2D matrices + pass + + + +def rebin(data: Quantity[ArrayLike], + axes: list[Quantity[ArrayLike]], + new_axes: list[Quantity[ArrayLike]], + mask: ArrayLike | None = None, + interpolation_order: int = 1): + + """ This algorithm is only for operations that preserve dimensionality, + i.e. non-projective rebinning. + """ + + pass diff --git a/sasdata/trend.py b/sasdata/trend.py index 9b1a371a4..16d1c67f3 100644 --- a/sasdata/trend.py +++ b/sasdata/trend.py @@ -1,89 +1,25 @@ -from dataclasses import dataclass +#!/usr/bin/env python -import numpy as np +from dataclasses import dataclass from sasdata.data import SasData -from sasdata.data_backing import Dataset, Group -from sasdata.quantities.quantity import Quantity -from sasdata.transforms.rebinning import calculate_interpolation_matrix_1d # Axis strs refer to the name of their associated NamedQuantity. -# TODO: This probably shouldn't be here but will keep it here for now. -# TODO: Not sure how to type hint the return. -def get_metadatum_from_path(data: SasData, metadata_path: list[str]): - current_group = data._raw_metadata - for path_item in metadata_path: - current_item = current_group.children.get(path_item, None) - if current_item is None or (isinstance(current_item, Dataset) and path_item != metadata_path[-1]): - raise ValueError('Path does not lead to valid a metadatum.') - elif isinstance(current_item, Group): - current_group = current_item - else: - return current_item.data - raise ValueError('End of path without finding a dataset.') - - @dataclass class Trend: data: list[SasData] - # This is going to be a path to a specific metadatum. - # - # TODO: But what if the trend axis will be a particular NamedQuantity? Will probably need to think on this. - trend_axis: list[str] + trend_axis: str # Designed to take in a particular value of the trend axis, and return the SasData object that matches it. # TODO: Not exaclty sure what item's type will be. It could depend on where it is pointing to. def __getitem__(self, item) -> SasData: - for datum in self.data: - metadatum = get_metadatum_from_path(datum, self.trend_axis) - if metadatum == item: - return datum - raise KeyError() - @property - def trend_axes(self) -> list[float]: - return [get_metadatum_from_path(datum, self.trend_axis) for datum in self.data] + raise NotImplementedError() - # TODO: Assumes there are at least 2 items in data. Is this reasonable to assume? Should there be error handling for - # situations where this may not be the case? def all_axis_match(self, axis: str) -> bool: - reference_data = self.data[0] - data_axis = reference_data[axis] - for datum in self.data[1::]: - axis_datum = datum[axis] - # FIXME: Linter is complaining about typing. - if not np.all(np.isclose(axis_datum.value, data_axis.value)): - return False - return True - - # TODO: For now, return a new trend, but decide later. Shouldn't be too hard to change. - def interpolate(self, axis: str) -> "Trend": - new_data: list[SasData] = [] - reference_data = self.data[0] - # TODO: I don't like the repetition here. Can probably abstract a function for this ot make it clearer. - data_axis = reference_data[axis] - for i, datum in enumerate(self.data): - if i == 0: - # This is already the reference axis; no need to interpolate it. - continue - # TODO: Again, repetition - axis_datum = datum[axis] - # TODO: There are other options which may need to be filled (or become new params to this method) - mat, _ = calculate_interpolation_matrix_1d(axis_datum, data_axis) - new_quantities: dict[str, Quantity] = {} - for name, quantity in datum._data_contents.items(): - if name == axis: - new_quantities[name] = data_axis - continue - new_quantities[name] = quantity @ mat + raise NotImplementedError() - new_datum = SasData( - name=datum.name, - data_contents=new_quantities, - dataset_type=datum.dataset_type, - metadata=datum.metadata, - ) - new_data.append(new_datum) - new_trend = Trend(new_data, - self.trend_axis) - return new_trend + # TODO: Not sure if this should return a new trend, or just mutate the existing trend + # TODO: May be some details on the method as well. + def interpolate(self, axis: str) -> Self: + raise NotImplementedError() diff --git a/sasdata/util.py b/sasdata/util.py new file mode 100644 index 000000000..8decc68be --- /dev/null +++ b/sasdata/util.py @@ -0,0 +1,18 @@ +from collections.abc import Callable +from typing import TypeVar + +T = TypeVar("T") + +def cache[T](fun: Callable[[], T]): + """ Decorator to store values """ + + cache_state = [False, None] + + def wrapper() -> T: + if not cache_state[0]: + cache_state[0] = True + cache_state[1] = fun() + + return cache_state[1] + + return wrapper diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv new file mode 100644 index 000000000..8e9c70665 --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv @@ -0,0 +1,105 @@ +3.624299999999999744e-02 7.295645247999999583e+01 1.637502872666669873e+01 +4.068929999999999769e-02 3.496757764333329987e+01 1.132330254166670080e+01 +4.510000000000000120e-02 2.871506291000000033e+01 8.366418418333330109e+00 +4.957960000000000145e-02 3.062621534000000167e+01 6.807088010000000189e+00 +5.414959999999999912e-02 1.698840335499999910e+01 5.315930135000000334e+00 +5.867460000000000037e-02 1.810732352000000134e+01 4.582343003333329889e+00 +6.313670000000000393e-02 1.758858145166669829e+01 3.753068668333329860e+00 +6.771770000000000567e-02 1.874808681500000063e+01 3.129801861666670071e+00 +7.237100000000000477e-02 1.219239694000000007e+01 2.701832888333330018e+00 +7.692330000000000001e-02 1.502033604000000011e+01 2.415586504999999828e+00 +8.164470000000000061e-02 1.051882241166670084e+01 2.003147743333329789e+00 +8.639470000000000482e-02 1.266539752666670005e+01 1.813845073333330005e+00 +9.106759999999999855e-02 1.164225125833329955e+01 1.590423455000000041e+00 +9.573710000000000553e-02 9.248378555000000389e+00 1.453449206666669991e+00 +1.004952999999999957e-01 1.082198768499999986e+01 1.296534581666670016e+00 +1.052397000000000055e-01 9.754544071666670035e+00 1.192202876666669908e+00 +1.099886000000000058e-01 9.770793396666670461e+00 1.074958141666670031e+00 +1.148422000000000054e-01 9.667035006666669261e+00 9.803857316666669819e-01 +1.197769999999999946e-01 8.381104240000000871e+00 8.964596183333329860e-01 +1.247698000000000002e-01 7.884219706666669936e+00 8.320707283333329540e-01 +1.298370000000000080e-01 8.175124921666670375e+00 7.497416000000000080e-01 +1.349077999999999944e-01 7.421197476666669957e+00 7.207336583333330271e-01 +1.399244000000000043e-01 8.545903931666670061e+00 6.648524133333330033e-01 +1.450733999999999913e-01 7.172791390000000433e+00 6.314494133333330428e-01 +1.502658000000000049e-01 6.110795001666669890e+00 5.924928833333330536e-01 +1.556062000000000001e-01 7.011488443333329990e+00 5.430119199999999813e-01 +1.572456999999999883e-01 7.121472013333329798e+00 1.740741033333330079e-01 +1.609471000000000096e-01 7.438929439999999893e+00 5.263131250000000483e-01 +1.661874999999999880e-01 6.540084590000000198e+00 4.946959550000000205e-01 +1.706292000000000086e-01 6.367655253333330378e+00 1.455746566666669961e-01 +1.715615000000000057e-01 6.476111691666670112e+00 4.707941449999999972e-01 +1.771270000000000067e-01 5.720913878333329983e+00 4.355610400000000104e-01 +1.827315999999999940e-01 6.117868691666670244e+00 4.186226383333330192e-01 +1.842428999999999872e-01 5.857041180000000402e+00 1.254778649999999940e-01 +1.883173999999999959e-01 5.849837826666670182e+00 4.069392433333329784e-01 +1.939794999999999991e-01 5.447672994999999574e+00 3.927526633333329742e-01 +1.982414999999999872e-01 5.391186461666669594e+00 1.085076650000000031e-01 +1.997663000000000078e-01 5.394637556666670442e+00 3.662608233333329855e-01 +2.055810999999999888e-01 5.784545713333329786e+00 3.603836316666669815e-01 +2.114655000000000007e-01 4.574601945000000391e+00 3.312713700000000094e-01 +2.120113000000000136e-01 5.084515549999999884e+00 9.927742500000000248e-02 +2.161903000000000019e-01 4.516358434999999893e+00 4.168106166666670220e-01 +2.259823999999999999e-01 4.782964421666670241e+00 8.791053666666670541e-02 +2.397845000000000115e-01 4.501217386666669817e+00 8.259429166666669431e-02 +2.537096999999999825e-01 4.179436571666670375e+00 7.562756833333329765e-02 +2.676275000000000182e-01 3.979478888333329856e+00 6.987285499999999761e-02 +2.817857999999999752e-01 3.702226940000000077e+00 6.482911333333329917e-02 +2.956398000000000081e-01 3.605992423333329810e+00 6.203536333333330155e-02 +3.099044000000000243e-01 3.377018353333329781e+00 5.670042833333330257e-02 +3.240645999999999805e-01 3.095807218333329836e+00 5.498817999999999762e-02 +3.388027000000000122e-01 2.841171323333330001e+00 4.897826333333329951e-02 +3.539140000000000064e-01 2.795649415000000193e+00 4.845330666666670255e-02 +3.687090000000000090e-01 2.622854690000000044e+00 4.475559833333329907e-02 +3.839813000000000254e-01 2.527809641666669993e+00 4.273165666666670082e-02 +3.988975000000000160e-01 2.232305030000000023e+00 4.094381166666669764e-02 +4.106734000000000218e-01 2.129986383333330124e+00 4.154637366666669857e-02 +4.136514000000000024e-01 2.084593566666669950e+00 3.891198166666669928e-02 +4.290628000000000219e-01 1.988620215000000080e+00 3.594587333333330165e-02 +4.295516999999999808e-01 1.964928603499999982e+00 3.519640899999999795e-02 +4.446014999999999828e-01 1.750614441666670018e+00 3.497378000000000292e-02 +4.466716000000000020e-01 1.709819834666669980e+00 3.112847050000000157e-02 +4.603325999999999807e-01 1.676685876666669905e+00 3.265084166666670090e-02 +4.685437000000000074e-01 1.638395569999999912e+00 3.101072850000000103e-02 +4.764860000000000206e-01 1.575855291666669933e+00 3.097528500000000171e-02 +4.834083000000000130e-01 1.443926158166670026e+00 2.913516383333330032e-02 +4.923204999999999942e-01 1.443778989999999984e+00 3.072023333333330150e-02 +5.046621000000000024e-01 1.382474827333330047e+00 2.709115466666670025e-02 +5.082708000000000226e-01 1.368563626666670086e+00 2.832584499999999880e-02 +5.230728999999999518e-01 1.117650907000000027e+00 2.515010599999999846e-02 +5.249162000000000550e-01 1.271594368333329950e+00 2.652784333333330080e-02 +5.416775999999999813e-01 1.132208539999999930e+00 2.601087833333329963e-02 +5.444001000000000534e-01 1.080469498666670081e+00 2.559191900000000117e-02 +5.583067999999999920e-01 1.032465565000000085e+00 2.510816333333330125e-02 +5.612614999999999688e-01 1.012286258500000091e+00 2.336018449999999885e-02 +5.753956999999999544e-01 9.763539783333330391e-01 2.332539999999999961e-02 +5.834072999999999620e-01 8.965217239999999643e-01 2.303063099999999933e-02 +5.927398999999999862e-01 9.096560916666670549e-01 2.248173499999999922e-02 +6.005747000000000169e-01 8.250965611666669641e-01 2.186496933333329992e-02 +6.099058000000000535e-01 8.168162183333329551e-01 2.170944500000000082e-02 +6.218546000000000351e-01 7.414260915000000507e-01 2.121375600000000028e-02 +6.275003000000000108e-01 7.444278466666669480e-01 2.046154333333330064e-02 +6.412082999999999533e-01 6.366966366666669819e-01 1.883217216666669899e-02 +6.447154999999999969e-01 6.422991433333330447e-01 2.075286000000000144e-02 +6.655497999999999692e-01 5.866493959999999896e-01 1.815403650000000160e-02 +6.843702000000000396e-01 5.515869356666670553e-01 2.025276583333330063e-02 +7.058105999999999547e-01 4.475886111666669831e-01 1.701240433333330027e-02 +7.258693999999999980e-01 4.775394179999999933e-01 1.840697383333329828e-02 +7.490480000000000471e-01 4.047520649999999942e-01 1.505153366666669990e-02 +7.720086999999999922e-01 3.731668894999999875e-01 1.706827766666670076e-02 +7.920989999999999975e-01 3.681129878333330163e-01 1.507231049999999996e-02 +8.155097999999999514e-01 3.208610430000000124e-01 1.529166149999999953e-02 +8.364475000000000104e-01 2.962226738333330056e-01 1.456896033333330079e-02 +8.619377000000000288e-01 2.765821119999999911e-01 1.371801400000000060e-02 +8.846403999999999934e-01 2.799105873333330163e-01 1.446314666666670065e-02 +9.081462000000000145e-01 2.318482950000000098e-01 1.260493333333330065e-02 +9.334447000000000161e-01 2.175556724999999914e-01 1.357374916666670081e-02 +9.551832000000000100e-01 1.903255399999999875e-01 1.273357800000000060e-02 +9.812971999999999806e-01 1.841620115000000002e-01 1.195187833333329931e-02 +1.006807800000000030e+00 1.608915558333330054e-01 1.233432733333329930e-02 +1.030406600000000061e+00 1.533644885000000069e-01 1.172346633333330029e-02 +1.057784300000000011e+00 1.661925581666670038e-01 1.091501716666670035e-02 +1.084600999999999926e+00 1.630933589999999933e-01 1.128103283333329980e-02 +1.109902299999999897e+00 1.327154809999999963e-01 1.088576583333330031e-02 +1.137751600000000085e+00 1.179623709999999964e-01 1.042595833333329926e-02 +1.166036300000000026e+00 1.293750036666669878e-01 1.024355400000000020e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv new file mode 100644 index 000000000..bfbf36dcd --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv @@ -0,0 +1,105 @@ +3.625559999999999894e-02 4.452644707000000324e+01 1.628119149999999848e+01 +4.070349999999999663e-02 2.677295466333330154e+01 1.128515222166669929e+01 +4.511570000000000163e-02 2.350029203500000108e+01 8.338724138333329705e+00 +4.959680000000000338e-02 1.744413458166669884e+01 6.751264438333329565e+00 +5.416850000000000137e-02 9.909433441666669395e+00 5.280963783333329609e+00 +5.869510000000000005e-02 1.174714312999999954e+01 4.547423594999999708e+00 +6.315869999999999818e-02 1.312634901166670076e+01 3.725749208333330120e+00 +6.774130000000000429e-02 1.654730030333330149e+01 3.113655078333330106e+00 +7.239619999999999389e-02 7.792796271666669661e+00 2.672180411666670086e+00 +7.695009999999999351e-02 1.265325572666669984e+01 2.397233363333330036e+00 +8.167309999999999848e-02 6.069752713333330441e+00 1.971069876666670107e+00 +8.642469999999999319e-02 1.300927747833329917e+01 1.813635340000000040e+00 +9.109929999999999417e-02 9.757094948333330464e+00 1.573592551666670003e+00 +9.577040000000000552e-02 5.713518095000000407e+00 1.422093728333329921e+00 +1.005303000000000030e-01 7.313534973333330136e+00 1.265234731666670109e+00 +1.052763000000000032e-01 8.841184973333330532e+00 1.182077201666670074e+00 +1.100268999999999969e-01 7.404252198333329815e+00 1.051346621666670034e+00 +1.148821000000000009e-01 8.380590695000000423e+00 9.664303683333329564e-01 +1.198187000000000002e-01 7.413483668333330279e+00 8.855263516666670442e-01 +1.248133000000000020e-01 6.593134025000000342e+00 8.175650066666669824e-01 +1.298822000000000032e-01 6.731246111666670195e+00 7.333046399999999521e-01 +1.349548000000000136e-01 5.519098301666669926e+00 6.986229283333329487e-01 +1.399730999999999892e-01 7.581442331666670142e+00 6.528076566666669578e-01 +1.451239000000000001e-01 4.842304316666670161e+00 6.043489516666670225e-01 +1.503181000000000100e-01 5.135523888333329623e+00 5.802922499999999539e-01 +1.556604000000000043e-01 6.037988904999999740e+00 5.310080216666670516e-01 +1.573070000000000024e-01 6.020141886666669606e+00 1.700767950000000028e-01 +1.610031000000000101e-01 6.268605329999999753e+00 5.111983383333329467e-01 +1.662453999999999876e-01 5.536486726666669966e+00 4.815289200000000269e-01 +1.706957000000000058e-01 5.285752210000000062e+00 1.415798849999999887e-01 +1.716212000000000015e-01 5.016643598333329734e+00 4.522174083333330152e-01 +1.771887000000000045e-01 5.127789406666670047e+00 4.276572833333330270e-01 +1.827951999999999910e-01 5.311901800000000229e+00 4.077617766666670196e-01 +1.843146999999999980e-01 5.273006283333329769e+00 1.230909116666669967e-01 +1.883829999999999949e-01 4.028933333333330147e+00 3.832458766666669847e-01 +1.940469999999999973e-01 4.805727509999999647e+00 3.842635300000000198e-01 +1.983187999999999895e-01 4.783697818333330076e+00 1.059592133333329966e-01 +1.998358000000000079e-01 4.823453656666670142e+00 3.585670233333330126e-01 +2.056525999999999910e-01 4.659267076666670171e+00 3.454626916666669878e-01 +2.115392000000000106e-01 3.961550343333330115e+00 3.229926716666670083e-01 +2.120939000000000019e-01 4.350835990000000209e+00 9.606802500000000133e-02 +2.162656000000000023e-01 4.681036608333330129e+00 4.188060433333329891e-01 +2.260705000000000076e-01 4.224838659999999635e+00 8.541253666666670519e-02 +2.398779000000000050e-01 3.935926101666670007e+00 7.996145500000000073e-02 +2.538084999999999924e-01 3.694058728333330155e+00 7.335489833333329324e-02 +2.677318000000000198e-01 3.684019681666669932e+00 6.840629833333329579e-02 +2.818956000000000239e-01 3.452043701666669850e+00 6.355296333333329550e-02 +2.957549999999999901e-01 3.354666878333329993e+00 6.073878666666669701e-02 +3.100250999999999979e-01 3.092418856666669935e+00 5.527531000000000111e-02 +3.241909000000000041e-01 2.870290291666670157e+00 5.380070499999999728e-02 +3.389346999999999777e-01 2.729991994999999783e+00 4.836916333333329820e-02 +3.540519999999999778e-01 2.658729508333330216e+00 4.771163500000000224e-02 +3.688526999999999778e-01 2.488934241666670211e+00 4.403299000000000102e-02 +3.841308999999999974e-01 2.412009111666669980e+00 4.209804999999999797e-02 +3.990528999999999882e-01 2.203036439999999985e+00 4.070905166666669711e-02 +4.105667000000000066e-01 1.996977714666670067e+00 4.083280150000000164e-02 +4.138126999999999778e-01 2.043262161666670185e+00 3.862582833333329940e-02 +4.292300000000000004e-01 1.982205959999999934e+00 3.583282166666670182e-02 +4.294401999999999942e-01 1.834877223666669943e+00 3.458454216666669717e-02 +4.447747000000000228e-01 1.712660204999999936e+00 3.471672166666670001e-02 +4.465555999999999970e-01 1.615437673500000004e+00 3.068944266666669834e-02 +4.605119999999999769e-01 1.681440621666669966e+00 3.260043333333329657e-02 +4.684220000000000050e-01 1.529958281999999947e+00 3.049975383333329917e-02 +4.766716999999999760e-01 1.561241171666670091e+00 3.083583000000000157e-02 +4.832827000000000095e-01 1.369049060333330070e+00 2.875037449999999842e-02 +4.925123000000000140e-01 1.406416503333330015e+00 3.046807833333330107e-02 +5.045309999999999517e-01 1.316827885166669931e+00 2.677764066666669940e-02 +5.084689000000000014e-01 1.339987331666669945e+00 2.812536666666669988e-02 +5.229369999999999852e-01 1.082862526333330022e+00 2.496820599999999973e-02 +5.251208000000000542e-01 1.259172833333330077e+00 2.640966666666669932e-02 +5.418887000000000009e-01 1.134540908333329989e+00 2.596733000000000027e-02 +5.442586999999999842e-01 1.026980480500000015e+00 2.532101549999999854e-02 +5.585244000000000320e-01 1.057657990000000048e+00 2.518052499999999874e-02 +5.611156999999999950e-01 9.343203683333329845e-01 2.299225916666669881e-02 +5.756198999999999621e-01 9.598931866666670087e-01 2.319752666666670057e-02 +5.832557000000000436e-01 8.443178690000000541e-01 2.277228483333329848e-02 +5.929708999999999675e-01 9.115965033333329748e-01 2.244499833333329919e-02 +6.004186999999999719e-01 7.992612106666669991e-01 2.172028233333329894e-02 +6.101434999999999498e-01 8.528685350000000387e-01 2.184797833333329900e-02 +6.216930999999999985e-01 7.049236858333329803e-01 2.102741616666670144e-02 +6.277447999999999917e-01 7.853513183333330483e-01 2.062051499999999898e-02 +6.410417000000000476e-01 6.132204243333330140e-01 1.871036433333329863e-02 +6.449667999999999513e-01 7.011444599999999694e-01 2.101788333333329956e-02 +6.653769000000000489e-01 5.661603698333329548e-01 1.804829366666670099e-02 +6.841924999999999812e-01 5.085138883333329973e-01 2.002898349999999994e-02 +7.056272000000000100e-01 4.352650703333330040e-01 1.694186849999999855e-02 +7.256808000000000147e-01 4.355121908333329794e-01 1.820155999999999857e-02 +7.488534000000000024e-01 3.927147446666670039e-01 1.498729066666669961e-02 +7.718082000000000553e-01 3.535320510000000138e-01 1.696024266666670138e-02 +7.918933000000000222e-01 3.527103021666669891e-01 1.499266833333330086e-02 +8.152979999999999672e-01 3.240461856666669860e-01 1.528614783333329986e-02 +8.362302999999999820e-01 2.791947966666670222e-01 1.448550166666670060e-02 +8.617137999999999742e-01 2.463675190000000070e-01 1.359101549999999943e-02 +8.844106000000000467e-01 2.696912470000000228e-01 1.440389033333329925e-02 +9.079102999999999479e-01 2.246905299999999994e-01 1.256477649999999946e-02 +9.332021999999999817e-01 2.085629360000000043e-01 1.352310049999999944e-02 +9.549351000000000367e-01 1.738771078333329889e-01 1.265774100000000013e-02 +9.810423000000000338e-01 1.708308721666670082e-01 1.189189666666670003e-02 +1.006546299999999894e+00 1.505248680000000061e-01 1.228292216666669948e-02 +1.030138999999999916e+00 1.537520601666670095e-01 1.171224066666669977e-02 +1.057509599999999939e+00 1.534308791666670058e-01 1.086003916666669969e-02 +1.084319299999999986e+00 1.338797798333329903e-01 1.116524300000000004e-02 +1.109614000000000100e+00 1.189064603333330056e-01 1.082743033333329920e-02 +1.137456000000000023e+00 1.107916548333330031e-01 1.039160416666670000e-02 +1.165733499999999978e+00 1.125385351666669947e-01 1.017680349999999963e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv new file mode 100644 index 000000000..9ae1c5f3e --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv @@ -0,0 +1,105 @@ +3.624610000000000332e-02 5.667029333499999666e+01 1.635708034166669833e+01 +4.069289999999999713e-02 2.663486052833329865e+01 1.131616966500000032e+01 +4.510390000000000232e-02 2.091145430999999988e+01 8.353784624999999409e+00 +4.958379999999999732e-02 1.655762528666669908e+01 6.766916158333329712e+00 +5.415430000000000244e-02 7.405398096666670149e+00 5.285856098333329811e+00 +5.867970000000000130e-02 1.609157327499999823e+01 4.579871853333330023e+00 +6.314219999999999555e-02 2.074624494500000083e+01 3.774208823333330187e+00 +6.772359999999999491e-02 1.622769223499999924e+01 3.121007619999999871e+00 +7.237720000000000264e-02 8.100976058333330343e+00 2.681633823333330113e+00 +7.692999999999999838e-02 7.297140411666670268e+00 2.370097993333330155e+00 +8.165179999999999660e-02 8.662000215000000836e+00 1.993900453333329992e+00 +8.640209999999999557e-02 1.195176863500000053e+01 1.811378463333330080e+00 +9.107550000000000368e-02 1.017929826333329935e+01 1.581605778333329937e+00 +9.574539999999999440e-02 8.299761948333330253e+00 1.447854706666670044e+00 +1.005039999999999961e-01 7.184010728333330320e+00 1.267957188333330043e+00 +1.052488000000000035e-01 7.705754226666670093e+00 1.175315996666669971e+00 +1.099981000000000014e-01 6.940137736666669888e+00 1.050239939999999983e+00 +1.148520999999999986e-01 7.227232895000000212e+00 9.582211533333330200e-01 +1.197872999999999993e-01 6.058664864999999899e+00 8.747766333333329980e-01 +1.247806000000000054e-01 5.235616768333329674e+00 8.060124016666669888e-01 +1.298481999999999970e-01 6.895559143333329644e+00 7.374701233333329498e-01 +1.349194999999999978e-01 5.596115646666669718e+00 7.017485283333330104e-01 +1.399364999999999915e-01 7.271002904999999572e+00 6.515097483333329720e-01 +1.450858999999999899e-01 5.001139740000000167e+00 6.081432883333329764e-01 +1.502787999999999902e-01 5.397041578333330314e+00 5.852662783333330010e-01 +1.556196999999999997e-01 5.201047356666670396e+00 5.230793849999999523e-01 +1.572660999999999920e-01 5.527525920000000426e+00 1.689539216666670063e-01 +1.609609999999999930e-01 6.050507654999999652e+00 5.103277550000000495e-01 +1.662019000000000135e-01 5.215723743333329665e+00 4.792083599999999999e-01 +1.706513000000000058e-01 5.031433279999999897e+00 1.411615750000000113e-01 +1.715762999999999872e-01 4.986483428333330359e+00 4.534299233333329848e-01 +1.771423000000000025e-01 5.106750501666669884e+00 4.289189133333329851e-01 +1.827474000000000043e-01 5.398633823333329751e+00 4.103611200000000236e-01 +1.842668000000000084e-01 4.914610723333329823e+00 1.221897900000000065e-01 +1.883336999999999928e-01 4.776135458333330419e+00 3.942386333333329773e-01 +1.939963000000000104e-01 4.310256373333330338e+00 3.794851616666670147e-01 +1.982673000000000074e-01 4.375084450000000125e+00 1.047416733333329936e-01 +1.997836000000000056e-01 4.425991520000000179e+00 3.548793383333330165e-01 +2.055989000000000011e-01 4.542295369999999721e+00 3.452195166666670034e-01 +2.114837999999999996e-01 4.392925553333330235e+00 3.296180283333329797e-01 +2.120387999999999995e-01 4.102498828333329683e+00 9.538819833333339604e-02 +2.162090000000000123e-01 4.067448908333330060e+00 4.099168333333330083e-01 +2.260118000000000127e-01 3.879140883333330070e+00 8.427184499999999800e-02 +2.398155999999999899e-01 3.717842756666669857e+00 7.930888666666670306e-02 +2.537425999999999848e-01 3.531988756666669893e+00 7.293178499999999898e-02 +2.676623000000000197e-01 3.501111030000000124e+00 6.786378666666670334e-02 +2.818223999999999729e-01 3.329498083333330083e+00 6.325724833333329356e-02 +2.956782000000000021e-01 3.079447669999999970e+00 5.969948499999999658e-02 +3.099446000000000145e-01 2.946954811666670171e+00 5.483356999999999815e-02 +3.241067000000000253e-01 2.705831398333330196e+00 5.323661166666669720e-02 +3.388467000000000007e-01 2.601996516666670090e+00 4.799289000000000333e-02 +3.539599999999999969e-01 2.517872383333330077e+00 4.725612833333329987e-02 +3.687568999999999986e-01 2.374362781666670141e+00 4.368410333333330037e-02 +3.840311000000000141e-01 2.195996148333330122e+00 4.125977166666670165e-02 +3.989493000000000067e-01 2.109030429999999789e+00 4.042385333333330111e-02 +4.107986000000000137e-01 1.888483604166669938e+00 4.043749766666669687e-02 +4.137051999999999952e-01 1.969810571666670063e+00 3.843483833333329741e-02 +4.291185000000000138e-01 1.859797011666669997e+00 3.539587999999999762e-02 +4.296826999999999730e-01 1.762954635166670059e+00 3.439219566666670141e-02 +4.446591999999999767e-01 1.624618943333330012e+00 3.443567000000000156e-02 +4.468077999999999772e-01 1.588049316333330019e+00 3.067751716666669917e-02 +4.603923999999999794e-01 1.585295316666669896e+00 3.227559333333329672e-02 +4.686866000000000088e-01 1.509168766666669992e+00 3.051112400000000058e-02 +4.765479000000000243e-01 1.429500135000000061e+00 3.031986666666669841e-02 +4.835556999999999772e-01 1.309360340500000053e+00 2.857159116666670162e-02 +4.923843999999999999e-01 1.363123808333329912e+00 3.037624166666669928e-02 +5.048160000000000425e-01 1.296483956833329954e+00 2.677855866666669846e-02 +5.083368000000000331e-01 1.254868451666669937e+00 2.782200166666669999e-02 +5.232324000000000419e-01 1.028253859833329953e+00 2.481625150000000071e-02 +5.249844000000000177e-01 1.223231273333329927e+00 2.634227000000000096e-02 +5.417480000000000073e-01 1.058531658333329961e+00 2.569255333333329838e-02 +5.445661000000000529e-01 1.022632484000000064e+00 2.537817800000000124e-02 +5.583793000000000228e-01 1.009770163333330029e+00 2.504100833333329848e-02 +5.614325999999999484e-01 9.522996788333329965e-01 2.313905700000000107e-02 +5.754704000000000486e-01 9.158985283333339611e-01 2.307270666666669939e-02 +5.835850999999999678e-01 8.544030651666669751e-01 2.288279616666670166e-02 +5.928168000000000326e-01 8.553651300000000290e-01 2.224781666666670113e-02 +6.007578000000000085e-01 7.747371155000000176e-01 2.167619850000000042e-02 +6.099849999999999994e-01 7.987110383333330121e-01 2.165553833333330042e-02 +6.220442000000000471e-01 6.615610463333330138e-01 2.089781950000000124e-02 +6.275817000000000201e-01 7.150054516666669580e-01 2.035196333333329916e-02 +6.414037999999999684e-01 6.088626698333330367e-01 1.874337833333329997e-02 +6.447992000000000168e-01 6.630811316666670452e-01 2.089752166666669977e-02 +6.657526999999999751e-01 5.716572943333330103e-01 1.811807299999999843e-02 +6.845788999999999902e-01 5.092866856666670161e-01 2.008440916666669879e-02 +7.060256999999999783e-01 4.113589818333330261e-01 1.688841199999999848e-02 +7.260906999999999778e-01 4.258370573333329911e-01 1.820484666666670123e-02 +7.492763000000000062e-01 3.814062795000000006e-01 1.498164383333329928e-02 +7.722440999999999889e-01 3.582434820000000020e-01 1.702263550000000097e-02 +7.923405000000000031e-01 3.290160251666670033e-01 1.493438950000000078e-02 +8.157583999999999946e-01 3.190799841666669967e-01 1.530228649999999975e-02 +8.367025000000000157e-01 2.762952625000000273e-01 1.450753649999999943e-02 +8.622005000000000363e-01 2.544186793333330088e-01 1.365137966666669922e-02 +8.849101000000000328e-01 2.424038613333329983e-01 1.432358516666669933e-02 +9.084231000000000389e-01 2.172930054999999971e-01 1.256612799999999933e-02 +9.337292000000000369e-01 2.202721591666670087e-01 1.359930866666670020e-02 +9.554743999999999460e-01 1.777866800000000025e-01 1.269970833333330072e-02 +9.815962999999999772e-01 1.676419470000000134e-01 1.190602366666669923e-02 +1.007114700000000029e+00 1.595580418333329975e-01 1.234223233333330005e-02 +1.030720700000000045e+00 1.541775503333329966e-01 1.173861049999999975e-02 +1.058106800000000014e+00 1.554276226666669869e-01 1.088984299999999975e-02 +1.084931700000000054e+00 1.440364893333329899e-01 1.122487333333329999e-02 +1.110240600000000022e+00 1.198653424999999995e-01 1.085281416666670010e-02 +1.138098400000000066e+00 1.211473946666670048e-01 1.044690799999999954e-02 +1.166391799999999979e+00 1.189307901666669942e-01 1.021903716666669980e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv new file mode 100644 index 000000000..ee5f13e07 --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 6.302187949999999717e+01 1.635904319500000170e+01 +4.070000000000000007e-02 2.785521429499999968e+01 1.130956581166669928e+01 +4.511180000000000051e-02 1.008215536333329965e+01 8.312546360000000689e+00 +4.959249999999999770e-02 1.581932412333330085e+01 6.758513281666670203e+00 +5.416379999999999806e-02 7.750620351666669627e+00 5.282679641666669923e+00 +5.868999999999999911e-02 1.257659237500000060e+01 4.560014873333329888e+00 +6.315320000000000655e-02 1.891331758666670027e+01 3.761777425000000008e+00 +6.773540000000000116e-02 1.328150150333330082e+01 3.102479755000000061e+00 +7.238989999999999314e-02 9.795755306666670492e+00 2.689289660000000026e+00 +7.694339999999999513e-02 1.021541878833330053e+01 2.386645821666669942e+00 +8.166600000000000248e-02 7.264236756666670125e+00 1.982897978333330036e+00 +8.641719999999999957e-02 9.727612021666670827e+00 1.793249476666670006e+00 +9.109140000000000292e-02 9.940133039999999198e+00 1.578285125000000066e+00 +9.576210000000000278e-02 5.869161616666669801e+00 1.426304660000000002e+00 +1.005216000000000026e-01 6.271050506666670188e+00 1.258989316666669911e+00 +1.052672000000000052e-01 4.575212496666670070e+00 1.144957958333330028e+00 +1.100174000000000013e-01 6.675946670000000083e+00 1.046739891666669919e+00 +1.148721999999999938e-01 4.569861300000000348e+00 9.307519933333330275e-01 +1.198083000000000065e-01 4.073412075000000243e+00 8.536948699999999945e-01 +1.248023999999999939e-01 5.517398765000000260e+00 8.081908083333330106e-01 +1.298709000000000113e-01 6.055929844999999645e+00 7.277152516666669513e-01 +1.349431000000000103e-01 4.214499321666670184e+00 6.853886750000000028e-01 +1.399610000000000021e-01 4.711855326666669619e+00 6.206856016666669751e-01 +1.451112999999999986e-01 4.280988370000000209e+00 5.992362466666669718e-01 +1.503050999999999970e-01 3.350940026666669791e+00 5.604130616666670450e-01 +1.556469000000000047e-01 4.037392881666669986e+00 5.086757983333329847e-01 +1.572660999999999920e-01 4.116049464999999685e+00 1.639383783333329958e-01 +1.609891999999999990e-01 4.767404383333330387e+00 4.936060199999999787e-01 +1.662309999999999899e-01 4.092517224999999925e+00 4.643677516666669947e-01 +1.706513000000000058e-01 3.775210913333329810e+00 1.365719850000000068e-01 +1.716062999999999894e-01 4.067082121666669714e+00 4.413313999999999848e-01 +1.771733000000000058e-01 3.397890750000000182e+00 4.070909349999999871e-01 +1.827794000000000085e-01 4.061001236666670344e+00 3.925402433333329832e-01 +1.842668000000000084e-01 3.799252254999999856e+00 1.178310383333329991e-01 +1.883665999999999952e-01 3.208655455000000156e+00 3.733191000000000148e-01 +1.940302000000000138e-01 3.206445976666670195e+00 3.650098783333329822e-01 +1.982673000000000074e-01 3.425276903333330125e+00 1.008325449999999956e-01 +1.998185000000000100e-01 3.354815260000000077e+00 3.406662516666669749e-01 +2.056348000000000065e-01 3.721227830000000125e+00 3.339491649999999923e-01 +2.115208000000000088e-01 3.612948971666670062e+00 3.193275150000000062e-01 +2.120387999999999995e-01 3.205896688333329969e+00 9.145261000000000362e-02 +2.162467999999999890e-01 3.645113248333330169e+00 4.021025750000000176e-01 +2.260118000000000127e-01 3.104582965000000083e+00 8.081593333333329798e-02 +2.398155999999999899e-01 3.037513673333330111e+00 7.613482000000000582e-02 +2.537425999999999848e-01 2.836682165000000033e+00 6.969811833333329487e-02 +2.676623000000000197e-01 2.819590748333329788e+00 6.462849833333329796e-02 +2.818223999999999729e-01 2.721404538333330070e+00 6.033223166666670106e-02 +2.956782000000000021e-01 2.736251186666669888e+00 5.799425166666669768e-02 +3.099446000000000145e-01 2.543946483333329844e+00 5.286760000000000070e-02 +3.241067000000000253e-01 2.287160831666669836e+00 5.112056499999999976e-02 +3.388467000000000007e-01 2.288673078333329780e+00 4.649771999999999933e-02 +3.539599999999999969e-01 2.199149091666670053e+00 4.568711999999999773e-02 +3.687568999999999986e-01 2.068072668333329922e+00 4.217328666666669834e-02 +3.840311000000000141e-01 1.969221529999999998e+00 4.012745166666670249e-02 +3.989493000000000067e-01 1.908232941666669902e+00 3.938963333333329875e-02 +4.107629999999999892e-01 1.727702871333330004e+00 3.958386533333330126e-02 +4.137051999999999952e-01 1.726875600000000066e+00 3.720425833333330240e-02 +4.291185000000000138e-01 1.581841901666670047e+00 3.398506666666670228e-02 +4.296455000000000135e-01 1.691278518333330094e+00 3.404221949999999830e-02 +4.446591999999999767e-01 1.488087740000000103e+00 3.374035333333329917e-02 +4.467690999999999746e-01 1.413946998166669911e+00 2.991126200000000096e-02 +4.603923999999999794e-01 1.391984139999999925e+00 3.130147333333330173e-02 +4.686460000000000070e-01 1.392956528666670080e+00 2.997462383333330052e-02 +4.765479000000000243e-01 1.301627080000000047e+00 2.965699000000000113e-02 +4.835137999999999936e-01 1.193676802499999967e+00 2.800566683333330018e-02 +4.923843999999999999e-01 1.242278698333330045e+00 2.973970833333329858e-02 +5.047722000000000042e-01 1.149708217833329993e+00 2.613050733333329920e-02 +5.083368000000000331e-01 1.161310218333329924e+00 2.733334000000000111e-02 +5.231871000000000160e-01 9.503032668333329935e-01 2.446244750000000148e-02 +5.249844000000000177e-01 1.102167341666669964e+00 2.571981833333330039e-02 +5.417480000000000073e-01 9.754589783333329489e-01 2.525416166666670167e-02 +5.445189000000000279e-01 9.366835949999999800e-01 2.497178450000000008e-02 +5.583793000000000228e-01 8.831162099999999571e-01 2.438054666666670048e-02 +5.613839000000000468e-01 8.824506341666670250e-01 2.281443349999999828e-02 +5.754704000000000486e-01 8.100822066666669707e-01 2.253018666666670167e-02 +5.835346000000000144e-01 7.776236106666669645e-01 2.252483566666670101e-02 +5.928168000000000326e-01 7.764561633333330049e-01 2.182597999999999830e-02 +6.007057000000000091e-01 6.983251131666670108e-01 2.131793766666669962e-02 +6.099849999999999994e-01 7.099790583333329685e-01 2.117932666666669933e-02 +6.219902999999999960e-01 6.466382168333330016e-01 2.081252199999999997e-02 +6.275817000000000201e-01 6.603706066666670260e-01 2.006477833333330033e-02 +6.413482000000000349e-01 5.710830485000000234e-01 1.856948533333329862e-02 +6.447992000000000168e-01 5.732715750000000332e-01 2.040912500000000018e-02 +6.656950000000000367e-01 5.203726888333329859e-01 1.789587166666670170e-02 +6.845196000000000058e-01 4.749653629999999738e-01 1.990720683333329841e-02 +7.059646000000000532e-01 3.822856073333329996e-01 1.675657983333329881e-02 +7.260278000000000009e-01 3.886542691666670102e-01 1.802539466666670115e-02 +7.492113999999999718e-01 3.564554191666670091e-01 1.487377883333330063e-02 +7.721772000000000080e-01 3.333074428333330230e-01 1.689668533333330003e-02 +7.922717999999999705e-01 3.187338046666670088e-01 1.488059016666670037e-02 +8.156877999999999629e-01 3.010368924999999862e-01 1.521491216666670011e-02 +8.366301000000000432e-01 2.406595508333330136e-01 1.435568400000000050e-02 +8.621258000000000532e-01 2.223576200000000058e-01 1.352156766666669924e-02 +8.848333999999999921e-01 2.207387865000000060e-01 1.422139816666669922e-02 +9.083444000000000518e-01 2.134049949999999862e-01 1.254214099999999971e-02 +9.336484000000000449e-01 1.885945263333330124e-01 1.346345033333330027e-02 +9.553916000000000075e-01 1.698076676666669949e-01 1.265998783333329922e-02 +9.815112999999999754e-01 1.668850050000000029e-01 1.189438716666670059e-02 +1.007027499999999964e+00 1.441018685000000077e-01 1.227580483333329947e-02 +1.030631400000000086e+00 1.406578583333329968e-01 1.168073399999999991e-02 +1.058015099999999986e+00 1.399035711666669901e-01 1.082874783333329961e-02 +1.084837700000000016e+00 1.486492919999999884e-01 1.123307866666669978e-02 +1.110144500000000090e+00 1.008698655000000027e-01 1.077987283333329931e-02 +1.137999800000000006e+00 1.027075286666670056e-01 1.037853683333330064e-02 +1.166290800000000072e+00 1.157098001666670012e-01 1.020088966666670045e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv new file mode 100644 index 000000000..1c5c261ee --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 2.859171986188329811e+03 2.282233352000000082e+01 +4.070000000000000007e-02 1.037695935384999984e+03 1.390765389166669941e+01 +4.511180000000000051e-02 4.617414862783330136e+02 9.644274246666670436e+00 +4.959249999999999770e-02 2.830472148050000101e+02 7.651757100000000200e+00 +5.416379999999999806e-02 1.737180786733329967e+02 5.901133003333329796e+00 +5.868999999999999911e-02 1.284318533800000068e+02 5.055296333333330061e+00 +6.315320000000000655e-02 1.083304533916670067e+02 4.179970964999999872e+00 +6.773540000000000116e-02 8.164665742500000079e+01 3.449109084999999908e+00 +7.238989999999999314e-02 6.842710629666669320e+01 3.015091889999999886e+00 +7.694339999999999513e-02 6.503887503333329789e+01 2.712566869999999852e+00 +8.166600000000000248e-02 5.768616606333330310e+01 2.292022508333329878e+00 +8.641719999999999957e-02 4.726633163000000337e+01 2.052834279999999900e+00 +9.109140000000000292e-02 4.170182763166670270e+01 1.806841736666670029e+00 +9.576210000000000278e-02 3.278791741500000256e+01 1.635979810000000034e+00 +1.005216000000000026e-01 3.137094696333329935e+01 1.457612156666669989e+00 +1.052672000000000052e-01 2.858316747499999977e+01 1.352856671666669897e+00 +1.100174000000000013e-01 2.685582243333330155e+01 1.222659363333330029e+00 +1.148721999999999938e-01 2.463809722666670154e+01 1.115379456666669933e+00 +1.198083000000000065e-01 1.979913578000000030e+01 1.002652691666670037e+00 +1.248023999999999939e-01 1.884005529499999909e+01 9.371682333333329895e-01 +1.298709000000000113e-01 2.011378014833330141e+01 8.660532583333330203e-01 +1.349431000000000103e-01 1.548196221999999977e+01 8.040137483333329449e-01 +1.399610000000000021e-01 1.553817986500000004e+01 7.396018783333330182e-01 +1.451112999999999986e-01 1.380290046833330031e+01 7.008050850000000498e-01 +1.503050999999999970e-01 1.290957537833329916e+01 6.659874700000000258e-01 +1.556469000000000047e-01 1.188963399333329995e+01 5.958023666666669715e-01 +1.572456999999999883e-01 1.305280697499999931e+01 1.930089849999999940e-01 +1.609891999999999990e-01 1.134609165166670053e+01 5.714861916666670316e-01 +1.662309999999999899e-01 1.103891432833330022e+01 5.468199316666669807e-01 +1.706292000000000086e-01 1.121912493499999997e+01 1.614639983333329976e-01 +1.716062999999999894e-01 1.098087770333330049e+01 5.221648316666670508e-01 +1.771733000000000058e-01 9.846715853333330770e+00 4.826313150000000052e-01 +1.827794000000000085e-01 1.030369242166669963e+01 4.679303400000000002e-01 +1.842428999999999872e-01 9.629214631666670243e+00 1.387244099999999924e-01 +1.883665999999999952e-01 9.108624106666670883e+00 4.454082083333330000e-01 +1.940302000000000138e-01 8.056377178333329780e+00 4.232006716666670276e-01 +1.982414999999999872e-01 8.605072379999999299e+00 1.202604099999999981e-01 +1.998185000000000100e-01 8.229729869999999892e+00 3.995894999999999864e-01 +2.056348000000000065e-01 8.070094290000000115e+00 3.879820366666669740e-01 +2.115208000000000088e-01 7.741634115000000094e+00 3.686955350000000187e-01 +2.120113000000000136e-01 7.664225765000000301e+00 1.093220133333329958e-01 +2.162467999999999890e-01 7.363320653333330412e+00 4.626756216666669808e-01 +2.259823999999999999e-01 6.848802841666669750e+00 9.609777999999999376e-02 +2.397845000000000115e-01 6.337189861666669977e+00 9.020952999999999611e-02 +2.537096999999999825e-01 5.738702153333330003e+00 8.211384833333329469e-02 +2.676275000000000182e-01 5.346591223333329701e+00 7.572218666666670484e-02 +2.817857999999999752e-01 5.009933698333330021e+00 7.051459333333330581e-02 +2.956398000000000081e-01 4.597692046666669974e+00 6.646157833333329878e-02 +3.099044000000000243e-01 4.193400725000000051e+00 6.031815000000000093e-02 +3.240645999999999805e-01 3.804645918333330101e+00 5.825413166666670167e-02 +3.388027000000000122e-01 3.560888523333329836e+00 5.213344166666669666e-02 +3.539140000000000064e-01 3.375211385000000064e+00 5.107971833333330158e-02 +3.687090000000000090e-01 3.188264295000000192e+00 4.732182333333329743e-02 +3.839813000000000254e-01 2.892990108333330035e+00 4.441047333333329739e-02 +3.988975000000000160e-01 2.640608908333330174e+00 4.290645666666669661e-02 +4.106379000000000001e-01 2.501690660833329805e+00 4.331324033333330131e-02 +4.136514000000000024e-01 2.477246653333330162e+00 4.077528500000000139e-02 +4.290628000000000219e-01 2.358423203333329887e+00 3.769917166666669761e-02 +4.295145000000000213e-01 2.266923564999999918e+00 3.645828216666670285e-02 +4.446014999999999828e-01 2.023246533333329822e+00 3.627248666666670063e-02 +4.466328999999999994e-01 2.032174506166669836e+00 3.243397416666669864e-02 +4.603325999999999807e-01 1.951935533333329920e+00 3.395880333333330114e-02 +4.685032000000000085e-01 1.797322475499999905e+00 3.168831166666669780e-02 +4.764860000000000206e-01 1.814704324999999896e+00 3.212894000000000166e-02 +4.833663999999999739e-01 1.722621554333330085e+00 3.037123383333329915e-02 +4.923204999999999942e-01 1.658358661666669898e+00 3.178619500000000320e-02 +5.046184000000000225e-01 1.539108265666669917e+00 2.774163983333330016e-02 +5.082708000000000226e-01 1.547966548333330028e+00 2.920229666666670013e-02 +5.230276000000000369e-01 1.345057283333330078e+00 2.608127533333329945e-02 +5.249162000000000550e-01 1.417396718333330030e+00 2.724554333333329900e-02 +5.416775999999999813e-01 1.270799306666670070e+00 2.670250999999999875e-02 +5.443529999999999758e-01 1.250087865666670073e+00 2.633086933333329827e-02 +5.583067999999999920e-01 1.165305416666670091e+00 2.577655499999999961e-02 +5.612129000000000145e-01 1.147836548999999984e+00 2.393862083333329893e-02 +5.753956999999999544e-01 1.115183805000000028e+00 2.400332833333329932e-02 +5.833568000000000087e-01 1.044019996999999922e+00 2.366755300000000090e-02 +5.927398999999999862e-01 1.004017331666670065e+00 2.296542000000000028e-02 +6.005226999999999649e-01 9.482225546666670501e-01 2.240195116666670108e-02 +6.099058000000000535e-01 9.388455449999999480e-01 2.233828499999999939e-02 +6.218008000000000424e-01 8.511757086666670302e-01 2.168908733333330119e-02 +6.275003000000000108e-01 8.553386066666669452e-01 2.101305833333329959e-02 +6.411527999999999672e-01 7.761240236666669956e-01 1.940277716666670080e-02 +6.447154999999999969e-01 7.270576883333329521e-01 2.120466833333330137e-02 +6.654921999999999782e-01 7.007768106666669716e-01 1.861042133333330045e-02 +6.843110000000000026e-01 6.466361541666669766e-01 2.069310833333330019e-02 +7.057493999999999712e-01 5.771519323333329510e-01 1.752841666666669906e-02 +7.258065000000000211e-01 5.204018098333329512e-01 1.860044799999999859e-02 +7.489831000000000127e-01 4.984340896666670240e-01 1.540761000000000040e-02 +7.719418000000000113e-01 4.436713720000000083e-01 1.738589999999999927e-02 +7.920304000000000233e-01 4.316635041666669892e-01 1.532890283333330009e-02 +8.154392000000000307e-01 3.868879691666670118e-01 1.556857449999999969e-02 +8.363751000000000380e-01 3.670109628333330098e-01 1.484866983333330004e-02 +8.618630000000000457e-01 3.329731463333330255e-01 1.392995016666669951e-02 +8.845638000000000112e-01 3.302565831666670060e-01 1.467645416666669977e-02 +9.080675999999999748e-01 2.757098590000000016e-01 1.276754683333329934e-02 +9.333637999999999657e-01 2.804865558333329845e-01 1.382540016666669938e-02 +9.551005000000000189e-01 2.398962168333330092e-01 1.292395533333329932e-02 +9.812121999999999788e-01 2.360268241666670097e-01 1.213837400000000039e-02 +1.006720599999999965e+00 2.134167958333330062e-01 1.253179649999999930e-02 +1.030317399999999939e+00 2.102511210000000130e-01 1.193319533333330081e-02 +1.057692700000000041e+00 2.135461601666669984e-01 1.107935333333330032e-02 +1.084507099999999946e+00 1.969431385000000034e-01 1.140526600000000071e-02 +1.109806099999999907e+00 1.561050018333330069e-01 1.096976283333329916e-02 +1.137653000000000025e+00 1.629041234999999976e-01 1.057719600000000051e-02 +1.165935399999999955e+00 1.774132069999999894e-01 1.040658966666670009e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv new file mode 100644 index 000000000..3fc895617 --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv @@ -0,0 +1,105 @@ +3.623980000000000257e-02 4.717095203250000282e+02 1.736400694499999986e+01 +4.068580000000000113e-02 2.786014172683330230e+02 1.198827076999999974e+01 +4.509610000000000007e-02 1.807710803516669955e+02 8.834240069999999889e+00 +4.957530000000000270e-02 1.404167299050000111e+02 7.187393765000000379e+00 +5.414490000000000275e-02 1.070548824566670021e+02 5.660295944999999662e+00 +5.866960000000000230e-02 9.429733434666670178e+01 4.914365443333330141e+00 +6.313130000000000130e-02 8.753748113499999306e+01 4.086659178333330367e+00 +6.771190000000000542e-02 8.007891920833330346e+01 3.441741584999999937e+00 +7.236470000000000402e-02 5.999202779333329971e+01 2.970499293333329849e+00 +7.691660000000000164e-02 5.902839900166669906e+01 2.678938321666669786e+00 +8.163760000000000461e-02 4.960764509333330352e+01 2.245417474999999996e+00 +8.638719999999999732e-02 4.414010876166670272e+01 2.032560301666670011e+00 +9.105969999999999342e-02 4.256424763833329905e+01 1.812761751666670085e+00 +9.572880000000000278e-02 3.308233848333330229e+01 1.638201501666670001e+00 +1.004865999999999954e-01 2.810971494833329842e+01 1.433384486666670066e+00 +1.052305999999999936e-01 2.588485028666670118e+01 1.331128581666670030e+00 +1.099790999999999963e-01 2.266535039333329848e+01 1.188278135000000013e+00 +1.148321999999999954e-01 2.068870146000000076e+01 1.081535063333330049e+00 +1.197666000000000008e-01 1.976825064833330003e+01 1.002416109999999971e+00 +1.247589999999999949e-01 1.708519936000000072e+01 9.212166283333329542e-01 +1.298257999999999912e-01 1.961539944500000132e+01 8.615532866666669731e-01 +1.348960999999999910e-01 1.509279464499999968e+01 8.002327049999999886e-01 +1.399122999999999895e-01 1.461401991333329953e+01 7.302237983333329518e-01 +1.450607999999999898e-01 1.234817605166669985e+01 6.862621599999999544e-01 +1.502527999999999919e-01 1.236984282499999921e+01 6.604921383333329787e-01 +1.555927000000000004e-01 1.196552256666669933e+01 5.966093183333329719e-01 +1.572660999999999920e-01 1.278021405166670021e+01 1.919547649999999994e-01 +1.609331999999999985e-01 1.153752966666669977e+01 5.736198133333330063e-01 +1.661730999999999903e-01 1.078861117833329963e+01 5.440816866666670082e-01 +1.706513000000000058e-01 1.087118622666669943e+01 1.601861350000000073e-01 +1.715465999999999935e-01 9.877732214999999982e+00 5.101304616666669789e-01 +1.771117000000000108e-01 1.016148657499999963e+01 4.860413033333330080e-01 +1.827158000000000115e-01 1.012859923499999937e+01 4.659961616666670192e-01 +1.842668000000000084e-01 9.892309961666670759e+00 1.394281016666669981e-01 +1.883010999999999990e-01 9.370592901666670471e+00 4.483600366666670167e-01 +1.939626999999999879e-01 7.953713988333330320e+00 4.220674716666670268e-01 +1.982673000000000074e-01 8.536490116666669792e+00 1.198682733333329975e-01 +1.997490000000000099e-01 8.016174306666670191e+00 3.972042266666669930e-01 +2.055633000000000044e-01 7.936747634999999690e+00 3.864501066666670148e-01 +2.114472000000000018e-01 7.092097319999999705e+00 3.613801233333330254e-01 +2.120387999999999995e-01 7.719984431666669700e+00 1.093860133333330042e-01 +2.161715999999999915e-01 7.279911723333330364e+00 4.614210216666669861e-01 +2.260118000000000127e-01 6.899103116666670310e+00 9.616077666666669743e-02 +2.398155999999999899e-01 6.131303501666669931e+00 8.927448999999999801e-02 +2.537425999999999848e-01 5.657937448333330011e+00 8.168489666666670090e-02 +2.676623000000000197e-01 5.142021448333330191e+00 7.478100833333330144e-02 +2.818223999999999729e-01 4.914665098333330207e+00 7.002304500000000598e-02 +2.956782000000000021e-01 4.446721935000000236e+00 6.572301166666670580e-02 +3.099446000000000145e-01 4.282954679999999570e+00 6.061547666666670248e-02 +3.241067000000000253e-01 3.767117071666670203e+00 5.800978500000000121e-02 +3.388467000000000007e-01 3.499952983333329826e+00 5.180699999999999888e-02 +3.539599999999999969e-01 3.303444670000000194e+00 5.069738166666670071e-02 +3.687568999999999986e-01 2.950319708333330126e+00 4.620904333333329672e-02 +3.840311000000000141e-01 2.864367984999999894e+00 4.422433499999999656e-02 +3.989493000000000067e-01 2.552979848333329915e+00 4.244176999999999672e-02 +4.107629999999999892e-01 2.431688859833330163e+00 4.295243233333329719e-02 +4.137051999999999952e-01 2.340746346666669808e+00 4.009275166666669693e-02 +4.291185000000000138e-01 2.236674611666670032e+00 3.708904500000000104e-02 +4.296455000000000135e-01 2.145105044333329936e+00 3.592934700000000037e-02 +4.446591999999999767e-01 1.951663006666670030e+00 3.589577499999999782e-02 +4.467690999999999746e-01 1.941018092166669984e+00 3.204738566666669869e-02 +4.603923999999999794e-01 1.841567858333329921e+00 3.340552499999999841e-02 +4.686460000000000070e-01 1.795296687500000044e+00 3.165418133333330192e-02 +4.765479000000000243e-01 1.725552725000000009e+00 3.166947999999999985e-02 +4.835137999999999936e-01 1.648896234833330032e+00 3.002704050000000111e-02 +4.923843999999999999e-01 1.592235150000000043e+00 3.142748499999999806e-02 +5.047722000000000042e-01 1.524318554666669989e+00 2.765916716666669967e-02 +5.083368000000000331e-01 1.470192684999999999e+00 2.879683666666670028e-02 +5.231871000000000160e-01 1.276008043333330066e+00 2.578494833333330044e-02 +5.249844000000000177e-01 1.335736669999999959e+00 2.682150333333329847e-02 +5.417480000000000073e-01 1.255200871666670048e+00 2.659473333333330081e-02 +5.445189000000000279e-01 1.181751707666669926e+00 2.602010650000000092e-02 +5.583793000000000228e-01 1.119981195000000040e+00 2.552491833333329907e-02 +5.613839000000000468e-01 1.109540133333329903e+00 2.376074416666670158e-02 +5.754704000000000486e-01 1.035568078333330089e+00 2.359670999999999991e-02 +5.835346000000000144e-01 1.009673415166669974e+00 2.350527950000000019e-02 +5.928168000000000326e-01 9.958746566666669686e-01 2.289775833333329916e-02 +6.007057000000000091e-01 9.162153768333329840e-01 2.224946400000000005e-02 +6.099849999999999994e-01 8.912180400000000446e-01 2.207391333333329902e-02 +6.219902999999999960e-01 8.127960751666669648e-01 2.151158183333330004e-02 +6.275817000000000201e-01 8.004247816666669735e-01 2.072389499999999912e-02 +6.413482000000000349e-01 7.426332359999999744e-01 1.925514349999999861e-02 +6.447992000000000168e-01 7.076525866666669717e-01 2.108122000000000121e-02 +6.656950000000000367e-01 6.442563610000000551e-01 1.837696600000000152e-02 +6.845196000000000058e-01 6.085390748333330269e-01 2.050695833333330068e-02 +7.059646000000000532e-01 5.280073378333329792e-01 1.732566899999999840e-02 +7.260278000000000009e-01 5.220653703333330009e-01 1.859470200000000115e-02 +7.492113999999999718e-01 4.598426163333330097e-01 1.525465250000000023e-02 +7.721772000000000080e-01 4.332637708333330062e-01 1.732895283333329983e-02 +7.922717999999999705e-01 4.105990393333330268e-01 1.523655316666669944e-02 +8.156877999999999629e-01 3.602943534999999975e-01 1.545041316666669919e-02 +8.366301000000000432e-01 3.406887861666669792e-01 1.473824349999999957e-02 +8.621258000000000532e-01 3.067601776666670221e-01 1.382606316666670082e-02 +8.848333999999999921e-01 3.015524316666670090e-01 1.454982116666670051e-02 +9.083444000000000518e-01 2.607474308333330160e-01 1.270642616666669937e-02 +9.336484000000000449e-01 2.588003018333330241e-01 1.373286349999999940e-02 +9.553916000000000075e-01 2.226530176666670080e-01 1.285228899999999938e-02 +9.815112999999999754e-01 2.127235584999999929e-01 1.205009299999999957e-02 +1.007027499999999964e+00 2.082924603333330127e-01 1.250585733333330063e-02 +1.030631400000000086e+00 1.912464838333330086e-01 1.185822249999999960e-02 +1.058015099999999986e+00 1.948314409999999941e-01 1.101004149999999966e-02 +1.084837700000000016e+00 1.896849941666670092e-01 1.137308499999999979e-02 +1.110144500000000090e+00 1.497566153333330097e-01 1.094208966666669960e-02 +1.137999800000000006e+00 1.454676966666670068e-01 1.051448583333330043e-02 +1.166290800000000072e+00 1.467227160000000030e-01 1.029956333333329963e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv new file mode 100644 index 000000000..5ef6a3266 --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 2.531792558183329902e+02 1.680830338499999854e+01 +4.070000000000000007e-02 1.901177223299999923e+02 1.173664666500000031e+01 +4.511180000000000051e-02 1.217924648083329942e+02 8.645296186666669769e+00 +4.959249999999999770e-02 1.094275780066670052e+02 7.073034475000000043e+00 +5.416379999999999806e-02 8.791320813333329909e+01 5.581711248333330211e+00 +5.868999999999999911e-02 8.309104453833330695e+01 4.860535583333329690e+00 +6.315320000000000655e-02 7.081360745666670198e+01 4.003961999999999577e+00 +6.773540000000000116e-02 6.343291181166669901e+01 3.355398363333330192e+00 +7.238989999999999314e-02 4.842191466166669755e+01 2.903796691666669982e+00 +7.694339999999999513e-02 4.694420552666669977e+01 2.605583116666669863e+00 +8.166600000000000248e-02 4.367521950333330238e+01 2.207077676666670207e+00 +8.641719999999999957e-02 3.957930205499999943e+01 1.999356729999999915e+00 +9.109140000000000292e-02 3.553857484166670133e+01 1.762052579999999979e+00 +9.576210000000000278e-02 2.783675838666669833e+01 1.597004463333330015e+00 +1.005216000000000026e-01 2.705964543666669897e+01 1.423240978333329965e+00 +1.052672000000000052e-01 2.262947438833329983e+01 1.302317253333330038e+00 +1.100174000000000013e-01 2.182584247666670052e+01 1.179366926666669979e+00 +1.148721999999999938e-01 2.121788853500000016e+01 1.084366495000000041e+00 +1.198083000000000065e-01 1.779511935000000022e+01 9.833421683333329888e-01 +1.248023999999999939e-01 1.651748253666670152e+01 9.145048883333329881e-01 +1.298709000000000113e-01 1.721928703000000027e+01 8.380137100000000228e-01 +1.349431000000000103e-01 1.436323046666669967e+01 7.917284633333330213e-01 +1.399610000000000021e-01 1.550343697666670018e+01 7.379972516666669646e-01 +1.451112999999999986e-01 1.303663926666670037e+01 6.920347900000000108e-01 +1.503050999999999970e-01 1.200503839166669984e+01 6.556345366666670449e-01 +1.556469000000000047e-01 1.229304255666670009e+01 5.989305183333329952e-01 +1.573070000000000024e-01 1.257057899666670053e+01 1.910309249999999903e-01 +1.609891999999999990e-01 1.193592632666669928e+01 5.769697900000000379e-01 +1.662309999999999899e-01 1.125234698666669964e+01 5.482133000000000145e-01 +1.706957000000000058e-01 1.058112505166669948e+01 1.590339783333329926e-01 +1.716062999999999894e-01 1.070644689999999954e+01 5.183003699999999547e-01 +1.771733000000000058e-01 9.479454351666669609e+00 4.778282466666670114e-01 +1.827794000000000085e-01 9.400985496666670826e+00 4.569814249999999967e-01 +1.843146999999999980e-01 9.549487438333329692e+00 1.380682866666670117e-01 +1.883665999999999952e-01 8.342261173333330504e+00 4.359566316666669827e-01 +1.940302000000000138e-01 8.124126898333329905e+00 4.232381216666670221e-01 +1.983187999999999895e-01 8.328415036666669380e+00 1.189532799999999946e-01 +1.998185000000000100e-01 8.328210934999999537e+00 3.999954083333330246e-01 +2.056348000000000065e-01 8.350671104999999983e+00 3.905236483333329733e-01 +2.115208000000000088e-01 6.929636241666670138e+00 3.588886250000000167e-01 +2.120939000000000019e-01 7.535892504999999630e+00 1.085254183333329986e-01 +2.162467999999999890e-01 7.407988318333329936e+00 4.625349066666670228e-01 +2.260705000000000076e-01 6.743451298333329902e+00 9.541167166666669752e-02 +2.398779000000000050e-01 6.099490819999999758e+00 8.899463999999999986e-02 +2.538084999999999924e-01 5.555039073333330357e+00 8.113394833333330280e-02 +2.677318000000000198e-01 5.152730110000000252e+00 7.469547999999999466e-02 +2.818956000000000239e-01 4.837557096666669665e+00 6.957829666666670576e-02 +2.957549999999999901e-01 4.369791838333330070e+00 6.527595833333330044e-02 +3.100250999999999979e-01 4.110463069999999774e+00 5.977720166666670304e-02 +3.241909000000000041e-01 3.813721606666669928e+00 5.811357666666670113e-02 +3.389346999999999777e-01 3.461479851666669827e+00 5.155417166666669687e-02 +3.540519999999999778e-01 3.230298750000000219e+00 5.028755499999999767e-02 +3.688526999999999778e-01 2.998165658333329819e+00 4.634052999999999783e-02 +3.841308999999999974e-01 2.784144708333330165e+00 4.378963833333329725e-02 +3.990528999999999882e-01 2.595613363333329815e+00 4.256657166666669850e-02 +4.108341999999999827e-01 2.335089765499999803e+00 4.258898366666669794e-02 +4.138126999999999778e-01 2.324415418333329875e+00 3.994880166666670007e-02 +4.292300000000000004e-01 2.216248561666669836e+00 3.693022666666669757e-02 +4.297198999999999880e-01 2.134554158666670087e+00 3.596130699999999791e-02 +4.447747000000000228e-01 1.890609146666669904e+00 3.555346833333330320e-02 +4.468464999999999798e-01 1.908117816499999897e+00 3.198120466666670020e-02 +4.605119999999999769e-01 1.871098863333330087e+00 3.348654166666670262e-02 +4.687272000000000105e-01 1.810652348333330108e+00 3.178039216666669886e-02 +4.766716999999999760e-01 1.698277889999999957e+00 3.148857166666670093e-02 +4.835976000000000163e-01 1.613169754500000108e+00 2.993151466666670035e-02 +4.925123000000000140e-01 1.548358499999999971e+00 3.116390166666669834e-02 +5.048597000000000223e-01 1.494630669833330039e+00 2.759253283333330115e-02 +5.084689000000000014e-01 1.491590500000000041e+00 2.885127333333329866e-02 +5.232776999999999568e-01 1.248566430833329965e+00 2.572220416666669979e-02 +5.251208000000000542e-01 1.383180581666670017e+00 2.700447666666670049e-02 +5.418887000000000009e-01 1.221960488333329931e+00 2.639246833333330072e-02 +5.446132999999999669e-01 1.208971178333329899e+00 2.618446533333329898e-02 +5.585244000000000320e-01 1.107120358333330001e+00 2.542247833333330029e-02 +5.614812000000000136e-01 1.085889866500000078e+00 2.370511449999999909e-02 +5.756198999999999621e-01 1.024119451666670066e+00 2.350574000000000066e-02 +5.836356999999999795e-01 9.666399098333330331e-01 2.336446566666669847e-02 +5.929708999999999675e-01 9.753983600000000198e-01 2.276144833333329856e-02 +6.008097999999999494e-01 8.857038164999999630e-01 2.215761016666669900e-02 +6.101434999999999498e-01 9.144217283333330171e-01 2.215592499999999992e-02 +6.220980999999999872e-01 8.054969749999999484e-01 2.151697083333330152e-02 +6.277447999999999917e-01 7.972735800000000372e-01 2.067797666666670170e-02 +6.414592999999999545e-01 7.033510668333330385e-01 1.912904316666669963e-02 +6.449667999999999513e-01 7.010848466666670387e-01 2.101707333333329916e-02 +6.658104000000000244e-01 6.363828563333330246e-01 1.837497983333330129e-02 +6.846381999999999746e-01 5.758642446666669690e-01 2.039069533333329881e-02 +7.060868999999999618e-01 5.109788090000000338e-01 1.728495966666670006e-02 +7.261535999999999547e-01 4.885223020000000194e-01 1.847847583333329935e-02 +7.493412999999999879e-01 4.387949984999999775e-01 1.519840233333329994e-02 +7.723109999999999697e-01 3.923397161666670185e-01 1.717436333333329998e-02 +7.924090999999999774e-01 3.993512075000000272e-01 1.521433699999999965e-02 +8.158290999999999737e-01 3.564691013333329828e-01 1.545670316666669999e-02 +8.367750000000000465e-01 3.230009236666669947e-01 1.469029500000000078e-02 +8.622752000000000194e-01 2.878051181666669844e-01 1.377513966666669976e-02 +8.849867000000000150e-01 2.848005155000000177e-01 1.450056933333329981e-02 +9.085018000000000260e-01 2.630901753333330095e-01 1.273161166666669959e-02 +9.338100999999999763e-01 2.556641304999999753e-01 1.373873700000000087e-02 +9.555571000000000481e-01 2.110106781666669928e-01 1.282516266666670034e-02 +9.816814000000000373e-01 1.989191335000000116e-01 1.201689483333330012e-02 +1.007201999999999931e+00 1.798726026666669919e-01 1.241756500000000020e-02 +1.030810000000000004e+00 1.697684260000000001e-01 1.179553216666670047e-02 +1.058198500000000042e+00 1.911874938333329998e-01 1.101163099999999916e-02 +1.085025700000000093e+00 1.546144220000000014e-01 1.126302133333329999e-02 +1.110336800000000013e+00 1.274498698333330071e-01 1.087918116666669946e-02 +1.138196999999999903e+00 1.312019681666669879e-01 1.048030450000000079e-02 +1.166492899999999944e+00 1.202452754999999984e-01 1.022370933333329943e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv new file mode 100644 index 000000000..51227d3b8 --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv @@ -0,0 +1,105 @@ +3.624299999999999744e-02 2.421839941750000094e+02 1.681259771499999900e+01 +4.068929999999999769e-02 1.253477160583330061e+02 1.158261931833330038e+01 +4.510000000000000120e-02 1.038159109083329952e+02 8.606540843333329249e+00 +4.957960000000000145e-02 9.508877155000000414e+01 7.037626288333330038e+00 +5.414959999999999912e-02 7.142443308833330207e+01 5.530319266666669620e+00 +5.867460000000000037e-02 6.747951957166669956e+01 4.803320423333330424e+00 +6.313670000000000393e-02 6.491403129500000091e+01 3.984481885000000112e+00 +6.771770000000000567e-02 5.688806046833330043e+01 3.329560004999999823e+00 +7.237100000000000477e-02 4.031379161166670144e+01 2.864987329999999943e+00 +7.692330000000000001e-02 4.363721252500000247e+01 2.591659659999999921e+00 +8.164470000000000061e-02 3.499940050499999700e+01 2.159604903333330217e+00 +8.639470000000000482e-02 3.331168452000000002e+01 1.961486934999999932e+00 +9.106759999999999855e-02 3.141853618500000067e+01 1.737193953333330043e+00 +9.573710000000000553e-02 2.514925802833329982e+01 1.580249494999999893e+00 +1.004952999999999957e-01 2.418445705499999931e+01 1.404480071666670105e+00 +1.052397000000000055e-01 2.311071394833329862e+01 1.309208076666670051e+00 +1.099886000000000058e-01 2.234431306333329914e+01 1.186371084999999992e+00 +1.148422000000000054e-01 2.015011891333330141e+01 1.077548355000000013e+00 +1.197769999999999946e-01 1.762490517499999854e+01 9.840672733333329925e-01 +1.247698000000000002e-01 1.703488854000000075e+01 9.213895800000000413e-01 +1.298370000000000080e-01 1.644401272166669870e+01 8.327218266666670532e-01 +1.349077999999999944e-01 1.614025673666670002e+01 8.110203433333329492e-01 +1.399244000000000043e-01 1.432045983666669997e+01 7.277294366666670067e-01 +1.450733999999999913e-01 1.348007003166670081e+01 6.981156733333330200e-01 +1.502658000000000049e-01 1.217057146500000009e+01 6.589065133333330548e-01 +1.556062000000000001e-01 1.311354035333330081e+01 6.087518283333329672e-01 +1.573412999999999895e-01 1.262766263333329952e+01 1.918068450000000036e-01 +1.609471000000000096e-01 1.195521582166669994e+01 5.786270049999999721e-01 +1.661874999999999880e-01 1.070419187999999977e+01 5.435432616666669992e-01 +1.707328999999999930e-01 1.060603477499999947e+01 1.596232366666670011e-01 +1.715615000000000057e-01 1.106375028666669991e+01 5.234683166666670440e-01 +1.771270000000000067e-01 9.097135046666670277e+00 4.748174949999999783e-01 +1.827315999999999940e-01 9.232441778333329907e+00 4.562185283333329844e-01 +1.843548999999999882e-01 9.582483613333330652e+00 1.386399050000000077e-01 +1.883173999999999959e-01 9.681451038333330317e+00 4.521609416666669823e-01 +1.939794999999999991e-01 8.227612430000000643e+00 4.254379616666669750e-01 +1.983621000000000134e-01 8.295318078333329126e+00 1.192443799999999970e-01 +1.997663000000000078e-01 8.131970284999999521e+00 3.988034016666670012e-01 +2.055810999999999888e-01 7.142658796666670362e+00 3.773835349999999922e-01 +2.114655000000000007e-01 7.164933761666669731e+00 3.624743966666669759e-01 +2.121402000000000010e-01 7.387669431666670228e+00 1.083523799999999981e-01 +2.161903000000000019e-01 6.864321103333329788e+00 4.553583783333329804e-01 +2.261198000000000097e-01 6.847039901666669870e+00 9.614554833333330275e-02 +2.399302000000000101e-01 6.151464958333329847e+00 8.952354166666670610e-02 +2.538638999999999757e-01 5.563245829999999614e+00 8.146051666666670465e-02 +2.677901999999999783e-01 5.162996156666669556e+00 7.501275500000000040e-02 +2.819571000000000160e-01 4.731078383333329640e+00 6.938886333333330048e-02 +2.958196000000000159e-01 4.470382223333330352e+00 6.595420000000000449e-02 +3.100928000000000018e-01 4.071269568333329758e+00 5.983178000000000107e-02 +3.242616999999999861e-01 3.818289136666670025e+00 5.835058500000000342e-02 +3.390086999999999962e-01 3.464278166666669989e+00 5.175618166666669934e-02 +3.541291999999999773e-01 3.297458013333330218e+00 5.076983000000000190e-02 +3.689332000000000167e-01 3.070901008333330129e+00 4.683460500000000137e-02 +3.842147000000000201e-01 2.769801061666670172e+00 4.388707166666670073e-02 +3.991399999999999948e-01 2.510583560000000158e+00 4.232430333333329908e-02 +4.106022999999999756e-01 2.374815773499999949e+00 4.286182233333329927e-02 +4.139030000000000209e-01 2.373871081666670158e+00 4.032223833333330176e-02 +4.293236999999999748e-01 2.231085370000000179e+00 3.713437166666670036e-02 +4.294773000000000063e-01 2.156539414333329852e+00 3.612328016666670194e-02 +4.448717999999999839e-01 1.876962131666670031e+00 3.561285166666670193e-02 +4.465942999999999996e-01 1.963582529333329996e+00 3.226501116666669750e-02 +4.606124999999999803e-01 1.886281606666670108e+00 3.367513833333329876e-02 +4.684626000000000068e-01 1.795604685000000034e+00 3.177854483333329705e-02 +4.767757000000000245e-01 1.729912848333329922e+00 3.174894833333329752e-02 +4.833245999999999931e-01 1.643333701666670033e+00 3.012282700000000132e-02 +4.926197999999999966e-01 1.601281793333330095e+00 3.152871666666669931e-02 +5.045747000000000426e-01 1.513868059666670041e+00 2.772222300000000070e-02 +5.085798000000000263e-01 1.480025179999999940e+00 2.889593166666670071e-02 +5.229823000000000111e-01 1.292098316666669966e+00 2.594417883333329997e-02 +5.252354000000000189e-01 1.389690103333329985e+00 2.712855999999999948e-02 +5.420070000000000165e-01 1.207626951666670001e+00 2.641061333333330138e-02 +5.443057999999999508e-01 1.171074812333330106e+00 2.606778300000000062e-02 +5.586463000000000401e-01 1.131968480000000055e+00 2.562754666666669859e-02 +5.611642999999999493e-01 1.119771183833329964e+00 2.388942000000000149e-02 +5.757455000000000211e-01 1.050324178333329916e+00 2.370775166666670014e-02 +5.833063000000000553e-01 9.890430198333329814e-01 2.349970633333330061e-02 +5.931003000000000247e-01 9.529422783333330038e-01 2.272385333333330065e-02 +6.004707000000000239e-01 9.087951714999999986e-01 2.229426183333330092e-02 +6.102765999999999469e-01 8.968441200000000224e-01 2.213925333333329956e-02 +6.217470000000000496e-01 8.116193323333330545e-01 2.157820200000000119e-02 +6.278818000000000454e-01 7.745292049999999984e-01 2.063141833333330052e-02 +6.410972000000000337e-01 7.304547335000000086e-01 1.926881999999999900e-02 +6.451074999999999449e-01 7.030634049999999746e-01 2.109099333333330079e-02 +6.654345000000000399e-01 6.451808323333330097e-01 1.843812350000000044e-02 +6.842517000000000182e-01 5.969281796666670026e-01 2.051784966666669874e-02 +7.056883000000000461e-01 4.875458616666670242e-01 1.721726566666669997e-02 +7.257436999999999916e-01 5.206052460000000215e-01 1.864389433333329960e-02 +7.489183000000000368e-01 4.716855048333329914e-01 1.534349166666670004e-02 +7.718749999999999778e-01 3.996116843333329949e-01 1.723059933333330115e-02 +7.919618000000000491e-01 3.949704010000000265e-01 1.521841983333330033e-02 +8.153685999999999989e-01 3.711572033333330189e-01 1.553813883333329988e-02 +8.363026999999999544e-01 3.373120053333329982e-01 1.476541233333330053e-02 +8.617884000000000100e-01 3.012111169999999727e-01 1.384248800000000001e-02 +8.844872000000000289e-01 3.093801609999999869e-01 1.462152149999999991e-02 +9.079890000000000461e-01 2.725293346666670113e-01 1.278188633333329945e-02 +9.332829999999999737e-01 2.562172424999999976e-01 1.375849099999999943e-02 +9.550178000000000278e-01 2.195073688333329942e-01 1.287299783333330054e-02 +9.811271999999999771e-01 1.993873673333330099e-01 1.203331399999999982e-02 +1.006633399999999900e+00 1.965978770000000042e-01 1.249421516666670076e-02 +1.030228200000000038e+00 1.888581198333330047e-01 1.187900783333330039e-02 +1.057601100000000072e+00 2.019180355000000093e-01 1.106158266666669963e-02 +1.084413199999999966e+00 1.710308969999999873e-01 1.133507299999999933e-02 +1.109710100000000033e+00 1.385269876666669897e-01 1.092970799999999978e-02 +1.137554500000000024e+00 1.323425321666669985e-01 1.049619949999999920e-02 +1.165834400000000048e+00 1.352444690000000060e-01 1.028587266666670073e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv new file mode 100644 index 000000000..e4a5c8ff1 --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv @@ -0,0 +1,105 @@ +3.623830000000000107e-02 1.262534512933330006e+02 1.649893105666669868e+01 +4.068399999999999794e-02 1.096408472683330046e+02 1.152156481833329948e+01 +4.509420000000000095e-02 6.843298548666669490e+01 8.484508865000000455e+00 +4.957310000000000189e-02 5.337196919333329959e+01 6.882409771666670117e+00 +5.414259999999999906e-02 4.824018401499999698e+01 5.433445991666670416e+00 +5.866699999999999693e-02 4.665372951666670076e+01 4.705492196666670068e+00 +6.312850000000000406e-02 5.221271013999999866e+01 3.917987768333329957e+00 +6.770890000000000242e-02 4.827582027833329903e+01 3.280544881666669799e+00 +7.236159999999999815e-02 3.618855914666669804e+01 2.837183351666670017e+00 +7.691330000000000389e-02 3.079150051333330040e+01 2.510836073333329921e+00 +8.163410000000000111e-02 3.296728457500000076e+01 2.143401925000000041e+00 +8.638339999999999907e-02 3.069841431000000043e+01 1.940150145000000048e+00 +9.105580000000000618e-02 2.710592771666669876e+01 1.703459686666670025e+00 +9.572469999999999590e-02 2.329590637833329936e+01 1.563327263333329942e+00 +1.004822999999999966e-01 2.091072460333329985e+01 1.376591528333330094e+00 +1.052260000000000001e-01 1.912562908333330114e+01 1.273402691666670083e+00 +1.099742999999999971e-01 1.787115249333330169e+01 1.146192773333329917e+00 +1.148272999999999933e-01 1.794118791666669921e+01 1.055988855000000060e+00 +1.197614000000000040e-01 1.653599519333329937e+01 9.723875616666669552e-01 +1.247536000000000062e-01 1.582743532666670028e+01 9.084356083333330334e-01 +1.298200999999999938e-01 1.478155951166669979e+01 8.152435350000000192e-01 +1.348902999999999908e-01 1.334408521333329922e+01 7.818770066666670404e-01 +1.399062000000000083e-01 1.377281605666670039e+01 7.205883533333330426e-01 +1.450545000000000029e-01 1.181691977333330001e+01 6.799812333333330461e-01 +1.502462999999999993e-01 1.213584320000000005e+01 6.572146300000000219e-01 +1.555860000000000021e-01 1.192358865166669979e+01 5.953690533333330093e-01 +1.572933999999999999e-01 1.181612013833330010e+01 1.889312700000000123e-01 +1.609261999999999915e-01 1.175466066000000076e+01 5.752044899999999572e-01 +1.661659000000000053e-01 1.042143580833329963e+01 5.392668716666669804e-01 +1.706808999999999965e-01 1.011778497999999971e+01 1.577585016666669948e-01 +1.715392000000000028e-01 9.758357795000000223e+00 5.081139666666669719e-01 +1.771040000000000114e-01 8.903400566666670457e+00 4.716962699999999731e-01 +1.827079000000000064e-01 9.178007346666669619e+00 4.546196783333329994e-01 +1.842987000000000097e-01 9.009516103333330861e+00 1.364224366666670074e-01 +1.882929000000000130e-01 8.406366826666669567e+00 4.368516150000000264e-01 +1.939542999999999962e-01 7.892936534999999587e+00 4.208100816666670019e-01 +1.983015999999999945e-01 7.968528981666669786e+00 1.178380566666669960e-01 +1.997403000000000095e-01 7.734987613333330181e+00 3.934730833333329736e-01 +2.055543999999999982e-01 7.979108915000000302e+00 3.863922049999999886e-01 +2.114380999999999899e-01 6.834691483333330098e+00 3.579354766666669740e-01 +2.120755000000000001e-01 7.473622876666669690e+00 1.084324933333330049e-01 +2.161621999999999988e-01 6.843431601666670083e+00 4.540542233333330069e-01 +2.260508999999999991e-01 6.624537448333329692e+00 9.508442500000000019e-02 +2.398570999999999898e-01 6.030806045000000282e+00 8.883706333333329930e-02 +2.537865999999999733e-01 5.548485336666669987e+00 8.121552666666670417e-02 +2.677086000000000188e-01 5.056279183333329819e+00 7.439664999999999473e-02 +2.818711999999999884e-01 4.746517688333329765e+00 6.929181333333329917e-02 +2.957293999999999756e-01 4.360488485000000303e+00 6.532353000000000465e-02 +3.099983000000000044e-01 4.042259101666670240e+00 5.956615500000000257e-02 +3.241628999999999761e-01 3.667612291666670021e+00 5.754424666666670130e-02 +3.389054000000000233e-01 3.392261260000000167e+00 5.132888666666669819e-02 +3.540212999999999832e-01 3.153369070000000107e+00 5.001504333333330055e-02 +3.688208000000000042e-01 2.957433689999999782e+00 4.622241666666670329e-02 +3.840975999999999835e-01 2.782086464999999897e+00 4.383930500000000202e-02 +3.990183999999999953e-01 2.497954614999999823e+00 4.216718166666669904e-02 +4.106379000000000001e-01 2.347253106833329994e+00 4.254085666666670290e-02 +4.137768000000000002e-01 2.313526113333329803e+00 3.995030166666670157e-02 +4.291927999999999854e-01 2.205677500000000180e+00 3.693004333333330114e-02 +4.295145000000000213e-01 2.125140473833329935e+00 3.583346700000000079e-02 +4.447362000000000259e-01 1.900926653333329996e+00 3.564656666666669860e-02 +4.466328999999999994e-01 1.939722618500000051e+00 3.202840516666669718e-02 +4.604721999999999982e-01 1.890633683333329929e+00 3.361991000000000285e-02 +4.685032000000000085e-01 1.753475375666670111e+00 3.146806816666670309e-02 +4.766304000000000096e-01 1.692544018333330014e+00 3.150160500000000197e-02 +4.833663999999999739e-01 1.571138671166669942e+00 2.967553150000000126e-02 +4.924697000000000102e-01 1.562743266666670072e+00 3.127265833333330025e-02 +5.046184000000000225e-01 1.517538195333330009e+00 2.762060549999999920e-02 +5.084248000000000101e-01 1.452519751666669912e+00 2.870172666666670133e-02 +5.230276000000000369e-01 1.280607860833330003e+00 2.579378549999999937e-02 +5.250753000000000226e-01 1.364635400000000054e+00 2.694985833333329861e-02 +5.418418000000000401e-01 1.180339848333330055e+00 2.622176999999999841e-02 +5.443529999999999758e-01 1.172893769833329936e+00 2.597214383333330129e-02 +5.584759999999999724e-01 1.116791568333330043e+00 2.550004666666669945e-02 +5.612129000000000145e-01 1.071752901666670033e+00 2.359418099999999879e-02 +5.755700000000000260e-01 1.003165499999999932e+00 2.343291166666670172e-02 +5.833568000000000087e-01 9.490407108333329678e-01 2.324037416666669895e-02 +5.929195000000000437e-01 9.286979850000000036e-01 2.255620333333329883e-02 +6.005226999999999649e-01 8.938147573333330431e-01 2.214501316666669939e-02 +6.100906000000000384e-01 8.779068549999999860e-01 2.199904499999999832e-02 +6.218008000000000424e-01 8.078191183333329750e-01 2.148254866666670163e-02 +6.276903999999999817e-01 7.890844949999999969e-01 2.066168499999999908e-02 +6.411527999999999672e-01 6.990414535000000207e-01 1.907308200000000162e-02 +6.449108999999999536e-01 7.027759316666669642e-01 2.104888333333329933e-02 +6.654921999999999782e-01 6.693195063333330364e-01 1.846815400000000051e-02 +6.843110000000000026e-01 5.654079498333329790e-01 2.030432683333329921e-02 +7.057493999999999712e-01 4.733216641666669888e-01 1.710506283333329894e-02 +7.258065000000000211e-01 4.881572298333329840e-01 1.844279849999999957e-02 +7.489831000000000127e-01 4.439720878333329734e-01 1.519038399999999948e-02 +7.719418000000000113e-01 4.063687451666669892e-01 1.720554133333329974e-02 +7.920304000000000233e-01 4.025809184999999957e-01 1.519988700000000047e-02 +8.154392000000000307e-01 3.522328571666670238e-01 1.541253149999999988e-02 +8.363751000000000380e-01 3.005755748333330257e-01 1.457862766666669953e-02 +8.618630000000000457e-01 2.801856756666670223e-01 1.372444566666669932e-02 +8.845638000000000112e-01 3.046253318333330129e-01 1.455751649999999925e-02 +9.080675999999999748e-01 2.540008221666669730e-01 1.267830250000000041e-02 +9.333637999999999657e-01 2.481020686666670083e-01 1.368678783333330054e-02 +9.551005000000000189e-01 1.938199579999999866e-01 1.274076333333330063e-02 +9.812121999999999788e-01 1.905731619999999904e-01 1.196892649999999926e-02 +1.006720599999999965e+00 1.784818836666670072e-01 1.239337400000000040e-02 +1.030317399999999939e+00 1.750911911666669929e-01 1.179671083333330012e-02 +1.057692700000000041e+00 1.705610396666669970e-01 1.092493383333329945e-02 +1.084507099999999946e+00 1.719191243333330066e-01 1.130716749999999965e-02 +1.109806099999999907e+00 1.366376699999999889e-01 1.089438483333329995e-02 +1.137653000000000025e+00 1.239800338333330032e-01 1.044124700000000072e-02 +1.165935399999999955e+00 1.310211675000000076e-01 1.024458533333330069e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv new file mode 100644 index 000000000..2b03b80a5 --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 1.213206534416670053e+02 1.651067908166670151e+01 +4.070000000000000007e-02 8.158564289333330066e+01 1.146150313666669973e+01 +4.511180000000000051e-02 6.728303165833330013e+01 8.493610868333329122e+00 +4.959249999999999770e-02 5.609321657833329766e+01 6.902234358333330100e+00 +5.416379999999999806e-02 4.208391674666670212e+01 5.417946521666669568e+00 +5.868999999999999911e-02 4.572918046833329697e+01 4.708583066666670369e+00 +6.315320000000000655e-02 4.506950746166670285e+01 3.890110903333329873e+00 +6.773540000000000116e-02 3.932771859999999720e+01 3.240109296666669803e+00 +7.238989999999999314e-02 3.425092975666670014e+01 2.830867521666669884e+00 +7.694339999999999513e-02 2.785716006499999864e+01 2.497106951666669961e+00 +8.166600000000000248e-02 2.647316349333329910e+01 2.106834523333330100e+00 +8.641719999999999957e-02 2.865549820000000025e+01 1.929370503333329934e+00 +9.109140000000000292e-02 2.617781355833329826e+01 1.699746431666669944e+00 +9.576210000000000278e-02 2.262414874833330103e+01 1.560889624999999947e+00 +1.005216000000000026e-01 2.072404344833330114e+01 1.377539340000000001e+00 +1.052672000000000052e-01 1.924028949499999896e+01 1.276625569999999987e+00 +1.100174000000000013e-01 1.836748323999999855e+01 1.152518286666670111e+00 +1.148721999999999938e-01 1.699007782666669897e+01 1.049408108333329981e+00 +1.198083000000000065e-01 1.493712180833330017e+01 9.595881783333329862e-01 +1.248023999999999939e-01 1.484142020166670051e+01 9.009069050000000356e-01 +1.298709000000000113e-01 1.473895257666669956e+01 8.163899350000000110e-01 +1.349431000000000103e-01 1.308340819666669930e+01 7.807371766666669766e-01 +1.399610000000000021e-01 1.350568340499999920e+01 7.192249033333329988e-01 +1.451112999999999986e-01 1.173611615333330072e+01 6.804578466666669767e-01 +1.503050999999999970e-01 1.154060497666669960e+01 6.523238550000000080e-01 +1.556469000000000047e-01 1.191625231333330071e+01 5.964806683333330195e-01 +1.573344999999999883e-01 1.139197852166670089e+01 1.879402166666669927e-01 +1.609891999999999990e-01 1.125507998666670062e+01 5.708663616666670437e-01 +1.662309999999999899e-01 1.041113468166670053e+01 5.402433599999999503e-01 +1.707255000000000023e-01 1.013307594333329931e+01 1.580824633333330065e-01 +1.716062999999999894e-01 9.500610554999999735e+00 5.062648633333329817e-01 +1.771733000000000058e-01 8.706795813333329193e+00 4.704599616666669815e-01 +1.827794000000000085e-01 9.156035623333330875e+00 4.553047450000000107e-01 +1.843469000000000080e-01 9.118870355000000316e+00 1.370399833333330042e-01 +1.883665999999999952e-01 7.952454938333329615e+00 4.325042000000000053e-01 +1.940302000000000138e-01 8.034647969999999972e+00 4.232443883333329993e-01 +1.983534999999999882e-01 8.119139649999999264e+00 1.185909816666669975e-01 +1.998185000000000100e-01 7.527596430000000005e+00 3.919050766666670182e-01 +2.056348000000000065e-01 7.553855535000000287e+00 3.822255366666669762e-01 +2.115208000000000088e-01 6.617426820000000376e+00 3.561540533333329983e-01 +2.121309999999999862e-01 7.390867828333330003e+00 1.083323783333329932e-01 +2.162467999999999890e-01 6.635593964999999983e+00 4.517541333333329745e-01 +2.261101000000000083e-01 6.488236141666670065e+00 9.474941333333329607e-02 +2.399198999999999915e-01 5.939089416666670118e+00 8.864513000000000253e-02 +2.538528999999999924e-01 5.445706584999999933e+00 8.096326333333329905e-02 +2.677785999999999778e-01 5.020975218333330048e+00 7.440106833333330616e-02 +2.819448999999999983e-01 4.782109235000000069e+00 6.958310166666670238e-02 +2.958067999999999809e-01 4.377367741666669865e+00 6.553075166666670615e-02 +3.100794000000000050e-01 4.070373518333330054e+00 5.980910666666670178e-02 +3.242476000000000247e-01 3.688249826666670117e+00 5.775312500000000238e-02 +3.389940000000000175e-01 3.411490240000000007e+00 5.151532000000000333e-02 +3.541138999999999815e-01 3.221007965000000084e+00 5.041618500000000225e-02 +3.689172000000000007e-01 2.942401639999999929e+00 4.624927499999999941e-02 +3.841980999999999868e-01 2.767105533333329870e+00 4.386071833333329839e-02 +3.991226999999999969e-01 2.564823933333329808e+00 4.256582833333329846e-02 +4.106734000000000218e-01 2.300881685499999829e+00 4.238948299999999864e-02 +4.138850000000000029e-01 2.413576710000000070e+00 4.049426666666670199e-02 +4.293050999999999950e-01 2.233726248333329778e+00 3.713503166666669991e-02 +4.295516999999999808e-01 2.156876818999999834e+00 3.601888033333330158e-02 +4.448524999999999840e-01 1.902652508333330106e+00 3.572283666666670188e-02 +4.466716000000000020e-01 1.934442038833330102e+00 3.205653166666670023e-02 +4.605926000000000187e-01 1.874115690000000001e+00 3.360869833333329781e-02 +4.685437000000000074e-01 1.737730488500000003e+00 3.144913299999999717e-02 +4.767550999999999872e-01 1.772107871666670054e+00 3.193823833333329920e-02 +4.834083000000000130e-01 1.581873448666669901e+00 2.976716433333330067e-02 +4.925984999999999947e-01 1.570737606666670061e+00 3.137136000000000091e-02 +5.046621000000000024e-01 1.492830698499999942e+00 2.756047650000000016e-02 +5.085577999999999488e-01 1.485373084999999982e+00 2.891283166666670096e-02 +5.230728999999999518e-01 1.159546245333330061e+00 2.533816566666670031e-02 +5.252126000000000294e-01 1.354185358333330091e+00 2.695080999999999866e-02 +5.419834999999999514e-01 1.186315898333329955e+00 2.629908666666670031e-02 +5.444001000000000534e-01 1.201936935333330014e+00 2.613158683333329999e-02 +5.586221000000000103e-01 1.109243371666670086e+00 2.550917499999999852e-02 +5.612614999999999688e-01 1.098874749833330000e+00 2.373973216666670077e-02 +5.757206000000000268e-01 1.029040688333330067e+00 2.359920000000000073e-02 +5.834072999999999620e-01 9.811238644999999980e-01 2.340685516666669852e-02 +5.930746000000000073e-01 9.534806916666670462e-01 2.272023833333329870e-02 +6.005747000000000169e-01 8.956047156666669951e-01 2.218217800000000031e-02 +6.102501999999999649e-01 8.805252883333329894e-01 2.205115333333329888e-02 +6.218546000000000351e-01 8.076579554999999688e-01 2.150926133333330020e-02 +6.278546000000000404e-01 8.143317416666669972e-01 2.081983000000000097e-02 +6.412082999999999533e-01 7.185076576666670212e-01 1.917512450000000146e-02 +6.450795999999999752e-01 7.187583950000000499e-01 2.116659499999999985e-02 +6.655497999999999692e-01 6.417931828333329758e-01 1.838261283333330123e-02 +6.843702000000000396e-01 5.677104609999999996e-01 2.033867249999999835e-02 +7.058105999999999547e-01 5.146355146666670155e-01 1.728668516666670082e-02 +7.258693999999999980e-01 5.183306771666670310e-01 1.859332783333330144e-02 +7.490480000000000471e-01 4.413184218333329745e-01 1.519721516666669957e-02 +7.720086999999999922e-01 4.069291728333330194e-01 1.722663266666669968e-02 +7.920989999999999975e-01 3.912903401666669723e-01 1.517220816666670080e-02 +8.155097999999999514e-01 3.620392363333330144e-01 1.546880433333329939e-02 +8.364475000000000104e-01 3.218374210000000124e-01 1.467598383333330002e-02 +8.619377000000000288e-01 2.793489951666670024e-01 1.373524349999999915e-02 +8.846403999999999934e-01 2.729738648333330242e-01 1.444214883333330007e-02 +9.081462000000000145e-01 2.731246803333329809e-01 1.275928200000000026e-02 +9.334447000000000161e-01 2.513956430000000020e-01 1.371339566666670076e-02 +9.551832000000000100e-01 2.075616728333329886e-01 1.280443116666669934e-02 +9.812971999999999806e-01 2.026315226666670077e-01 1.202260966666669935e-02 +1.006807800000000030e+00 1.715856353333329865e-01 1.237966916666670067e-02 +1.030406600000000061e+00 1.813217336666670121e-01 1.183022066666669994e-02 +1.057784300000000011e+00 1.874246033333329953e-01 1.099227083333330010e-02 +1.084600999999999926e+00 1.682342156666669919e-01 1.130467983333329970e-02 +1.109902299999999897e+00 1.305937931666669993e-01 1.088363799999999930e-02 +1.137751600000000085e+00 1.264251891666670069e-01 1.045857849999999936e-02 +1.166036300000000026e+00 1.206125236666669986e-01 1.021913349999999977e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv new file mode 100644 index 000000000..e8e9c9a0b --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 8.265676436333329491e+01 1.638320715333329858e+01 +4.070000000000000007e-02 5.464383480166669926e+01 1.136626790833330070e+01 +4.511180000000000051e-02 2.996549328500000087e+01 8.362137733333330658e+00 +4.959249999999999770e-02 3.902000664833330035e+01 6.829579628333330099e+00 +5.416379999999999806e-02 2.960868386499999971e+01 5.359635035000000158e+00 +5.868999999999999911e-02 2.775202533166670094e+01 4.620562245000000345e+00 +6.315320000000000655e-02 2.923420741833329828e+01 3.806268636666669813e+00 +6.773540000000000116e-02 2.925570898666670061e+01 3.181662941666670186e+00 +7.238989999999999314e-02 2.438109743166669929e+01 2.769415394999999780e+00 +7.694339999999999513e-02 2.082174377999999848e+01 2.449056793333329818e+00 +8.166600000000000248e-02 2.093264007666670068e+01 2.067833788333329981e+00 +8.641719999999999957e-02 2.065156679166669917e+01 1.869354308333329939e+00 +9.109140000000000292e-02 2.096371475999999845e+01 1.658336066666669995e+00 +9.576210000000000278e-02 1.686565956500000141e+01 1.512923419999999908e+00 +1.005216000000000026e-01 1.674424940666670025e+01 1.343149441666670052e+00 +1.052672000000000052e-01 1.453594207833329932e+01 1.233355748333329949e+00 +1.100174000000000013e-01 1.743436942499999986e+01 1.141890178333329953e+00 +1.148721999999999938e-01 1.514907325499999935e+01 1.030380964999999982e+00 +1.198083000000000065e-01 1.335097668833330076e+01 9.427780516666669497e-01 +1.248023999999999939e-01 1.334016233833330034e+01 8.846290449999999472e-01 +1.298709000000000113e-01 1.370878951499999943e+01 8.044898483333330352e-01 +1.349431000000000103e-01 1.169732300833329930e+01 7.648545733333329544e-01 +1.399610000000000021e-01 1.178831958166670013e+01 6.994071549999999471e-01 +1.451112999999999986e-01 1.065116290166669977e+01 6.676857533333330208e-01 +1.503050999999999970e-01 9.325193926666669242e+00 6.273500633333329857e-01 +1.556469000000000047e-01 1.029459589333329994e+01 5.781039766666670188e-01 +1.572456999999999883e-01 1.000640059000000015e+01 1.830944850000000013e-01 +1.609891999999999990e-01 1.045812633999999974e+01 5.605480683333330383e-01 +1.662309999999999899e-01 9.379805284999999770e+00 5.273011283333329802e-01 +1.706292000000000086e-01 9.152038171666669442e+00 1.545153300000000063e-01 +1.716062999999999894e-01 9.072271783333329509e+00 5.002084749999999858e-01 +1.771733000000000058e-01 8.299759079999999400e+00 4.647556766666670058e-01 +1.827794000000000085e-01 8.918414625000000484e+00 4.514085349999999996e-01 +1.842428999999999872e-01 8.303275895000000517e+00 1.338776349999999948e-01 +1.883665999999999952e-01 8.087114149999999668e+00 4.329608600000000029e-01 +1.940302000000000138e-01 6.940626968333329927e+00 4.097805333333329747e-01 +1.982414999999999872e-01 7.399220633333330355e+00 1.156899150000000043e-01 +1.998185000000000100e-01 7.671813116666670318e+00 3.925434549999999856e-01 +2.056348000000000065e-01 7.058416683333329722e+00 3.753756766666669908e-01 +2.115208000000000088e-01 6.186979153333330039e+00 3.502447450000000240e-01 +2.120113000000000136e-01 6.509825833333329648e+00 1.046767516666669978e-01 +2.162467999999999890e-01 6.237968744999999871e+00 4.443455150000000242e-01 +2.259823999999999999e-01 6.054194650000000344e+00 9.278840666666669790e-02 +2.397845000000000115e-01 5.564811654999999746e+00 8.685724833333340056e-02 +2.537096999999999825e-01 5.167096618333330227e+00 7.958348833333329930e-02 +2.676275000000000182e-01 4.857346653333330266e+00 7.348198000000000230e-02 +2.817857999999999752e-01 4.540460176666670122e+00 6.833893833333329337e-02 +2.956398000000000081e-01 4.237780543333330208e+00 6.471250666666669704e-02 +3.099044000000000243e-01 3.935048769999999863e+00 5.903304000000000190e-02 +3.240645999999999805e-01 3.478254921666669830e+00 5.662396666666669881e-02 +3.388027000000000122e-01 3.303115776666670111e+00 5.088800999999999741e-02 +3.539140000000000064e-01 3.111107356666670043e+00 4.976782999999999901e-02 +3.687090000000000090e-01 2.860701315000000022e+00 4.573441000000000312e-02 +3.839813000000000254e-01 2.699693565000000017e+00 4.341666500000000012e-02 +3.988975000000000160e-01 2.495346641666670084e+00 4.210437499999999944e-02 +4.106734000000000218e-01 2.304978501333330154e+00 4.227540733333329942e-02 +4.136514000000000024e-01 2.281161938333330141e+00 3.975256666666669714e-02 +4.290628000000000219e-01 2.190969609999999790e+00 3.681797500000000278e-02 +4.295516999999999808e-01 2.110397390999999789e+00 3.571657216666670326e-02 +4.446014999999999828e-01 1.879588453333330023e+00 3.550642500000000118e-02 +4.466716000000000020e-01 1.816268564666670082e+00 3.148649049999999866e-02 +4.603325999999999807e-01 1.793649588333330103e+00 3.313105499999999953e-02 +4.685437000000000074e-01 1.770170460833329962e+00 3.148902633333330175e-02 +4.764860000000000206e-01 1.682140176666669928e+00 3.141608500000000331e-02 +4.834083000000000130e-01 1.536765404999999918e+00 2.947832866666669910e-02 +4.923204999999999942e-01 1.511959243333329983e+00 3.099057499999999937e-02 +5.046621000000000024e-01 1.465441131499999994e+00 2.736933133333329868e-02 +5.082708000000000226e-01 1.365583310000000106e+00 2.825172333333330135e-02 +5.230728999999999518e-01 1.154780808166669948e+00 2.524863800000000033e-02 +5.249162000000000550e-01 1.329800611666670074e+00 2.675280666666670151e-02 +5.416775999999999813e-01 1.188958583333330044e+00 2.623523499999999911e-02 +5.444001000000000534e-01 1.154485974333330001e+00 2.585743066666670170e-02 +5.583067999999999920e-01 1.077189841666670089e+00 2.527868166666669830e-02 +5.612614999999999688e-01 1.051792144833330056e+00 2.347724083333330158e-02 +5.753956999999999544e-01 1.014095294999999952e+00 2.346036166666670003e-02 +5.834072999999999620e-01 9.588631039999999661e-01 2.325032483333330097e-02 +5.927398999999999862e-01 9.388917833333330076e-01 2.258296499999999998e-02 +6.005747000000000169e-01 8.756694673333329515e-01 2.203778849999999886e-02 +6.099058000000000535e-01 8.473022983333330371e-01 2.182166666666670099e-02 +6.218546000000000351e-01 7.881510335000000422e-01 2.137202599999999883e-02 +6.275003000000000108e-01 7.785123416666670515e-01 2.058900166666670015e-02 +6.412082999999999533e-01 7.088910750000000371e-01 1.908878433333329946e-02 +6.447154999999999969e-01 6.898300916666669780e-01 2.096122833333330035e-02 +6.655497999999999692e-01 6.325061706666670336e-01 1.830133016666669887e-02 +6.843702000000000396e-01 5.535274884999999978e-01 2.022582083333330019e-02 +7.058105999999999547e-01 4.772884753333330177e-01 1.710068249999999873e-02 +7.258693999999999980e-01 4.794482545000000040e-01 1.838371499999999839e-02 +7.490480000000000471e-01 4.303608649999999813e-01 1.512209783333329921e-02 +7.720086999999999922e-01 3.958678310000000033e-01 1.713988450000000080e-02 +7.920989999999999975e-01 3.804415833333329999e-01 1.509590366666670007e-02 +8.155097999999999514e-01 3.391658666666669819e-01 1.534219399999999997e-02 +8.364475000000000104e-01 2.920511656666670008e-01 1.453006433333330072e-02 +8.619377000000000288e-01 2.768105268333330149e-01 1.369777266666669970e-02 +8.846403999999999934e-01 2.773741731666670152e-01 1.443021766666669967e-02 +9.081462000000000145e-01 2.284839270000000033e-01 1.257401600000000036e-02 +9.334447000000000161e-01 2.262680790000000108e-01 1.358766933333330033e-02 +9.551832000000000100e-01 2.014745451666669906e-01 1.275664699999999943e-02 +9.812971999999999806e-01 1.828399243333329871e-01 1.193000216666669985e-02 +1.006807800000000030e+00 1.768480391666669982e-01 1.237525766666669989e-02 +1.030406600000000061e+00 1.607457411666670111e-01 1.173357283333329934e-02 +1.057784300000000011e+00 1.603443938333329877e-01 1.087976483333330004e-02 +1.084600999999999926e+00 1.672401265000000026e-01 1.127955949999999950e-02 +1.109902299999999897e+00 1.308651896666669923e-01 1.086452716666670010e-02 +1.137751600000000085e+00 1.208445169999999985e-01 1.042120399999999988e-02 +1.166036300000000026e+00 1.219414448333329959e-01 1.020481383333330001e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv new file mode 100644 index 000000000..c576fb9ba --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv @@ -0,0 +1,105 @@ +3.625710000000000044e-02 7.586499487000000386e+01 1.637401323166670153e+01 +4.070529999999999982e-02 4.481643682666670259e+01 1.134473448500000003e+01 +4.511769999999999670e-02 3.187475403666670104e+01 8.372120233333330219e+00 +4.959899999999999726e-02 2.997679580000000144e+01 6.801308398333329563e+00 +5.417079999999999812e-02 2.394855565499999983e+01 5.340431286666669664e+00 +5.869760000000000255e-02 2.142582576833330066e+01 4.594792676666670239e+00 +6.316149999999999542e-02 3.089957102166669856e+01 3.816311058333329953e+00 +6.774429999999999341e-02 2.654007947166670078e+01 3.169185818333330129e+00 +7.239929999999999977e-02 1.943375908333329960e+01 2.742530958333329938e+00 +7.695340000000000513e-02 1.976728253666669843e+01 2.443851029999999813e+00 +8.167670000000000485e-02 1.925900297000000094e+01 2.058348746666669893e+00 +8.642850000000000532e-02 1.891829230833329945e+01 1.858069830000000033e+00 +9.110319999999999530e-02 1.827805419833330092e+01 1.639507476666669961e+00 +9.577460000000000140e-02 1.569160155166670023e+01 1.504524439999999963e+00 +1.005346000000000017e-01 1.326347007166669911e+01 1.315847523333329994e+00 +1.052808999999999967e-01 1.528716061000000082e+01 1.240626203333329958e+00 +1.100316999999999962e-01 1.357029930000000029e+01 1.108701733333329997e+00 +1.148871000000000059e-01 1.268526336333330029e+01 1.008324261666670107e+00 +1.198237999999999942e-01 1.157206131499999913e+01 9.266636050000000013e-01 +1.248187000000000046e-01 1.139260776499999928e+01 8.664271866666669597e-01 +1.298877999999999977e-01 1.288652256499999993e+01 7.969746983333330093e-01 +1.349605999999999861e-01 1.079102049499999971e+01 7.560191466666670301e-01 +1.399791999999999981e-01 1.105679143000000053e+01 6.920319183333329960e-01 +1.451301000000000119e-01 1.044385611833330074e+01 6.659680816666669889e-01 +1.503246000000000027e-01 9.389620521666669717e+00 6.284466633333329888e-01 +1.556671000000000027e-01 9.365269319999999453e+00 5.685768949999999711e-01 +1.572933999999999999e-01 9.202126339999999516e+00 1.807199866666669985e-01 +1.610100999999999893e-01 9.725111731666670423e+00 5.526473100000000027e-01 +1.662526000000000004e-01 8.453553321666669618e+00 5.170390433333329483e-01 +1.706808999999999965e-01 8.508661829999999426e+00 1.525917300000000087e-01 +1.716285999999999923e-01 8.248625778333330771e+00 4.912094450000000223e-01 +1.771963000000000010e-01 7.860151886666669974e+00 4.601271083333329792e-01 +1.828030999999999962e-01 8.179063558333330874e+00 4.431557566666670112e-01 +1.842987000000000097e-01 7.789301021666670266e+00 1.322509683333329966e-01 +1.883911000000000058e-01 7.284922560000000047e+00 4.239183200000000151e-01 +1.940553999999999890e-01 6.860865920000000173e+00 4.091373166666669725e-01 +1.983015999999999945e-01 6.984366938333329777e+00 1.143283233333329957e-01 +1.998445000000000082e-01 7.321059296666669880e+00 3.888106266666669919e-01 +2.056614999999999971e-01 6.516638536666669701e+00 3.691254600000000163e-01 +2.115482999999999947e-01 5.813378858333329902e+00 3.460794933333329881e-01 +2.120755000000000001e-01 6.410695145000000039e+00 1.044179233333329959e-01 +2.162748999999999922e-01 6.046752721666670105e+00 4.416217800000000193e-01 +2.260508999999999991e-01 5.970100884999999913e+00 9.257100833333330170e-02 +2.398570999999999898e-01 5.328183368333330172e+00 8.599138666666669706e-02 +2.537865999999999733e-01 5.025059630000000332e+00 7.909936500000000481e-02 +2.677086000000000188e-01 4.638679231666669622e+00 7.265197833333329747e-02 +2.818711999999999884e-01 4.320586221666670390e+00 6.748263000000000178e-02 +2.957293999999999756e-01 4.003143766666670267e+00 6.376038000000000538e-02 +3.099983000000000044e-01 3.820362695000000031e+00 5.861029000000000239e-02 +3.241628999999999761e-01 3.476478435000000200e+00 5.668581000000000314e-02 +3.389054000000000233e-01 3.203212216666670109e+00 5.052067666666670148e-02 +3.540212999999999832e-01 3.082675891666669887e+00 4.970334166666669912e-02 +3.688208000000000042e-01 2.852994409999999981e+00 4.575685000000000169e-02 +3.840975999999999835e-01 2.619206445000000105e+00 4.310591500000000159e-02 +3.990183999999999953e-01 2.447015261666670050e+00 4.192961333333330293e-02 +4.106022999999999756e-01 2.250148667666670210e+00 4.208387400000000028e-02 +4.137768000000000002e-01 2.199470903333330174e+00 3.941821333333329902e-02 +4.291927999999999854e-01 2.152990283333330090e+00 3.668624166666670239e-02 +4.294773000000000063e-01 2.066339865166670009e+00 3.559078633333329772e-02 +4.447362000000000259e-01 1.856158275000000080e+00 3.543832166666670280e-02 +4.465942999999999996e-01 1.863514126000000104e+00 3.172593550000000345e-02 +4.604721999999999982e-01 1.785743791666670077e+00 3.313367500000000132e-02 +4.684626000000000068e-01 1.701883971166670007e+00 3.125393900000000141e-02 +4.766304000000000096e-01 1.673134868333330028e+00 3.141082333333330284e-02 +4.833245999999999931e-01 1.561424375333329895e+00 2.963426116666669982e-02 +4.924697000000000102e-01 1.528741043333329941e+00 3.110879000000000075e-02 +5.045747000000000426e-01 1.440318964999999896e+00 2.730927600000000038e-02 +5.084248000000000101e-01 1.414442154999999923e+00 2.852017166666670142e-02 +5.229823000000000111e-01 1.195010044500000035e+00 2.544837383333330150e-02 +5.250753000000000226e-01 1.305492214999999900e+00 2.666661666666670163e-02 +5.418418000000000401e-01 1.152673440000000049e+00 2.608773333333330030e-02 +5.443057999999999508e-01 1.145610492499999911e+00 2.585580999999999990e-02 +5.584759999999999724e-01 1.067225758333329999e+00 2.525753999999999846e-02 +5.611642999999999493e-01 1.067666433166670092e+00 2.357715833333329930e-02 +5.755700000000000260e-01 1.029394661666670041e+00 2.355942499999999842e-02 +5.833063000000000553e-01 9.377488744999999959e-01 2.319254466666669998e-02 +5.929195000000000437e-01 9.657185166666669707e-01 2.274125999999999925e-02 +6.004707000000000239e-01 8.602252591666670334e-01 2.200228683333330104e-02 +6.100906000000000384e-01 8.435776883333330201e-01 2.182633499999999879e-02 +6.217470000000000496e-01 7.760975660000000165e-01 2.134885499999999992e-02 +6.276903999999999817e-01 7.741666183333330009e-01 2.058969000000000077e-02 +6.410972000000000337e-01 7.019246166666669451e-01 1.908517183333329967e-02 +6.449108999999999536e-01 6.851353900000000108e-01 2.095862666666669857e-02 +6.654345000000000399e-01 5.961630181666669470e-01 1.818150283333330036e-02 +6.842517000000000182e-01 5.507593983333329835e-01 2.023759049999999948e-02 +7.056883000000000461e-01 4.903288296666670210e-01 1.717216466666670119e-02 +7.257436999999999916e-01 4.865799499999999833e-01 1.843612033333329875e-02 +7.489183000000000368e-01 4.252237993333329857e-01 1.512044316666670031e-02 +7.718749999999999778e-01 3.910920323333330062e-01 1.713838283333329882e-02 +7.919618000000000491e-01 3.921714671666670093e-01 1.515910683333330025e-02 +8.153685999999999989e-01 3.357406613333330236e-01 1.534501599999999952e-02 +8.363026999999999544e-01 3.075498956666670169e-01 1.460560383333329992e-02 +8.617884000000000100e-01 2.857851470000000171e-01 1.374501849999999921e-02 +8.844872000000000289e-01 2.740424961666669823e-01 1.443190633333329975e-02 +9.079890000000000461e-01 2.574230581666669959e-01 1.269050000000000039e-02 +9.332829999999999737e-01 2.258197691666669893e-01 1.359980449999999980e-02 +9.550178000000000278e-01 1.934376846666669980e-01 1.273933533333329940e-02 +9.811271999999999771e-01 1.665732448333329951e-01 1.188447333333329976e-02 +1.006633399999999900e+00 1.640185443333329884e-01 1.234030849999999922e-02 +1.030228200000000038e+00 1.357939996666669979e-01 1.165456533333330061e-02 +1.057601100000000072e+00 1.607766528333330058e-01 1.089187166666670016e-02 +1.084413199999999966e+00 1.505459054999999935e-01 1.123158833333329915e-02 +1.109710100000000033e+00 1.282342724999999961e-01 1.086581349999999994e-02 +1.137554500000000024e+00 1.161345933333329944e-01 1.041549200000000015e-02 +1.165834400000000048e+00 1.239725849999999963e-01 1.022116500000000081e-02 \ No newline at end of file diff --git a/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv new file mode 100644 index 000000000..c869ca7de --- /dev/null +++ b/test/mumag/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv @@ -0,0 +1,105 @@ +3.625239999999999713e-02 5.114892415500000311e+01 1.631213251166670020e+01 +4.070000000000000007e-02 4.576787608166669941e+01 1.134772132833330005e+01 +4.511180000000000051e-02 4.331816215999999997e+01 8.407984515000000769e+00 +4.959249999999999770e-02 2.519454865000000154e+01 6.784784965000000057e+00 +5.416379999999999806e-02 1.407789967999999980e+01 5.302135776666670353e+00 +5.868999999999999911e-02 1.337527417166669963e+01 4.558895663333330184e+00 +6.315320000000000655e-02 2.088227957833329995e+01 3.767553325000000175e+00 +6.773540000000000116e-02 2.352067832833330030e+01 3.153463791666669902e+00 +7.238989999999999314e-02 1.459065788833330046e+01 2.714546644999999980e+00 +7.694339999999999513e-02 1.643097480333329941e+01 2.423213508333330157e+00 +8.166600000000000248e-02 1.564276924666670077e+01 2.035339249999999822e+00 +8.641719999999999957e-02 1.609254856500000130e+01 1.837833853333330048e+00 +9.109140000000000292e-02 1.279946007166670086e+01 1.598433549999999981e+00 +9.576210000000000278e-02 1.168004799999999932e+01 1.472505774999999906e+00 +1.005216000000000026e-01 1.239115217500000021e+01 1.308776653333330042e+00 +1.052672000000000052e-01 1.104442360666669920e+01 1.203200884999999998e+00 +1.100174000000000013e-01 1.264824788499999997e+01 1.100505863333330003e+00 +1.148721999999999938e-01 1.068150069333329988e+01 9.895295950000000396e-01 +1.198083000000000065e-01 1.062919121333329997e+01 9.177280949999999660e-01 +1.248023999999999939e-01 8.480228023333330256e+00 8.376397483333329896e-01 +1.298709000000000113e-01 1.054387282333330056e+01 7.736622133333329598e-01 +1.349431000000000103e-01 8.823326103333329229e+00 7.353996000000000421e-01 +1.399610000000000021e-01 9.107303678333330765e+00 6.707318450000000487e-01 +1.451112999999999986e-01 7.568946575000000010e+00 6.354211899999999691e-01 +1.503050999999999970e-01 7.486937655000000191e+00 6.076642716666670330e-01 +1.556469000000000047e-01 8.316071640000000542e+00 5.572019216666670438e-01 +1.572933999999999999e-01 8.082806423333330770e+00 1.772221983333329975e-01 +1.609891999999999990e-01 8.406204656666670161e+00 5.374420016666670019e-01 +1.662309999999999899e-01 7.305961626666669595e+00 5.035922400000000243e-01 +1.706808999999999965e-01 7.409980823333330413e+00 1.490785450000000067e-01 +1.716062999999999894e-01 7.126663556666669841e+00 4.782201200000000263e-01 +1.771733000000000058e-01 6.104670323333330373e+00 4.398585833333329975e-01 +1.827794000000000085e-01 6.314649313333330127e+00 4.207942599999999755e-01 +1.842987000000000097e-01 6.985669296666669581e+00 1.295300000000000062e-01 +1.883665999999999952e-01 7.196837438333330006e+00 4.229003000000000068e-01 +1.940302000000000138e-01 5.456149725000000394e+00 3.926154199999999928e-01 +1.983015999999999945e-01 6.101519538333329606e+00 1.111746183333330029e-01 +1.998185000000000100e-01 6.715507050000000255e+00 3.818104066666669905e-01 +2.056348000000000065e-01 5.954089436666669677e+00 3.622545733333329965e-01 +2.115208000000000088e-01 5.823000606666670187e+00 3.462099583333330122e-01 +2.120755000000000001e-01 5.689073146666670411e+00 1.016859966666670001e-01 +2.162467999999999890e-01 5.274567024999999632e+00 4.291691899999999782e-01 +2.260508999999999991e-01 5.306054011666669901e+00 9.002336499999999408e-02 +2.398570999999999898e-01 4.872989734999999989e+00 8.416759833333330165e-02 +2.537865999999999733e-01 4.590923198333330291e+00 7.736351666666670124e-02 +2.677086000000000188e-01 4.288802803333330083e+00 7.121471833333330170e-02 +2.818711999999999884e-01 4.093612151666669696e+00 6.655526166666669852e-02 +2.957293999999999756e-01 3.790488160000000217e+00 6.286535166666669394e-02 +3.099983000000000044e-01 3.646502630000000078e+00 5.789795166666669712e-02 +3.241628999999999761e-01 3.269809508333330061e+00 5.578990999999999811e-02 +3.389054000000000233e-01 3.057003066666669877e+00 4.992672166666670130e-02 +3.540212999999999832e-01 3.010102380000000188e+00 4.942106333333329965e-02 +3.688208000000000042e-01 2.669906414999999811e+00 4.496581333333329877e-02 +3.840975999999999835e-01 2.619258584999999862e+00 4.314465499999999704e-02 +3.990183999999999953e-01 2.335828473333330102e+00 4.143680999999999753e-02 +4.106379000000000001e-01 2.148179208166669962e+00 4.160297799999999879e-02 +4.137768000000000002e-01 2.129094906666670006e+00 3.911823833333329808e-02 +4.291927999999999854e-01 2.070782439999999891e+00 3.633175833333329718e-02 +4.295145000000000213e-01 2.006558257333329820e+00 3.534480766666669993e-02 +4.447362000000000259e-01 1.796411879999999961e+00 3.518650999999999723e-02 +4.466328999999999994e-01 1.795892682000000073e+00 3.145603500000000025e-02 +4.604721999999999982e-01 1.744876515000000072e+00 3.296921333333330262e-02 +4.685032000000000085e-01 1.640983006833329982e+00 3.099933850000000102e-02 +4.766304000000000096e-01 1.643527214999999986e+00 3.129624333333329983e-02 +4.833663999999999739e-01 1.494623838666669924e+00 2.933965966666670158e-02 +4.924697000000000102e-01 1.485128543333330109e+00 3.092004166666669981e-02 +5.046184000000000225e-01 1.428664912499999939e+00 2.726148050000000087e-02 +5.084248000000000101e-01 1.392996424999999983e+00 2.844018666666670025e-02 +5.230276000000000369e-01 1.160762609500000098e+00 2.531033383333329903e-02 +5.250753000000000226e-01 1.272159111666669951e+00 2.652694499999999969e-02 +5.418418000000000401e-01 1.157124196666670102e+00 2.613007999999999997e-02 +5.443529999999999758e-01 1.137421045666670016e+00 2.582160033333329857e-02 +5.584759999999999724e-01 1.068463686666669910e+00 2.528335666666670090e-02 +5.612129000000000145e-01 1.030207043666669930e+00 2.342105016666670009e-02 +5.755700000000000260e-01 9.590708749999999894e-01 2.323855999999999838e-02 +5.833568000000000087e-01 9.226566683333330410e-01 2.312843766666669923e-02 +5.929195000000000437e-01 9.361494049999999900e-01 2.261169999999999847e-02 +6.005226999999999649e-01 8.377321681666669573e-01 2.190618299999999921e-02 +6.100906000000000384e-01 8.074355933333330348e-01 2.165867833333329912e-02 +6.218008000000000424e-01 7.338905468333329907e-01 2.116956166666670094e-02 +6.276903999999999817e-01 7.588048750000000453e-01 2.052974999999999939e-02 +6.411527999999999672e-01 6.602236648333329461e-01 1.891721183333330142e-02 +6.449108999999999536e-01 6.976061483333330093e-01 2.103810166666670103e-02 +6.654921999999999782e-01 5.868389913333329488e-01 1.814479133333329886e-02 +6.843110000000000026e-01 5.442379206666669855e-01 2.020865366666670104e-02 +7.057493999999999712e-01 4.561023925000000090e-01 1.703726683333330050e-02 +7.258065000000000211e-01 4.680557555000000036e-01 1.835656600000000124e-02 +7.489831000000000127e-01 4.286472281666670048e-01 1.513358700000000043e-02 +7.719418000000000113e-01 3.942902281666669784e-01 1.715291783333329836e-02 +7.920304000000000233e-01 3.917498161666669865e-01 1.515774683333329965e-02 +8.154392000000000307e-01 3.437863165000000221e-01 1.537817166666670052e-02 +8.363751000000000380e-01 2.882515494999999817e-01 1.453092849999999998e-02 +8.618630000000000457e-01 2.511196196666670155e-01 1.361783299999999933e-02 +8.845638000000000112e-01 2.644882184999999830e-01 1.439263916666670001e-02 +9.080675999999999748e-01 2.444909116666670046e-01 1.264447816666670020e-02 +9.333637999999999657e-01 2.291532736666669900e-01 1.361314100000000048e-02 +9.551005000000000189e-01 1.942403736666669933e-01 1.274254833333329957e-02 +9.812121999999999788e-01 1.854263468333330056e-01 1.195107366666670057e-02 +1.006720599999999965e+00 1.833105325000000119e-01 1.241118433333330065e-02 +1.030317399999999939e+00 1.560276093333330116e-01 1.172809033333330024e-02 +1.057692700000000041e+00 1.687616888333330067e-01 1.091902633333330028e-02 +1.084507099999999946e+00 1.609880563333329906e-01 1.126864266666669986e-02 +1.109806099999999907e+00 1.237764021666669934e-01 1.085079116666669979e-02 +1.137653000000000025e+00 1.252411816666670064e-01 1.044549983333330039e-02 +1.165935399999999955e+00 1.143170270000000016e-01 1.018908599999999998e-02 \ No newline at end of file diff --git a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv index 92b38bcf5..160f11da2 100644 --- a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv +++ b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 5.247581629999999677e+03 5.122294999999999732e+01 -3.090999999999999998e-02 3.911350339999999960e+03 4.422301999999999822e+01 -3.452999999999999819e-02 2.897911560000000009e+03 3.806515000000000271e+01 -3.812999999999999723e-02 2.151411560000000009e+03 3.279795000000000016e+01 -4.173999999999999932e-02 1.629610879999999952e+03 2.854479999999999862e+01 -4.542999999999999816e-02 1.229812930000000051e+03 2.479730999999999952e+01 -4.646000000000000130e-02 1.191418850000000020e+03 2.440716000000000108e+01 -4.909000000000000169e-02 9.198557799999999816e+02 2.144593000000000060e+01 -5.254999999999999949e-02 7.981839199999999437e+02 1.997728999999999999e+01 -5.270999999999999991e-02 7.205761899999999969e+02 1.898125999999999891e+01 -5.630999999999999894e-02 5.509914999999999736e+02 1.659806000000000026e+01 -5.870999999999999830e-02 5.012570499999999925e+02 1.583125000000000071e+01 -5.988000000000000267e-02 4.332142900000000054e+02 1.471757999999999988e+01 -6.353999999999999926e-02 3.420333299999999781e+02 1.307732999999999990e+01 -6.482999999999999874e-02 3.398080699999999865e+02 1.303472000000000008e+01 -6.716999999999999360e-02 2.726683699999999817e+02 1.167622000000000071e+01 -7.073000000000000120e-02 2.204248299999999858e+02 1.049821000000000026e+01 -7.095999999999999530e-02 2.235476199999999949e+02 1.057230999999999987e+01 -7.434999999999999942e-02 1.760958799999999940e+02 9.383390000000000342e+00 -7.724000000000000310e-02 1.542382200000000125e+02 8.781750000000000611e+00 -7.799999999999999989e-02 1.457825499999999863e+02 8.537639999999999674e+00 -8.164000000000000423e-02 1.201677600000000012e+02 7.751380000000000159e+00 -8.346000000000000640e-02 1.089934400000000068e+02 7.382189999999999586e+00 -8.525000000000000633e-02 9.836262000000000683e+01 7.012940000000000396e+00 -8.881999999999999618e-02 8.192439000000000249e+01 6.400170000000000137e+00 -8.962000000000000521e-02 7.733648999999999774e+01 6.218379999999999797e+00 -9.572999999999999565e-02 5.882012000000000285e+01 5.423099999999999810e+00 -1.018000000000000016e-01 4.406902000000000186e+01 4.694090000000000096e+00 -1.080300000000000010e-01 3.487624000000000279e+01 4.175900000000000389e+00 -1.141999999999999960e-01 2.769241999999999848e+01 3.721049999999999969e+00 -1.202399999999999997e-01 2.227824000000000026e+01 3.337530000000000108e+00 -1.263900000000000023e-01 1.858717000000000041e+01 3.048540000000000028e+00 -1.325999999999999956e-01 1.587791999999999959e+01 2.817619999999999791e+00 -1.388199999999999990e-01 1.416899000000000086e+01 2.661669999999999980e+00 -1.449499999999999955e-01 1.174597999999999942e+01 2.423430000000000195e+00 -1.509900000000000131e-01 1.047161000000000008e+01 2.288190000000000168e+00 -1.571599999999999941e-01 9.681599999999999540e+00 2.200180000000000025e+00 -1.633799999999999975e-01 8.894579999999999487e+00 2.108859999999999957e+00 -1.695599999999999885e-01 8.317479999999999762e+00 2.039299999999999891e+00 -1.756800000000000028e-01 7.913870000000000182e+00 1.989200000000000079e+00 -1.818599999999999939e-01 7.771530000000000271e+00 1.971230000000000038e+00 -1.880699999999999872e-01 7.882909999999999862e+00 1.985309999999999908e+00 -1.941799999999999915e-01 7.707720000000000127e+00 1.963130000000000042e+00 -2.002800000000000136e-01 7.676859999999999573e+00 1.959189999999999987e+00 -2.064199999999999924e-01 7.872259999999999813e+00 1.983970000000000011e+00 -2.126000000000000112e-01 7.870400000000000063e+00 1.983729999999999993e+00 -2.187500000000000000e-01 7.977940000000000254e+00 1.997239999999999904e+00 -2.248699999999999866e-01 8.152039999999999509e+00 2.018920000000000048e+00 -2.310500000000000054e-01 8.298420000000000130e+00 2.036960000000000104e+00 -2.372700000000000087e-01 8.716689999999999827e+00 2.087660000000000071e+00 -2.434399999999999897e-01 8.782600000000000406e+00 2.095540000000000180e+00 -2.495600000000000041e-01 8.933479999999999421e+00 2.113469999999999960e+00 -2.556899999999999729e-01 9.374109999999999943e+00 2.164960000000000218e+00 -2.618500000000000272e-01 9.457430000000000447e+00 2.174560000000000048e+00 -2.680500000000000105e-01 9.702469999999999928e+00 2.202550000000000008e+00 -2.742100000000000093e-01 9.923930000000000362e+00 2.227549999999999919e+00 -2.802999999999999936e-01 1.008966000000000030e+01 2.246070000000000011e+00 -2.864599999999999924e-01 1.031367999999999974e+01 2.270869999999999944e+00 -2.926699999999999857e-01 1.058960000000000079e+01 2.301039999999999974e+00 +2.732000000000000053e-02 5.247581629999999677e+03 5.122294999999999732e+01 +3.090999999999999998e-02 3.911350339999999960e+03 4.422301999999999822e+01 +3.452999999999999819e-02 2.897911560000000009e+03 3.806515000000000271e+01 +3.812999999999999723e-02 2.151411560000000009e+03 3.279795000000000016e+01 +4.173999999999999932e-02 1.629610879999999952e+03 2.854479999999999862e+01 +4.542999999999999816e-02 1.229812930000000051e+03 2.479730999999999952e+01 +4.646000000000000130e-02 1.191418850000000020e+03 2.440716000000000108e+01 +4.909000000000000169e-02 9.198557799999999816e+02 2.144593000000000060e+01 +5.254999999999999949e-02 7.981839199999999437e+02 1.997728999999999999e+01 +5.270999999999999991e-02 7.205761899999999969e+02 1.898125999999999891e+01 +5.630999999999999894e-02 5.509914999999999736e+02 1.659806000000000026e+01 +5.870999999999999830e-02 5.012570499999999925e+02 1.583125000000000071e+01 +5.988000000000000267e-02 4.332142900000000054e+02 1.471757999999999988e+01 +6.353999999999999926e-02 3.420333299999999781e+02 1.307732999999999990e+01 +6.482999999999999874e-02 3.398080699999999865e+02 1.303472000000000008e+01 +6.716999999999999360e-02 2.726683699999999817e+02 1.167622000000000071e+01 +7.073000000000000120e-02 2.204248299999999858e+02 1.049821000000000026e+01 +7.095999999999999530e-02 2.235476199999999949e+02 1.057230999999999987e+01 +7.434999999999999942e-02 1.760958799999999940e+02 9.383390000000000342e+00 +7.724000000000000310e-02 1.542382200000000125e+02 8.781750000000000611e+00 +7.799999999999999989e-02 1.457825499999999863e+02 8.537639999999999674e+00 +8.164000000000000423e-02 1.201677600000000012e+02 7.751380000000000159e+00 +8.346000000000000640e-02 1.089934400000000068e+02 7.382189999999999586e+00 +8.525000000000000633e-02 9.836262000000000683e+01 7.012940000000000396e+00 +8.881999999999999618e-02 8.192439000000000249e+01 6.400170000000000137e+00 +8.962000000000000521e-02 7.733648999999999774e+01 6.218379999999999797e+00 +9.572999999999999565e-02 5.882012000000000285e+01 5.423099999999999810e+00 +1.018000000000000016e-01 4.406902000000000186e+01 4.694090000000000096e+00 +1.080300000000000010e-01 3.487624000000000279e+01 4.175900000000000389e+00 +1.141999999999999960e-01 2.769241999999999848e+01 3.721049999999999969e+00 +1.202399999999999997e-01 2.227824000000000026e+01 3.337530000000000108e+00 +1.263900000000000023e-01 1.858717000000000041e+01 3.048540000000000028e+00 +1.325999999999999956e-01 1.587791999999999959e+01 2.817619999999999791e+00 +1.388199999999999990e-01 1.416899000000000086e+01 2.661669999999999980e+00 +1.449499999999999955e-01 1.174597999999999942e+01 2.423430000000000195e+00 +1.509900000000000131e-01 1.047161000000000008e+01 2.288190000000000168e+00 +1.571599999999999941e-01 9.681599999999999540e+00 2.200180000000000025e+00 +1.633799999999999975e-01 8.894579999999999487e+00 2.108859999999999957e+00 +1.695599999999999885e-01 8.317479999999999762e+00 2.039299999999999891e+00 +1.756800000000000028e-01 7.913870000000000182e+00 1.989200000000000079e+00 +1.818599999999999939e-01 7.771530000000000271e+00 1.971230000000000038e+00 +1.880699999999999872e-01 7.882909999999999862e+00 1.985309999999999908e+00 +1.941799999999999915e-01 7.707720000000000127e+00 1.963130000000000042e+00 +2.002800000000000136e-01 7.676859999999999573e+00 1.959189999999999987e+00 +2.064199999999999924e-01 7.872259999999999813e+00 1.983970000000000011e+00 +2.126000000000000112e-01 7.870400000000000063e+00 1.983729999999999993e+00 +2.187500000000000000e-01 7.977940000000000254e+00 1.997239999999999904e+00 +2.248699999999999866e-01 8.152039999999999509e+00 2.018920000000000048e+00 +2.310500000000000054e-01 8.298420000000000130e+00 2.036960000000000104e+00 +2.372700000000000087e-01 8.716689999999999827e+00 2.087660000000000071e+00 +2.434399999999999897e-01 8.782600000000000406e+00 2.095540000000000180e+00 +2.495600000000000041e-01 8.933479999999999421e+00 2.113469999999999960e+00 +2.556899999999999729e-01 9.374109999999999943e+00 2.164960000000000218e+00 +2.618500000000000272e-01 9.457430000000000447e+00 2.174560000000000048e+00 +2.680500000000000105e-01 9.702469999999999928e+00 2.202550000000000008e+00 +2.742100000000000093e-01 9.923930000000000362e+00 2.227549999999999919e+00 +2.802999999999999936e-01 1.008966000000000030e+01 2.246070000000000011e+00 +2.864599999999999924e-01 1.031367999999999974e+01 2.270869999999999944e+00 +2.926699999999999857e-01 1.058960000000000079e+01 2.301039999999999974e+00 2.988199999999999745e-01 1.062256999999999962e+01 2.304619999999999891e+00 \ No newline at end of file diff --git a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv index 831fa6a9d..80562dff5 100644 --- a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv +++ b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 3.883615650000000187e+03 4.406595000000000084e+01 -3.090000000000000038e-02 3.072013609999999971e+03 3.919192000000000320e+01 -3.452999999999999819e-02 2.355659860000000208e+03 3.431953000000000031e+01 -3.812999999999999723e-02 1.806985030000000052e+03 3.005815000000000126e+01 -4.173999999999999932e-02 1.389839799999999968e+03 2.636132999999999882e+01 -4.542000000000000204e-02 1.072684349999999995e+03 2.315906000000000020e+01 -4.644000000000000211e-02 9.624380499999999756e+02 2.193669999999999831e+01 -4.907999999999999863e-02 8.065360500000000457e+02 2.008153000000000077e+01 -5.253000000000000030e-02 6.666923000000000457e+02 1.825777000000000072e+01 -5.270999999999999991e-02 6.432540800000000445e+02 1.793395999999999901e+01 -5.630000000000000282e-02 4.985809499999999730e+02 1.578894000000000020e+01 -5.868999999999999911e-02 4.290448299999999904e+02 1.464658000000000015e+01 -5.986999999999999961e-02 3.918163299999999936e+02 1.399671999999999983e+01 -6.353000000000000314e-02 3.098850299999999720e+02 1.244758999999999993e+01 -6.481000000000000649e-02 2.946982499999999732e+02 1.213874000000000031e+01 -6.715999999999999748e-02 2.516384400000000028e+02 1.121692000000000000e+01 -7.072000000000000508e-02 2.028407500000000141e+02 1.007076999999999956e+01 -7.094000000000000306e-02 1.948358800000000031e+02 9.870050000000000878e+00 -7.434000000000000330e-02 1.633427599999999984e+02 9.037219999999999587e+00 -7.721000000000000085e-02 1.371933899999999937e+02 8.282310000000000727e+00 -7.799000000000000377e-02 1.347819700000000012e+02 8.209199999999999164e+00 -8.162999999999999423e-02 1.123165999999999940e+02 7.493879999999999875e+00 -8.343000000000000416e-02 9.602442000000000633e+01 6.929079999999999906e+00 -8.523999999999999633e-02 9.249591999999999814e+01 6.800589999999999691e+00 -8.880000000000000393e-02 7.934887999999999408e+01 6.298759999999999692e+00 -8.959000000000000297e-02 7.016214999999999691e+01 5.922930000000000028e+00 -9.568999999999999728e-02 5.357988000000000284e+01 5.175900000000000389e+00 -1.017699999999999994e-01 4.050641000000000247e+01 4.500359999999999694e+00 -1.079900000000000027e-01 3.194395000000000095e+01 3.996500000000000163e+00 -1.141599999999999976e-01 2.563089000000000084e+01 3.579870000000000108e+00 -1.202000000000000013e-01 2.144641999999999982e+01 3.274630000000000152e+00 -1.263499999999999901e-01 1.696240999999999843e+01 2.912249999999999783e+00 -1.325600000000000112e-01 1.453672000000000075e+01 2.695990000000000109e+00 -1.387700000000000045e-01 1.265718999999999994e+01 2.515670000000000073e+00 -1.449000000000000010e-01 1.114897000000000027e+01 2.361029999999999962e+00 -1.509399999999999908e-01 1.005156999999999989e+01 2.241830000000000211e+00 -1.571099999999999997e-01 9.313710000000000377e+00 2.157970000000000166e+00 -1.633300000000000030e-01 8.668530000000000513e+00 2.081890000000000018e+00 -1.695099999999999940e-01 7.810069999999999624e+00 1.976120000000000099e+00 -1.756300000000000083e-01 7.695079999999999920e+00 1.961519999999999930e+00 -1.817999999999999894e-01 7.222220000000000084e+00 1.900290000000000035e+00 -1.880100000000000104e-01 7.386999999999999567e+00 1.921850000000000058e+00 -1.941199999999999870e-01 7.239320000000000199e+00 1.902539999999999898e+00 -2.002200000000000091e-01 7.279099999999999682e+00 1.907759999999999900e+00 -2.063500000000000056e-01 7.406340000000000146e+00 1.924360000000000070e+00 -2.125299999999999967e-01 7.439199999999999591e+00 1.928630000000000067e+00 -2.186800000000000133e-01 7.556879999999999598e+00 1.943820000000000103e+00 -2.247899999999999898e-01 7.730520000000000280e+00 1.966029999999999944e+00 -2.309799999999999909e-01 8.106099999999999639e+00 2.013220000000000010e+00 -2.371999999999999942e-01 8.398609999999999687e+00 2.049220000000000041e+00 -2.433599999999999930e-01 8.171440000000000481e+00 2.021319999999999784e+00 -2.494800000000000073e-01 8.478289999999999438e+00 2.058920000000000083e+00 -2.556100000000000039e-01 8.796279999999999433e+00 2.097170000000000201e+00 -2.617700000000000027e-01 8.973420000000000840e+00 2.118189999999999795e+00 -2.679699999999999860e-01 9.270730000000000359e+00 2.152989999999999959e+00 -2.741299999999999848e-01 9.463879999999999626e+00 2.175300000000000011e+00 -2.802100000000000146e-01 9.409150000000000347e+00 2.169000000000000039e+00 -2.863700000000000134e-01 9.709509999999999863e+00 2.203349999999999920e+00 -2.925800000000000067e-01 9.851300000000000168e+00 2.219380000000000130e+00 +2.732000000000000053e-02 3.883615650000000187e+03 4.406595000000000084e+01 +3.090000000000000038e-02 3.072013609999999971e+03 3.919192000000000320e+01 +3.452999999999999819e-02 2.355659860000000208e+03 3.431953000000000031e+01 +3.812999999999999723e-02 1.806985030000000052e+03 3.005815000000000126e+01 +4.173999999999999932e-02 1.389839799999999968e+03 2.636132999999999882e+01 +4.542000000000000204e-02 1.072684349999999995e+03 2.315906000000000020e+01 +4.644000000000000211e-02 9.624380499999999756e+02 2.193669999999999831e+01 +4.907999999999999863e-02 8.065360500000000457e+02 2.008153000000000077e+01 +5.253000000000000030e-02 6.666923000000000457e+02 1.825777000000000072e+01 +5.270999999999999991e-02 6.432540800000000445e+02 1.793395999999999901e+01 +5.630000000000000282e-02 4.985809499999999730e+02 1.578894000000000020e+01 +5.868999999999999911e-02 4.290448299999999904e+02 1.464658000000000015e+01 +5.986999999999999961e-02 3.918163299999999936e+02 1.399671999999999983e+01 +6.353000000000000314e-02 3.098850299999999720e+02 1.244758999999999993e+01 +6.481000000000000649e-02 2.946982499999999732e+02 1.213874000000000031e+01 +6.715999999999999748e-02 2.516384400000000028e+02 1.121692000000000000e+01 +7.072000000000000508e-02 2.028407500000000141e+02 1.007076999999999956e+01 +7.094000000000000306e-02 1.948358800000000031e+02 9.870050000000000878e+00 +7.434000000000000330e-02 1.633427599999999984e+02 9.037219999999999587e+00 +7.721000000000000085e-02 1.371933899999999937e+02 8.282310000000000727e+00 +7.799000000000000377e-02 1.347819700000000012e+02 8.209199999999999164e+00 +8.162999999999999423e-02 1.123165999999999940e+02 7.493879999999999875e+00 +8.343000000000000416e-02 9.602442000000000633e+01 6.929079999999999906e+00 +8.523999999999999633e-02 9.249591999999999814e+01 6.800589999999999691e+00 +8.880000000000000393e-02 7.934887999999999408e+01 6.298759999999999692e+00 +8.959000000000000297e-02 7.016214999999999691e+01 5.922930000000000028e+00 +9.568999999999999728e-02 5.357988000000000284e+01 5.175900000000000389e+00 +1.017699999999999994e-01 4.050641000000000247e+01 4.500359999999999694e+00 +1.079900000000000027e-01 3.194395000000000095e+01 3.996500000000000163e+00 +1.141599999999999976e-01 2.563089000000000084e+01 3.579870000000000108e+00 +1.202000000000000013e-01 2.144641999999999982e+01 3.274630000000000152e+00 +1.263499999999999901e-01 1.696240999999999843e+01 2.912249999999999783e+00 +1.325600000000000112e-01 1.453672000000000075e+01 2.695990000000000109e+00 +1.387700000000000045e-01 1.265718999999999994e+01 2.515670000000000073e+00 +1.449000000000000010e-01 1.114897000000000027e+01 2.361029999999999962e+00 +1.509399999999999908e-01 1.005156999999999989e+01 2.241830000000000211e+00 +1.571099999999999997e-01 9.313710000000000377e+00 2.157970000000000166e+00 +1.633300000000000030e-01 8.668530000000000513e+00 2.081890000000000018e+00 +1.695099999999999940e-01 7.810069999999999624e+00 1.976120000000000099e+00 +1.756300000000000083e-01 7.695079999999999920e+00 1.961519999999999930e+00 +1.817999999999999894e-01 7.222220000000000084e+00 1.900290000000000035e+00 +1.880100000000000104e-01 7.386999999999999567e+00 1.921850000000000058e+00 +1.941199999999999870e-01 7.239320000000000199e+00 1.902539999999999898e+00 +2.002200000000000091e-01 7.279099999999999682e+00 1.907759999999999900e+00 +2.063500000000000056e-01 7.406340000000000146e+00 1.924360000000000070e+00 +2.125299999999999967e-01 7.439199999999999591e+00 1.928630000000000067e+00 +2.186800000000000133e-01 7.556879999999999598e+00 1.943820000000000103e+00 +2.247899999999999898e-01 7.730520000000000280e+00 1.966029999999999944e+00 +2.309799999999999909e-01 8.106099999999999639e+00 2.013220000000000010e+00 +2.371999999999999942e-01 8.398609999999999687e+00 2.049220000000000041e+00 +2.433599999999999930e-01 8.171440000000000481e+00 2.021319999999999784e+00 +2.494800000000000073e-01 8.478289999999999438e+00 2.058920000000000083e+00 +2.556100000000000039e-01 8.796279999999999433e+00 2.097170000000000201e+00 +2.617700000000000027e-01 8.973420000000000840e+00 2.118189999999999795e+00 +2.679699999999999860e-01 9.270730000000000359e+00 2.152989999999999959e+00 +2.741299999999999848e-01 9.463879999999999626e+00 2.175300000000000011e+00 +2.802100000000000146e-01 9.409150000000000347e+00 2.169000000000000039e+00 +2.863700000000000134e-01 9.709509999999999863e+00 2.203349999999999920e+00 +2.925800000000000067e-01 9.851300000000000168e+00 2.219380000000000130e+00 2.987299999999999955e-01 9.904920000000000613e+00 2.225410000000000110e+00 \ No newline at end of file diff --git a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv index 59e4cde42..6e68726d8 100644 --- a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv +++ b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 2.792353740000000016e+03 3.736545000000000272e+01 -3.090000000000000038e-02 2.271702040000000125e+03 3.370239000000000118e+01 -3.452000000000000207e-02 1.788897279999999910e+03 2.990733000000000175e+01 -3.812000000000000111e-02 1.407023470000000088e+03 2.652380000000000138e+01 -4.173000000000000320e-02 1.095009520000000066e+03 2.339882000000000062e+01 -4.542000000000000204e-02 8.376734699999999521e+02 2.046549999999999869e+01 -4.644000000000000211e-02 7.836296200000000454e+02 1.979430999999999941e+01 -4.907000000000000250e-02 6.414952399999999670e+02 1.790943000000000040e+01 -5.253000000000000030e-02 5.516777200000000221e+02 1.660839999999999961e+01 -5.269999999999999685e-02 5.141714299999999866e+02 1.603388999999999953e+01 -5.628999999999999976e-02 3.988418399999999906e+02 1.412165000000000070e+01 -5.868999999999999911e-02 3.579082799999999907e+02 1.337737000000000087e+01 -5.985999999999999654e-02 3.164397999999999911e+02 1.257854999999999990e+01 -6.351999999999999313e-02 2.486343500000000120e+02 1.114976000000000056e+01 -6.481000000000000649e-02 2.482066299999999899e+02 1.114016999999999946e+01 -6.715000000000000135e-02 2.006787799999999891e+02 1.001695999999999920e+01 -7.070999999999999508e-02 1.657927200000000028e+02 9.104739999999999611e+00 -7.094000000000000306e-02 1.667760000000000105e+02 9.131700000000000372e+00 -7.431999999999999718e-02 1.326982299999999952e+02 8.145500000000000185e+00 -7.721000000000000085e-02 1.181177100000000024e+02 7.684980000000000366e+00 -7.796999999999999764e-02 1.108474499999999949e+02 7.444709999999999717e+00 -8.161999999999999811e-02 9.087302999999999997e+01 6.740660000000000096e+00 -8.343000000000000416e-02 8.290343000000000018e+01 6.438299999999999912e+00 -8.522000000000000408e-02 7.588799000000000206e+01 6.159869999999999735e+00 -8.878999999999999393e-02 6.486343999999999710e+01 5.694890000000000008e+00 -8.959000000000000297e-02 6.133471999999999724e+01 5.537810000000000343e+00 -9.568999999999999728e-02 4.711737999999999715e+01 4.853729999999999656e+00 -1.017699999999999994e-01 3.554666000000000281e+01 4.215840000000000032e+00 -1.079900000000000027e-01 2.833098000000000027e+01 3.763710000000000111e+00 -1.141599999999999976e-01 2.318925000000000125e+01 3.405089999999999950e+00 -1.202000000000000013e-01 1.876435000000000031e+01 3.063029999999999919e+00 -1.263499999999999901e-01 1.568601999999999919e+01 2.800539999999999807e+00 -1.325600000000000112e-01 1.346410000000000018e+01 2.594619999999999926e+00 -1.387700000000000045e-01 1.173840000000000039e+01 2.422639999999999905e+00 -1.449000000000000010e-01 1.054757999999999996e+01 2.296469999999999789e+00 -1.509399999999999908e-01 9.084839999999999804e+00 2.131299999999999972e+00 -1.571099999999999997e-01 8.239589999999999748e+00 2.029729999999999812e+00 -1.633300000000000030e-01 7.767660000000000231e+00 1.970739999999999936e+00 -1.695099999999999940e-01 7.631929999999999659e+00 1.953449999999999909e+00 -1.756300000000000083e-01 7.253739999999999633e+00 1.904430000000000067e+00 -1.817999999999999894e-01 6.968580000000000219e+00 1.866630000000000011e+00 -1.880100000000000104e-01 7.029829999999999579e+00 1.874810000000000088e+00 -1.941199999999999870e-01 6.805609999999999715e+00 1.844670000000000032e+00 -2.002200000000000091e-01 7.007130000000000081e+00 1.871779999999999999e+00 -2.063500000000000056e-01 7.083709999999999951e+00 1.881979999999999986e+00 -2.125299999999999967e-01 6.971890000000000143e+00 1.867070000000000007e+00 -2.186800000000000133e-01 7.549360000000000070e+00 1.942849999999999966e+00 -2.247899999999999898e-01 7.451310000000000322e+00 1.930199999999999916e+00 -2.309799999999999909e-01 7.449589999999999712e+00 1.929969999999999963e+00 -2.371999999999999942e-01 7.776720000000000077e+00 1.971889999999999921e+00 -2.433599999999999930e-01 8.157130000000000436e+00 2.019550000000000178e+00 -2.494800000000000073e-01 8.339280000000000470e+00 2.041970000000000063e+00 -2.556100000000000039e-01 8.448100000000000165e+00 2.055250000000000021e+00 -2.617700000000000027e-01 8.746420000000000528e+00 2.091219999999999857e+00 -2.679699999999999860e-01 9.040720000000000312e+00 2.126110000000000166e+00 -2.741299999999999848e-01 9.130409999999999471e+00 2.136629999999999807e+00 -2.802100000000000146e-01 9.247719999999999274e+00 2.150319999999999787e+00 -2.863700000000000134e-01 9.291150000000000020e+00 2.155359999999999943e+00 -2.925800000000000067e-01 9.640140000000000597e+00 2.195469999999999811e+00 +2.732000000000000053e-02 2.792353740000000016e+03 3.736545000000000272e+01 +3.090000000000000038e-02 2.271702040000000125e+03 3.370239000000000118e+01 +3.452000000000000207e-02 1.788897279999999910e+03 2.990733000000000175e+01 +3.812000000000000111e-02 1.407023470000000088e+03 2.652380000000000138e+01 +4.173000000000000320e-02 1.095009520000000066e+03 2.339882000000000062e+01 +4.542000000000000204e-02 8.376734699999999521e+02 2.046549999999999869e+01 +4.644000000000000211e-02 7.836296200000000454e+02 1.979430999999999941e+01 +4.907000000000000250e-02 6.414952399999999670e+02 1.790943000000000040e+01 +5.253000000000000030e-02 5.516777200000000221e+02 1.660839999999999961e+01 +5.269999999999999685e-02 5.141714299999999866e+02 1.603388999999999953e+01 +5.628999999999999976e-02 3.988418399999999906e+02 1.412165000000000070e+01 +5.868999999999999911e-02 3.579082799999999907e+02 1.337737000000000087e+01 +5.985999999999999654e-02 3.164397999999999911e+02 1.257854999999999990e+01 +6.351999999999999313e-02 2.486343500000000120e+02 1.114976000000000056e+01 +6.481000000000000649e-02 2.482066299999999899e+02 1.114016999999999946e+01 +6.715000000000000135e-02 2.006787799999999891e+02 1.001695999999999920e+01 +7.070999999999999508e-02 1.657927200000000028e+02 9.104739999999999611e+00 +7.094000000000000306e-02 1.667760000000000105e+02 9.131700000000000372e+00 +7.431999999999999718e-02 1.326982299999999952e+02 8.145500000000000185e+00 +7.721000000000000085e-02 1.181177100000000024e+02 7.684980000000000366e+00 +7.796999999999999764e-02 1.108474499999999949e+02 7.444709999999999717e+00 +8.161999999999999811e-02 9.087302999999999997e+01 6.740660000000000096e+00 +8.343000000000000416e-02 8.290343000000000018e+01 6.438299999999999912e+00 +8.522000000000000408e-02 7.588799000000000206e+01 6.159869999999999735e+00 +8.878999999999999393e-02 6.486343999999999710e+01 5.694890000000000008e+00 +8.959000000000000297e-02 6.133471999999999724e+01 5.537810000000000343e+00 +9.568999999999999728e-02 4.711737999999999715e+01 4.853729999999999656e+00 +1.017699999999999994e-01 3.554666000000000281e+01 4.215840000000000032e+00 +1.079900000000000027e-01 2.833098000000000027e+01 3.763710000000000111e+00 +1.141599999999999976e-01 2.318925000000000125e+01 3.405089999999999950e+00 +1.202000000000000013e-01 1.876435000000000031e+01 3.063029999999999919e+00 +1.263499999999999901e-01 1.568601999999999919e+01 2.800539999999999807e+00 +1.325600000000000112e-01 1.346410000000000018e+01 2.594619999999999926e+00 +1.387700000000000045e-01 1.173840000000000039e+01 2.422639999999999905e+00 +1.449000000000000010e-01 1.054757999999999996e+01 2.296469999999999789e+00 +1.509399999999999908e-01 9.084839999999999804e+00 2.131299999999999972e+00 +1.571099999999999997e-01 8.239589999999999748e+00 2.029729999999999812e+00 +1.633300000000000030e-01 7.767660000000000231e+00 1.970739999999999936e+00 +1.695099999999999940e-01 7.631929999999999659e+00 1.953449999999999909e+00 +1.756300000000000083e-01 7.253739999999999633e+00 1.904430000000000067e+00 +1.817999999999999894e-01 6.968580000000000219e+00 1.866630000000000011e+00 +1.880100000000000104e-01 7.029829999999999579e+00 1.874810000000000088e+00 +1.941199999999999870e-01 6.805609999999999715e+00 1.844670000000000032e+00 +2.002200000000000091e-01 7.007130000000000081e+00 1.871779999999999999e+00 +2.063500000000000056e-01 7.083709999999999951e+00 1.881979999999999986e+00 +2.125299999999999967e-01 6.971890000000000143e+00 1.867070000000000007e+00 +2.186800000000000133e-01 7.549360000000000070e+00 1.942849999999999966e+00 +2.247899999999999898e-01 7.451310000000000322e+00 1.930199999999999916e+00 +2.309799999999999909e-01 7.449589999999999712e+00 1.929969999999999963e+00 +2.371999999999999942e-01 7.776720000000000077e+00 1.971889999999999921e+00 +2.433599999999999930e-01 8.157130000000000436e+00 2.019550000000000178e+00 +2.494800000000000073e-01 8.339280000000000470e+00 2.041970000000000063e+00 +2.556100000000000039e-01 8.448100000000000165e+00 2.055250000000000021e+00 +2.617700000000000027e-01 8.746420000000000528e+00 2.091219999999999857e+00 +2.679699999999999860e-01 9.040720000000000312e+00 2.126110000000000166e+00 +2.741299999999999848e-01 9.130409999999999471e+00 2.136629999999999807e+00 +2.802100000000000146e-01 9.247719999999999274e+00 2.150319999999999787e+00 +2.863700000000000134e-01 9.291150000000000020e+00 2.155359999999999943e+00 +2.925800000000000067e-01 9.640140000000000597e+00 2.195469999999999811e+00 2.987299999999999955e-01 9.537290000000000489e+00 2.183720000000000105e+00 \ No newline at end of file diff --git a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv index daf8f80a8..c33506202 100644 --- a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv +++ b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv @@ -1,60 +1,60 @@ -2.733000000000000013e-02 2.320909860000000208e+03 3.406544999999999845e+01 -3.090999999999999998e-02 1.910828909999999951e+03 3.090978000000000137e+01 -3.454000000000000126e-02 1.519815650000000005e+03 2.756643000000000043e+01 -3.814000000000000029e-02 1.188850680000000011e+03 2.438083999999999918e+01 -4.175000000000000239e-02 9.312768700000000308e+02 2.157865999999999929e+01 -4.544000000000000122e-02 7.201697299999999586e+02 1.897589999999999932e+01 -4.646000000000000130e-02 6.728012599999999566e+02 1.834122999999999948e+01 -4.909999999999999781e-02 5.453608799999999519e+02 1.651304000000000016e+01 -5.256000000000000255e-02 4.724414499999999748e+02 1.536946999999999974e+01 -5.272000000000000297e-02 4.318700699999999983e+02 1.469472999999999985e+01 -5.632000000000000201e-02 3.382353699999999890e+02 1.300453000000000081e+01 -5.870999999999999830e-02 3.073326000000000136e+02 1.239621999999999957e+01 -5.988999999999999879e-02 2.634156100000000151e+02 1.147639999999999993e+01 -6.356000000000000538e-02 2.076918699999999944e+02 1.019048000000000087e+01 -6.483999999999999486e-02 2.125336499999999944e+02 1.030857999999999919e+01 -6.718999999999999972e-02 1.688028199999999970e+02 9.187020000000000408e+00 -7.073999999999999733e-02 1.362696899999999971e+02 8.254379999999999384e+00 -7.097000000000000530e-02 1.410024300000000039e+02 8.396499999999999631e+00 -7.435999999999999555e-02 1.127603699999999947e+02 7.508670000000000400e+00 -7.724999999999999922e-02 9.965560999999999581e+01 7.058880000000000265e+00 -7.800999999999999601e-02 9.194693999999999789e+01 6.780369999999999564e+00 -8.165999999999999648e-02 7.522768999999999551e+01 6.133009999999999629e+00 -8.347000000000000253e-02 7.049939999999999429e+01 5.937149999999999928e+00 -8.526000000000000245e-02 6.411020000000000607e+01 5.661719999999999864e+00 -8.883000000000000618e-02 5.376234999999999786e+01 5.184709999999999930e+00 -8.963000000000000134e-02 5.217504000000000275e+01 5.107590000000000074e+00 -9.574000000000000565e-02 4.054399999999999693e+01 4.502439999999999998e+00 -1.018199999999999938e-01 3.096013999999999911e+01 3.934470000000000134e+00 -1.080399999999999971e-01 2.426012000000000057e+01 3.482819999999999805e+00 -1.142200000000000021e-01 1.991522000000000148e+01 3.155569999999999986e+00 -1.202600000000000058e-01 1.696463999999999928e+01 2.912440000000000140e+00 -1.264099999999999946e-01 1.406012999999999913e+01 2.651429999999999954e+00 -1.326199999999999879e-01 1.186475000000000080e+01 2.435649999999999871e+00 -1.388300000000000090e-01 1.075843000000000060e+01 2.319310000000000205e+00 -1.449699999999999878e-01 9.447770000000000223e+00 2.173449999999999882e+00 -1.510100000000000053e-01 8.521739999999999426e+00 2.064189999999999969e+00 -1.571799999999999864e-01 7.782460000000000377e+00 1.972620000000000040e+00 -1.634099999999999997e-01 7.576889999999999681e+00 1.946390000000000065e+00 -1.695800000000000085e-01 7.175270000000000259e+00 1.894109999999999960e+00 -1.756999999999999951e-01 6.609770000000000145e+00 1.817930000000000046e+00 -1.818799999999999861e-01 6.690150000000000041e+00 1.828950000000000076e+00 -1.880999999999999894e-01 6.763010000000000410e+00 1.838889999999999914e+00 -1.942000000000000115e-01 6.479930000000000412e+00 1.799989999999999979e+00 -2.003099999999999881e-01 6.931930000000000369e+00 1.861709999999999976e+00 -2.064499999999999946e-01 7.058690000000000353e+00 1.878649999999999931e+00 -2.126300000000000134e-01 6.966739999999999711e+00 1.866379999999999928e+00 -2.187699999999999922e-01 7.155350000000000321e+00 1.891469999999999985e+00 -2.248999999999999888e-01 7.328820000000000334e+00 1.914260000000000073e+00 -2.310800000000000076e-01 7.623789999999999623e+00 1.952409999999999979e+00 -2.373000000000000109e-01 7.870739999999999625e+00 1.983780000000000099e+00 -2.434699999999999920e-01 7.865639999999999965e+00 1.983130000000000059e+00 -2.495900000000000063e-01 8.081390000000000740e+00 2.010149999999999881e+00 -2.557300000000000129e-01 8.480309999999999349e+00 2.059159999999999879e+00 -2.618900000000000117e-01 8.708700000000000330e+00 2.086710000000000065e+00 -2.680899999999999950e-01 8.823320000000000718e+00 2.100389999999999979e+00 -2.742499999999999938e-01 9.030450000000000088e+00 2.124909999999999854e+00 -2.803300000000000236e-01 9.222670000000000812e+00 2.147400000000000198e+00 -2.864999999999999769e-01 9.345430000000000348e+00 2.161649999999999849e+00 -2.927100000000000257e-01 9.660539999999999239e+00 2.197789999999999910e+00 +2.733000000000000013e-02 2.320909860000000208e+03 3.406544999999999845e+01 +3.090999999999999998e-02 1.910828909999999951e+03 3.090978000000000137e+01 +3.454000000000000126e-02 1.519815650000000005e+03 2.756643000000000043e+01 +3.814000000000000029e-02 1.188850680000000011e+03 2.438083999999999918e+01 +4.175000000000000239e-02 9.312768700000000308e+02 2.157865999999999929e+01 +4.544000000000000122e-02 7.201697299999999586e+02 1.897589999999999932e+01 +4.646000000000000130e-02 6.728012599999999566e+02 1.834122999999999948e+01 +4.909999999999999781e-02 5.453608799999999519e+02 1.651304000000000016e+01 +5.256000000000000255e-02 4.724414499999999748e+02 1.536946999999999974e+01 +5.272000000000000297e-02 4.318700699999999983e+02 1.469472999999999985e+01 +5.632000000000000201e-02 3.382353699999999890e+02 1.300453000000000081e+01 +5.870999999999999830e-02 3.073326000000000136e+02 1.239621999999999957e+01 +5.988999999999999879e-02 2.634156100000000151e+02 1.147639999999999993e+01 +6.356000000000000538e-02 2.076918699999999944e+02 1.019048000000000087e+01 +6.483999999999999486e-02 2.125336499999999944e+02 1.030857999999999919e+01 +6.718999999999999972e-02 1.688028199999999970e+02 9.187020000000000408e+00 +7.073999999999999733e-02 1.362696899999999971e+02 8.254379999999999384e+00 +7.097000000000000530e-02 1.410024300000000039e+02 8.396499999999999631e+00 +7.435999999999999555e-02 1.127603699999999947e+02 7.508670000000000400e+00 +7.724999999999999922e-02 9.965560999999999581e+01 7.058880000000000265e+00 +7.800999999999999601e-02 9.194693999999999789e+01 6.780369999999999564e+00 +8.165999999999999648e-02 7.522768999999999551e+01 6.133009999999999629e+00 +8.347000000000000253e-02 7.049939999999999429e+01 5.937149999999999928e+00 +8.526000000000000245e-02 6.411020000000000607e+01 5.661719999999999864e+00 +8.883000000000000618e-02 5.376234999999999786e+01 5.184709999999999930e+00 +8.963000000000000134e-02 5.217504000000000275e+01 5.107590000000000074e+00 +9.574000000000000565e-02 4.054399999999999693e+01 4.502439999999999998e+00 +1.018199999999999938e-01 3.096013999999999911e+01 3.934470000000000134e+00 +1.080399999999999971e-01 2.426012000000000057e+01 3.482819999999999805e+00 +1.142200000000000021e-01 1.991522000000000148e+01 3.155569999999999986e+00 +1.202600000000000058e-01 1.696463999999999928e+01 2.912440000000000140e+00 +1.264099999999999946e-01 1.406012999999999913e+01 2.651429999999999954e+00 +1.326199999999999879e-01 1.186475000000000080e+01 2.435649999999999871e+00 +1.388300000000000090e-01 1.075843000000000060e+01 2.319310000000000205e+00 +1.449699999999999878e-01 9.447770000000000223e+00 2.173449999999999882e+00 +1.510100000000000053e-01 8.521739999999999426e+00 2.064189999999999969e+00 +1.571799999999999864e-01 7.782460000000000377e+00 1.972620000000000040e+00 +1.634099999999999997e-01 7.576889999999999681e+00 1.946390000000000065e+00 +1.695800000000000085e-01 7.175270000000000259e+00 1.894109999999999960e+00 +1.756999999999999951e-01 6.609770000000000145e+00 1.817930000000000046e+00 +1.818799999999999861e-01 6.690150000000000041e+00 1.828950000000000076e+00 +1.880999999999999894e-01 6.763010000000000410e+00 1.838889999999999914e+00 +1.942000000000000115e-01 6.479930000000000412e+00 1.799989999999999979e+00 +2.003099999999999881e-01 6.931930000000000369e+00 1.861709999999999976e+00 +2.064499999999999946e-01 7.058690000000000353e+00 1.878649999999999931e+00 +2.126300000000000134e-01 6.966739999999999711e+00 1.866379999999999928e+00 +2.187699999999999922e-01 7.155350000000000321e+00 1.891469999999999985e+00 +2.248999999999999888e-01 7.328820000000000334e+00 1.914260000000000073e+00 +2.310800000000000076e-01 7.623789999999999623e+00 1.952409999999999979e+00 +2.373000000000000109e-01 7.870739999999999625e+00 1.983780000000000099e+00 +2.434699999999999920e-01 7.865639999999999965e+00 1.983130000000000059e+00 +2.495900000000000063e-01 8.081390000000000740e+00 2.010149999999999881e+00 +2.557300000000000129e-01 8.480309999999999349e+00 2.059159999999999879e+00 +2.618900000000000117e-01 8.708700000000000330e+00 2.086710000000000065e+00 +2.680899999999999950e-01 8.823320000000000718e+00 2.100389999999999979e+00 +2.742499999999999938e-01 9.030450000000000088e+00 2.124909999999999854e+00 +2.803300000000000236e-01 9.222670000000000812e+00 2.147400000000000198e+00 +2.864999999999999769e-01 9.345430000000000348e+00 2.161649999999999849e+00 +2.927100000000000257e-01 9.660539999999999239e+00 2.197789999999999910e+00 2.988600000000000145e-01 9.559969999999999857e+00 2.186319999999999819e+00 \ No newline at end of file diff --git a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv index 2f696f3b5..17968ec9e 100644 --- a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv +++ b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv @@ -1,60 +1,60 @@ -2.733000000000000013e-02 1.791495509999999967e+03 2.992905000000000015e+01 -3.091999999999999957e-02 1.477992469999999912e+03 2.718449000000000026e+01 -3.454000000000000126e-02 1.172791189999999915e+03 2.421561000000000163e+01 -3.814000000000000029e-02 9.196233300000000099e+02 2.144322000000000017e+01 -4.175000000000000239e-02 7.160111200000000053e+02 1.892102999999999824e+01 -4.544000000000000122e-02 5.391461900000000469e+02 1.641867999999999839e+01 -4.646000000000000130e-02 4.929036699999999769e+02 1.569877999999999929e+01 -4.909999999999999781e-02 4.129331099999999992e+02 1.436894000000000027e+01 -5.256000000000000255e-02 3.482022600000000239e+02 1.319473999999999947e+01 -5.272999999999999909e-02 3.242194700000000012e+02 1.273222999999999949e+01 -5.632000000000000201e-02 2.454095199999999863e+02 1.107722000000000051e+01 -5.870999999999999830e-02 2.218204599999999971e+02 1.053139000000000003e+01 -5.990000000000000185e-02 1.931666899999999885e+02 9.827680000000000859e+00 -6.356000000000000538e-02 1.505020900000000097e+02 8.674739999999999895e+00 -6.483999999999999486e-02 1.511605900000000133e+02 8.693690000000000140e+00 -6.718999999999999972e-02 1.202856799999999993e+02 7.755180000000000184e+00 -7.074999999999999345e-02 9.616129999999999711e+01 6.934020000000000294e+00 -7.097000000000000530e-02 9.870516999999999541e+01 7.025140000000000384e+00 -7.435999999999999555e-02 7.818730999999999653e+01 6.252489999999999881e+00 -7.724999999999999922e-02 6.837958000000000425e+01 5.847199999999999953e+00 -7.802000000000000601e-02 6.371482000000000312e+01 5.644239999999999924e+00 -8.165999999999999648e-02 5.179379999999999740e+01 5.088899999999999757e+00 -8.347000000000000253e-02 4.836007000000000033e+01 4.917320000000000135e+00 -8.526999999999999857e-02 4.457972000000000179e+01 4.721210000000000129e+00 -8.884000000000000230e-02 3.751116999999999990e+01 4.330770000000000231e+00 -8.963000000000000134e-02 3.544118999999999886e+01 4.209579999999999878e+00 -9.574000000000000565e-02 2.739192999999999856e+01 3.700810000000000155e+00 -1.018199999999999938e-01 2.084316000000000102e+01 3.228250000000000064e+00 -1.080399999999999971e-01 1.702296000000000120e+01 2.917440000000000033e+00 -1.142200000000000021e-01 1.391883999999999943e+01 2.638069999999999915e+00 -1.202600000000000058e-01 1.148202000000000034e+01 2.396040000000000170e+00 -1.264099999999999946e-01 9.887589999999999435e+00 2.223460000000000214e+00 -1.326199999999999879e-01 8.618710000000000093e+00 2.075899999999999856e+00 -1.388300000000000090e-01 7.875820000000000043e+00 1.984420000000000073e+00 -1.449699999999999878e-01 7.119869999999999699e+00 1.886779999999999902e+00 -1.510100000000000053e-01 6.691399999999999793e+00 1.829129999999999923e+00 -1.571799999999999864e-01 6.133020000000000138e+00 1.751139999999999919e+00 -1.634099999999999997e-01 5.984770000000000145e+00 1.729850000000000110e+00 -1.695800000000000085e-01 5.802669999999999995e+00 1.703330000000000011e+00 -1.756999999999999951e-01 5.772070000000000256e+00 1.698830000000000062e+00 -1.818799999999999861e-01 5.866640000000000299e+00 1.712690000000000046e+00 -1.880999999999999894e-01 5.880740000000000300e+00 1.714749999999999996e+00 -1.942000000000000115e-01 5.856810000000000294e+00 1.711260000000000003e+00 -2.003099999999999881e-01 6.138060000000000294e+00 1.751870000000000038e+00 -2.064499999999999946e-01 6.406990000000000407e+00 1.789830000000000032e+00 -2.126300000000000134e-01 6.462060000000000137e+00 1.797509999999999941e+00 -2.187699999999999922e-01 6.501079999999999970e+00 1.802929999999999922e+00 -2.248999999999999888e-01 6.991179999999999950e+00 1.869650000000000034e+00 -2.310800000000000076e-01 7.014639999999999986e+00 1.872779999999999889e+00 -2.373000000000000109e-01 7.136879999999999669e+00 1.889029999999999987e+00 -2.434699999999999920e-01 7.547889999999999766e+00 1.942660000000000053e+00 -2.495900000000000063e-01 7.608620000000000161e+00 1.950460000000000083e+00 -2.557300000000000129e-01 7.913459999999999717e+00 1.989149999999999974e+00 -2.618900000000000117e-01 8.245919999999999916e+00 2.030510000000000037e+00 -2.680899999999999950e-01 8.604509999999999437e+00 2.074190000000000200e+00 -2.742499999999999938e-01 8.711750000000000327e+00 2.087070000000000203e+00 -2.803300000000000236e-01 8.863739999999999952e+00 2.105199999999999960e+00 -2.864999999999999769e-01 8.911099999999999355e+00 2.110819999999999919e+00 -2.927100000000000257e-01 9.338430000000000675e+00 2.160839999999999872e+00 +2.733000000000000013e-02 1.791495509999999967e+03 2.992905000000000015e+01 +3.091999999999999957e-02 1.477992469999999912e+03 2.718449000000000026e+01 +3.454000000000000126e-02 1.172791189999999915e+03 2.421561000000000163e+01 +3.814000000000000029e-02 9.196233300000000099e+02 2.144322000000000017e+01 +4.175000000000000239e-02 7.160111200000000053e+02 1.892102999999999824e+01 +4.544000000000000122e-02 5.391461900000000469e+02 1.641867999999999839e+01 +4.646000000000000130e-02 4.929036699999999769e+02 1.569877999999999929e+01 +4.909999999999999781e-02 4.129331099999999992e+02 1.436894000000000027e+01 +5.256000000000000255e-02 3.482022600000000239e+02 1.319473999999999947e+01 +5.272999999999999909e-02 3.242194700000000012e+02 1.273222999999999949e+01 +5.632000000000000201e-02 2.454095199999999863e+02 1.107722000000000051e+01 +5.870999999999999830e-02 2.218204599999999971e+02 1.053139000000000003e+01 +5.990000000000000185e-02 1.931666899999999885e+02 9.827680000000000859e+00 +6.356000000000000538e-02 1.505020900000000097e+02 8.674739999999999895e+00 +6.483999999999999486e-02 1.511605900000000133e+02 8.693690000000000140e+00 +6.718999999999999972e-02 1.202856799999999993e+02 7.755180000000000184e+00 +7.074999999999999345e-02 9.616129999999999711e+01 6.934020000000000294e+00 +7.097000000000000530e-02 9.870516999999999541e+01 7.025140000000000384e+00 +7.435999999999999555e-02 7.818730999999999653e+01 6.252489999999999881e+00 +7.724999999999999922e-02 6.837958000000000425e+01 5.847199999999999953e+00 +7.802000000000000601e-02 6.371482000000000312e+01 5.644239999999999924e+00 +8.165999999999999648e-02 5.179379999999999740e+01 5.088899999999999757e+00 +8.347000000000000253e-02 4.836007000000000033e+01 4.917320000000000135e+00 +8.526999999999999857e-02 4.457972000000000179e+01 4.721210000000000129e+00 +8.884000000000000230e-02 3.751116999999999990e+01 4.330770000000000231e+00 +8.963000000000000134e-02 3.544118999999999886e+01 4.209579999999999878e+00 +9.574000000000000565e-02 2.739192999999999856e+01 3.700810000000000155e+00 +1.018199999999999938e-01 2.084316000000000102e+01 3.228250000000000064e+00 +1.080399999999999971e-01 1.702296000000000120e+01 2.917440000000000033e+00 +1.142200000000000021e-01 1.391883999999999943e+01 2.638069999999999915e+00 +1.202600000000000058e-01 1.148202000000000034e+01 2.396040000000000170e+00 +1.264099999999999946e-01 9.887589999999999435e+00 2.223460000000000214e+00 +1.326199999999999879e-01 8.618710000000000093e+00 2.075899999999999856e+00 +1.388300000000000090e-01 7.875820000000000043e+00 1.984420000000000073e+00 +1.449699999999999878e-01 7.119869999999999699e+00 1.886779999999999902e+00 +1.510100000000000053e-01 6.691399999999999793e+00 1.829129999999999923e+00 +1.571799999999999864e-01 6.133020000000000138e+00 1.751139999999999919e+00 +1.634099999999999997e-01 5.984770000000000145e+00 1.729850000000000110e+00 +1.695800000000000085e-01 5.802669999999999995e+00 1.703330000000000011e+00 +1.756999999999999951e-01 5.772070000000000256e+00 1.698830000000000062e+00 +1.818799999999999861e-01 5.866640000000000299e+00 1.712690000000000046e+00 +1.880999999999999894e-01 5.880740000000000300e+00 1.714749999999999996e+00 +1.942000000000000115e-01 5.856810000000000294e+00 1.711260000000000003e+00 +2.003099999999999881e-01 6.138060000000000294e+00 1.751870000000000038e+00 +2.064499999999999946e-01 6.406990000000000407e+00 1.789830000000000032e+00 +2.126300000000000134e-01 6.462060000000000137e+00 1.797509999999999941e+00 +2.187699999999999922e-01 6.501079999999999970e+00 1.802929999999999922e+00 +2.248999999999999888e-01 6.991179999999999950e+00 1.869650000000000034e+00 +2.310800000000000076e-01 7.014639999999999986e+00 1.872779999999999889e+00 +2.373000000000000109e-01 7.136879999999999669e+00 1.889029999999999987e+00 +2.434699999999999920e-01 7.547889999999999766e+00 1.942660000000000053e+00 +2.495900000000000063e-01 7.608620000000000161e+00 1.950460000000000083e+00 +2.557300000000000129e-01 7.913459999999999717e+00 1.989149999999999974e+00 +2.618900000000000117e-01 8.245919999999999916e+00 2.030510000000000037e+00 +2.680899999999999950e-01 8.604509999999999437e+00 2.074190000000000200e+00 +2.742499999999999938e-01 8.711750000000000327e+00 2.087070000000000203e+00 +2.803300000000000236e-01 8.863739999999999952e+00 2.105199999999999960e+00 +2.864999999999999769e-01 8.911099999999999355e+00 2.110819999999999919e+00 +2.927100000000000257e-01 9.338430000000000675e+00 2.160839999999999872e+00 2.988600000000000145e-01 9.385640000000000427e+00 2.166290000000000049e+00 \ No newline at end of file diff --git a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv index e7dfab999..72272ed89 100644 --- a/test/mumag/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv +++ b/test/mumag/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 1.517870979999999918e+03 2.754878000000000071e+01 -3.090999999999999998e-02 1.252144950000000108e+03 2.502143999999999835e+01 -3.452999999999999819e-02 9.849326300000000174e+02 2.219157999999999831e+01 -3.812999999999999723e-02 7.635778900000000249e+02 1.953941999999999979e+01 -4.173999999999999932e-02 5.910564900000000534e+02 1.719093000000000160e+01 -4.542999999999999816e-02 4.454160299999999779e+02 1.492340000000000089e+01 -4.644000000000000211e-02 4.097451399999999921e+02 1.431337000000000081e+01 -4.907999999999999863e-02 3.412573399999999992e+02 1.306249000000000038e+01 -5.254000000000000337e-02 2.833860500000000116e+02 1.190348999999999968e+01 -5.270999999999999991e-02 2.587516299999999774e+02 1.137434999999999974e+01 -5.630000000000000282e-02 1.972410900000000140e+02 9.930790000000000006e+00 -5.868999999999999911e-02 1.820288400000000024e+02 9.540150000000000574e+00 -5.988000000000000267e-02 1.548462399999999946e+02 8.799039999999999750e+00 -6.353999999999999926e-02 1.208091600000000057e+02 7.772039999999999615e+00 -6.481000000000000649e-02 1.228846300000000014e+02 7.838510000000000311e+00 -6.716999999999999360e-02 9.485747999999999536e+01 6.886849999999999916e+00 -7.072000000000000508e-02 7.616365000000000407e+01 6.171050000000000146e+00 -7.094999999999999918e-02 7.959243999999999630e+01 6.308419999999999916e+00 -7.434000000000000330e-02 6.139544999999999675e+01 5.540549999999999642e+00 -7.721999999999999698e-02 5.528307999999999822e+01 5.257520000000000415e+00 -7.799000000000000377e-02 5.105310999999999666e+01 5.052380000000000315e+00 -8.164000000000000423e-02 4.131436000000000064e+01 4.545020000000000060e+00 -8.343000000000000416e-02 3.883191999999999666e+01 4.406349999999999767e+00 -8.523999999999999633e-02 3.386838999999999800e+01 4.115120000000000111e+00 -8.881000000000000005e-02 2.873742000000000019e+01 3.790610000000000035e+00 -8.959999999999999909e-02 2.744166999999999845e+01 3.704159999999999897e+00 -9.569999999999999341e-02 2.114314999999999856e+01 3.251399999999999846e+00 -1.017799999999999955e-01 1.639198000000000022e+01 2.862859999999999960e+00 -1.079999999999999988e-01 1.302345000000000041e+01 2.551810000000000134e+00 -1.141699999999999937e-01 1.067233000000000054e+01 2.310010000000000119e+00 -1.202099999999999974e-01 8.927680000000000504e+00 2.112779999999999880e+00 -1.263600000000000001e-01 7.691300000000000026e+00 1.961030000000000051e+00 -1.325600000000000112e-01 6.633219999999999672e+00 1.821159999999999890e+00 -1.387799999999999867e-01 6.187759999999999927e+00 1.758939999999999948e+00 -1.449100000000000110e-01 5.397269999999999790e+00 1.642749999999999932e+00 -1.509500000000000008e-01 5.127299999999999969e+00 1.601140000000000008e+00 -1.571200000000000097e-01 4.947350000000000136e+00 1.572789999999999910e+00 -1.633400000000000130e-01 4.791970000000000063e+00 1.547900000000000054e+00 -1.695200000000000040e-01 4.839830000000000076e+00 1.555609999999999937e+00 -1.756399999999999906e-01 4.855599999999999916e+00 1.558140000000000081e+00 -1.818099999999999994e-01 4.971189999999999998e+00 1.576580000000000092e+00 -1.880199999999999927e-01 4.996179999999999843e+00 1.580540000000000056e+00 -1.941299999999999970e-01 5.231489999999999974e+00 1.617329999999999934e+00 -2.002299999999999913e-01 5.461660000000000181e+00 1.652519999999999989e+00 -2.063699999999999979e-01 5.566430000000000433e+00 1.668299999999999894e+00 -2.125400000000000067e-01 5.749649999999999928e+00 1.695529999999999982e+00 -2.186899999999999955e-01 5.962720000000000020e+00 1.726660000000000084e+00 -2.248100000000000098e-01 6.366220000000000212e+00 1.784129999999999994e+00 -2.309900000000000009e-01 6.576419999999999710e+00 1.813339999999999952e+00 -2.372100000000000042e-01 6.993730000000000224e+00 1.869990000000000041e+00 -2.433800000000000130e-01 7.112300000000000288e+00 1.885780000000000012e+00 -2.494999999999999996e-01 7.346860000000000390e+00 1.916619999999999990e+00 -2.556300000000000239e-01 7.629410000000000025e+00 1.953130000000000033e+00 -2.617900000000000227e-01 7.827810000000000379e+00 1.978359999999999896e+00 -2.679900000000000060e-01 8.252810000000000201e+00 2.031359999999999832e+00 -2.741399999999999948e-01 8.304840000000000444e+00 2.037749999999999950e+00 -2.802200000000000246e-01 8.705450000000000799e+00 2.086320000000000174e+00 -2.863899999999999779e-01 8.881330000000000169e+00 2.107289999999999885e+00 -2.926000000000000267e-01 9.112230000000000274e+00 2.134510000000000129e+00 -2.987500000000000155e-01 9.303969999999999629e+00 2.156849999999999934e+00 +2.732000000000000053e-02 1.517870979999999918e+03 2.754878000000000071e+01 +3.090999999999999998e-02 1.252144950000000108e+03 2.502143999999999835e+01 +3.452999999999999819e-02 9.849326300000000174e+02 2.219157999999999831e+01 +3.812999999999999723e-02 7.635778900000000249e+02 1.953941999999999979e+01 +4.173999999999999932e-02 5.910564900000000534e+02 1.719093000000000160e+01 +4.542999999999999816e-02 4.454160299999999779e+02 1.492340000000000089e+01 +4.644000000000000211e-02 4.097451399999999921e+02 1.431337000000000081e+01 +4.907999999999999863e-02 3.412573399999999992e+02 1.306249000000000038e+01 +5.254000000000000337e-02 2.833860500000000116e+02 1.190348999999999968e+01 +5.270999999999999991e-02 2.587516299999999774e+02 1.137434999999999974e+01 +5.630000000000000282e-02 1.972410900000000140e+02 9.930790000000000006e+00 +5.868999999999999911e-02 1.820288400000000024e+02 9.540150000000000574e+00 +5.988000000000000267e-02 1.548462399999999946e+02 8.799039999999999750e+00 +6.353999999999999926e-02 1.208091600000000057e+02 7.772039999999999615e+00 +6.481000000000000649e-02 1.228846300000000014e+02 7.838510000000000311e+00 +6.716999999999999360e-02 9.485747999999999536e+01 6.886849999999999916e+00 +7.072000000000000508e-02 7.616365000000000407e+01 6.171050000000000146e+00 +7.094999999999999918e-02 7.959243999999999630e+01 6.308419999999999916e+00 +7.434000000000000330e-02 6.139544999999999675e+01 5.540549999999999642e+00 +7.721999999999999698e-02 5.528307999999999822e+01 5.257520000000000415e+00 +7.799000000000000377e-02 5.105310999999999666e+01 5.052380000000000315e+00 +8.164000000000000423e-02 4.131436000000000064e+01 4.545020000000000060e+00 +8.343000000000000416e-02 3.883191999999999666e+01 4.406349999999999767e+00 +8.523999999999999633e-02 3.386838999999999800e+01 4.115120000000000111e+00 +8.881000000000000005e-02 2.873742000000000019e+01 3.790610000000000035e+00 +8.959999999999999909e-02 2.744166999999999845e+01 3.704159999999999897e+00 +9.569999999999999341e-02 2.114314999999999856e+01 3.251399999999999846e+00 +1.017799999999999955e-01 1.639198000000000022e+01 2.862859999999999960e+00 +1.079999999999999988e-01 1.302345000000000041e+01 2.551810000000000134e+00 +1.141699999999999937e-01 1.067233000000000054e+01 2.310010000000000119e+00 +1.202099999999999974e-01 8.927680000000000504e+00 2.112779999999999880e+00 +1.263600000000000001e-01 7.691300000000000026e+00 1.961030000000000051e+00 +1.325600000000000112e-01 6.633219999999999672e+00 1.821159999999999890e+00 +1.387799999999999867e-01 6.187759999999999927e+00 1.758939999999999948e+00 +1.449100000000000110e-01 5.397269999999999790e+00 1.642749999999999932e+00 +1.509500000000000008e-01 5.127299999999999969e+00 1.601140000000000008e+00 +1.571200000000000097e-01 4.947350000000000136e+00 1.572789999999999910e+00 +1.633400000000000130e-01 4.791970000000000063e+00 1.547900000000000054e+00 +1.695200000000000040e-01 4.839830000000000076e+00 1.555609999999999937e+00 +1.756399999999999906e-01 4.855599999999999916e+00 1.558140000000000081e+00 +1.818099999999999994e-01 4.971189999999999998e+00 1.576580000000000092e+00 +1.880199999999999927e-01 4.996179999999999843e+00 1.580540000000000056e+00 +1.941299999999999970e-01 5.231489999999999974e+00 1.617329999999999934e+00 +2.002299999999999913e-01 5.461660000000000181e+00 1.652519999999999989e+00 +2.063699999999999979e-01 5.566430000000000433e+00 1.668299999999999894e+00 +2.125400000000000067e-01 5.749649999999999928e+00 1.695529999999999982e+00 +2.186899999999999955e-01 5.962720000000000020e+00 1.726660000000000084e+00 +2.248100000000000098e-01 6.366220000000000212e+00 1.784129999999999994e+00 +2.309900000000000009e-01 6.576419999999999710e+00 1.813339999999999952e+00 +2.372100000000000042e-01 6.993730000000000224e+00 1.869990000000000041e+00 +2.433800000000000130e-01 7.112300000000000288e+00 1.885780000000000012e+00 +2.494999999999999996e-01 7.346860000000000390e+00 1.916619999999999990e+00 +2.556300000000000239e-01 7.629410000000000025e+00 1.953130000000000033e+00 +2.617900000000000227e-01 7.827810000000000379e+00 1.978359999999999896e+00 +2.679900000000000060e-01 8.252810000000000201e+00 2.031359999999999832e+00 +2.741399999999999948e-01 8.304840000000000444e+00 2.037749999999999950e+00 +2.802200000000000246e-01 8.705450000000000799e+00 2.086320000000000174e+00 +2.863899999999999779e-01 8.881330000000000169e+00 2.107289999999999885e+00 +2.926000000000000267e-01 9.112230000000000274e+00 2.134510000000000129e+00 +2.987500000000000155e-01 9.303969999999999629e+00 2.156849999999999934e+00 diff --git a/test/mumag/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv b/test/mumag/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv new file mode 100644 index 000000000..efaf03f7e --- /dev/null +++ b/test/mumag/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv @@ -0,0 +1,53 @@ +0.02466 11161.7 105.066 +0.02779 8582.24 78.8702 +0.03118 6929.14 63.4309 +0.03472 5567.83 52.0489 +0.03798 4896.87 48.9428 +0.04103 4301.45 44.2537 +0.04439 3931.56 35.32 +0.04789 3532.24 33.8506 +0.05145 3225.93 29.1479 +0.05487 3001.52 30.0366 +0.05809 2808.67 26.8966 +0.06147 2656.59 24.6464 +0.06487 2544.49 24.3544 +0.06823 2417.04 22.1946 +0.07159 2285.04 21.753 +0.07491 2209.24 20.4624 +0.07817 2057.47 19.703 +0.08149 2022.7 18.6311 +0.08492 1895.55 17.4353 +0.08832 1842.28 17.2068 +0.09171 1764.56 16.4013 +0.09497 1702.47 16.2564 +0.09818 1650.68 15.7993 +0.10176 1598.61 13.5448 +0.10537 1517.07 14.6455 +0.10864 1470.19 13.6872 +0.11191 1422.64 13.7771 +0.11529 1373.82 12.5952 +0.11874 1333.67 12.468 +0.12204 1309.38 12.7116 +0.1253 1256.04 11.6755 +0.12868 1224.03 11.535 +0.13213 1180.94 10.9145 +0.13557 1163.16 10.9427 +0.13878 1135.89 11.2995 +0.14204 1129.91 10.3422 +0.14544 1101.7 10.3463 +0.14888 1050.46 9.68171 +0.1523 1034.3 9.79525 +0.15558 1022.51 9.86417 +0.15895 1003.15 9.06883 +0.16231 984.02 9.61305 +0.16567 956.076 8.69603 +0.16916 941.039 8.81872 +0.17256 914.22 8.5457 +0.1759 903.557 8.49062 +0.1792 862.822 8.49027 +0.18246 857.39 8.12443 +0.18596 822.372 7.58423 +0.18945 803.539 7.77639 +0.19275 787.933 7.6279 +0.19605 759.06 7.64242 +0.1993 746.444 7.32989 diff --git a/test/mumag/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv b/test/mumag/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv new file mode 100644 index 000000000..ede4f8121 --- /dev/null +++ b/test/mumag/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv @@ -0,0 +1,53 @@ +0.02466 9785.87 100.498 +0.02779 7387.61 74.8808 +0.03118 5638.9 58.6706 +0.03472 4473.77 47.7572 +0.03797 3723.19 43.7134 +0.04102 3256.4 39.3915 +0.04439 2850.7 30.7019 +0.04789 2561.59 29.3595 +0.05145 2280.01 24.9612 +0.05487 2158.85 25.8372 +0.05809 1997.24 23.0262 +0.06147 1891.61 21.0832 +0.06486 1796.03 20.6896 +0.06823 1698.02 18.8045 +0.07158 1613.84 18.4277 +0.0749 1560.07 17.3367 +0.07817 1481.58 16.8421 +0.08149 1400.5 15.6189 +0.08492 1362.71 14.8771 +0.08832 1326.21 14.6884 +0.09171 1308.1 14.1935 +0.09497 1238.48 13.9232 +0.09817 1217.12 13.6217 +0.10176 1182.01 11.7148 +0.10536 1125.29 12.6688 +0.10863 1086.39 11.8029 +0.1119 1069.27 11.9783 +0.11528 1037.53 10.9946 +0.11874 1000.25 10.8391 +0.12203 1030.21 11.3207 +0.12529 996.562 10.4091 +0.12867 937.635 10.1418 +0.13213 932.787 9.7458 +0.13557 936.093 9.83598 +0.13878 902.903 10.118 +0.14204 895.331 9.2379 +0.14544 894.523 9.3444 +0.14887 873.213 8.84172 +0.15229 870.028 8.99453 +0.15558 846.466 8.9992 +0.15895 842.358 8.32813 +0.1623 809.53 8.74144 +0.16566 822.783 8.08431 +0.16915 792.943 8.10552 +0.17255 774.308 7.87783 +0.1759 781.539 7.90816 +0.17919 756.562 7.97296 +0.18245 745.925 7.59066 +0.18596 725.982 7.13904 +0.18944 711.483 7.3287 +0.19275 709.157 7.24903 +0.19604 677.704 7.2411 +0.19929 659.648 6.90112 diff --git a/test/mumag/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv b/test/mumag/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv new file mode 100644 index 000000000..1c96f3d5f --- /dev/null +++ b/test/mumag/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv @@ -0,0 +1,53 @@ +0.02467 9119.79 98.2483 +0.02779 6716.34 72.6007 +0.03118 4992.66 56.2161 +0.03472 3831.98 45.1388 +0.03798 3145.6 40.9924 +0.04103 2635.02 36.2785 +0.0444 2353.33 28.4064 +0.04789 2051.02 26.7601 +0.05146 1820.51 22.7202 +0.05487 1702.5 23.3101 +0.0581 1582.43 20.8224 +0.06148 1455.78 18.7977 +0.06487 1396.8 18.5029 +0.06824 1347.58 16.9495 +0.07159 1258.02 16.4371 +0.07491 1231.28 15.5554 +0.07818 1164.47 15.0776 +0.0815 1146.97 14.2378 +0.08493 1109.77 13.533 +0.08833 1040.08 13.1167 +0.09172 1030.03 12.6919 +0.09498 996.502 12.5769 +0.09819 973.153 12.2625 +0.10178 933.855 10.4847 +0.10538 941.324 11.6421 +0.10865 891.14 10.747 +0.11192 890.927 10.9919 +0.1153 863.999 10.0862 +0.11876 860.652 10.1051 +0.12205 833.905 10.2392 +0.12531 831.414 9.54046 +0.12869 796.354 9.38666 +0.13215 809.376 9.11842 +0.13559 805.133 9.14629 +0.1388 791.474 9.50691 +0.14205 787.287 8.69915 +0.14546 761.22 8.65866 +0.1489 779.201 8.38098 +0.15232 771.323 8.50152 +0.1556 748.08 8.49235 +0.15897 748.238 7.8713 +0.16233 756.864 8.48551 +0.16569 723.545 7.61209 +0.16918 723.039 7.76626 +0.17258 714.249 7.58349 +0.17592 707.068 7.55031 +0.17922 695.999 7.67253 +0.18248 687.854 7.31121 +0.18599 672.503 6.89206 +0.18947 656.046 7.05985 +0.19277 644.64 6.93548 +0.19607 633.62 7.0287 +0.19932 617.369 6.7009 diff --git a/test/mumag/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv b/test/mumag/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv new file mode 100644 index 000000000..e349acefe --- /dev/null +++ b/test/mumag/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv @@ -0,0 +1,53 @@ +0.02466 8578.27 96.3713 +0.02778 6201.5 70.6884 +0.03117 4666.55 54.9081 +0.03471 3532.71 43.8556 +0.03797 2779.72 39.1195 +0.04102 2401.14 35.0436 +0.04438 2010.93 26.6446 +0.04788 1789.13 25.3004 +0.05144 1629 21.7057 +0.05485 1414.39 21.5471 +0.05808 1338.47 19.3969 +0.06145 1255.55 17.6425 +0.06485 1194.78 17.2789 +0.06822 1131.88 15.6792 +0.07157 1093.29 15.4062 +0.07489 1076.75 14.6325 +0.07815 990.83 13.9891 +0.08147 993.984 13.3123 +0.0849 949.429 12.5828 +0.0883 906.082 12.3081 +0.09169 901.543 11.9196 +0.09495 883.023 11.8721 +0.09815 842.784 11.4424 +0.10174 819.526 9.8676 +0.10534 802.736 10.7893 +0.10861 795.767 10.1828 +0.11188 791.163 10.3837 +0.11526 783.07 9.63416 +0.11872 771.734 9.59199 +0.12201 755.014 9.75865 +0.12527 763.25 9.14929 +0.12865 738.983 9.05459 +0.1321 735.65 8.71334 +0.13554 713.743 8.62175 +0.13875 720.548 9.08471 +0.142 726.975 8.37203 +0.14541 705.893 8.34698 +0.14884 717.099 8.0504 +0.15226 709.825 8.16294 +0.15554 709.595 8.27884 +0.15891 699.293 7.61937 +0.16227 704.678 8.19256 +0.16563 698.926 7.48706 +0.16912 685.563 7.56396 +0.17251 673.043 7.36594 +0.17586 671.398 7.36238 +0.17915 664.082 7.50135 +0.18241 667.157 7.20373 +0.18592 646.099 6.75787 +0.1894 640.973 6.98357 +0.1927 634.489 6.88246 +0.196 608.639 6.89728 +0.19924 599.163 6.60299 diff --git a/test/mumag/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv b/test/mumag/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv new file mode 100644 index 000000000..03d157c58 --- /dev/null +++ b/test/mumag/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv @@ -0,0 +1,53 @@ +0.02466 8403.24 95.8365 +0.02779 5866.26 69.5434 +0.03118 4356.78 53.6923 +0.03472 3299.25 42.8649 +0.03798 2597.38 38.2386 +0.04103 2129.79 33.557 +0.04439 1878.69 25.9888 +0.04789 1624.61 24.3861 +0.05145 1439.52 20.6737 +0.05487 1263.65 20.5759 +0.05809 1171.99 18.386 +0.06147 1079.56 16.577 +0.06487 1041.15 16.3129 +0.06823 1001.7 14.8847 +0.07159 961.645 14.563 +0.07491 923.442 13.6706 +0.07817 896.915 13.3973 +0.08149 883.652 12.6286 +0.08492 862.753 12.0581 +0.08832 824.722 11.795 +0.09171 784.35 11.1756 +0.09497 769.294 11.1579 +0.09818 755.349 10.8901 +0.10176 749.016 9.48228 +0.10537 742.393 10.4072 +0.10864 731.812 9.80011 +0.11191 725.902 9.97489 +0.11529 687.755 9.06119 +0.11874 695.826 9.13917 +0.12204 706.826 9.47552 +0.1253 686.062 8.69528 +0.12868 672.907 8.67583 +0.13213 693.14 8.48682 +0.13557 670.728 8.38538 +0.13878 665.705 8.76139 +0.14204 671.833 8.08011 +0.14544 675.608 8.18129 +0.14888 672.094 7.81614 +0.1523 674.683 7.97469 +0.15558 656.506 7.99112 +0.15895 676.236 7.50792 +0.16231 665.98 7.99164 +0.16567 649.237 7.2359 +0.16916 663.887 7.46039 +0.17256 654.732 7.28088 +0.1759 649.138 7.26044 +0.1792 637.918 7.36805 +0.18246 634.954 7.04588 +0.18596 615.952 6.61209 +0.18945 606.075 6.80618 +0.19275 602.38 6.72418 +0.19605 583.877 6.77081 +0.1993 592.832 6.58159 diff --git a/test/quantities/utest_math_operations.py b/test/quantities/utest_math_operations.py index 13fb27aa4..67e10813c 100644 --- a/test/quantities/utest_math_operations.py +++ b/test/quantities/utest_math_operations.py @@ -1,152 +1,152 @@ -""" Tests for math operations """ - -import numpy as np -import pytest - -from sasdata.quantities import units -from sasdata.quantities.quantity import NamedQuantity, tensordot, transpose - -order_list = [ - [0, 1, 2, 3], - [0, 2, 1], - [1, 0], - [0, 1], - [2, 0, 1], - [3, 1, 2, 0] -] - -@pytest.mark.parametrize("order", order_list) -def test_transpose_raw(order: list[int]): - """ Check that the transpose operation changes the order of indices correctly - uses sizes as way of tracking""" - - input_shape = tuple([i+1 for i in range(len(order))]) - expected_shape = tuple([i+1 for i in order]) - - input_mat = np.zeros(input_shape) - - measured_mat = transpose(input_mat, axes=tuple(order)) - - assert measured_mat.shape == expected_shape - - -@pytest.mark.parametrize("order", order_list) -def test_transpose_raw_with_quantity(order: list[int]): - """ Check that the transpose operation changes the order of indices correctly - uses sizes as way of tracking""" - input_shape = tuple([i + 1 for i in range(len(order))]) - expected_shape = tuple([i + 1 for i in order]) - - input_mat = NamedQuantity("testmat", np.zeros(input_shape), units=units.none) - - measured_mat = transpose(input_mat, axes=tuple(order)) - - assert measured_mat.value.shape == expected_shape - - -rng_seed = 1979 -tensor_product_with_identity_sizes = (4,6,5) - -@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) -def test_tensor_product_with_identity_quantities(index, size): - """ Check the correctness of the tensor product by multiplying by the identity (quantity, quantity)""" - np.random.seed(rng_seed) - - x = NamedQuantity("x", np.random.rand(*tensor_product_with_identity_sizes), units=units.meters) - y = NamedQuantity("y", np.eye(size), units.seconds) - - z = tensordot(x, y, index, 0) - - # Check units - assert z.units == units.meters * units.seconds - - # Expected sizes - last index gets moved to end - output_order = [i for i in (0, 1, 2) if i != index] + [index] - output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] - - assert z.value.shape == tuple(output_sizes) - - # Restore original order and check - reverse_order = [-1, -1, -1] - for to_index, from_index in enumerate(output_order): - reverse_order[from_index] = to_index - - z_reordered = transpose(z, axes = tuple(reverse_order)) - - assert z_reordered.value.shape == tensor_product_with_identity_sizes - - # Check values - - mat_in = x.in_si() - mat_out = transpose(z, axes=tuple(reverse_order)).in_si() - - assert np.all(np.abs(mat_in - mat_out) < 1e-10) - - -@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) -def test_tensor_product_with_identity_quantity_matrix(index, size): - """ Check the correctness of the tensor product by multiplying by the identity (quantity, matrix)""" - np.random.seed(rng_seed) - - x = NamedQuantity("x", np.random.rand(*tensor_product_with_identity_sizes), units.meters) - y = np.eye(size) - - z = tensordot(x, y, index, 0) - - assert z.units == units.meters - - # Expected sizes - last index gets moved to end - output_order = [i for i in (0, 1, 2) if i != index] + [index] - output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] - - assert z.value.shape == tuple(output_sizes) - - # Restore original order and check - reverse_order = [-1, -1, -1] - for to_index, from_index in enumerate(output_order): - reverse_order[from_index] = to_index - - z_reordered = transpose(z, axes = tuple(reverse_order)) - - assert z_reordered.value.shape == tensor_product_with_identity_sizes - - # Check values - - mat_in = x.in_si() - mat_out = transpose(z, axes=tuple(reverse_order)).in_si() - - assert np.all(np.abs(mat_in - mat_out) < 1e-10) - - -@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) -def test_tensor_product_with_identity_matrix_quantity(index, size): - """ Check the correctness of the tensor product by multiplying by the identity (matrix, quantity)""" - np.random.seed(rng_seed) - - x = np.random.rand(*tensor_product_with_identity_sizes) - y = NamedQuantity("y", np.eye(size), units.seconds) - - z = tensordot(x, y, index, 0) - - assert z.units == units.seconds - - - # Expected sizes - last index gets moved to end - output_order = [i for i in (0, 1, 2) if i != index] + [index] - output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] - - assert z.value.shape == tuple(output_sizes) - - # Restore original order and check - reverse_order = [-1, -1, -1] - for to_index, from_index in enumerate(output_order): - reverse_order[from_index] = to_index - - z_reordered = transpose(z, axes = tuple(reverse_order)) - - assert z_reordered.value.shape == tensor_product_with_identity_sizes - - # Check values - - mat_in = x - mat_out = transpose(z, axes=tuple(reverse_order)).in_si() - - assert np.all(np.abs(mat_in - mat_out) < 1e-10) +""" Tests for math operations """ + +import numpy as np +import pytest + +from sasdata.quantities import units +from sasdata.quantities.quantity import NamedQuantity, tensordot, transpose + +order_list = [ + [0, 1, 2, 3], + [0, 2, 1], + [1, 0], + [0, 1], + [2, 0, 1], + [3, 1, 2, 0] +] + +@pytest.mark.parametrize("order", order_list) +def test_transpose_raw(order: list[int]): + """ Check that the transpose operation changes the order of indices correctly - uses sizes as way of tracking""" + + input_shape = tuple([i+1 for i in range(len(order))]) + expected_shape = tuple([i+1 for i in order]) + + input_mat = np.zeros(input_shape) + + measured_mat = transpose(input_mat, axes=tuple(order)) + + assert measured_mat.shape == expected_shape + + +@pytest.mark.parametrize("order", order_list) +def test_transpose_raw(order: list[int]): + """ Check that the transpose operation changes the order of indices correctly - uses sizes as way of tracking""" + input_shape = tuple([i + 1 for i in range(len(order))]) + expected_shape = tuple([i + 1 for i in order]) + + input_mat = NamedQuantity("testmat", np.zeros(input_shape), units=units.none) + + measured_mat = transpose(input_mat, axes=tuple(order)) + + assert measured_mat.value.shape == expected_shape + + +rng_seed = 1979 +tensor_product_with_identity_sizes = (4,6,5) + +@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) +def test_tensor_product_with_identity_quantities(index, size): + """ Check the correctness of the tensor product by multiplying by the identity (quantity, quantity)""" + np.random.seed(rng_seed) + + x = NamedQuantity("x", np.random.rand(*tensor_product_with_identity_sizes), units=units.meters) + y = NamedQuantity("y", np.eye(size), units.seconds) + + z = tensordot(x, y, index, 0) + + # Check units + assert z.units == units.meters * units.seconds + + # Expected sizes - last index gets moved to end + output_order = [i for i in (0, 1, 2) if i != index] + [index] + output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] + + assert z.value.shape == tuple(output_sizes) + + # Restore original order and check + reverse_order = [-1, -1, -1] + for to_index, from_index in enumerate(output_order): + reverse_order[from_index] = to_index + + z_reordered = transpose(z, axes = tuple(reverse_order)) + + assert z_reordered.value.shape == tensor_product_with_identity_sizes + + # Check values + + mat_in = x.in_si() + mat_out = transpose(z, axes=tuple(reverse_order)).in_si() + + assert np.all(np.abs(mat_in - mat_out) < 1e-10) + + +@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) +def test_tensor_product_with_identity_quantity_matrix(index, size): + """ Check the correctness of the tensor product by multiplying by the identity (quantity, matrix)""" + np.random.seed(rng_seed) + + x = NamedQuantity("x", np.random.rand(*tensor_product_with_identity_sizes), units.meters) + y = np.eye(size) + + z = tensordot(x, y, index, 0) + + assert z.units == units.meters + + # Expected sizes - last index gets moved to end + output_order = [i for i in (0, 1, 2) if i != index] + [index] + output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] + + assert z.value.shape == tuple(output_sizes) + + # Restore original order and check + reverse_order = [-1, -1, -1] + for to_index, from_index in enumerate(output_order): + reverse_order[from_index] = to_index + + z_reordered = transpose(z, axes = tuple(reverse_order)) + + assert z_reordered.value.shape == tensor_product_with_identity_sizes + + # Check values + + mat_in = x.in_si() + mat_out = transpose(z, axes=tuple(reverse_order)).in_si() + + assert np.all(np.abs(mat_in - mat_out) < 1e-10) + + +@pytest.mark.parametrize("index, size", [tup for tup in enumerate(tensor_product_with_identity_sizes)]) +def test_tensor_product_with_identity_matrix_quantity(index, size): + """ Check the correctness of the tensor product by multiplying by the identity (matrix, quantity)""" + np.random.seed(rng_seed) + + x = np.random.rand(*tensor_product_with_identity_sizes) + y = NamedQuantity("y", np.eye(size), units.seconds) + + z = tensordot(x, y, index, 0) + + assert z.units == units.seconds + + + # Expected sizes - last index gets moved to end + output_order = [i for i in (0, 1, 2) if i != index] + [index] + output_sizes = [tensor_product_with_identity_sizes[i] for i in output_order] + + assert z.value.shape == tuple(output_sizes) + + # Restore original order and check + reverse_order = [-1, -1, -1] + for to_index, from_index in enumerate(output_order): + reverse_order[from_index] = to_index + + z_reordered = transpose(z, axes = tuple(reverse_order)) + + assert z_reordered.value.shape == tensor_product_with_identity_sizes + + # Check values + + mat_in = x + mat_out = transpose(z, axes=tuple(reverse_order)).in_si() + + assert np.all(np.abs(mat_in - mat_out) < 1e-10) diff --git a/test/quantities/utest_operations.py b/test/quantities/utest_operations.py index 2bfc400a4..f4599f1b4 100644 --- a/test/quantities/utest_operations.py +++ b/test/quantities/utest_operations.py @@ -1,3 +1,6 @@ +import math + +import numpy as np import pytest from sasdata.quantities.quantity import ( @@ -15,22 +18,38 @@ Variable, ) -operation_with_everything = \ - Div( - Pow( - Mul( - Sub( - Add( - Neg(Inv(MultiplicativeIdentity())), - Variable("x")), - Constant(7)), - AdditiveIdentity()), - 2), - Variable("y")) +x = Variable("x") +y = Variable("y") +z = Variable("z") -def test_serialise_deserialise(): - print(operation_with_everything._serialise_json()) +operation_with_everything = Div( + Pow( + Mul( + Sub(Add(Neg(Inv(MultiplicativeIdentity())), Ln(Transpose(x))), Log(Constant(7), 2)), + AdditiveIdentity(), + ), + 2, + ), + y, +) + + +@pytest.fixture(params=[Inv, Exp, Ln, Neg, Sin, ArcSin, Cos, ArcCos, Tan, ArcTan, Transpose]) +def unary_operation(request): + return request.param(x) + + +@pytest.fixture(params=[Add, Div, Dot, MatMul, Mul, Sub]) +def binary_operation(request): + return request.param(x, y) + +@pytest.fixture(params=[Log, Pow]) +def log_pow_operation(request): + return request.param(x, 2) + + +def test_serialise_deserialise(): serialised = operation_with_everything.serialise() deserialised = Operation.deserialise(serialised) reserialised = deserialised.serialise() @@ -38,41 +57,195 @@ def test_serialise_deserialise(): assert serialised == reserialised -@pytest.mark.parametrize("op, a, b, result", [ - (Add, 1, 1, 2), - (Add, 7, 8, 15), - (Sub, 1, 1, 0), - (Sub, 7, 8, -1), - (Mul, 1, 1, 1), - (Mul, 7, 8, 56), - (Div, 1, 1, 1), - (Div, 7, 8, 7/8), - (Pow, 1, 1, 1), - (Pow, 7, 2, 49)]) +def test_unary_serialise_deserialise(unary_operation): + serialised = unary_operation.serialise() + deserialised = Operation.deserialise(serialised) + reserialised = deserialised.serialise() + + assert serialised == reserialised + + +def test_binary_serialise_deserialise(binary_operation): + serialised = binary_operation.serialise() + deserialised = Operation.deserialise(serialised) + reserialised = deserialised.serialise() + + assert serialised == reserialised + + +def test_log_pow_serialise_deserialise(log_pow_operation): + serialised = log_pow_operation.serialise() + deserialised = Operation.deserialise(serialised) + reserialised = deserialised.serialise() + + assert serialised == reserialised + + +@pytest.mark.parametrize( + "op, summary", + [(AdditiveIdentity, "0 [Add.Id.]"), (MultiplicativeIdentity, "1 [Mul.Id.]"), (Operation, "Operation(\n)")], +) +def test_summary(op, summary): + f = op() + assert f.summary() == summary + + +def test_variable_summary(): + assert x.summary() == "x" + + +def test_unary_summary(unary_operation): + assert unary_operation.summary() == f"{unary_operation.__class__.__name__}(\n x\n)" + + +def test_binary_summary(binary_operation): + assert binary_operation.summary() == f"{binary_operation.__class__.__name__}(\n x\n y\n)" + + +def test_log_pow_summary(log_pow_operation): + assert log_pow_operation.summary() == f"{log_pow_operation.__class__.__name__}(\n x\n 2\n)" + + +@pytest.mark.parametrize("op, result", [(AdditiveIdentity, 0), (MultiplicativeIdentity, 1), (Operation, None)]) +def test_evaluation(op, result): + f = op() + assert f.evaluate({}) == result + + +@pytest.mark.parametrize( + "op, a, result", + [ + (Neg, 1, -1), + (Neg, -7, 7), + (Inv, 2, 0.5), + (Inv, 0.125, 8), + (Exp, 1, math.e), + (Exp, math.log(5.0), pytest.approx(5.0)), + (Ln, np.sqrt(math.e), 0.5), + (Ln, math.e**5, pytest.approx(5.0)), + (Sin, math.pi / 6.0, pytest.approx(0.5)), + (Sin, 0.5 * math.pi, pytest.approx(1.0)), + (Cos, 0.0, pytest.approx(1.0)), + (Cos, math.pi / 3.0, pytest.approx(0.5)), + (Tan, 0.0, pytest.approx(0.0)), + (Tan, 0.25 * math.pi, pytest.approx(1.0)), + (ArcSin, 1.0, 0.5 * math.pi), + (ArcSin, -1.0, -0.5 * math.pi), + (ArcCos, 1.0, 0.0), + (ArcCos, -1.0, math.pi), + (ArcTan, 0.0, 0.0), + (ArcTan, -1.0, -0.25 * math.pi), + ], +) +def test_unary_evaluation(op, a, result): + f = op(Constant(a)) + assert f.evaluate({}) == result + + +@pytest.mark.parametrize( + "op, a, b, result", + [ + (Add, 1, 1, 2), + (Add, 7, 8, 15), + (Sub, 1, 1, 0), + (Sub, 7, 8, -1), + (Mul, 1, 1, 1), + (Mul, 7, 8, 56), + (Div, 1, 1, 1), + (Div, 7, 8, 7.0 / 8.0), + (Dot, [1, 2], [2, 1], 4), + (Dot, [7, 8], [8, 7], 112), + (Pow, 1, 1, 1), + (Pow, 7, 2, 49), + (Log, 100, 10, 2), + (Log, 256, 2, 8), + ], +) def test_binary_evaluation(op, a, b, result): - f = op(Constant(a), b if op == Pow else Constant(b)) + f = op(Constant(a), b if op == Log or op == Pow else Constant(b)) assert f.evaluate({}) == result -x = Variable("x") -y = Variable("y") -z = Variable("z") -@pytest.mark.parametrize("x_over_x", [ - Div(x,x), - Mul(Inv(x), x), - Mul(x, Inv(x)), -]) -def test_dx_over_x_by_dx_should_be_zero(x_over_x): +@pytest.mark.parametrize( + "op, a, b, result", + [ + (MatMul, np.array([[1, 1], [1, 1]]), np.array([[1, 1], [1, 1]]), np.array([[2, 2], [2, 2]])), + (MatMul, np.array([[7, 7], [7, 7]]), np.array([[8, 8], [8, 8]]), np.array([[112, 112], [112, 112]])), + ], +) +def test_matmul_evaluation(op, a, b, result): + f = op(Constant(a), Constant(b)) + assert (f.evaluate({}) == result).all() - dfdx = x_over_x.derivative(x) - print(dfdx.summary()) +@pytest.mark.parametrize( + "op, a, result", + [(Transpose, np.array([[1, 2]]), np.array([[1], [2]])), (Transpose, [[1, 2], [3, 4]], [[1, 3], [2, 4]])], +) +def test_transpose_evaluation(op, a, result): + f = op(Constant(a)) + assert (f.evaluate({}) == result).all() + + +@pytest.mark.parametrize( + "op, result", + [(AdditiveIdentity, AdditiveIdentity()), (MultiplicativeIdentity, AdditiveIdentity()), (Operation, None)], +) +def test_derivative(op, result): + f = op() + assert f.derivative(x, simplify=False) == result + + +@pytest.mark.parametrize( + "op", + [ + (Neg(Neg(x))), + (Inv(Inv(x))), + ], +) +def test_clean_double_applications(op): + assert op._clean() == x + +@pytest.mark.parametrize( + "op", + [ + (Exp(Ln(x))), + (Ln(Exp(x))), + ], +) +def test_clean_exp_ln_functions(op): + assert op._clean() == x + + +@pytest.mark.parametrize( + "op", + [ + (Sin(ArcSin(x))), + (Cos(ArcCos(x))), + (Tan(ArcTan(x))), + (ArcSin(Sin(x))), + (ArcCos(Cos(x))), + (ArcTan(Tan(x))), + ], +) +def test_clean_trig_functions(op): + assert op._clean() == x + + +@pytest.mark.parametrize( + "x_over_x", + [ + Div(x, x), + Mul(Inv(x), x), + Mul(x, Inv(x)), + ], +) +def test_dx_over_x_by_dx_should_be_zero(x_over_x): + dfdx = x_over_x.derivative(x) assert dfdx == AdditiveIdentity() def test_d_xyz_by_components_should_be_1(): f = Mul(Mul(x, y), z) assert f.derivative(x).derivative(y).derivative(z) == MultiplicativeIdentity() - - diff --git a/test/quantities/utest_quantities.py b/test/quantities/utest_quantities.py index fed48f808..3ac18282d 100644 --- a/test/quantities/utest_quantities.py +++ b/test/quantities/utest_quantities.py @@ -83,7 +83,7 @@ def test_good_non_integer_unit_powers(unit_in, power, unit_out): def test_bad_non_integer_unit_powers(unit, power): """ Check that we get an error if we try and do something silly with powers""" with pytest.raises(units.DimensionError): - unit**power + x = unit**power @pytest.mark.parametrize("unit_1", si.all_si) @@ -122,7 +122,7 @@ def test_conversion_errors(unit_1, unit_2): else: with pytest.raises(UnitError): - Quantity(1, units.seconds).in_units_of(units.meters) + Quantity(1, unit_1).in_units_of(unit_2) @pytest.mark.quantity @@ -131,11 +131,3 @@ def test_equality(): assert Quantity(1.0, units.angstroms) == Quantity(0.1, units.nanometers) assert Quantity(1.0, units.angstroms) != Quantity(0.1, units.angstroms) assert Quantity(1.0, units.angstroms) == Quantity(1.0e-10, units.meters) - -@pytest.mark.quantity -def test_explicit_format(): - value = Quantity(1.0, units.electronvolts) - assert value.explicitly_formatted("J") == "1.602176634e-19 J" - assert value.explicitly_formatted("N m") == "1.602176634e-19 N m" - assert value.explicitly_formatted("m N") == "1.602176634e-19 m N" - assert value.explicitly_formatted("m kilogram m / hour / year") == "1.8201532008477443e-08 m kilogram m / hour / year" diff --git a/test/quantities/utest_quantity_error.py b/test/quantities/utest_quantity_error.py index ce8be4cee..e8e55337d 100644 --- a/test/quantities/utest_quantity_error.py +++ b/test/quantities/utest_quantity_error.py @@ -20,7 +20,6 @@ def test_addition_propagation(x_err, y_err, x_units, y_units): _, err = (x + y).in_si_with_standard_error() assert err == pytest.approx(expected_err, abs=1e-8) - @pytest.mark.parametrize("x_val, y_val, x_units, y_units", [(1, 1, units.meters, units.meters), (1, 1, units.centimeters, units.centimeters), diff --git a/test/quantities/utest_units.py b/test/quantities/utest_units.py index 3bc775313..258143e2a 100644 --- a/test/quantities/utest_units.py +++ b/test/quantities/utest_units.py @@ -1,5 +1,3 @@ -import math - import sasdata.quantities.units as units from sasdata.quantities.units import Unit @@ -11,7 +9,7 @@ def __init__(self, test_name: str, *units): def run_test(self): for i, unit_1 in enumerate(self.units): - for unit_2 in self.units[i + 1 :]: + for unit_2 in self.units[i+1:]: assert unit_1.equivalent(unit_2), "Units should be equivalent" assert unit_1 == unit_2, "Units should be equal" @@ -23,22 +21,11 @@ def __init__(self, test_name: str, *units): def run_test(self): for i, unit_1 in enumerate(self.units): - for unit_2 in self.units[i + 1 :]: + for unit_2 in self.units[i+1:]: assert unit_1.equivalent(unit_2), "Units should be equivalent" assert unit_1 != unit_2, "Units should not be equal" -class DissimilarUnits: - def __init__(self, test_name: str, *units): - self.test_name = "Dissimilar: " + test_name - self.units: list[Unit] = list(units) - - def run_test(self): - for i, unit_1 in enumerate(self.units): - for unit_2 in self.units[i + 1 :]: - assert not unit_1.equivalent(unit_2), "Units should not be equivalent" - - tests = [ EqualUnits("Pressure", @@ -49,19 +36,7 @@ def run_test(self): EqualUnits("Resistance", units.ohms, units.volts / units.amperes, - 1e-3/units.millisiemens), - - EquivalentButUnequalUnits("Angular frequency", - units.rotations / units.minutes, - units.degrees * units.hertz), - - EqualUnits("Angular frequency", - (units.rotations/units.minutes ), - (units.radians*units.hertz) * 2 * math.pi/60.0), - - DissimilarUnits("Frequency and Angular frequency", - (units.rotations/units.minutes), - (units.hertz)), + 1e-3/units.millisiemens) ] diff --git a/test/sasdataloader/data/1_33_1640_22.874115.csv b/test/sasdataloader/data/1_33_1640_22.874115.csv index 92b38bcf5..160f11da2 100644 --- a/test/sasdataloader/data/1_33_1640_22.874115.csv +++ b/test/sasdataloader/data/1_33_1640_22.874115.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 5.247581629999999677e+03 5.122294999999999732e+01 -3.090999999999999998e-02 3.911350339999999960e+03 4.422301999999999822e+01 -3.452999999999999819e-02 2.897911560000000009e+03 3.806515000000000271e+01 -3.812999999999999723e-02 2.151411560000000009e+03 3.279795000000000016e+01 -4.173999999999999932e-02 1.629610879999999952e+03 2.854479999999999862e+01 -4.542999999999999816e-02 1.229812930000000051e+03 2.479730999999999952e+01 -4.646000000000000130e-02 1.191418850000000020e+03 2.440716000000000108e+01 -4.909000000000000169e-02 9.198557799999999816e+02 2.144593000000000060e+01 -5.254999999999999949e-02 7.981839199999999437e+02 1.997728999999999999e+01 -5.270999999999999991e-02 7.205761899999999969e+02 1.898125999999999891e+01 -5.630999999999999894e-02 5.509914999999999736e+02 1.659806000000000026e+01 -5.870999999999999830e-02 5.012570499999999925e+02 1.583125000000000071e+01 -5.988000000000000267e-02 4.332142900000000054e+02 1.471757999999999988e+01 -6.353999999999999926e-02 3.420333299999999781e+02 1.307732999999999990e+01 -6.482999999999999874e-02 3.398080699999999865e+02 1.303472000000000008e+01 -6.716999999999999360e-02 2.726683699999999817e+02 1.167622000000000071e+01 -7.073000000000000120e-02 2.204248299999999858e+02 1.049821000000000026e+01 -7.095999999999999530e-02 2.235476199999999949e+02 1.057230999999999987e+01 -7.434999999999999942e-02 1.760958799999999940e+02 9.383390000000000342e+00 -7.724000000000000310e-02 1.542382200000000125e+02 8.781750000000000611e+00 -7.799999999999999989e-02 1.457825499999999863e+02 8.537639999999999674e+00 -8.164000000000000423e-02 1.201677600000000012e+02 7.751380000000000159e+00 -8.346000000000000640e-02 1.089934400000000068e+02 7.382189999999999586e+00 -8.525000000000000633e-02 9.836262000000000683e+01 7.012940000000000396e+00 -8.881999999999999618e-02 8.192439000000000249e+01 6.400170000000000137e+00 -8.962000000000000521e-02 7.733648999999999774e+01 6.218379999999999797e+00 -9.572999999999999565e-02 5.882012000000000285e+01 5.423099999999999810e+00 -1.018000000000000016e-01 4.406902000000000186e+01 4.694090000000000096e+00 -1.080300000000000010e-01 3.487624000000000279e+01 4.175900000000000389e+00 -1.141999999999999960e-01 2.769241999999999848e+01 3.721049999999999969e+00 -1.202399999999999997e-01 2.227824000000000026e+01 3.337530000000000108e+00 -1.263900000000000023e-01 1.858717000000000041e+01 3.048540000000000028e+00 -1.325999999999999956e-01 1.587791999999999959e+01 2.817619999999999791e+00 -1.388199999999999990e-01 1.416899000000000086e+01 2.661669999999999980e+00 -1.449499999999999955e-01 1.174597999999999942e+01 2.423430000000000195e+00 -1.509900000000000131e-01 1.047161000000000008e+01 2.288190000000000168e+00 -1.571599999999999941e-01 9.681599999999999540e+00 2.200180000000000025e+00 -1.633799999999999975e-01 8.894579999999999487e+00 2.108859999999999957e+00 -1.695599999999999885e-01 8.317479999999999762e+00 2.039299999999999891e+00 -1.756800000000000028e-01 7.913870000000000182e+00 1.989200000000000079e+00 -1.818599999999999939e-01 7.771530000000000271e+00 1.971230000000000038e+00 -1.880699999999999872e-01 7.882909999999999862e+00 1.985309999999999908e+00 -1.941799999999999915e-01 7.707720000000000127e+00 1.963130000000000042e+00 -2.002800000000000136e-01 7.676859999999999573e+00 1.959189999999999987e+00 -2.064199999999999924e-01 7.872259999999999813e+00 1.983970000000000011e+00 -2.126000000000000112e-01 7.870400000000000063e+00 1.983729999999999993e+00 -2.187500000000000000e-01 7.977940000000000254e+00 1.997239999999999904e+00 -2.248699999999999866e-01 8.152039999999999509e+00 2.018920000000000048e+00 -2.310500000000000054e-01 8.298420000000000130e+00 2.036960000000000104e+00 -2.372700000000000087e-01 8.716689999999999827e+00 2.087660000000000071e+00 -2.434399999999999897e-01 8.782600000000000406e+00 2.095540000000000180e+00 -2.495600000000000041e-01 8.933479999999999421e+00 2.113469999999999960e+00 -2.556899999999999729e-01 9.374109999999999943e+00 2.164960000000000218e+00 -2.618500000000000272e-01 9.457430000000000447e+00 2.174560000000000048e+00 -2.680500000000000105e-01 9.702469999999999928e+00 2.202550000000000008e+00 -2.742100000000000093e-01 9.923930000000000362e+00 2.227549999999999919e+00 -2.802999999999999936e-01 1.008966000000000030e+01 2.246070000000000011e+00 -2.864599999999999924e-01 1.031367999999999974e+01 2.270869999999999944e+00 -2.926699999999999857e-01 1.058960000000000079e+01 2.301039999999999974e+00 +2.732000000000000053e-02 5.247581629999999677e+03 5.122294999999999732e+01 +3.090999999999999998e-02 3.911350339999999960e+03 4.422301999999999822e+01 +3.452999999999999819e-02 2.897911560000000009e+03 3.806515000000000271e+01 +3.812999999999999723e-02 2.151411560000000009e+03 3.279795000000000016e+01 +4.173999999999999932e-02 1.629610879999999952e+03 2.854479999999999862e+01 +4.542999999999999816e-02 1.229812930000000051e+03 2.479730999999999952e+01 +4.646000000000000130e-02 1.191418850000000020e+03 2.440716000000000108e+01 +4.909000000000000169e-02 9.198557799999999816e+02 2.144593000000000060e+01 +5.254999999999999949e-02 7.981839199999999437e+02 1.997728999999999999e+01 +5.270999999999999991e-02 7.205761899999999969e+02 1.898125999999999891e+01 +5.630999999999999894e-02 5.509914999999999736e+02 1.659806000000000026e+01 +5.870999999999999830e-02 5.012570499999999925e+02 1.583125000000000071e+01 +5.988000000000000267e-02 4.332142900000000054e+02 1.471757999999999988e+01 +6.353999999999999926e-02 3.420333299999999781e+02 1.307732999999999990e+01 +6.482999999999999874e-02 3.398080699999999865e+02 1.303472000000000008e+01 +6.716999999999999360e-02 2.726683699999999817e+02 1.167622000000000071e+01 +7.073000000000000120e-02 2.204248299999999858e+02 1.049821000000000026e+01 +7.095999999999999530e-02 2.235476199999999949e+02 1.057230999999999987e+01 +7.434999999999999942e-02 1.760958799999999940e+02 9.383390000000000342e+00 +7.724000000000000310e-02 1.542382200000000125e+02 8.781750000000000611e+00 +7.799999999999999989e-02 1.457825499999999863e+02 8.537639999999999674e+00 +8.164000000000000423e-02 1.201677600000000012e+02 7.751380000000000159e+00 +8.346000000000000640e-02 1.089934400000000068e+02 7.382189999999999586e+00 +8.525000000000000633e-02 9.836262000000000683e+01 7.012940000000000396e+00 +8.881999999999999618e-02 8.192439000000000249e+01 6.400170000000000137e+00 +8.962000000000000521e-02 7.733648999999999774e+01 6.218379999999999797e+00 +9.572999999999999565e-02 5.882012000000000285e+01 5.423099999999999810e+00 +1.018000000000000016e-01 4.406902000000000186e+01 4.694090000000000096e+00 +1.080300000000000010e-01 3.487624000000000279e+01 4.175900000000000389e+00 +1.141999999999999960e-01 2.769241999999999848e+01 3.721049999999999969e+00 +1.202399999999999997e-01 2.227824000000000026e+01 3.337530000000000108e+00 +1.263900000000000023e-01 1.858717000000000041e+01 3.048540000000000028e+00 +1.325999999999999956e-01 1.587791999999999959e+01 2.817619999999999791e+00 +1.388199999999999990e-01 1.416899000000000086e+01 2.661669999999999980e+00 +1.449499999999999955e-01 1.174597999999999942e+01 2.423430000000000195e+00 +1.509900000000000131e-01 1.047161000000000008e+01 2.288190000000000168e+00 +1.571599999999999941e-01 9.681599999999999540e+00 2.200180000000000025e+00 +1.633799999999999975e-01 8.894579999999999487e+00 2.108859999999999957e+00 +1.695599999999999885e-01 8.317479999999999762e+00 2.039299999999999891e+00 +1.756800000000000028e-01 7.913870000000000182e+00 1.989200000000000079e+00 +1.818599999999999939e-01 7.771530000000000271e+00 1.971230000000000038e+00 +1.880699999999999872e-01 7.882909999999999862e+00 1.985309999999999908e+00 +1.941799999999999915e-01 7.707720000000000127e+00 1.963130000000000042e+00 +2.002800000000000136e-01 7.676859999999999573e+00 1.959189999999999987e+00 +2.064199999999999924e-01 7.872259999999999813e+00 1.983970000000000011e+00 +2.126000000000000112e-01 7.870400000000000063e+00 1.983729999999999993e+00 +2.187500000000000000e-01 7.977940000000000254e+00 1.997239999999999904e+00 +2.248699999999999866e-01 8.152039999999999509e+00 2.018920000000000048e+00 +2.310500000000000054e-01 8.298420000000000130e+00 2.036960000000000104e+00 +2.372700000000000087e-01 8.716689999999999827e+00 2.087660000000000071e+00 +2.434399999999999897e-01 8.782600000000000406e+00 2.095540000000000180e+00 +2.495600000000000041e-01 8.933479999999999421e+00 2.113469999999999960e+00 +2.556899999999999729e-01 9.374109999999999943e+00 2.164960000000000218e+00 +2.618500000000000272e-01 9.457430000000000447e+00 2.174560000000000048e+00 +2.680500000000000105e-01 9.702469999999999928e+00 2.202550000000000008e+00 +2.742100000000000093e-01 9.923930000000000362e+00 2.227549999999999919e+00 +2.802999999999999936e-01 1.008966000000000030e+01 2.246070000000000011e+00 +2.864599999999999924e-01 1.031367999999999974e+01 2.270869999999999944e+00 +2.926699999999999857e-01 1.058960000000000079e+01 2.301039999999999974e+00 2.988199999999999745e-01 1.062256999999999962e+01 2.304619999999999891e+00 \ No newline at end of file diff --git a/test/sasdataloader/data/2_42_1640_23.456895.csv b/test/sasdataloader/data/2_42_1640_23.456895.csv index 831fa6a9d..80562dff5 100644 --- a/test/sasdataloader/data/2_42_1640_23.456895.csv +++ b/test/sasdataloader/data/2_42_1640_23.456895.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 3.883615650000000187e+03 4.406595000000000084e+01 -3.090000000000000038e-02 3.072013609999999971e+03 3.919192000000000320e+01 -3.452999999999999819e-02 2.355659860000000208e+03 3.431953000000000031e+01 -3.812999999999999723e-02 1.806985030000000052e+03 3.005815000000000126e+01 -4.173999999999999932e-02 1.389839799999999968e+03 2.636132999999999882e+01 -4.542000000000000204e-02 1.072684349999999995e+03 2.315906000000000020e+01 -4.644000000000000211e-02 9.624380499999999756e+02 2.193669999999999831e+01 -4.907999999999999863e-02 8.065360500000000457e+02 2.008153000000000077e+01 -5.253000000000000030e-02 6.666923000000000457e+02 1.825777000000000072e+01 -5.270999999999999991e-02 6.432540800000000445e+02 1.793395999999999901e+01 -5.630000000000000282e-02 4.985809499999999730e+02 1.578894000000000020e+01 -5.868999999999999911e-02 4.290448299999999904e+02 1.464658000000000015e+01 -5.986999999999999961e-02 3.918163299999999936e+02 1.399671999999999983e+01 -6.353000000000000314e-02 3.098850299999999720e+02 1.244758999999999993e+01 -6.481000000000000649e-02 2.946982499999999732e+02 1.213874000000000031e+01 -6.715999999999999748e-02 2.516384400000000028e+02 1.121692000000000000e+01 -7.072000000000000508e-02 2.028407500000000141e+02 1.007076999999999956e+01 -7.094000000000000306e-02 1.948358800000000031e+02 9.870050000000000878e+00 -7.434000000000000330e-02 1.633427599999999984e+02 9.037219999999999587e+00 -7.721000000000000085e-02 1.371933899999999937e+02 8.282310000000000727e+00 -7.799000000000000377e-02 1.347819700000000012e+02 8.209199999999999164e+00 -8.162999999999999423e-02 1.123165999999999940e+02 7.493879999999999875e+00 -8.343000000000000416e-02 9.602442000000000633e+01 6.929079999999999906e+00 -8.523999999999999633e-02 9.249591999999999814e+01 6.800589999999999691e+00 -8.880000000000000393e-02 7.934887999999999408e+01 6.298759999999999692e+00 -8.959000000000000297e-02 7.016214999999999691e+01 5.922930000000000028e+00 -9.568999999999999728e-02 5.357988000000000284e+01 5.175900000000000389e+00 -1.017699999999999994e-01 4.050641000000000247e+01 4.500359999999999694e+00 -1.079900000000000027e-01 3.194395000000000095e+01 3.996500000000000163e+00 -1.141599999999999976e-01 2.563089000000000084e+01 3.579870000000000108e+00 -1.202000000000000013e-01 2.144641999999999982e+01 3.274630000000000152e+00 -1.263499999999999901e-01 1.696240999999999843e+01 2.912249999999999783e+00 -1.325600000000000112e-01 1.453672000000000075e+01 2.695990000000000109e+00 -1.387700000000000045e-01 1.265718999999999994e+01 2.515670000000000073e+00 -1.449000000000000010e-01 1.114897000000000027e+01 2.361029999999999962e+00 -1.509399999999999908e-01 1.005156999999999989e+01 2.241830000000000211e+00 -1.571099999999999997e-01 9.313710000000000377e+00 2.157970000000000166e+00 -1.633300000000000030e-01 8.668530000000000513e+00 2.081890000000000018e+00 -1.695099999999999940e-01 7.810069999999999624e+00 1.976120000000000099e+00 -1.756300000000000083e-01 7.695079999999999920e+00 1.961519999999999930e+00 -1.817999999999999894e-01 7.222220000000000084e+00 1.900290000000000035e+00 -1.880100000000000104e-01 7.386999999999999567e+00 1.921850000000000058e+00 -1.941199999999999870e-01 7.239320000000000199e+00 1.902539999999999898e+00 -2.002200000000000091e-01 7.279099999999999682e+00 1.907759999999999900e+00 -2.063500000000000056e-01 7.406340000000000146e+00 1.924360000000000070e+00 -2.125299999999999967e-01 7.439199999999999591e+00 1.928630000000000067e+00 -2.186800000000000133e-01 7.556879999999999598e+00 1.943820000000000103e+00 -2.247899999999999898e-01 7.730520000000000280e+00 1.966029999999999944e+00 -2.309799999999999909e-01 8.106099999999999639e+00 2.013220000000000010e+00 -2.371999999999999942e-01 8.398609999999999687e+00 2.049220000000000041e+00 -2.433599999999999930e-01 8.171440000000000481e+00 2.021319999999999784e+00 -2.494800000000000073e-01 8.478289999999999438e+00 2.058920000000000083e+00 -2.556100000000000039e-01 8.796279999999999433e+00 2.097170000000000201e+00 -2.617700000000000027e-01 8.973420000000000840e+00 2.118189999999999795e+00 -2.679699999999999860e-01 9.270730000000000359e+00 2.152989999999999959e+00 -2.741299999999999848e-01 9.463879999999999626e+00 2.175300000000000011e+00 -2.802100000000000146e-01 9.409150000000000347e+00 2.169000000000000039e+00 -2.863700000000000134e-01 9.709509999999999863e+00 2.203349999999999920e+00 -2.925800000000000067e-01 9.851300000000000168e+00 2.219380000000000130e+00 +2.732000000000000053e-02 3.883615650000000187e+03 4.406595000000000084e+01 +3.090000000000000038e-02 3.072013609999999971e+03 3.919192000000000320e+01 +3.452999999999999819e-02 2.355659860000000208e+03 3.431953000000000031e+01 +3.812999999999999723e-02 1.806985030000000052e+03 3.005815000000000126e+01 +4.173999999999999932e-02 1.389839799999999968e+03 2.636132999999999882e+01 +4.542000000000000204e-02 1.072684349999999995e+03 2.315906000000000020e+01 +4.644000000000000211e-02 9.624380499999999756e+02 2.193669999999999831e+01 +4.907999999999999863e-02 8.065360500000000457e+02 2.008153000000000077e+01 +5.253000000000000030e-02 6.666923000000000457e+02 1.825777000000000072e+01 +5.270999999999999991e-02 6.432540800000000445e+02 1.793395999999999901e+01 +5.630000000000000282e-02 4.985809499999999730e+02 1.578894000000000020e+01 +5.868999999999999911e-02 4.290448299999999904e+02 1.464658000000000015e+01 +5.986999999999999961e-02 3.918163299999999936e+02 1.399671999999999983e+01 +6.353000000000000314e-02 3.098850299999999720e+02 1.244758999999999993e+01 +6.481000000000000649e-02 2.946982499999999732e+02 1.213874000000000031e+01 +6.715999999999999748e-02 2.516384400000000028e+02 1.121692000000000000e+01 +7.072000000000000508e-02 2.028407500000000141e+02 1.007076999999999956e+01 +7.094000000000000306e-02 1.948358800000000031e+02 9.870050000000000878e+00 +7.434000000000000330e-02 1.633427599999999984e+02 9.037219999999999587e+00 +7.721000000000000085e-02 1.371933899999999937e+02 8.282310000000000727e+00 +7.799000000000000377e-02 1.347819700000000012e+02 8.209199999999999164e+00 +8.162999999999999423e-02 1.123165999999999940e+02 7.493879999999999875e+00 +8.343000000000000416e-02 9.602442000000000633e+01 6.929079999999999906e+00 +8.523999999999999633e-02 9.249591999999999814e+01 6.800589999999999691e+00 +8.880000000000000393e-02 7.934887999999999408e+01 6.298759999999999692e+00 +8.959000000000000297e-02 7.016214999999999691e+01 5.922930000000000028e+00 +9.568999999999999728e-02 5.357988000000000284e+01 5.175900000000000389e+00 +1.017699999999999994e-01 4.050641000000000247e+01 4.500359999999999694e+00 +1.079900000000000027e-01 3.194395000000000095e+01 3.996500000000000163e+00 +1.141599999999999976e-01 2.563089000000000084e+01 3.579870000000000108e+00 +1.202000000000000013e-01 2.144641999999999982e+01 3.274630000000000152e+00 +1.263499999999999901e-01 1.696240999999999843e+01 2.912249999999999783e+00 +1.325600000000000112e-01 1.453672000000000075e+01 2.695990000000000109e+00 +1.387700000000000045e-01 1.265718999999999994e+01 2.515670000000000073e+00 +1.449000000000000010e-01 1.114897000000000027e+01 2.361029999999999962e+00 +1.509399999999999908e-01 1.005156999999999989e+01 2.241830000000000211e+00 +1.571099999999999997e-01 9.313710000000000377e+00 2.157970000000000166e+00 +1.633300000000000030e-01 8.668530000000000513e+00 2.081890000000000018e+00 +1.695099999999999940e-01 7.810069999999999624e+00 1.976120000000000099e+00 +1.756300000000000083e-01 7.695079999999999920e+00 1.961519999999999930e+00 +1.817999999999999894e-01 7.222220000000000084e+00 1.900290000000000035e+00 +1.880100000000000104e-01 7.386999999999999567e+00 1.921850000000000058e+00 +1.941199999999999870e-01 7.239320000000000199e+00 1.902539999999999898e+00 +2.002200000000000091e-01 7.279099999999999682e+00 1.907759999999999900e+00 +2.063500000000000056e-01 7.406340000000000146e+00 1.924360000000000070e+00 +2.125299999999999967e-01 7.439199999999999591e+00 1.928630000000000067e+00 +2.186800000000000133e-01 7.556879999999999598e+00 1.943820000000000103e+00 +2.247899999999999898e-01 7.730520000000000280e+00 1.966029999999999944e+00 +2.309799999999999909e-01 8.106099999999999639e+00 2.013220000000000010e+00 +2.371999999999999942e-01 8.398609999999999687e+00 2.049220000000000041e+00 +2.433599999999999930e-01 8.171440000000000481e+00 2.021319999999999784e+00 +2.494800000000000073e-01 8.478289999999999438e+00 2.058920000000000083e+00 +2.556100000000000039e-01 8.796279999999999433e+00 2.097170000000000201e+00 +2.617700000000000027e-01 8.973420000000000840e+00 2.118189999999999795e+00 +2.679699999999999860e-01 9.270730000000000359e+00 2.152989999999999959e+00 +2.741299999999999848e-01 9.463879999999999626e+00 2.175300000000000011e+00 +2.802100000000000146e-01 9.409150000000000347e+00 2.169000000000000039e+00 +2.863700000000000134e-01 9.709509999999999863e+00 2.203349999999999920e+00 +2.925800000000000067e-01 9.851300000000000168e+00 2.219380000000000130e+00 2.987299999999999955e-01 9.904920000000000613e+00 2.225410000000000110e+00 \ No newline at end of file diff --git a/test/sasdataloader/data/3_61_1640_23.748285.csv b/test/sasdataloader/data/3_61_1640_23.748285.csv index 59e4cde42..6e68726d8 100644 --- a/test/sasdataloader/data/3_61_1640_23.748285.csv +++ b/test/sasdataloader/data/3_61_1640_23.748285.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 2.792353740000000016e+03 3.736545000000000272e+01 -3.090000000000000038e-02 2.271702040000000125e+03 3.370239000000000118e+01 -3.452000000000000207e-02 1.788897279999999910e+03 2.990733000000000175e+01 -3.812000000000000111e-02 1.407023470000000088e+03 2.652380000000000138e+01 -4.173000000000000320e-02 1.095009520000000066e+03 2.339882000000000062e+01 -4.542000000000000204e-02 8.376734699999999521e+02 2.046549999999999869e+01 -4.644000000000000211e-02 7.836296200000000454e+02 1.979430999999999941e+01 -4.907000000000000250e-02 6.414952399999999670e+02 1.790943000000000040e+01 -5.253000000000000030e-02 5.516777200000000221e+02 1.660839999999999961e+01 -5.269999999999999685e-02 5.141714299999999866e+02 1.603388999999999953e+01 -5.628999999999999976e-02 3.988418399999999906e+02 1.412165000000000070e+01 -5.868999999999999911e-02 3.579082799999999907e+02 1.337737000000000087e+01 -5.985999999999999654e-02 3.164397999999999911e+02 1.257854999999999990e+01 -6.351999999999999313e-02 2.486343500000000120e+02 1.114976000000000056e+01 -6.481000000000000649e-02 2.482066299999999899e+02 1.114016999999999946e+01 -6.715000000000000135e-02 2.006787799999999891e+02 1.001695999999999920e+01 -7.070999999999999508e-02 1.657927200000000028e+02 9.104739999999999611e+00 -7.094000000000000306e-02 1.667760000000000105e+02 9.131700000000000372e+00 -7.431999999999999718e-02 1.326982299999999952e+02 8.145500000000000185e+00 -7.721000000000000085e-02 1.181177100000000024e+02 7.684980000000000366e+00 -7.796999999999999764e-02 1.108474499999999949e+02 7.444709999999999717e+00 -8.161999999999999811e-02 9.087302999999999997e+01 6.740660000000000096e+00 -8.343000000000000416e-02 8.290343000000000018e+01 6.438299999999999912e+00 -8.522000000000000408e-02 7.588799000000000206e+01 6.159869999999999735e+00 -8.878999999999999393e-02 6.486343999999999710e+01 5.694890000000000008e+00 -8.959000000000000297e-02 6.133471999999999724e+01 5.537810000000000343e+00 -9.568999999999999728e-02 4.711737999999999715e+01 4.853729999999999656e+00 -1.017699999999999994e-01 3.554666000000000281e+01 4.215840000000000032e+00 -1.079900000000000027e-01 2.833098000000000027e+01 3.763710000000000111e+00 -1.141599999999999976e-01 2.318925000000000125e+01 3.405089999999999950e+00 -1.202000000000000013e-01 1.876435000000000031e+01 3.063029999999999919e+00 -1.263499999999999901e-01 1.568601999999999919e+01 2.800539999999999807e+00 -1.325600000000000112e-01 1.346410000000000018e+01 2.594619999999999926e+00 -1.387700000000000045e-01 1.173840000000000039e+01 2.422639999999999905e+00 -1.449000000000000010e-01 1.054757999999999996e+01 2.296469999999999789e+00 -1.509399999999999908e-01 9.084839999999999804e+00 2.131299999999999972e+00 -1.571099999999999997e-01 8.239589999999999748e+00 2.029729999999999812e+00 -1.633300000000000030e-01 7.767660000000000231e+00 1.970739999999999936e+00 -1.695099999999999940e-01 7.631929999999999659e+00 1.953449999999999909e+00 -1.756300000000000083e-01 7.253739999999999633e+00 1.904430000000000067e+00 -1.817999999999999894e-01 6.968580000000000219e+00 1.866630000000000011e+00 -1.880100000000000104e-01 7.029829999999999579e+00 1.874810000000000088e+00 -1.941199999999999870e-01 6.805609999999999715e+00 1.844670000000000032e+00 -2.002200000000000091e-01 7.007130000000000081e+00 1.871779999999999999e+00 -2.063500000000000056e-01 7.083709999999999951e+00 1.881979999999999986e+00 -2.125299999999999967e-01 6.971890000000000143e+00 1.867070000000000007e+00 -2.186800000000000133e-01 7.549360000000000070e+00 1.942849999999999966e+00 -2.247899999999999898e-01 7.451310000000000322e+00 1.930199999999999916e+00 -2.309799999999999909e-01 7.449589999999999712e+00 1.929969999999999963e+00 -2.371999999999999942e-01 7.776720000000000077e+00 1.971889999999999921e+00 -2.433599999999999930e-01 8.157130000000000436e+00 2.019550000000000178e+00 -2.494800000000000073e-01 8.339280000000000470e+00 2.041970000000000063e+00 -2.556100000000000039e-01 8.448100000000000165e+00 2.055250000000000021e+00 -2.617700000000000027e-01 8.746420000000000528e+00 2.091219999999999857e+00 -2.679699999999999860e-01 9.040720000000000312e+00 2.126110000000000166e+00 -2.741299999999999848e-01 9.130409999999999471e+00 2.136629999999999807e+00 -2.802100000000000146e-01 9.247719999999999274e+00 2.150319999999999787e+00 -2.863700000000000134e-01 9.291150000000000020e+00 2.155359999999999943e+00 -2.925800000000000067e-01 9.640140000000000597e+00 2.195469999999999811e+00 +2.732000000000000053e-02 2.792353740000000016e+03 3.736545000000000272e+01 +3.090000000000000038e-02 2.271702040000000125e+03 3.370239000000000118e+01 +3.452000000000000207e-02 1.788897279999999910e+03 2.990733000000000175e+01 +3.812000000000000111e-02 1.407023470000000088e+03 2.652380000000000138e+01 +4.173000000000000320e-02 1.095009520000000066e+03 2.339882000000000062e+01 +4.542000000000000204e-02 8.376734699999999521e+02 2.046549999999999869e+01 +4.644000000000000211e-02 7.836296200000000454e+02 1.979430999999999941e+01 +4.907000000000000250e-02 6.414952399999999670e+02 1.790943000000000040e+01 +5.253000000000000030e-02 5.516777200000000221e+02 1.660839999999999961e+01 +5.269999999999999685e-02 5.141714299999999866e+02 1.603388999999999953e+01 +5.628999999999999976e-02 3.988418399999999906e+02 1.412165000000000070e+01 +5.868999999999999911e-02 3.579082799999999907e+02 1.337737000000000087e+01 +5.985999999999999654e-02 3.164397999999999911e+02 1.257854999999999990e+01 +6.351999999999999313e-02 2.486343500000000120e+02 1.114976000000000056e+01 +6.481000000000000649e-02 2.482066299999999899e+02 1.114016999999999946e+01 +6.715000000000000135e-02 2.006787799999999891e+02 1.001695999999999920e+01 +7.070999999999999508e-02 1.657927200000000028e+02 9.104739999999999611e+00 +7.094000000000000306e-02 1.667760000000000105e+02 9.131700000000000372e+00 +7.431999999999999718e-02 1.326982299999999952e+02 8.145500000000000185e+00 +7.721000000000000085e-02 1.181177100000000024e+02 7.684980000000000366e+00 +7.796999999999999764e-02 1.108474499999999949e+02 7.444709999999999717e+00 +8.161999999999999811e-02 9.087302999999999997e+01 6.740660000000000096e+00 +8.343000000000000416e-02 8.290343000000000018e+01 6.438299999999999912e+00 +8.522000000000000408e-02 7.588799000000000206e+01 6.159869999999999735e+00 +8.878999999999999393e-02 6.486343999999999710e+01 5.694890000000000008e+00 +8.959000000000000297e-02 6.133471999999999724e+01 5.537810000000000343e+00 +9.568999999999999728e-02 4.711737999999999715e+01 4.853729999999999656e+00 +1.017699999999999994e-01 3.554666000000000281e+01 4.215840000000000032e+00 +1.079900000000000027e-01 2.833098000000000027e+01 3.763710000000000111e+00 +1.141599999999999976e-01 2.318925000000000125e+01 3.405089999999999950e+00 +1.202000000000000013e-01 1.876435000000000031e+01 3.063029999999999919e+00 +1.263499999999999901e-01 1.568601999999999919e+01 2.800539999999999807e+00 +1.325600000000000112e-01 1.346410000000000018e+01 2.594619999999999926e+00 +1.387700000000000045e-01 1.173840000000000039e+01 2.422639999999999905e+00 +1.449000000000000010e-01 1.054757999999999996e+01 2.296469999999999789e+00 +1.509399999999999908e-01 9.084839999999999804e+00 2.131299999999999972e+00 +1.571099999999999997e-01 8.239589999999999748e+00 2.029729999999999812e+00 +1.633300000000000030e-01 7.767660000000000231e+00 1.970739999999999936e+00 +1.695099999999999940e-01 7.631929999999999659e+00 1.953449999999999909e+00 +1.756300000000000083e-01 7.253739999999999633e+00 1.904430000000000067e+00 +1.817999999999999894e-01 6.968580000000000219e+00 1.866630000000000011e+00 +1.880100000000000104e-01 7.029829999999999579e+00 1.874810000000000088e+00 +1.941199999999999870e-01 6.805609999999999715e+00 1.844670000000000032e+00 +2.002200000000000091e-01 7.007130000000000081e+00 1.871779999999999999e+00 +2.063500000000000056e-01 7.083709999999999951e+00 1.881979999999999986e+00 +2.125299999999999967e-01 6.971890000000000143e+00 1.867070000000000007e+00 +2.186800000000000133e-01 7.549360000000000070e+00 1.942849999999999966e+00 +2.247899999999999898e-01 7.451310000000000322e+00 1.930199999999999916e+00 +2.309799999999999909e-01 7.449589999999999712e+00 1.929969999999999963e+00 +2.371999999999999942e-01 7.776720000000000077e+00 1.971889999999999921e+00 +2.433599999999999930e-01 8.157130000000000436e+00 2.019550000000000178e+00 +2.494800000000000073e-01 8.339280000000000470e+00 2.041970000000000063e+00 +2.556100000000000039e-01 8.448100000000000165e+00 2.055250000000000021e+00 +2.617700000000000027e-01 8.746420000000000528e+00 2.091219999999999857e+00 +2.679699999999999860e-01 9.040720000000000312e+00 2.126110000000000166e+00 +2.741299999999999848e-01 9.130409999999999471e+00 2.136629999999999807e+00 +2.802100000000000146e-01 9.247719999999999274e+00 2.150319999999999787e+00 +2.863700000000000134e-01 9.291150000000000020e+00 2.155359999999999943e+00 +2.925800000000000067e-01 9.640140000000000597e+00 2.195469999999999811e+00 2.987299999999999955e-01 9.537290000000000489e+00 2.183720000000000105e+00 \ No newline at end of file diff --git a/test/sasdataloader/data/4_103_1640_24.039675.csv b/test/sasdataloader/data/4_103_1640_24.039675.csv index daf8f80a8..c33506202 100644 --- a/test/sasdataloader/data/4_103_1640_24.039675.csv +++ b/test/sasdataloader/data/4_103_1640_24.039675.csv @@ -1,60 +1,60 @@ -2.733000000000000013e-02 2.320909860000000208e+03 3.406544999999999845e+01 -3.090999999999999998e-02 1.910828909999999951e+03 3.090978000000000137e+01 -3.454000000000000126e-02 1.519815650000000005e+03 2.756643000000000043e+01 -3.814000000000000029e-02 1.188850680000000011e+03 2.438083999999999918e+01 -4.175000000000000239e-02 9.312768700000000308e+02 2.157865999999999929e+01 -4.544000000000000122e-02 7.201697299999999586e+02 1.897589999999999932e+01 -4.646000000000000130e-02 6.728012599999999566e+02 1.834122999999999948e+01 -4.909999999999999781e-02 5.453608799999999519e+02 1.651304000000000016e+01 -5.256000000000000255e-02 4.724414499999999748e+02 1.536946999999999974e+01 -5.272000000000000297e-02 4.318700699999999983e+02 1.469472999999999985e+01 -5.632000000000000201e-02 3.382353699999999890e+02 1.300453000000000081e+01 -5.870999999999999830e-02 3.073326000000000136e+02 1.239621999999999957e+01 -5.988999999999999879e-02 2.634156100000000151e+02 1.147639999999999993e+01 -6.356000000000000538e-02 2.076918699999999944e+02 1.019048000000000087e+01 -6.483999999999999486e-02 2.125336499999999944e+02 1.030857999999999919e+01 -6.718999999999999972e-02 1.688028199999999970e+02 9.187020000000000408e+00 -7.073999999999999733e-02 1.362696899999999971e+02 8.254379999999999384e+00 -7.097000000000000530e-02 1.410024300000000039e+02 8.396499999999999631e+00 -7.435999999999999555e-02 1.127603699999999947e+02 7.508670000000000400e+00 -7.724999999999999922e-02 9.965560999999999581e+01 7.058880000000000265e+00 -7.800999999999999601e-02 9.194693999999999789e+01 6.780369999999999564e+00 -8.165999999999999648e-02 7.522768999999999551e+01 6.133009999999999629e+00 -8.347000000000000253e-02 7.049939999999999429e+01 5.937149999999999928e+00 -8.526000000000000245e-02 6.411020000000000607e+01 5.661719999999999864e+00 -8.883000000000000618e-02 5.376234999999999786e+01 5.184709999999999930e+00 -8.963000000000000134e-02 5.217504000000000275e+01 5.107590000000000074e+00 -9.574000000000000565e-02 4.054399999999999693e+01 4.502439999999999998e+00 -1.018199999999999938e-01 3.096013999999999911e+01 3.934470000000000134e+00 -1.080399999999999971e-01 2.426012000000000057e+01 3.482819999999999805e+00 -1.142200000000000021e-01 1.991522000000000148e+01 3.155569999999999986e+00 -1.202600000000000058e-01 1.696463999999999928e+01 2.912440000000000140e+00 -1.264099999999999946e-01 1.406012999999999913e+01 2.651429999999999954e+00 -1.326199999999999879e-01 1.186475000000000080e+01 2.435649999999999871e+00 -1.388300000000000090e-01 1.075843000000000060e+01 2.319310000000000205e+00 -1.449699999999999878e-01 9.447770000000000223e+00 2.173449999999999882e+00 -1.510100000000000053e-01 8.521739999999999426e+00 2.064189999999999969e+00 -1.571799999999999864e-01 7.782460000000000377e+00 1.972620000000000040e+00 -1.634099999999999997e-01 7.576889999999999681e+00 1.946390000000000065e+00 -1.695800000000000085e-01 7.175270000000000259e+00 1.894109999999999960e+00 -1.756999999999999951e-01 6.609770000000000145e+00 1.817930000000000046e+00 -1.818799999999999861e-01 6.690150000000000041e+00 1.828950000000000076e+00 -1.880999999999999894e-01 6.763010000000000410e+00 1.838889999999999914e+00 -1.942000000000000115e-01 6.479930000000000412e+00 1.799989999999999979e+00 -2.003099999999999881e-01 6.931930000000000369e+00 1.861709999999999976e+00 -2.064499999999999946e-01 7.058690000000000353e+00 1.878649999999999931e+00 -2.126300000000000134e-01 6.966739999999999711e+00 1.866379999999999928e+00 -2.187699999999999922e-01 7.155350000000000321e+00 1.891469999999999985e+00 -2.248999999999999888e-01 7.328820000000000334e+00 1.914260000000000073e+00 -2.310800000000000076e-01 7.623789999999999623e+00 1.952409999999999979e+00 -2.373000000000000109e-01 7.870739999999999625e+00 1.983780000000000099e+00 -2.434699999999999920e-01 7.865639999999999965e+00 1.983130000000000059e+00 -2.495900000000000063e-01 8.081390000000000740e+00 2.010149999999999881e+00 -2.557300000000000129e-01 8.480309999999999349e+00 2.059159999999999879e+00 -2.618900000000000117e-01 8.708700000000000330e+00 2.086710000000000065e+00 -2.680899999999999950e-01 8.823320000000000718e+00 2.100389999999999979e+00 -2.742499999999999938e-01 9.030450000000000088e+00 2.124909999999999854e+00 -2.803300000000000236e-01 9.222670000000000812e+00 2.147400000000000198e+00 -2.864999999999999769e-01 9.345430000000000348e+00 2.161649999999999849e+00 -2.927100000000000257e-01 9.660539999999999239e+00 2.197789999999999910e+00 +2.733000000000000013e-02 2.320909860000000208e+03 3.406544999999999845e+01 +3.090999999999999998e-02 1.910828909999999951e+03 3.090978000000000137e+01 +3.454000000000000126e-02 1.519815650000000005e+03 2.756643000000000043e+01 +3.814000000000000029e-02 1.188850680000000011e+03 2.438083999999999918e+01 +4.175000000000000239e-02 9.312768700000000308e+02 2.157865999999999929e+01 +4.544000000000000122e-02 7.201697299999999586e+02 1.897589999999999932e+01 +4.646000000000000130e-02 6.728012599999999566e+02 1.834122999999999948e+01 +4.909999999999999781e-02 5.453608799999999519e+02 1.651304000000000016e+01 +5.256000000000000255e-02 4.724414499999999748e+02 1.536946999999999974e+01 +5.272000000000000297e-02 4.318700699999999983e+02 1.469472999999999985e+01 +5.632000000000000201e-02 3.382353699999999890e+02 1.300453000000000081e+01 +5.870999999999999830e-02 3.073326000000000136e+02 1.239621999999999957e+01 +5.988999999999999879e-02 2.634156100000000151e+02 1.147639999999999993e+01 +6.356000000000000538e-02 2.076918699999999944e+02 1.019048000000000087e+01 +6.483999999999999486e-02 2.125336499999999944e+02 1.030857999999999919e+01 +6.718999999999999972e-02 1.688028199999999970e+02 9.187020000000000408e+00 +7.073999999999999733e-02 1.362696899999999971e+02 8.254379999999999384e+00 +7.097000000000000530e-02 1.410024300000000039e+02 8.396499999999999631e+00 +7.435999999999999555e-02 1.127603699999999947e+02 7.508670000000000400e+00 +7.724999999999999922e-02 9.965560999999999581e+01 7.058880000000000265e+00 +7.800999999999999601e-02 9.194693999999999789e+01 6.780369999999999564e+00 +8.165999999999999648e-02 7.522768999999999551e+01 6.133009999999999629e+00 +8.347000000000000253e-02 7.049939999999999429e+01 5.937149999999999928e+00 +8.526000000000000245e-02 6.411020000000000607e+01 5.661719999999999864e+00 +8.883000000000000618e-02 5.376234999999999786e+01 5.184709999999999930e+00 +8.963000000000000134e-02 5.217504000000000275e+01 5.107590000000000074e+00 +9.574000000000000565e-02 4.054399999999999693e+01 4.502439999999999998e+00 +1.018199999999999938e-01 3.096013999999999911e+01 3.934470000000000134e+00 +1.080399999999999971e-01 2.426012000000000057e+01 3.482819999999999805e+00 +1.142200000000000021e-01 1.991522000000000148e+01 3.155569999999999986e+00 +1.202600000000000058e-01 1.696463999999999928e+01 2.912440000000000140e+00 +1.264099999999999946e-01 1.406012999999999913e+01 2.651429999999999954e+00 +1.326199999999999879e-01 1.186475000000000080e+01 2.435649999999999871e+00 +1.388300000000000090e-01 1.075843000000000060e+01 2.319310000000000205e+00 +1.449699999999999878e-01 9.447770000000000223e+00 2.173449999999999882e+00 +1.510100000000000053e-01 8.521739999999999426e+00 2.064189999999999969e+00 +1.571799999999999864e-01 7.782460000000000377e+00 1.972620000000000040e+00 +1.634099999999999997e-01 7.576889999999999681e+00 1.946390000000000065e+00 +1.695800000000000085e-01 7.175270000000000259e+00 1.894109999999999960e+00 +1.756999999999999951e-01 6.609770000000000145e+00 1.817930000000000046e+00 +1.818799999999999861e-01 6.690150000000000041e+00 1.828950000000000076e+00 +1.880999999999999894e-01 6.763010000000000410e+00 1.838889999999999914e+00 +1.942000000000000115e-01 6.479930000000000412e+00 1.799989999999999979e+00 +2.003099999999999881e-01 6.931930000000000369e+00 1.861709999999999976e+00 +2.064499999999999946e-01 7.058690000000000353e+00 1.878649999999999931e+00 +2.126300000000000134e-01 6.966739999999999711e+00 1.866379999999999928e+00 +2.187699999999999922e-01 7.155350000000000321e+00 1.891469999999999985e+00 +2.248999999999999888e-01 7.328820000000000334e+00 1.914260000000000073e+00 +2.310800000000000076e-01 7.623789999999999623e+00 1.952409999999999979e+00 +2.373000000000000109e-01 7.870739999999999625e+00 1.983780000000000099e+00 +2.434699999999999920e-01 7.865639999999999965e+00 1.983130000000000059e+00 +2.495900000000000063e-01 8.081390000000000740e+00 2.010149999999999881e+00 +2.557300000000000129e-01 8.480309999999999349e+00 2.059159999999999879e+00 +2.618900000000000117e-01 8.708700000000000330e+00 2.086710000000000065e+00 +2.680899999999999950e-01 8.823320000000000718e+00 2.100389999999999979e+00 +2.742499999999999938e-01 9.030450000000000088e+00 2.124909999999999854e+00 +2.803300000000000236e-01 9.222670000000000812e+00 2.147400000000000198e+00 +2.864999999999999769e-01 9.345430000000000348e+00 2.161649999999999849e+00 +2.927100000000000257e-01 9.660539999999999239e+00 2.197789999999999910e+00 2.988600000000000145e-01 9.559969999999999857e+00 2.186319999999999819e+00 \ No newline at end of file diff --git a/test/sasdataloader/data/5_312_1640_24.331065.csv b/test/sasdataloader/data/5_312_1640_24.331065.csv index 2f696f3b5..17968ec9e 100644 --- a/test/sasdataloader/data/5_312_1640_24.331065.csv +++ b/test/sasdataloader/data/5_312_1640_24.331065.csv @@ -1,60 +1,60 @@ -2.733000000000000013e-02 1.791495509999999967e+03 2.992905000000000015e+01 -3.091999999999999957e-02 1.477992469999999912e+03 2.718449000000000026e+01 -3.454000000000000126e-02 1.172791189999999915e+03 2.421561000000000163e+01 -3.814000000000000029e-02 9.196233300000000099e+02 2.144322000000000017e+01 -4.175000000000000239e-02 7.160111200000000053e+02 1.892102999999999824e+01 -4.544000000000000122e-02 5.391461900000000469e+02 1.641867999999999839e+01 -4.646000000000000130e-02 4.929036699999999769e+02 1.569877999999999929e+01 -4.909999999999999781e-02 4.129331099999999992e+02 1.436894000000000027e+01 -5.256000000000000255e-02 3.482022600000000239e+02 1.319473999999999947e+01 -5.272999999999999909e-02 3.242194700000000012e+02 1.273222999999999949e+01 -5.632000000000000201e-02 2.454095199999999863e+02 1.107722000000000051e+01 -5.870999999999999830e-02 2.218204599999999971e+02 1.053139000000000003e+01 -5.990000000000000185e-02 1.931666899999999885e+02 9.827680000000000859e+00 -6.356000000000000538e-02 1.505020900000000097e+02 8.674739999999999895e+00 -6.483999999999999486e-02 1.511605900000000133e+02 8.693690000000000140e+00 -6.718999999999999972e-02 1.202856799999999993e+02 7.755180000000000184e+00 -7.074999999999999345e-02 9.616129999999999711e+01 6.934020000000000294e+00 -7.097000000000000530e-02 9.870516999999999541e+01 7.025140000000000384e+00 -7.435999999999999555e-02 7.818730999999999653e+01 6.252489999999999881e+00 -7.724999999999999922e-02 6.837958000000000425e+01 5.847199999999999953e+00 -7.802000000000000601e-02 6.371482000000000312e+01 5.644239999999999924e+00 -8.165999999999999648e-02 5.179379999999999740e+01 5.088899999999999757e+00 -8.347000000000000253e-02 4.836007000000000033e+01 4.917320000000000135e+00 -8.526999999999999857e-02 4.457972000000000179e+01 4.721210000000000129e+00 -8.884000000000000230e-02 3.751116999999999990e+01 4.330770000000000231e+00 -8.963000000000000134e-02 3.544118999999999886e+01 4.209579999999999878e+00 -9.574000000000000565e-02 2.739192999999999856e+01 3.700810000000000155e+00 -1.018199999999999938e-01 2.084316000000000102e+01 3.228250000000000064e+00 -1.080399999999999971e-01 1.702296000000000120e+01 2.917440000000000033e+00 -1.142200000000000021e-01 1.391883999999999943e+01 2.638069999999999915e+00 -1.202600000000000058e-01 1.148202000000000034e+01 2.396040000000000170e+00 -1.264099999999999946e-01 9.887589999999999435e+00 2.223460000000000214e+00 -1.326199999999999879e-01 8.618710000000000093e+00 2.075899999999999856e+00 -1.388300000000000090e-01 7.875820000000000043e+00 1.984420000000000073e+00 -1.449699999999999878e-01 7.119869999999999699e+00 1.886779999999999902e+00 -1.510100000000000053e-01 6.691399999999999793e+00 1.829129999999999923e+00 -1.571799999999999864e-01 6.133020000000000138e+00 1.751139999999999919e+00 -1.634099999999999997e-01 5.984770000000000145e+00 1.729850000000000110e+00 -1.695800000000000085e-01 5.802669999999999995e+00 1.703330000000000011e+00 -1.756999999999999951e-01 5.772070000000000256e+00 1.698830000000000062e+00 -1.818799999999999861e-01 5.866640000000000299e+00 1.712690000000000046e+00 -1.880999999999999894e-01 5.880740000000000300e+00 1.714749999999999996e+00 -1.942000000000000115e-01 5.856810000000000294e+00 1.711260000000000003e+00 -2.003099999999999881e-01 6.138060000000000294e+00 1.751870000000000038e+00 -2.064499999999999946e-01 6.406990000000000407e+00 1.789830000000000032e+00 -2.126300000000000134e-01 6.462060000000000137e+00 1.797509999999999941e+00 -2.187699999999999922e-01 6.501079999999999970e+00 1.802929999999999922e+00 -2.248999999999999888e-01 6.991179999999999950e+00 1.869650000000000034e+00 -2.310800000000000076e-01 7.014639999999999986e+00 1.872779999999999889e+00 -2.373000000000000109e-01 7.136879999999999669e+00 1.889029999999999987e+00 -2.434699999999999920e-01 7.547889999999999766e+00 1.942660000000000053e+00 -2.495900000000000063e-01 7.608620000000000161e+00 1.950460000000000083e+00 -2.557300000000000129e-01 7.913459999999999717e+00 1.989149999999999974e+00 -2.618900000000000117e-01 8.245919999999999916e+00 2.030510000000000037e+00 -2.680899999999999950e-01 8.604509999999999437e+00 2.074190000000000200e+00 -2.742499999999999938e-01 8.711750000000000327e+00 2.087070000000000203e+00 -2.803300000000000236e-01 8.863739999999999952e+00 2.105199999999999960e+00 -2.864999999999999769e-01 8.911099999999999355e+00 2.110819999999999919e+00 -2.927100000000000257e-01 9.338430000000000675e+00 2.160839999999999872e+00 +2.733000000000000013e-02 1.791495509999999967e+03 2.992905000000000015e+01 +3.091999999999999957e-02 1.477992469999999912e+03 2.718449000000000026e+01 +3.454000000000000126e-02 1.172791189999999915e+03 2.421561000000000163e+01 +3.814000000000000029e-02 9.196233300000000099e+02 2.144322000000000017e+01 +4.175000000000000239e-02 7.160111200000000053e+02 1.892102999999999824e+01 +4.544000000000000122e-02 5.391461900000000469e+02 1.641867999999999839e+01 +4.646000000000000130e-02 4.929036699999999769e+02 1.569877999999999929e+01 +4.909999999999999781e-02 4.129331099999999992e+02 1.436894000000000027e+01 +5.256000000000000255e-02 3.482022600000000239e+02 1.319473999999999947e+01 +5.272999999999999909e-02 3.242194700000000012e+02 1.273222999999999949e+01 +5.632000000000000201e-02 2.454095199999999863e+02 1.107722000000000051e+01 +5.870999999999999830e-02 2.218204599999999971e+02 1.053139000000000003e+01 +5.990000000000000185e-02 1.931666899999999885e+02 9.827680000000000859e+00 +6.356000000000000538e-02 1.505020900000000097e+02 8.674739999999999895e+00 +6.483999999999999486e-02 1.511605900000000133e+02 8.693690000000000140e+00 +6.718999999999999972e-02 1.202856799999999993e+02 7.755180000000000184e+00 +7.074999999999999345e-02 9.616129999999999711e+01 6.934020000000000294e+00 +7.097000000000000530e-02 9.870516999999999541e+01 7.025140000000000384e+00 +7.435999999999999555e-02 7.818730999999999653e+01 6.252489999999999881e+00 +7.724999999999999922e-02 6.837958000000000425e+01 5.847199999999999953e+00 +7.802000000000000601e-02 6.371482000000000312e+01 5.644239999999999924e+00 +8.165999999999999648e-02 5.179379999999999740e+01 5.088899999999999757e+00 +8.347000000000000253e-02 4.836007000000000033e+01 4.917320000000000135e+00 +8.526999999999999857e-02 4.457972000000000179e+01 4.721210000000000129e+00 +8.884000000000000230e-02 3.751116999999999990e+01 4.330770000000000231e+00 +8.963000000000000134e-02 3.544118999999999886e+01 4.209579999999999878e+00 +9.574000000000000565e-02 2.739192999999999856e+01 3.700810000000000155e+00 +1.018199999999999938e-01 2.084316000000000102e+01 3.228250000000000064e+00 +1.080399999999999971e-01 1.702296000000000120e+01 2.917440000000000033e+00 +1.142200000000000021e-01 1.391883999999999943e+01 2.638069999999999915e+00 +1.202600000000000058e-01 1.148202000000000034e+01 2.396040000000000170e+00 +1.264099999999999946e-01 9.887589999999999435e+00 2.223460000000000214e+00 +1.326199999999999879e-01 8.618710000000000093e+00 2.075899999999999856e+00 +1.388300000000000090e-01 7.875820000000000043e+00 1.984420000000000073e+00 +1.449699999999999878e-01 7.119869999999999699e+00 1.886779999999999902e+00 +1.510100000000000053e-01 6.691399999999999793e+00 1.829129999999999923e+00 +1.571799999999999864e-01 6.133020000000000138e+00 1.751139999999999919e+00 +1.634099999999999997e-01 5.984770000000000145e+00 1.729850000000000110e+00 +1.695800000000000085e-01 5.802669999999999995e+00 1.703330000000000011e+00 +1.756999999999999951e-01 5.772070000000000256e+00 1.698830000000000062e+00 +1.818799999999999861e-01 5.866640000000000299e+00 1.712690000000000046e+00 +1.880999999999999894e-01 5.880740000000000300e+00 1.714749999999999996e+00 +1.942000000000000115e-01 5.856810000000000294e+00 1.711260000000000003e+00 +2.003099999999999881e-01 6.138060000000000294e+00 1.751870000000000038e+00 +2.064499999999999946e-01 6.406990000000000407e+00 1.789830000000000032e+00 +2.126300000000000134e-01 6.462060000000000137e+00 1.797509999999999941e+00 +2.187699999999999922e-01 6.501079999999999970e+00 1.802929999999999922e+00 +2.248999999999999888e-01 6.991179999999999950e+00 1.869650000000000034e+00 +2.310800000000000076e-01 7.014639999999999986e+00 1.872779999999999889e+00 +2.373000000000000109e-01 7.136879999999999669e+00 1.889029999999999987e+00 +2.434699999999999920e-01 7.547889999999999766e+00 1.942660000000000053e+00 +2.495900000000000063e-01 7.608620000000000161e+00 1.950460000000000083e+00 +2.557300000000000129e-01 7.913459999999999717e+00 1.989149999999999974e+00 +2.618900000000000117e-01 8.245919999999999916e+00 2.030510000000000037e+00 +2.680899999999999950e-01 8.604509999999999437e+00 2.074190000000000200e+00 +2.742499999999999938e-01 8.711750000000000327e+00 2.087070000000000203e+00 +2.803300000000000236e-01 8.863739999999999952e+00 2.105199999999999960e+00 +2.864999999999999769e-01 8.911099999999999355e+00 2.110819999999999919e+00 +2.927100000000000257e-01 9.338430000000000675e+00 2.160839999999999872e+00 2.988600000000000145e-01 9.385640000000000427e+00 2.166290000000000049e+00 \ No newline at end of file diff --git a/test/sasdataloader/data/6_1270_1640_24.331065.csv b/test/sasdataloader/data/6_1270_1640_24.331065.csv index e7dfab999..72272ed89 100644 --- a/test/sasdataloader/data/6_1270_1640_24.331065.csv +++ b/test/sasdataloader/data/6_1270_1640_24.331065.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 1.517870979999999918e+03 2.754878000000000071e+01 -3.090999999999999998e-02 1.252144950000000108e+03 2.502143999999999835e+01 -3.452999999999999819e-02 9.849326300000000174e+02 2.219157999999999831e+01 -3.812999999999999723e-02 7.635778900000000249e+02 1.953941999999999979e+01 -4.173999999999999932e-02 5.910564900000000534e+02 1.719093000000000160e+01 -4.542999999999999816e-02 4.454160299999999779e+02 1.492340000000000089e+01 -4.644000000000000211e-02 4.097451399999999921e+02 1.431337000000000081e+01 -4.907999999999999863e-02 3.412573399999999992e+02 1.306249000000000038e+01 -5.254000000000000337e-02 2.833860500000000116e+02 1.190348999999999968e+01 -5.270999999999999991e-02 2.587516299999999774e+02 1.137434999999999974e+01 -5.630000000000000282e-02 1.972410900000000140e+02 9.930790000000000006e+00 -5.868999999999999911e-02 1.820288400000000024e+02 9.540150000000000574e+00 -5.988000000000000267e-02 1.548462399999999946e+02 8.799039999999999750e+00 -6.353999999999999926e-02 1.208091600000000057e+02 7.772039999999999615e+00 -6.481000000000000649e-02 1.228846300000000014e+02 7.838510000000000311e+00 -6.716999999999999360e-02 9.485747999999999536e+01 6.886849999999999916e+00 -7.072000000000000508e-02 7.616365000000000407e+01 6.171050000000000146e+00 -7.094999999999999918e-02 7.959243999999999630e+01 6.308419999999999916e+00 -7.434000000000000330e-02 6.139544999999999675e+01 5.540549999999999642e+00 -7.721999999999999698e-02 5.528307999999999822e+01 5.257520000000000415e+00 -7.799000000000000377e-02 5.105310999999999666e+01 5.052380000000000315e+00 -8.164000000000000423e-02 4.131436000000000064e+01 4.545020000000000060e+00 -8.343000000000000416e-02 3.883191999999999666e+01 4.406349999999999767e+00 -8.523999999999999633e-02 3.386838999999999800e+01 4.115120000000000111e+00 -8.881000000000000005e-02 2.873742000000000019e+01 3.790610000000000035e+00 -8.959999999999999909e-02 2.744166999999999845e+01 3.704159999999999897e+00 -9.569999999999999341e-02 2.114314999999999856e+01 3.251399999999999846e+00 -1.017799999999999955e-01 1.639198000000000022e+01 2.862859999999999960e+00 -1.079999999999999988e-01 1.302345000000000041e+01 2.551810000000000134e+00 -1.141699999999999937e-01 1.067233000000000054e+01 2.310010000000000119e+00 -1.202099999999999974e-01 8.927680000000000504e+00 2.112779999999999880e+00 -1.263600000000000001e-01 7.691300000000000026e+00 1.961030000000000051e+00 -1.325600000000000112e-01 6.633219999999999672e+00 1.821159999999999890e+00 -1.387799999999999867e-01 6.187759999999999927e+00 1.758939999999999948e+00 -1.449100000000000110e-01 5.397269999999999790e+00 1.642749999999999932e+00 -1.509500000000000008e-01 5.127299999999999969e+00 1.601140000000000008e+00 -1.571200000000000097e-01 4.947350000000000136e+00 1.572789999999999910e+00 -1.633400000000000130e-01 4.791970000000000063e+00 1.547900000000000054e+00 -1.695200000000000040e-01 4.839830000000000076e+00 1.555609999999999937e+00 -1.756399999999999906e-01 4.855599999999999916e+00 1.558140000000000081e+00 -1.818099999999999994e-01 4.971189999999999998e+00 1.576580000000000092e+00 -1.880199999999999927e-01 4.996179999999999843e+00 1.580540000000000056e+00 -1.941299999999999970e-01 5.231489999999999974e+00 1.617329999999999934e+00 -2.002299999999999913e-01 5.461660000000000181e+00 1.652519999999999989e+00 -2.063699999999999979e-01 5.566430000000000433e+00 1.668299999999999894e+00 -2.125400000000000067e-01 5.749649999999999928e+00 1.695529999999999982e+00 -2.186899999999999955e-01 5.962720000000000020e+00 1.726660000000000084e+00 -2.248100000000000098e-01 6.366220000000000212e+00 1.784129999999999994e+00 -2.309900000000000009e-01 6.576419999999999710e+00 1.813339999999999952e+00 -2.372100000000000042e-01 6.993730000000000224e+00 1.869990000000000041e+00 -2.433800000000000130e-01 7.112300000000000288e+00 1.885780000000000012e+00 -2.494999999999999996e-01 7.346860000000000390e+00 1.916619999999999990e+00 -2.556300000000000239e-01 7.629410000000000025e+00 1.953130000000000033e+00 -2.617900000000000227e-01 7.827810000000000379e+00 1.978359999999999896e+00 -2.679900000000000060e-01 8.252810000000000201e+00 2.031359999999999832e+00 -2.741399999999999948e-01 8.304840000000000444e+00 2.037749999999999950e+00 -2.802200000000000246e-01 8.705450000000000799e+00 2.086320000000000174e+00 -2.863899999999999779e-01 8.881330000000000169e+00 2.107289999999999885e+00 -2.926000000000000267e-01 9.112230000000000274e+00 2.134510000000000129e+00 -2.987500000000000155e-01 9.303969999999999629e+00 2.156849999999999934e+00 +2.732000000000000053e-02 1.517870979999999918e+03 2.754878000000000071e+01 +3.090999999999999998e-02 1.252144950000000108e+03 2.502143999999999835e+01 +3.452999999999999819e-02 9.849326300000000174e+02 2.219157999999999831e+01 +3.812999999999999723e-02 7.635778900000000249e+02 1.953941999999999979e+01 +4.173999999999999932e-02 5.910564900000000534e+02 1.719093000000000160e+01 +4.542999999999999816e-02 4.454160299999999779e+02 1.492340000000000089e+01 +4.644000000000000211e-02 4.097451399999999921e+02 1.431337000000000081e+01 +4.907999999999999863e-02 3.412573399999999992e+02 1.306249000000000038e+01 +5.254000000000000337e-02 2.833860500000000116e+02 1.190348999999999968e+01 +5.270999999999999991e-02 2.587516299999999774e+02 1.137434999999999974e+01 +5.630000000000000282e-02 1.972410900000000140e+02 9.930790000000000006e+00 +5.868999999999999911e-02 1.820288400000000024e+02 9.540150000000000574e+00 +5.988000000000000267e-02 1.548462399999999946e+02 8.799039999999999750e+00 +6.353999999999999926e-02 1.208091600000000057e+02 7.772039999999999615e+00 +6.481000000000000649e-02 1.228846300000000014e+02 7.838510000000000311e+00 +6.716999999999999360e-02 9.485747999999999536e+01 6.886849999999999916e+00 +7.072000000000000508e-02 7.616365000000000407e+01 6.171050000000000146e+00 +7.094999999999999918e-02 7.959243999999999630e+01 6.308419999999999916e+00 +7.434000000000000330e-02 6.139544999999999675e+01 5.540549999999999642e+00 +7.721999999999999698e-02 5.528307999999999822e+01 5.257520000000000415e+00 +7.799000000000000377e-02 5.105310999999999666e+01 5.052380000000000315e+00 +8.164000000000000423e-02 4.131436000000000064e+01 4.545020000000000060e+00 +8.343000000000000416e-02 3.883191999999999666e+01 4.406349999999999767e+00 +8.523999999999999633e-02 3.386838999999999800e+01 4.115120000000000111e+00 +8.881000000000000005e-02 2.873742000000000019e+01 3.790610000000000035e+00 +8.959999999999999909e-02 2.744166999999999845e+01 3.704159999999999897e+00 +9.569999999999999341e-02 2.114314999999999856e+01 3.251399999999999846e+00 +1.017799999999999955e-01 1.639198000000000022e+01 2.862859999999999960e+00 +1.079999999999999988e-01 1.302345000000000041e+01 2.551810000000000134e+00 +1.141699999999999937e-01 1.067233000000000054e+01 2.310010000000000119e+00 +1.202099999999999974e-01 8.927680000000000504e+00 2.112779999999999880e+00 +1.263600000000000001e-01 7.691300000000000026e+00 1.961030000000000051e+00 +1.325600000000000112e-01 6.633219999999999672e+00 1.821159999999999890e+00 +1.387799999999999867e-01 6.187759999999999927e+00 1.758939999999999948e+00 +1.449100000000000110e-01 5.397269999999999790e+00 1.642749999999999932e+00 +1.509500000000000008e-01 5.127299999999999969e+00 1.601140000000000008e+00 +1.571200000000000097e-01 4.947350000000000136e+00 1.572789999999999910e+00 +1.633400000000000130e-01 4.791970000000000063e+00 1.547900000000000054e+00 +1.695200000000000040e-01 4.839830000000000076e+00 1.555609999999999937e+00 +1.756399999999999906e-01 4.855599999999999916e+00 1.558140000000000081e+00 +1.818099999999999994e-01 4.971189999999999998e+00 1.576580000000000092e+00 +1.880199999999999927e-01 4.996179999999999843e+00 1.580540000000000056e+00 +1.941299999999999970e-01 5.231489999999999974e+00 1.617329999999999934e+00 +2.002299999999999913e-01 5.461660000000000181e+00 1.652519999999999989e+00 +2.063699999999999979e-01 5.566430000000000433e+00 1.668299999999999894e+00 +2.125400000000000067e-01 5.749649999999999928e+00 1.695529999999999982e+00 +2.186899999999999955e-01 5.962720000000000020e+00 1.726660000000000084e+00 +2.248100000000000098e-01 6.366220000000000212e+00 1.784129999999999994e+00 +2.309900000000000009e-01 6.576419999999999710e+00 1.813339999999999952e+00 +2.372100000000000042e-01 6.993730000000000224e+00 1.869990000000000041e+00 +2.433800000000000130e-01 7.112300000000000288e+00 1.885780000000000012e+00 +2.494999999999999996e-01 7.346860000000000390e+00 1.916619999999999990e+00 +2.556300000000000239e-01 7.629410000000000025e+00 1.953130000000000033e+00 +2.617900000000000227e-01 7.827810000000000379e+00 1.978359999999999896e+00 +2.679900000000000060e-01 8.252810000000000201e+00 2.031359999999999832e+00 +2.741399999999999948e-01 8.304840000000000444e+00 2.037749999999999950e+00 +2.802200000000000246e-01 8.705450000000000799e+00 2.086320000000000174e+00 +2.863899999999999779e-01 8.881330000000000169e+00 2.107289999999999885e+00 +2.926000000000000267e-01 9.112230000000000274e+00 2.134510000000000129e+00 +2.987500000000000155e-01 9.303969999999999629e+00 2.156849999999999934e+00 diff --git a/test/sasdataloader/data/nxcansas_1Dand2D_multisasdata.h5 b/test/sasdataloader/data/nxcansas_1Dand2D_multisasdata.h5 index 4002fcb7c..125c90633 100644 Binary files a/test/sasdataloader/data/nxcansas_1Dand2D_multisasdata.h5 and b/test/sasdataloader/data/nxcansas_1Dand2D_multisasdata.h5 differ diff --git a/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry.h5 b/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry.h5 index 220ae520b..fdce32035 100644 Binary files a/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry.h5 and b/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry.h5 differ diff --git a/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry_multisasdata.h5 b/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry_multisasdata.h5 index 917a5f4f9..fee4255d5 100644 Binary files a/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry_multisasdata.h5 and b/test/sasdataloader/data/nxcansas_1Dand2D_multisasentry_multisasdata.h5 differ diff --git a/test/sasdataloader/reference/14250.txt b/test/sasdataloader/reference/14250.txt new file mode 100644 index 000000000..6f11aba78 --- /dev/null +++ b/test/sasdataloader/reference/14250.txt @@ -0,0 +1,51 @@ +sasentry01 + [FILE_ID_HERE/sasentry01/sasdata/I] [[0.0 ... 0.0]] ± [[0.0 ... 0.0]] cm⁻¹ + [FILE_ID_HERE/sasentry01/sasdata/Qx] [[-0.11925 ... 0.11925000000000001]] Å⁻¹ + [FILE_ID_HERE/sasentry01/sasdata/Qy] [[-0.11925 ... 0.11925000000000001]] Å⁻¹ +Metadata: + + High C high V 63, 900oC, 10h 1.65T_SANS, Run: 14250 + =================================================== + +Definition: High C high V 63, 900oC, 10h 1.65T_SANS +Process: + Name: Mantid_generated_NXcanSAS + Date: 2016-12-06T17:15:48 + Description: None + Term: None + Notes: None +Sample: + ID: None + Transmission: None + Thickness: None + Temperature: None + Position: None + Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None +Collimation: + Length: None +Detector: + Name: None + Distance: None + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Source: + Radiation: Spallation Neutron Source + Shape: None + Wavelength: None + Min. Wavelength: None + Max. Wavelength: None + Wavelength Spread: None + Beam Size: None +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + diff --git a/test/sasdataloader/reference/33837.txt b/test/sasdataloader/reference/33837.txt new file mode 100644 index 000000000..26f36b96b --- /dev/null +++ b/test/sasdataloader/reference/33837.txt @@ -0,0 +1,50 @@ +sasentry01 + [FILE_ID_HERE/sasentry01/sasdata/I] [5.416094671273121 ... 0.33697913143947616] ± [0.6152247543248875 ... 0.19365125082205084] m + [FILE_ID_HERE/sasentry01/sasdata/Q] [0.0041600000000000005 ... 0.6189241619415587] m +Metadata: + + MH4_5deg_16T_SLOW, Run: 33837 + ============================= + +Definition: MH4_5deg_16T_SLOW +Process: + Name: Mantid_generated_NXcanSAS + Date: 11-May-2016 12:20:43 + Description: None + Term: None + Notes: None +Sample: + ID: None + Transmission: None + Thickness: None + Temperature: None + Position: None + Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None +Collimation: + Length: None +Detector: + Name: None + Distance: None + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Source: + Radiation: Spallation Neutron Source + Shape: None + Wavelength: None + Min. Wavelength: None + Max. Wavelength: None + Wavelength Spread: None + Beam Size: None +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + diff --git a/test/sasdataloader/reference/33837_v3.txt b/test/sasdataloader/reference/33837_v3.txt new file mode 100644 index 000000000..f4d205b2a --- /dev/null +++ b/test/sasdataloader/reference/33837_v3.txt @@ -0,0 +1,50 @@ +sasentry01 + [FILE_ID_HERE/sasentry01/sasdata/I] [5.416094671273121 ... 0.33697913143947616] ± [0.6152247543248875 ... 0.19365125082205084] none + [FILE_ID_HERE/sasentry01/sasdata/Q] [0.0041600000000000005 ... 0.6189241619415587] Å⁻¹ +Metadata: + + MH4_5deg_16T_SLOW, Run: 33837 + ============================= + +Definition: MH4_5deg_16T_SLOW +Process: + Name: Mantid_generated_NXcanSAS + Date: 2016-07-04T10:34:34 + Description: None + Term: None + Notes: None +Sample: + ID: None + Transmission: None + Thickness: None + Temperature: None + Position: None + Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None +Collimation: + Length: None +Detector: + Name: None + Distance: None + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Source: + Radiation: Spallation Neutron Source + Shape: None + Wavelength: None + Min. Wavelength: None + Max. Wavelength: None + Wavelength Spread: None + Beam Size: None +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + diff --git a/test/sasdataloader/reference/BAM.txt b/test/sasdataloader/reference/BAM.txt new file mode 100644 index 000000000..bf6328b1c --- /dev/null +++ b/test/sasdataloader/reference/BAM.txt @@ -0,0 +1,51 @@ +sasentry01 + [FILE_ID_HERE/sasentry01/data/I] [[-4132.585671758142 ... -4139.954861346877]] ± [[1000000000.0 ... 1000000000.0]] m⁻¹ + [FILE_ID_HERE/sasentry01/data/Imask] [[True ... True]] m⁻¹ + [FILE_ID_HERE/sasentry01/data/Q] [[[-0.10733919639695527 ... 0.0]]] Å⁻¹ +Metadata: + + Qais oriented iron test 1, Run: 12345 + ===================================== + +Definition: Qais oriented iron test 1 +Process: + Name: None + Date: None + Description: None + Term: None + Notes: None +Sample: + ID: None + Transmission: None + Thickness: None + Temperature: None + Position: None + Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None +Collimation: + Length: None +Detector: + Name: None + Distance: None + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Source: + Radiation: None + Shape: None + Wavelength: None + Min. Wavelength: None + Max. Wavelength: None + Wavelength Spread: None + Beam Size: None +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + diff --git a/test/sasdataloader/reference/ISIS_1_0.txt b/test/sasdataloader/reference/ISIS_1_0.txt index 57ff7ed28..14f071620 100644 --- a/test/sasdataloader/reference/ISIS_1_0.txt +++ b/test/sasdataloader/reference/ISIS_1_0.txt @@ -11,9 +11,7 @@ Process: Name: Mantid generated CanSAS1D XML Date: 02-Aug-2013 16:54:14 Description: None - Terms: - svn: 2.5.3 - user_file: K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt + Term: {'svn': '2.5.3', 'user_file': 'K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt'} Sample: ID: TK49 c10_SANS Transmission: None @@ -47,3 +45,4 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None + diff --git a/test/sasdataloader/reference/ISIS_1_1.txt b/test/sasdataloader/reference/ISIS_1_1.txt index 48df868f5..731c1b6cf 100644 --- a/test/sasdataloader/reference/ISIS_1_1.txt +++ b/test/sasdataloader/reference/ISIS_1_1.txt @@ -11,9 +11,7 @@ Process: Name: Mantid generated CanSAS1D XML Date: 02-Aug-2013 16:53:56 Description: None - Terms: - svn: 2.5.3 - user_file: K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt + Term: {'svn': '2.5.3', 'user_file': 'K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt'} Sample: ID: TK49 c10_SANS Transmission: None @@ -47,3 +45,4 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None + diff --git a/test/sasdataloader/reference/ISIS_1_1_doubletrans.txt b/test/sasdataloader/reference/ISIS_1_1_doubletrans.txt index 48df868f5..731c1b6cf 100644 --- a/test/sasdataloader/reference/ISIS_1_1_doubletrans.txt +++ b/test/sasdataloader/reference/ISIS_1_1_doubletrans.txt @@ -11,9 +11,7 @@ Process: Name: Mantid generated CanSAS1D XML Date: 02-Aug-2013 16:53:56 Description: None - Terms: - svn: 2.5.3 - user_file: K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt + Term: {'svn': '2.5.3', 'user_file': 'K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt'} Sample: ID: TK49 c10_SANS Transmission: None @@ -47,3 +45,4 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None + diff --git a/test/sasdataloader/reference/ISIS_1_1_notrans.txt b/test/sasdataloader/reference/ISIS_1_1_notrans.txt index 48df868f5..731c1b6cf 100644 --- a/test/sasdataloader/reference/ISIS_1_1_notrans.txt +++ b/test/sasdataloader/reference/ISIS_1_1_notrans.txt @@ -11,9 +11,7 @@ Process: Name: Mantid generated CanSAS1D XML Date: 02-Aug-2013 16:53:56 Description: None - Terms: - svn: 2.5.3 - user_file: K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt + Term: {'svn': '2.5.3', 'user_file': 'K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt'} Sample: ID: TK49 c10_SANS Transmission: None @@ -47,3 +45,4 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None + diff --git a/test/sasdataloader/reference/MAR07232_rest.txt b/test/sasdataloader/reference/MAR07232_rest.txt index e98b20bd2..8a9e16ce4 100644 --- a/test/sasdataloader/reference/MAR07232_rest.txt +++ b/test/sasdataloader/reference/MAR07232_rest.txt @@ -1,24 +1,31 @@ sasentry01 - Qy - Qx - I Metadata: MAR07232_rest_out.dat, Run: 2 ============================= Definition: MAR07232_rest_out.dat +Process: + Name: None + Date: None + Description: None + Term: None + Notes: None Sample: - ID: - Transmission: 0.84357 + ID: None + Transmission: [0.84357] Thickness: None Temperature: None Position: None Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None Collimation: Length: None Detector: - Name: + Name: None Distance: None Offset: None Orientation: None @@ -33,3 +40,21 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None +<<<<<<< HEAD +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + + +||||||| parent of 0b6ad967 (Metadata is a dataclass) +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + +======= + +>>>>>>> 0b6ad967 (Metadata is a dataclass) \ No newline at end of file diff --git a/test/sasdataloader/reference/TestExtensions.txt b/test/sasdataloader/reference/TestExtensions.txt index e833c9da7..d04c7ef45 100644 --- a/test/sasdataloader/reference/TestExtensions.txt +++ b/test/sasdataloader/reference/TestExtensions.txt @@ -1,4 +1,4 @@ -TK49 c10_SANS +None Q I Metadata: @@ -10,10 +10,8 @@ Definition: TK49 c10_SANS Process: Name: Mantid generated CanSAS1D XML Date: 02-Aug-2013 16:53:56 - Description: - Terms: - svn: 2.5.3 - user_file: K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt + Description: None + Term: {'svn': '2.5.3', 'user_file': 'K:/masks/MASKLOQ_MAN_132E_Lu_Banjo_12mm.txt'} Sample: ID: TK49 c10_SANS Transmission: None @@ -47,3 +45,4 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None + diff --git a/test/sasdataloader/reference/cansas1d.txt b/test/sasdataloader/reference/cansas1d.txt index e16366bba..7563b9b65 100644 --- a/test/sasdataloader/reference/cansas1d.txt +++ b/test/sasdataloader/reference/cansas1d.txt @@ -1,4 +1,4 @@ -Test title +None Q I Metadata: @@ -11,34 +11,12 @@ Process: Name: spol Date: 04-Sep-2007 18:35:02 Description: None - Terms: - radialstep: 10.0 mm - sector_width: 180.0 deg - sector_orient: 0.0 deg - MASK_file: USER:MASK.COM - Notes: - AvA1 0.0000E+00 AsA2 1.0000E+00 XvA3 1.0526E+03 XsA4 - 5.2200E-02 XfA5 0.0000E+00 - S... 13597 0 2.26E+02 2A 5mM 0%D2O Sbak 13594 0 1.13E+02 - H2O Buffer - V... 13552 3 1.00E+00 H2O5m + Term: {'radialstep': '10.000', 'sector_width': '180.0', 'sector_orient': '0.0', 'MASK_file': 'USER:MASK.COM'} Process: Name: NCNR-IGOR Date: 03-SEP-2006 11:42:47 - Description: - Terms: - average_type: Circular - SAM_file: SEP06064.SA3_AJJ_L205 - BKD_file: SEP06064.SA3_AJJ_L205 - EMP_file: SEP06064.SA3_AJJ_L205 - DIV_file: SEP06064.SA3_AJJ_L205 - MASK_file: SEP06064.SA3_AJJ_L205 - ABS:TSTAND: 1 - ABS:DSTAND: 1.0 mm - ABS:IZERO: 230.09 - ABS:XSECT: 1.0 mm - Notes: - No Information + Description: None + Term: {'average_type': 'Circular', 'SAM_file': 'SEP06064.SA3_AJJ_L205', 'BKD_file': 'SEP06064.SA3_AJJ_L205', 'EMP_file': 'SEP06064.SA3_AJJ_L205', 'DIV_file': 'SEP06064.SA3_AJJ_L205', 'MASK_file': 'SEP06064.SA3_AJJ_L205', 'ABS:TSTAND': '1', 'ABS:DSTAND': '1', 'ABS:IZERO': '230.09', 'ABS:XSECT': '1'} Sample: ID: SI600-new-long Transmission: 0.327 @@ -48,14 +26,6 @@ Sample: Orientation: Rot3(roll=22.5 deg, pitch=0.02 deg, yaw=None) Collimation: Length: 123.0 mm - Aperture: - Name: source - Aperture size: Vec3(x=50.0 mm, y=None, z=None) - Aperture distance: 11.0 m - Aperture: - Name: sample - Aperture size: Vec3(x=1.0 mm, y=None, z=None) - Aperture distance: None Detector: Name: fictional hybrid Distance: 4.15 m diff --git a/test/sasdataloader/reference/cansas1d_badunits.txt b/test/sasdataloader/reference/cansas1d_badunits.txt index 4c61f204e..3868aead0 100644 --- a/test/sasdataloader/reference/cansas1d_badunits.txt +++ b/test/sasdataloader/reference/cansas1d_badunits.txt @@ -1,4 +1,4 @@ -Test title +None Q I Metadata: @@ -11,32 +11,12 @@ Process: Name: spol Date: 04-Sep-2007 18:35:02 Description: None - Terms: - radialstep: 10.0 mm - sector_width: 4.1416 rad - sector_orient: 0.0 deg - MASK_file: USER:MASK.COM - Notes: - AvA1 0.0000E+00 AsA2 1.0000E+00 XvA3 1.0526E+03 XsA4 - 5.2200E-02 XfA5 0.0000E+00 - S... 13597 0 2.26E+02 2A 5mM 0%D2O Sbak 13594 0 1.13E+02 - H2O Buffer - V... 13552 3 1.00E+00 H2O5m + Term: {'radialstep': '10.000', 'sector_width': '4.1416', 'sector_orient': '0.0', 'MASK_file': 'USER:MASK.COM'} Process: Name: NCNR-IGOR Date: 03-SEP-2006 11:42:47 Description: - Terms: - average_type: Circular - SAM_file: SEP06064.SA3_AJJ_L205 - BKD_file: SEP06064.SA3_AJJ_L205 - EMP_file: SEP06064.SA3_AJJ_L205 - DIV_file: SEP06064.SA3_AJJ_L205 - MASK_file: SEP06064.SA3_AJJ_L205 - ABS:TSTAND: 1 - ABS:DSTAND: 1.0 mm - ABS:IZERO: 230.09 - ABS:XSECT: 1.0 mm + Term: {'average_type': 'Circular', 'SAM_file': 'SEP06064.SA3_AJJ_L205', 'BKD_file': 'SEP06064.SA3_AJJ_L205', 'EMP_file': 'SEP06064.SA3_AJJ_L205', 'DIV_file': 'SEP06064.SA3_AJJ_L205', 'MASK_file': 'SEP06064.SA3_AJJ_L205', 'ABS:TSTAND': '1', 'ABS:DSTAND': '1', 'ABS:IZERO': '230.09', 'ABS:XSECT': '1'} Sample: ID: SI600-new-long Transmission: 0.327 @@ -46,19 +26,11 @@ Sample: Orientation: Rot3(roll=0.39269908 rad, pitch=0.00034906585 rad, yaw=None) Collimation: Length: 0.123 m - Aperture: - Name: source - Aperture size: Vec3(x=50000.0 µm, y=None, z=None) - Aperture distance: 1100.0 cm - Aperture: - Name: sample - Aperture size: Vec3(x=0.1 cm, y=None, z=None) - Aperture distance: None Detector: Name: fictional hybrid Distance: 4.15 m - Offset: Vec3(x=1000000.0 nm, y=2000.0 µm, z=None) - Orientation: Rot3(roll=0.0174533 rad, pitch=0.0 rad, yaw=0.0 rad) + Offset: Vec3(x=1000000.0 nm, y=2000.0 none, z=None) + Orientation: Rot3(roll=0.0174533 none, pitch=0.0 rad, yaw=0.0 none) Beam center: Vec3(x=0.32264 m, y=0.32768 m, z=None) Pixel size: Vec3(x=0.5 cm, y=0.5 cm, z=None) Slit length: None @@ -69,4 +41,4 @@ Source: Min. Wavelength: 2.2 Å Max. Wavelength: 10.0 Å Wavelength Spread: 14.3 % - Beam Size: BeamSize(name='bm', size=Vec3(x=0.012 m, y=13000.0 µm, z=None)) + Beam Size: BeamSize(name='bm', size=Vec3(x=0.012 m, y=13000.0 none, z=None)) diff --git a/test/sasdataloader/reference/cansas1d_notitle.txt b/test/sasdataloader/reference/cansas1d_notitle.txt index ca8abac25..b21da686f 100644 --- a/test/sasdataloader/reference/cansas1d_notitle.txt +++ b/test/sasdataloader/reference/cansas1d_notitle.txt @@ -1,44 +1,22 @@ -SasData01 +None Q I Metadata: None, Run: 1234 - =============== + =========== Definition: None Process: Name: spol Date: 04-Sep-2007 18:35:02 Description: None - Terms: - radialstep: 10.0 mm - sector_width: 180.0 deg - sector_orient: 0.0 deg - MASK_file: USER:MASK.COM - Notes: - AvA1 0.0000E+00 AsA2 1.0000E+00 XvA3 1.0526E+03 XsA4 - 5.2200E-02 XfA5 0.0000E+00 - S... 13597 0 2.26E+02 2A 5mM 0%D2O Sbak 13594 0 1.13E+02 - H2O Buffer - V... 13552 3 1.00E+00 H2O5m + Term: {'radialstep': '10.000', 'sector_width': '180.0', 'sector_orient': '0.0', 'MASK_file': 'USER:MASK.COM'} Process: Name: NCNR-IGOR Date: 03-SEP-2006 11:42:47 Description: - Terms: - average_type: Circular - SAM_file: SEP06064.SA3_AJJ_L205 - BKD_file: SEP06064.SA3_AJJ_L205 - EMP_file: SEP06064.SA3_AJJ_L205 - DIV_file: SEP06064.SA3_AJJ_L205 - MASK_file: SEP06064.SA3_AJJ_L205 - ABS:TSTAND: 1 - ABS:DSTAND: 1.0 mm - ABS:IZERO: 230.09 - ABS:XSECT: 1.0 mm - Notes: - No Information + Term: {'average_type': 'Circular', 'SAM_file': 'SEP06064.SA3_AJJ_L205', 'BKD_file': 'SEP06064.SA3_AJJ_L205', 'EMP_file': 'SEP06064.SA3_AJJ_L205', 'DIV_file': 'SEP06064.SA3_AJJ_L205', 'MASK_file': 'SEP06064.SA3_AJJ_L205', 'ABS:TSTAND': '1', 'ABS:DSTAND': '1', 'ABS:IZERO': '230.09', 'ABS:XSECT': '1'} Sample: ID: SI600-new-long Transmission: 0.327 @@ -48,14 +26,6 @@ Sample: Orientation: Rot3(roll=22.5 deg, pitch=0.02 deg, yaw=None) Collimation: Length: 123.0 mm - Aperture: - Name: source - Aperture size: Vec3(x=50.0 mm, y=None, z=None) - Aperture distance: 11.0 m - Aperture: - Name: sample - Aperture size: Vec3(x=1.0 mm, y=None, z=None) - Aperture distance: None Detector: Name: fictional hybrid Distance: 4.15 m diff --git a/test/sasdataloader/reference/cansas1d_slit.txt b/test/sasdataloader/reference/cansas1d_slit.txt index cbc9bdcfe..7ef9093f8 100644 --- a/test/sasdataloader/reference/cansas1d_slit.txt +++ b/test/sasdataloader/reference/cansas1d_slit.txt @@ -1,8 +1,8 @@ -Test title - dQw +None + I dQl Q - I + dQw Metadata: Test title, Run: 1234 @@ -13,32 +13,12 @@ Process: Name: spol Date: 04-Sep-2007 18:35:02 Description: None - Terms: - radialstep: 10.0 mm - sector_width: 180.0 deg - sector_orient: 0.0 deg - MASK_file: USER:MASK.COM - Notes: - AvA1 0.0000E+00 AsA2 1.0000E+00 XvA3 1.0526E+03 XsA4 - 5.2200E-02 XfA5 0.0000E+00 - S... 13597 0 2.26E+02 2A 5mM 0%D2O Sbak 13594 0 1.13E+02 - H2O Buffer - V... 13552 3 1.00E+00 H2O5m + Term: {'radialstep': '10.000', 'sector_width': '180.0', 'sector_orient': '0.0', 'MASK_file': 'USER:MASK.COM'} Process: Name: NCNR-IGOR Date: 03-SEP-2006 11:42:47 Description: - Terms: - average_type: Circular - SAM_file: SEP06064.SA3_AJJ_L205 - BKD_file: SEP06064.SA3_AJJ_L205 - EMP_file: SEP06064.SA3_AJJ_L205 - DIV_file: SEP06064.SA3_AJJ_L205 - MASK_file: SEP06064.SA3_AJJ_L205 - ABS:TSTAND: 1 - ABS:DSTAND: 1.0 mm - ABS:IZERO: 230.09 - ABS:XSECT: 1.0 mm + Term: {'average_type': 'Circular', 'SAM_file': 'SEP06064.SA3_AJJ_L205', 'BKD_file': 'SEP06064.SA3_AJJ_L205', 'EMP_file': 'SEP06064.SA3_AJJ_L205', 'DIV_file': 'SEP06064.SA3_AJJ_L205', 'MASK_file': 'SEP06064.SA3_AJJ_L205', 'ABS:TSTAND': '1', 'ABS:DSTAND': '1', 'ABS:IZERO': '230.09', 'ABS:XSECT': '1'} Sample: ID: SI600-new-long Transmission: 0.327 @@ -48,14 +28,6 @@ Sample: Orientation: Rot3(roll=22.5 deg, pitch=0.02 deg, yaw=None) Collimation: Length: 123.0 mm - Aperture: - Name: source - Aperture size: Vec3(x=50.0 mm, y=None, z=None) - Aperture distance: 11.0 m - Aperture: - Name: sample - Aperture size: Vec3(x=1.0 mm, y=None, z=None) - Aperture distance: None Detector: Name: fictional hybrid Distance: 4.15 m diff --git a/test/sasdataloader/reference/cansas1d_units.txt b/test/sasdataloader/reference/cansas1d_units.txt index 68db7bc45..21845aa8c 100644 --- a/test/sasdataloader/reference/cansas1d_units.txt +++ b/test/sasdataloader/reference/cansas1d_units.txt @@ -1,4 +1,4 @@ -Test title +None Q I Metadata: @@ -11,32 +11,12 @@ Process: Name: spol Date: 04-Sep-2007 18:35:02 Description: None - Terms: - radialstep: 10.0 mm - sector_width: 4.1416 rad - sector_orient: 0.0 deg - MASK_file: USER:MASK.COM - Notes: - AvA1 0.0000E+00 AsA2 1.0000E+00 XvA3 1.0526E+03 XsA4 - 5.2200E-02 XfA5 0.0000E+00 - S... 13597 0 2.26E+02 2A 5mM 0%D2O Sbak 13594 0 1.13E+02 - H2O Buffer - V... 13552 3 1.00E+00 H2O5m + Term: {'radialstep': '10.000', 'sector_width': '4.1416', 'sector_orient': '0.0', 'MASK_file': 'USER:MASK.COM'} Process: Name: NCNR-IGOR Date: 03-SEP-2006 11:42:47 Description: - Terms: - average_type: Circular - SAM_file: SEP06064.SA3_AJJ_L205 - BKD_file: SEP06064.SA3_AJJ_L205 - EMP_file: SEP06064.SA3_AJJ_L205 - DIV_file: SEP06064.SA3_AJJ_L205 - MASK_file: SEP06064.SA3_AJJ_L205 - ABS:TSTAND: 1 - ABS:DSTAND: 1.0 mm - ABS:IZERO: 230.09 - ABS:XSECT: 1.0 mm + Term: {'average_type': 'Circular', 'SAM_file': 'SEP06064.SA3_AJJ_L205', 'BKD_file': 'SEP06064.SA3_AJJ_L205', 'EMP_file': 'SEP06064.SA3_AJJ_L205', 'DIV_file': 'SEP06064.SA3_AJJ_L205', 'MASK_file': 'SEP06064.SA3_AJJ_L205', 'ABS:TSTAND': '1', 'ABS:DSTAND': '1', 'ABS:IZERO': '230.09', 'ABS:XSECT': '1'} Sample: ID: SI600-new-long Transmission: 0.327 @@ -46,19 +26,11 @@ Sample: Orientation: Rot3(roll=0.39269908 rad, pitch=0.00034906585 rad, yaw=None) Collimation: Length: 0.123 m - Aperture: - Name: source - Aperture size: Vec3(x=50000.0 µm, y=None, z=None) - Aperture distance: 1100.0 cm - Aperture: - Name: sample - Aperture size: Vec3(x=0.1 cm, y=None, z=None) - Aperture distance: None Detector: Name: fictional hybrid Distance: 4.15 m - Offset: Vec3(x=1000000.0 nm, y=2000.0 µm, z=None) - Orientation: Rot3(roll=0.0174533 rad, pitch=0.0 rad, yaw=0.0 rad) + Offset: Vec3(x=1000000.0 nm, y=2000.0 none, z=None) + Orientation: Rot3(roll=0.0174533 none, pitch=0.0 rad, yaw=0.0 none) Beam center: Vec3(x=0.32264 m, y=0.32768 m, z=None) Pixel size: Vec3(x=0.5 cm, y=0.5 cm, z=None) Slit length: None @@ -69,4 +41,4 @@ Source: Min. Wavelength: 2.2 Å Max. Wavelength: 10.0 Å Wavelength Spread: 14.3 % - Beam Size: BeamSize(name='bm', size=Vec3(x=0.012 m, y=13000.0 µm, z=None)) + Beam Size: BeamSize(name='bm', size=Vec3(x=0.012 m, y=13000.0 none, z=None)) diff --git a/test/sasdataloader/reference/cansas_test.txt b/test/sasdataloader/reference/cansas_test.txt index 60333cc05..46f1e4e87 100644 --- a/test/sasdataloader/reference/cansas_test.txt +++ b/test/sasdataloader/reference/cansas_test.txt @@ -1,4 +1,4 @@ -ILL-D11 example1: 2A 5mM 0%D2O +None Q I Metadata: @@ -11,17 +11,7 @@ Process: Name: spol Date: 04-Sep-2007 18:12:27 Description: None - Terms: - radialstep: 10.0 mm - sector_width: 180.0 deg - sector_orient: 0.0 deg - Flux_monitor: 1.00 - Count_time: 900.0 s - Q_resolution: estimated - Notes: - AvA1 0.0000E+00 AsA2 1.0000E+00 XvA3 1.1111E+01 XsA4 5.2200E-02 XfA5 0.0000E+00 - S... 13586 0 5.63E+01 2A 5mM 0%D2O Sbak 13567 0 1.88E+01 H2O buffer - Sbak 13533 0 7.49E+00 H2O buffer V... 13552 1 1.00E+00 Normal 10m from + Term: {'radialstep': '10.000', 'sector_width': '180.0', 'sector_orient': '0.0', 'Flux_monitor': '1.00', 'Count_time': '900.000', 'Q_resolution': 'estimated'} Sample: ID: None Transmission: 0.0 diff --git a/test/sasdataloader/reference/cansas_test_modified.txt b/test/sasdataloader/reference/cansas_test_modified.txt index 9ccd51e73..56d65ae88 100644 --- a/test/sasdataloader/reference/cansas_test_modified.txt +++ b/test/sasdataloader/reference/cansas_test_modified.txt @@ -1,4 +1,4 @@ -ILL-D11 example1: 2A 5mM 0%D2O +None Q I Metadata: @@ -11,17 +11,7 @@ Process: Name: spol Date: 04-Sep-2007 18:12:27 Description: None - Terms: - radialstep: 10.0 mm - sector_width: 180.0 deg - sector_orient: 0.0 deg - Flux_monitor: 1.00 - Count_time: 900.0 s - Q_resolution: estimated - Notes: - AvA1 0.0000E+00 AsA2 1.0000E+00 XvA3 1.1111E+01 XsA4 5.2200E-02 XfA5 0.0000E+00 - S... 13586 0 5.63E+01 2A 5mM 0%D2O Sbak 13567 0 1.88E+01 H2O buffer - Sbak 13533 0 7.49E+00 H2O buffer V... 13552 1 1.00E+00 Normal 10m from + Term: {'radialstep': '10.000', 'sector_width': '180.0', 'sector_orient': '0.0', 'Flux_monitor': '1.00', 'Count_time': '900.000', 'Q_resolution': 'estimated'} Sample: ID: This is a test file Transmission: 0.0 diff --git a/test/sasdataloader/reference/nxcansas_1Dand2D_multisasdata.txt b/test/sasdataloader/reference/nxcansas_1Dand2D_multisasdata.txt index 8f13d2536..5763cf71f 100644 --- a/test/sasdataloader/reference/nxcansas_1Dand2D_multisasdata.txt +++ b/test/sasdataloader/reference/nxcansas_1Dand2D_multisasdata.txt @@ -1,7 +1,4 @@ sasentry01 - Qy - Qx - I Metadata: MH4_5deg_16T_SLOW, Run: 33837 @@ -9,29 +6,27 @@ Metadata: Definition: MH4_5deg_16T_SLOW Process: - Name: Mantid generated CanSAS1D XML - Date: 11-May-2016 12:15:34 + Name: None + Date: None Description: None + Term: None + Notes: None Sample: - ID: + ID: None Transmission: None Thickness: None Temperature: None Position: None Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None Collimation: Length: None Detector: - Name: front-detector - Distance: 2845.260009765625 mm - Offset: None - Orientation: None - Beam center: None - Pixel size: None - Slit length: None -Detector: - Name: rear-detector - Distance: 4385.27978515625 mm + Name: None + Distance: None Offset: None Orientation: None Beam center: None diff --git a/test/sasdataloader/reference/nxcansas_1Dand2D_multisasentry.txt b/test/sasdataloader/reference/nxcansas_1Dand2D_multisasentry.txt index 3d375dcf7..769f5ee49 100644 --- a/test/sasdataloader/reference/nxcansas_1Dand2D_multisasentry.txt +++ b/test/sasdataloader/reference/nxcansas_1Dand2D_multisasentry.txt @@ -1,12 +1,99 @@ sasentry01 - dQ - Q - I Metadata: MH4_5deg_16T_SLOW, Run: 33837 ============================= +Definition: MH4_5deg_16T_SLOW +Process: + Name: None + Date: None + Description: None + Term: None + Notes: None +Sample: + ID: None + Transmission: None + Thickness: None + Temperature: None + Position: None + Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None +Collimation: + Length: None +Detector: + Name: None + Distance: None + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Source: + Radiation: Spallation Neutron Source + Shape: None + Wavelength: None + Min. Wavelength: None + Max. Wavelength: None + Wavelength Spread: None + Beam Size: None +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + +<<<<<<< HEAD +<<<<<<< HEAD + MH4_5deg_16T_SLOW, Run: 33837 + ============================= + +Definition: MH4_5deg_16T_SLOW +Process: + Name: Mantid generated CanSAS1D XML + Date: 11-May-2016 12:15:34 + Description: None +Sample: + ID: + Transmission: None + Thickness: None + Temperature: None + Position: None + Orientation: None +Collimation: + Length: None +Detector: + Name: front-detector + Distance: 2845.26 mm + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Detector: + Name: rear-detector + Distance: 4385.28 mm + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Source: + Radiation: Spallation Neutron Source + Shape: None + Wavelength: None + Min. Wavelength: None + Max. Wavelength: None + Wavelength Spread: None + Beam Size: None + +||||||| parent of cb5f3ffb (Add tests for dataset) + MH4_5deg_16T_SLOW, Run: 33837 + ============================= + Definition: MH4_5deg_16T_SLOW Process: Name: Mantid generated CanSAS1D XML @@ -45,12 +132,13 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None -sasentry02 - Qy - Qx - I -Metadata: +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None +||||||| original MH4_5deg_16T_SLOW, Run: 33837 ============================= @@ -59,6 +147,7 @@ Process: Name: Mantid generated CanSAS1D XML Date: 11-May-2016 12:15:34 Description: None + Term: None Sample: ID: Transmission: None @@ -92,3 +181,8 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None diff --git a/test/sasdataloader/reference/simpleexamplefile.txt b/test/sasdataloader/reference/simpleexamplefile.txt index 58c9c66b6..a81384082 100644 --- a/test/sasdataloader/reference/simpleexamplefile.txt +++ b/test/sasdataloader/reference/simpleexamplefile.txt @@ -1,9 +1,48 @@ sasentry01 - Q - I Metadata: - None, Run: [] - ============= + None, Run: None + =============== Definition: None +Process: + Name: None + Date: None + Description: None + Term: None + Notes: None +Sample: + ID: None + Transmission: None + Thickness: None + Temperature: None + Position: None + Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None +Collimation: + Length: None +Detector: + Name: None + Distance: None + Offset: None + Orientation: None + Beam center: None + Pixel size: None + Slit length: None +Source: + Radiation: None + Shape: None + Wavelength: None + Min. Wavelength: None + Max. Wavelength: None + Wavelength Spread: None + Beam Size: None +Transmission Spectrum: + Name: None + Timestamp: None + Wavelengths: None + Transmission: None + diff --git a/test/sasdataloader/reference/sphere2micron.txt b/test/sasdataloader/reference/sphere2micron.txt index 3df15c420..87f3b192d 100644 --- a/test/sasdataloader/reference/sphere2micron.txt +++ b/test/sasdataloader/reference/sphere2micron.txt @@ -1,12 +1,8 @@ Sesans - Wavelength - SpinEchoLength - Polarisation - Depolarisation Metadata: - Polystyrene of Markus Strobl, Full Sine, ++ only, Run: [] - ========================================================== + Title, Run: [] + ============ Definition: Polystyrene of Markus Strobl, Full Sine, ++ only Process: @@ -20,7 +16,7 @@ Process: Sample: ID: None Transmission: None - Thickness: 0.2 cm + Thickness: None Temperature: None Position: None Orientation: None diff --git a/test/sasdataloader/reference/sphere_isis.txt b/test/sasdataloader/reference/sphere_isis.txt index e92cfbf3a..53cd10147 100644 --- a/test/sasdataloader/reference/sphere_isis.txt +++ b/test/sasdataloader/reference/sphere_isis.txt @@ -1,11 +1,8 @@ Sesans - Wavelength - SpinEchoLength - Depolarisation Metadata: PMMA in Mixed Deuterated decalin, Run: [] - ========================================= + ======================================= Definition: PMMA in Mixed Deuterated decalin Process: diff --git a/test/sasdataloader/reference/valid_cansas_xml.txt b/test/sasdataloader/reference/valid_cansas_xml.txt index 3b3993aba..5e73076fa 100644 --- a/test/sasdataloader/reference/valid_cansas_xml.txt +++ b/test/sasdataloader/reference/valid_cansas_xml.txt @@ -11,9 +11,7 @@ Process: Name: Mantid generated CanSAS1D XML Date: 10-Oct-2013 16:00:29 Description: None - Terms: - svn: 2.6.20130902.1504 - user_file: K:/masks/MASKLOQ_MAN_133D_Xpress_8mm.txt + Term: {'svn': '2.6.20130902.1504', 'user_file': 'K:/masks/MASKLOQ_MAN_133D_Xpress_8mm.txt'} Sample: ID: LOQ_Standard_TK49_SANS Transmission: None @@ -47,3 +45,4 @@ Source: Max. Wavelength: None Wavelength Spread: None Beam Size: None + diff --git a/test/sasdataloader/reference/x25000_no_di.txt b/test/sasdataloader/reference/x25000_no_di.txt index b0cad2ee3..a36a709bb 100644 --- a/test/sasdataloader/reference/x25000_no_di.txt +++ b/test/sasdataloader/reference/x25000_no_di.txt @@ -1,25 +1,31 @@ sasentry01 - mask - Qy - Qx - I Metadata: , Run: ======= Definition: +Process: + Name: None + Date: None + Description: None + Term: None + Notes: None Sample: - ID: + ID: None Transmission: None Thickness: None Temperature: None Position: None Orientation: None +Aperture: + Name: None + Aperture size: None + Aperture distance: None Collimation: Length: None Detector: - Name: + Name: None Distance: None Offset: None Orientation: None diff --git a/test/sasdataloader/utest_data_names.py b/test/sasdataloader/utest_data_names.py new file mode 100644 index 000000000..11dcb6773 --- /dev/null +++ b/test/sasdataloader/utest_data_names.py @@ -0,0 +1,43 @@ +""" +Tests for generation of unique, but reproducible, names for data quantities +""" + +import os + +import pytest + +from sasdata.data import SasData +from sasdata.temp_ascii_reader import load_data_default_params +from sasdata.temp_hdf5_reader import load_data as hdf_load_data +from sasdata.temp_xml_reader import load_data as xml_load_data + + +def local_load(path: str) -> SasData: + """Get local file path""" + base = os.path.join(os.path.dirname(__file__), path) + if os.path.exists(f"{base}.h5"): + return hdf_load_data(f"{base}.h5").values() + if os.path.exists(f"{base}.xml"): + return xml_load_data(f"{base}.xml").values() + if os.path.exists(f"{base}.txt"): + return load_data_default_params(f"{base}.txt") + assert False + + +test_file_names = [ + ("ascii_test_1", "::Q:3KrS58TPgclJ1rgyr0VQp3"), + ("ISIS_1_1", "TK49 c10_SANS:79680:Q:4TghWEoJi6xxhyeDXhS751"), + ("cansas1d", "Test title:1234:Q:440tNBqdx9jvci6CgjmrmD"), + ("MAR07232_rest", "MAR07232_rest_out.dat:2:/sasentry01/sasdata01/Qx:2Y0qTTb054KSJnJaJv0rFl"), + ("simpleexamplefile", "::/sasentry01/sasdata01/Q:uoHMeB8mukElC1uLCy7Sd"), +] + + +@pytest.mark.names +@pytest.mark.parametrize("x", test_file_names) +def test_quantity_name(x): + (f, expected) = x + data = [v for v in local_load(f"data/{f}")][0] + if data.metadata.title is not None: + assert data.abscissae.unique_id.startswith(data.metadata.title) + assert data.abscissae.unique_id == expected diff --git a/test/sasdataloader/utest_new_sesans.py b/test/sasdataloader/utest_new_sesans.py index d91f8bedf..c17155094 100644 --- a/test/sasdataloader/utest_new_sesans.py +++ b/test/sasdataloader/utest_new_sesans.py @@ -4,20 +4,9 @@ import os -import numpy as np import pytest -from sasdata.model_requirements import ( - ComposeRequirements, - ModellingRequirements, - NullModel, - PinholeModel, - SesansModel, - SlitModel, - guess_requirements, -) -from sasdata.quantities import unit_parser, units -from sasdata.quantities.quantity import Quantity +from sasdata.temp_hdf5_reader import load_data from sasdata.temp_sesans_reader import load_data test_file_names = ["sphere2micron", "sphere_isis"] @@ -36,100 +25,3 @@ def test_load_file(f): with open(local_load(f"reference/{f}.txt")) as infile: expected = "".join(infile.readlines()) assert data.summary() == expected - -@pytest.mark.sesans -def test_sesans_modelling(): - data = load_data(local_load("sesans_data/sphere2micron.ses")) - req = guess_requirements(data) - assert type(req) is SesansModel - - def form_volume(x): - return np.pi * 4.0 / 3.0 * x**3 - - radius = 10000 - contrast = 5.4e-7 # Contrast is hard coded for best fit - form = contrast * form_volume(radius) - f2 = 1.0e-4*form*form - - xi_squared = smear(req, data._data_contents["SpinEchoLength"].value, full_data=data, y = data._data_contents["Depolarisation"].in_units_of(unit_parser.parse("A-2 cm-1")) / f2, radius=radius) - assert 1.0 < xi_squared < 1.5 - -@pytest.mark.sesans -def test_pinhole_zero(): - assert pinhole_smear(0) == 0 - -@pytest.mark.sesans -def test_pinhole_smear(): - smearing = [3**x for x in range(-1, 6)] - smears = [pinhole_smear(x) for x in smearing] - old = 0 - for factor, smear in zip(smearing, smears): - print(factor, smear) - assert old < smear < 1.2 - old = smear - assert pinhole_smear(3**6) > 1.2 - -@pytest.mark.sesans -def test_slit_zero(): - assert slit_smear(0, 0) == 0 - -@pytest.mark.sesans -def test_slit_smear(): - smears = [(length, width, slit_smear(3**length, 3**width)) for length in range(-1, 6) for width in range(-1, 6) if length + width == 6] - for length, width, smear in smears: - print(length, width, smear) - assert smear < 1.2 - assert slit_smear(3**6, 1) > 1.2 - assert slit_smear(1, 3**6) > 1.2 - - -def slit_smear(length: float, width): - data = Quantity(np.linspace(1e-4, 1e-1, 1000), units.per_angstrom) - diff = np.diff(data.value, prepend=0) - req = SlitModel(diff * length, diff * width) - return smear(req, data.value) - - -def pinhole_smear(smearing: float): - data = Quantity(np.linspace(1e-4, 1e-1, 1000), units.per_angstrom) - req = PinholeModel(np.diff(data.value, prepend=0) * smearing) - return smear(req, data.value) - - -def smear(req: ModellingRequirements, data: np.ndarray, y=None, full_data=None, radius=200): - def sphere(q): - def sas_3j1x_x(x): - return (np.sin(x) - x * np.cos(x))/x**3 - - return sas_3j1x_x(q * radius)**2 - - inner_q = req.preprocess_q(data, full_data) - result = req.postprocess_iq(sphere(inner_q), data) - - if y is None: - y = sphere(data) - - xi_squared = np.sum( ((y - result)/result )**2 ) / len(y) - return xi_squared - - - -@pytest.mark.sesans -def test_model_algebra(): - ses = SesansModel() - pin = PinholeModel(np.linspace(1e-3, 1, 1000)) - slit = SlitModel(np.linspace(1e-3, 1, 1000), np.linspace(1e-3, 1, 1000)) - null = NullModel() - - # Ignore slit smearing if we perform a sesans transform afterwards - assert type(pin + ses) is SesansModel - assert type(slit + ses) is SesansModel - # However, it is possible for the spin echo lengths to have some - # smearing between them. - assert type(ses + pin) is ComposeRequirements - assert type(null + ses) is SesansModel - assert type(null + slit) is SlitModel - assert type(null + pin) is PinholeModel - assert type(ses + null) is SesansModel - assert type(pin + null) is PinholeModel - assert type(slit + null) is SlitModel diff --git a/test/sasdataloader/utest_sasdataload.py b/test/sasdataloader/utest_sasdataload.py index 735904352..7952d6a28 100644 --- a/test/sasdataloader/utest_sasdataload.py +++ b/test/sasdataloader/utest_sasdataload.py @@ -2,455 +2,60 @@ Unit tests for the new recursive cansas reader """ -import io -import json import os -from dataclasses import dataclass, field -from typing import Any -import numpy as np import pytest -import sasdata.quantities.units as units -from sasdata.data import SasData, SasDataEncoder -from sasdata.dataset_types import one_dim -from sasdata.guess import guess_columns -from sasdata.quantities.quantity import Quantity -from sasdata.quantities.units import per_angstrom -from sasdata.temp_ascii_reader import ( - AsciiMetadataCategory, - AsciiReaderMetadata, - AsciiReaderParams, - load_data_default_params, -) -from sasdata.temp_ascii_reader import load_data as ascii_load_data from sasdata.temp_hdf5_reader import load_data as hdf_load_data -from sasdata.temp_sesans_reader import load_data as sesans_load_data from sasdata.temp_xml_reader import load_data as xml_load_data - -def local_load(path: str): - """Get local file path""" - base = os.path.join(os.path.dirname(__file__), path) - if os.path.exists(f"{base}.h5"): - return f"{base}.h5" - if os.path.exists(f"{base}.xml"): - return f"{base}.xml" - return f"{base}" - - -def local_reference_load(path: str): - return local_load(f"{os.path.join('reference', path)}") - - -def local_data_load(path: str): - return local_load(f"{os.path.join('data', path)}") - - -def local_json_load(path: str): - return local_load(f"{os.path.join('json', path)}") - - -def local_sesans_load(path: str): - return local_load(f"{os.path.join('sesans_data', path)}") - - -@pytest.mark.sasdata -def test_filter_data(): - data = xml_load_data(local_load("data/cansas1d_notitle")) - for k, v in data.items(): - assert v.metadata.raw.filter("transmission") == ["0.327"] - assert v.metadata.raw.filter("wavelength")[0] == Quantity(6.0, units.angstroms) - assert v.metadata.raw.filter("SDD")[0] == Quantity(4.15, units.meters) - data = hdf_load_data(local_load("data/nxcansas_1Dand2D_multisasentry")) - for k, v in data.items(): - assert v.metadata.raw.filter("radiation") == ["Spallation Neutron Source"] - assert v.metadata.raw.filter("SDD") == [ - Quantity(np.array([2845.26], dtype=np.float32), units.millimeters), - Quantity(np.array([4385.28], dtype=np.float32), units.millimeters), - ] - - -@dataclass(kw_only=True) -class BaseTestCase: - expected_values: dict[int, dict[str, float]] - expected_metadata: dict[str, Any] = field(default_factory=dict) - metadata_file: None | str = None - json_file: None | str = None - round_trip: bool = False - - -@dataclass(kw_only=True) -class AsciiTestCase(BaseTestCase): - # If this is a string of strings then the other params will be guessed. - reader_params: AsciiReaderParams | str - - -@dataclass(kw_only=True) -class BulkAsciiTestCase(AsciiTestCase): - reader_params: AsciiReaderParams - expected_values: dict[str, dict[int, dict[str, float]]] - expected_metadata: dict[str, dict[str, Any]] = field(default_factory=dict) - - -@dataclass(kw_only=True) -class XmlTestCase(BaseTestCase): - filename: str - entry: str = "sasentry01" - round_trip: bool = True - - -@dataclass(kw_only=True) -class Hdf5TestCase(BaseTestCase): - filename: str - entry: str = "sasentry01" - round_trip: bool = True - - -@dataclass(kw_only=True) -class SesansTestCase(BaseTestCase): - filename: str - - -test_cases = [ - pytest.param( - AsciiTestCase( - reader_params=local_data_load("ascii_test_1.txt"), - expected_values={ - 0: {"Q": 0.002618, "I": 0.02198, "dI": 0.002704}, - -1: {"Q": 0.0497, "I": 8.346, "dI": 0.191}, - }, - ), - marks=pytest.mark.xfail(reason="The ASCII reader cannot make the right guesses for this file."), - ), - AsciiTestCase( - reader_params=local_data_load("test_3_columns.txt"), - expected_values={ - 0: {"Q": 0, "I": 2.83954, "dI": 0.6}, - -1: {"Q": 1.22449, "I": 7.47487, "dI": 1.05918}, - }, - ), - pytest.param( - AsciiTestCase( - reader_params=local_data_load("detector_rectangular.DAT"), - expected_values={ - 0: { - "Qx": -0.009160664, - "Qy": -0.1683881, - "I": 16806.79, - "dI": 0.01366757, - }, - -1: { - "Qx": 0.2908819, - "Qy": 0.1634992, - "I": 8147.779, - "dI": 0.05458562, - }, - }, - ), - marks=pytest.mark.xfail( - reason="Guesses for 2D ASCII files are currently wrong, so the data loaded won't be correct." - ), - ), - BulkAsciiTestCase( - reader_params=AsciiReaderParams( - filenames=[ - local_data_load(filename) - for filename in [ - "1_33_1640_22.874115.csv", - "2_42_1640_23.456895.csv", - "3_61_1640_23.748285.csv", - "4_103_1640_24.039675.csv", - "5_312_1640_24.331065.csv", - "6_1270_1640_24.331065.csv", - ] - ], - columns=[(column, per_angstrom) for column in guess_columns(3, one_dim)], - separator_dict={"Comma": True}, - metadata=AsciiReaderMetadata( - master_metadata={ - "magnetic": AsciiMetadataCategory( - values={ - "counting_index": 0, - "applied_magnetic_field": 1, - "saturation_magnetization": 2, - "demagnetizing_field": 3, - } - ) - } - ), - ), - expected_values={}, - expected_metadata={ - "1_33_1640_22.874115.csv": { - "counting_index": ["1"], - "applied_magnetic_field": ["33"], - "saturation_magnetization": ["1640"], - "demagnetizing_field": ["22"], - }, - "6_1270_1640_24.331065.csv": { - "counting_index": ["6"], - "applied_magnetic_field": ["1270"], - "saturation_magnetization": ["1640"], - "demagnetizing_field": ["24"], - }, - }, - ), - XmlTestCase( - filename=local_data_load("ISIS_1_0.xml"), - entry="79680main_1D_2.2_10.0", - expected_values={ - 0: {"Q": 0.009, "I": 85.3333, "dI": 0.852491, "dQ": 0}, - -2: {"Q": 0.281, "I": 0.408902, "dQ": 0}, - -1: {"Q": 0.283, "I": 0, "dI": 0, "dQ": 0}, - }, - expected_metadata={ - # TODO: Add more. - "radiation": "neutron" - }, - ), - Hdf5TestCase( - filename=local_data_load("simpleexamplefile.h5"), - metadata_file=local_reference_load("simpleexamplefile.txt"), - expected_values={ - 0: {"Q": 0.5488135039273248, "I": 0.6778165367962301}, - -1: {"Q": 0.004695476192547066, "I": 0.4344166255581208}, - }, - ), - Hdf5TestCase( - filename=local_data_load("MAR07232_rest.h5"), - metadata_file=local_reference_load("MAR07232_rest.txt"), - expected_values={}, - ), - Hdf5TestCase( - filename=local_data_load("x25000_no_di.h5"), - expected_values={}, - ), - Hdf5TestCase( - filename=local_data_load("nxcansas_1Dand2D_multisasentry.h5"), - metadata_file=local_reference_load("nxcansas_1Dand2D_multisasentry.txt"), - expected_values={}, - ), - Hdf5TestCase( - filename=local_data_load("nxcansas_1Dand2D_multisasdata.h5"), - metadata_file=local_reference_load("nxcansas_1Dand2D_multisasdata.txt"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("ISIS_1_0.xml"), - entry="79680main_1D_2.2_10.0", - metadata_file=local_reference_load("ISIS_1_0.txt"), - json_file=local_json_load("ISIS_1_0.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("ISIS_1_1.xml"), - entry="79680main_1D_2.2_10.0", - metadata_file=local_reference_load("ISIS_1_1.txt"), - json_file=local_json_load("ISIS_1_1.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("ISIS_1_1_doubletrans.xml"), - entry="79680main_1D_2.2_10.0", - metadata_file=local_reference_load("ISIS_1_1_doubletrans.txt"), - json_file=local_json_load("ISIS_1_1_doubletrans.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("ISIS_1_1_notrans.xml"), - entry="79680main_1D_2.2_10.0", - metadata_file=local_reference_load("ISIS_1_1_notrans.txt"), - json_file=local_json_load("ISIS_1_1_notrans.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("TestExtensions.xml"), - entry="TK49 c10_SANS", - metadata_file=local_reference_load("TestExtensions.txt"), - json_file=local_json_load("TestExtensions.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("cansas1d.xml"), - entry="Test title", - metadata_file=local_reference_load("cansas1d.txt"), - json_file=local_json_load("cansas1d.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("cansas1d_badunits.xml"), - entry="Test title", - metadata_file=local_reference_load("cansas1d_badunits.txt"), - json_file=local_json_load("cansas1d_badunits.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("cansas1d_notitle.xml"), - entry="SasData01", - metadata_file=local_reference_load("cansas1d_notitle.txt"), - json_file=local_json_load("cansas1d_notitle.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("cansas1d_slit.xml"), - entry="Test title", - metadata_file=local_reference_load("cansas1d_slit.txt"), - json_file=local_json_load("cansas1d_slit.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("cansas1d_units.xml"), - entry="Test title", - metadata_file=local_reference_load("cansas1d_units.txt"), - json_file=local_json_load("cansas1d_units.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("cansas_test.xml"), - entry="ILL-D11 example1: 2A 5mM 0%D2O", - metadata_file=local_reference_load("cansas_test.txt"), - json_file=local_json_load("cansas_test.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("cansas_test_modified.xml"), - entry="ILL-D11 example1: 2A 5mM 0%D2O", - metadata_file=local_reference_load("cansas_test_modified.txt"), - json_file=local_json_load("cansas_test_modified.json"), - expected_values={}, - ), - XmlTestCase( - filename=local_data_load("valid_cansas_xml.xml"), - entry="80514main_1D_2.2_10.0", - metadata_file=local_reference_load("valid_cansas_xml.txt"), - json_file=local_json_load("valid_cansas_xml.json"), - expected_values={}, - ), - SesansTestCase( - filename=local_sesans_load("sphere2micron.ses"), - metadata_file=local_reference_load("sphere2micron.txt"), - expected_values={ - 0: {"SpinEchoLength": 391.56, "Depolarisation": 0.0041929}, - -1: {"SpinEchoLength": 46099, "Depolarisation": -0.19956}, - }, - ), +test_hdf_file_names = [ + # "simpleexamplefile", + "nxcansas_1Dand2D_multisasentry", + "nxcansas_1Dand2D_multisasdata", + "MAR07232_rest", + "x25000_no_di", ] +test_xml_file_names = [ + "ISIS_1_0", + "ISIS_1_1", + "ISIS_1_1_doubletrans", + "ISIS_1_1_notrans", + "TestExtensions", + "cansas1d", + "cansas1d_badunits", + "cansas1d_notitle", + "cansas1d_slit", + "cansas1d_units", + "cansas_test", + "cansas_test_modified", + "cansas_xml_multisasentry_multisasdata", + "valid_cansas_xml", +] -def join_actual_expected( - actual: list[SasData], expected: dict[str, dict[int, dict[str, float]]] -) -> list[tuple[SasData, dict[int, dict[str, float]]]]: - return_value = [] - for actual_datum in actual: - matching_expected_datum = expected.get(actual_datum.name) - if matching_expected_datum is None: - continue - return_value.append((actual_datum, matching_expected_datum)) - return return_value - - -def is_uncertainty(column: str) -> bool: - for uncertainty_str in ["I", "Q", "Qx", "Qy"]: - if column == "d" + uncertainty_str: - return True - return False - - -@pytest.mark.dataload -@pytest.mark.parametrize("test_case", test_cases) -def test_load_file(test_case: BaseTestCase): - match test_case: - case BulkAsciiTestCase(): - loaded_data = ascii_load_data(test_case.reader_params) - case AsciiTestCase(): - if isinstance(test_case.reader_params, str): - loaded_data = load_data_default_params(test_case.reader_params)[0] - elif isinstance(test_case.reader_params, AsciiReaderParams): - loaded_data = ascii_load_data(test_case.reader_params)[0] - else: - raise TypeError("Invalid type for reader_params.") - case Hdf5TestCase(): - combined_data = hdf_load_data(test_case.filename) - loaded_data = combined_data[test_case.entry] - # TODO: Support SESANS - case XmlTestCase(): - # Not bulk, so just assume we get one dataset. - combined_data = xml_load_data(test_case.filename) - loaded_data = combined_data[test_case.entry] - case SesansTestCase(): - loaded_data = sesans_load_data(test_case.filename) - combined_data = {"only": loaded_data} - case _: - raise ValueError("Invalid loader") - if isinstance(test_case, BulkAsciiTestCase): - loaded_expected_pairs = join_actual_expected(loaded_data, test_case.expected_values) - metadata_filenames = test_case.expected_metadata.keys() - else: - loaded_expected_pairs = [(loaded_data, test_case.expected_values)] - metadata_filenames = [loaded_data.name] - for loaded, expected in loaded_expected_pairs: - for index, values in expected.items(): - for column, expected_value in values.items(): - if is_uncertainty(column): - assert loaded._data_contents[column[1::]]._variance[index] == pytest.approx(expected_value**2) - else: - assert loaded._data_contents[column].value[index] == pytest.approx(expected_value) - - for filename in metadata_filenames: - current_metadata_dict = test_case.expected_metadata.get(filename) - current_datum = ( - next(filter(lambda d: d.name == filename, loaded_data)) if isinstance(loaded_data, list) else loaded_data - ) - if current_metadata_dict is None: - continue - for metadata_key, value in current_metadata_dict.items(): - assert current_datum.metadata.raw.filter(metadata_key) == value - if test_case.metadata_file is not None: - with open(test_case.metadata_file, encoding="utf-8") as infile: - expected = "".join(infile.readlines()) - keys = sorted([d for d in combined_data]) - assert "".join(combined_data[k].summary() for k in keys) == expected +def local_load(path: str): + """Get local file path""" + return os.path.join(os.path.dirname(__file__), path) - if test_case.json_file is not None: - # Test serialisation - with open(test_case.json_file, encoding="utf-8") as infile: - expected = json.loads("".join(infile.readlines())) - assert json.loads(SasDataEncoder().encode(combined_data)) == expected - # Test deserialisation - with open(test_case.json_file, encoding="utf-8") as infile: - raw = json.loads("".join(infile.readlines())) - parsed = {} - for k in raw: - parsed[k] = SasData.from_json(raw[k]) +@pytest.mark.sasdata +@pytest.mark.parametrize("f", test_hdf_file_names) +def test_hdf_load_file(f): + data = hdf_load_data(local_load(f"data/{f}.h5")) - for k in combined_data: - expect = combined_data[k] - pars = parsed[k] - assert pars.name == expect.name - # assert pars._data_contents == expect._data_contents - assert pars.dataset_type == expect.dataset_type - assert pars.mask == expect.mask - assert pars.model_requirements == expect.model_requirements + with open(local_load(f"reference/{f}.txt")) as infile: + expected = "".join(infile.readlines()) + keys = sorted([d for d in data]) + assert "".join(data[k].summary() for k in keys) == expected - if test_case.round_trip: - bio = io.BytesIO() - SasData.save_h5(combined_data, bio) - bio.seek(0) - result = hdf_load_data(bio) - bio.close() +@pytest.mark.current +@pytest.mark.parametrize("f", test_xml_file_names) +def test_xml_load_file(f): + data = xml_load_data(local_load(f"data/{f}.xml")) - for name, entry in result.items(): - assert combined_data[name].metadata.title == entry.metadata.title - assert combined_data[name].metadata.run == entry.metadata.run - assert combined_data[name].metadata.definition == entry.metadata.definition - assert combined_data[name].metadata.process == entry.metadata.process - assert combined_data[name].metadata.instrument == entry.metadata.instrument - assert combined_data[name].metadata.sample == entry.metadata.sample - assert combined_data[name].ordinate.units == entry.ordinate.units - assert np.all(combined_data[name].ordinate.value == entry.ordinate.value) - assert combined_data[name].abscissae.units == entry.abscissae.units - assert np.all(combined_data[name].abscissae.value == entry.abscissae.value) + with open(local_load(f"reference/{f}.txt")) as infile: + expected = "".join(infile.readlines()) + assert data[0].summary() == expected diff --git a/test/slicers/__init__.py b/test/slicers/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test/slicers/meshes_for_testing.py b/test/slicers/meshes_for_testing.py new file mode 100644 index 000000000..7e39ec75c --- /dev/null +++ b/test/slicers/meshes_for_testing.py @@ -0,0 +1,115 @@ +""" +Meshes used in testing along with some expected values +""" + +import numpy as np + +from sasdata.slicing.meshes.mesh import Mesh +from sasdata.slicing.meshes.meshmerge import meshmerge +from sasdata.slicing.meshes.voronoi_mesh import voronoi_mesh + +coords = np.arange(-4, 5) +grid_mesh = voronoi_mesh(*np.meshgrid(coords, coords)) + + +item_1 = np.array([ + [-3.5, -0.5], + [-0.5, 3.5], + [ 0.5, 3.5], + [ 3.5, -0.5], + [ 0.0, 1.5]], dtype=float) + +item_2 = np.array([ + [-1.0, -2.0], + [-2.0, -2.0], + [-2.0, -1.0], + [-1.0, -1.0]], dtype=float) + +mesh_points = np.concatenate((item_1, item_2), axis=0) +cells = [[0,1,2,3,4],[5,6,7,8]] + +shape_mesh = Mesh(mesh_points, cells) + +# Subset of the mappings that meshmerge should include +# This can be read off the plots generated below + + +expected_shape_mappings = [ + (100, -1), + (152, -1), + (141, -1), + (172, -1), + (170, -1), + (0, -1), + (1, -1), + (8, 0), + (9, 0), + (37, 0), + (83, 0), + (190, 1), + (186, 1), + (189, 1), + (193, 1) +] + +expected_grid_mappings = [ + (89, 0), + (90, 1), + (148, 16), + (175, 35), + (60, 47), + (44, 47), + (80, 60) +] + +# +# Mesh location tests +# + +location_test_mesh_points = np.array([ + [0, 0], # 0 + [0, 1], # 1 + [0, 2], # 2 + [1, 0], # 3 + [1, 1], # 4 + [1, 2], # 5 + [2, 0], # 6 + [2, 1], # 7 + [2, 2]], dtype=float) + +location_test_mesh_cells = [ + [0, 1, 4, 3], + [1, 2, 5, 4], + [3, 4, 7, 6], + [4, 5, 8, 7]] + +location_test_mesh = Mesh(location_test_mesh_points, location_test_mesh_cells) + +test_coords = 0.25 + 0.5*np.arange(4) +location_test_points_x, location_test_points_y = np.meshgrid(test_coords, test_coords) + +if __name__ == "__main__": + + import matplotlib.pyplot as plt + + combined_mesh, _, _ = meshmerge(grid_mesh, shape_mesh) + + plt.figure() + combined_mesh.show(actually_show=False, show_labels=True, color='k') + grid_mesh.show(actually_show=False, show_labels=True, color='r') + + plt.xlim([-5, 5]) + plt.ylim([-5, 5]) + + plt.figure() + combined_mesh.show(actually_show=False, show_labels=True, color='k') + shape_mesh.show(actually_show=False, show_labels=True, color='r') + + plt.xlim([-5, 5]) + plt.ylim([-5, 5]) + + plt.figure() + location_test_mesh.show(actually_show=False, show_labels=True) + plt.scatter(location_test_points_x, location_test_points_y) + + plt.show() diff --git a/test/slicers/utest_meshmerge.py b/test/slicers/utest_meshmerge.py new file mode 100644 index 000000000..a4a1645c2 --- /dev/null +++ b/test/slicers/utest_meshmerge.py @@ -0,0 +1,31 @@ +""" +Tests for mesh merging operations. + +It's pretty hard to test componentwise, but we can do some tests of the general behaviour +""" + +from sasdata.slicing.meshes.meshmerge import meshmerge +from test.slicers.meshes_for_testing import expected_grid_mappings, expected_shape_mappings, grid_mesh, shape_mesh + + +def test_meshmerge_mappings(): + """ Test the output of meshmerge is correct + + IMPORTANT IF TESTS FAIL!!!... The docs for scipy.spatial.Voronoi and Delaunay + say that the ordering of faces might depend on machine precession. Thus, these + tests might not be reliable... we'll see how they play out + """ + + import sys + if sys.platform == "darwin": + # It does indeed rely on machine precision, only run on windows and linux + return + + combined_mesh, grid_mappings, shape_mappings = meshmerge(grid_mesh, shape_mesh) + + for triangle_cell, grid_cell in expected_grid_mappings: + assert grid_mappings[triangle_cell] == grid_cell + + for triangle_cell, shape_cell in expected_shape_mappings: + assert shape_mappings[triangle_cell] == shape_cell + diff --git a/test/slicers/utest_point_assignment.py b/test/slicers/utest_point_assignment.py new file mode 100644 index 000000000..a82f1c790 --- /dev/null +++ b/test/slicers/utest_point_assignment.py @@ -0,0 +1,5 @@ + + + +def test_location_assignment(): + pass diff --git a/test/transforms/utest_NDrebin.py b/test/transforms/utest_NDrebin.py new file mode 100644 index 000000000..e5365a95d --- /dev/null +++ b/test/transforms/utest_NDrebin.py @@ -0,0 +1,272 @@ +import time + +import numpy as np +from matplotlib import pyplot as plt + +from sasdata.transforms.NDrebin import NDRebin + + +def test_1D_exact(show_plots: bool): + # Parameters for the Gaussian function + mu = 0.0 # Mean + sigma = 1.0 # Standard deviation + + # fiducial + xreal = np.linspace(-5, 5, 11) + Ireal = np.exp(-((xreal - mu) ** 2) / (2 * sigma ** 2)) / (sigma * np.sqrt(2 * np.pi)) + + # rebin to the exact same bins + rebin = NDRebin(Ireal, xreal, + lower=-5.5, upper=5.5, num_bins=11) + rebin.run() + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + + assert all(Ibin == Ireal) + assert all(qbin[0] == xreal) + + # Plot + if show_plots: + plt.figure() + plt.plot(qbin[0], Ibin, 'o', linewidth=2, label='bin') + plt.plot(xreal, Ireal, 'k-', linewidth=2, label='exact') + + plt.xlabel('x') + plt.ylabel('I') + plt.legend() + plt.tight_layout() + plt.show() + + + # rebin to the exact same bins with fractional + rebin = NDRebin(Ireal, xreal, + lower=-5.5, upper=5.5, num_bins=11, fractional=True) + rebin.run() + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + + assert all(Ibin == Ireal) + + # Plot + if show_plots: + plt.figure() + plt.plot(qbin[0], Ibin, 'o', linewidth=2, label='fractional bin') + plt.plot(xreal, Ireal, 'k-', linewidth=2, label='exact') + + plt.xlabel('x') + plt.ylabel('I') + plt.legend() + plt.tight_layout() + plt.show() + + + +def test_2D(show_plots: bool): + # Parameters of the 2D Gaussian + mu = np.array([0.15, 0.0, 0.0]) # Mean vector + sigma = np.array([0.015, 0.055, 0.05]) # Std dev in x and y + noise = 0. + SDD = 2.7 + k_0 = 2*np.pi/5 + pix_x = 1./128. + pix_y = 1./128. + + # Generate our 2D detector grid + x = np.arange(-64,64)*pix_x + y = np.arange(-64,64)*pix_y + + [xmesh, ymesh] = np.meshgrid(x, y) + + # calculate qx, qy, qz + qx = k_0*xmesh/np.sqrt(xmesh**2+ymesh**2+SDD**2) + qy = k_0*ymesh/np.sqrt(xmesh**2+ymesh**2+SDD**2) + qz = k_0-k_0*SDD/np.sqrt(xmesh**2+ymesh**2+SDD**2) + + # qmat + qmat0 = np.stack([qx,qy,qz], axis=2) + + # now rotate about y + angle_list = np.pi/180*np.linspace(-15,15,int(30/.25)) + qmat = np.zeros((len(x), len(y), len(angle_list), 3)) + for ind in range(len(angle_list)): + new_qmat = np.copy(qmat0) + new_qmat[:,:,0] = np.cos(angle_list[ind])*qmat0[:,:,0] - \ + np.sin(angle_list[ind])*qmat0[:,:,2] + new_qmat[:,:,2] = np.sin(angle_list[ind])*qmat0[:,:,0] + \ + np.cos(angle_list[ind])*qmat0[:,:,2] + qmat[:,:,ind,:] = qmat0 + + + # Evaluate Gaussian: + # G(x,y) = (1/(2πσxσy)) * exp(-[(x-μx)^2/(2σx^2) + (y-μy)^2/(2σy^2)]) + I_2D = ( + np.exp( + -((qmat[:,:,:,0] - mu[0])**2) / (2 * sigma[0]**2) + -((qmat[:,:,:,1] - mu[1])**2) / (2 * sigma[1]**2) + -((qmat[:,:,:,2] - mu[2])**2) / (2 * sigma[2]**2) + ) / + (2 * np.pi * sigma[0] * sigma[1] * sigma[2]) + ) + + # Add uniform noise + I_2D = I_2D - noise + 2 * noise * np.random.rand(*I_2D.shape) + + # Rebin in 2D. + # You can choose finite steps for both x and y depending on how you want bins defined. + start = time.perf_counter() + rebin = NDRebin(I_2D, qmat, + step_size=[0.006, 0.006, np.inf]) + rebin.run() + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + end = time.perf_counter() + print(f"Computed {qmat.size/3} points in {end - start:.6f} seconds") + + start = time.perf_counter() + rebin = NDRebin(I_2D, qmat, + step_size=[0.0035, 0.0035, np.inf], + fractional=True) + rebin.run() + Ibin2 = rebin.binned_data + qbin2 = rebin.bin_centers_list + end = time.perf_counter() + print(f"Computed {qmat.size/3} points with fractional binning in {end - start:.6f} seconds") + + + if show_plots: + # Fiducial 2D + [xmesh, ymesh] = np.meshgrid(qbin2[0], qbin2[1]) + Ireal = ( + np.exp( + -((xmesh - mu[0])**2) / (2 * sigma[0]**2) + -((ymesh - mu[1])**2) / (2 * sigma[1]**2) + ) / + (2 * np.pi * sigma[0] * sigma[1]) + ) + + # Plot a 1D slice of the binned data along x (y bins aggregated) + plt.figure(figsize=(4,8)) + + plt.subplot(3, 1, 1) + plt.pcolormesh(qbin[0], qbin[1], np.squeeze(Ibin.T), shading='nearest') + plt.xlabel('x') + plt.ylabel('y') + plt.title('sum') + plt.colorbar() + plt.tight_layout() + + plt.subplot(3, 1, 2) + plt.pcolormesh(qbin2[0], qbin2[1], np.squeeze(Ibin2.T), shading='nearest') + plt.xlabel('x') + plt.ylabel('y') + plt.title('sum') + plt.colorbar() + plt.tight_layout() + + plt.subplot(3, 1, 3) + plt.pcolormesh(xmesh, ymesh, Ireal, shading='nearest') + plt.xlabel('x') + plt.ylabel('y') + plt.title('real') + plt.colorbar() + plt.tight_layout() + plt.show() + + +def test_syntax(): + # test syntax + Ndims = 4 + Nvals = int(1e4) + qmat = np.random.rand(Ndims, Nvals) + Imat = np.random.rand(Nvals) + + rebin = NDRebin(Imat, qmat, + step_size=0.1*np.random.rand(Ndims)+0.05, + lower=0.1*np.random.rand(Ndims)+0.0, + upper=0.1*np.random.rand(Ndims)+0.9) + rebin.run() + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + + + # test syntax + Ndims = 2 + Nvals = int(1e4) + qmat = np.random.rand(Ndims, 100, Nvals) + Imat = np.random.rand(100, Nvals) + Imat_errs = np.random.rand(100, Nvals) + + rebin = NDRebin(Imat, qmat, + data_errs = Imat_errs, + num_bins=[10,20], + axes = np.eye(2), + fractional=True) + rebin.run() + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + Ibin_errs = rebin.binned_data_errs + bins_list = rebin.bins_list + step_size = rebin.step_size + num_bins = rebin.num_bins + + +# test ND gaussian +def test_ND(): + Ndims = 4 + mu = np.zeros(Ndims) # Mean vector + sigma = np.random.rand(Ndims) # Std dev in x and y + noise = 0.1 + Nvals = int(1e6) + + # Generate random points (x, y) in a 2D square + qmat = -5 + 10 * np.random.rand(Ndims, Nvals) + + # Evaluate 2D Gaussian: + # G(x,y) = (1/(2πσxσy)) * exp(-[(x-μx)^2/(2σx^2) + (y-μy)^2/(2σy^2)]) + exp_op = np.zeros(Nvals) + sigma_tot = 1 + for ind in range(Ndims): + exp_op = exp_op -((qmat[ind,:] - mu[ind])**2) / (2 * sigma[ind]**2) + sigma_tot = sigma_tot * sigma[ind] + I_ND = ( + np.exp(exp_op) / + (2 * np.pi * sigma_tot) + ) + + # Add uniform noise + I_ND = I_ND - noise + 2 * noise * np.random.rand(1,Nvals) + + # Rebin in 2D. + # You can choose finite steps for both x and y depending on how you want bins defined. + start = time.perf_counter() + rebin = NDRebin(I_ND, qmat, + step_size=0.2*np.random.rand(Ndims)+0.1, + lower=[1,2,3,0], + upper=[9,8,7,9.5] + ) + rebin.run() + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + end = time.perf_counter() + print(f"Computed {Nvals} points in {end - start:.6f} seconds") + + start = time.perf_counter() + rebin = NDRebin(I_ND, qmat, + step_size=0.2*np.random.rand(Ndims)+0.1, + lower=[1,2,3,0], + upper=[9,8,7,9.5], + fractional=True + ) + rebin.run() + Ibin = rebin.binned_data + qbin = rebin.bin_centers_list + end = time.perf_counter() + print(f"Computed {Nvals} points with fractional binning in {end - start:.6f} seconds") + + + +if __name__ == "__main__": + test_1D_exact(show_plots=True) + test_2D(show_plots=True) + test_syntax() + test_ND() diff --git a/test/transforms/utest_interpolation.py b/test/transforms/utest_interpolation.py index bfb0e54a3..9ac701ceb 100644 --- a/test/transforms/utest_interpolation.py +++ b/test/transforms/utest_interpolation.py @@ -1,101 +1,101 @@ -from collections.abc import Callable - -import numpy as np -import pytest -from matplotlib import pyplot as plt -from numpy.typing import ArrayLike - -from sasdata.quantities import units -from sasdata.quantities.plotting import quantity_plot -from sasdata.quantities.quantity import NamedQuantity, Quantity -from sasdata.transforms.rebinning import InterpolationOptions, calculate_interpolation_matrix_1d - -test_functions = [ - lambda x: x**2, - lambda x: 2*x, - lambda x: x**3 -] - -test_interpolation_orders = [ - InterpolationOptions.LINEAR, - InterpolationOptions.CUBIC -] - - -@pytest.mark.parametrize("fun", test_functions) -@pytest.mark.parametrize("order", test_interpolation_orders) -def test_interpolate_matrix_inside(fun: Callable[[Quantity[ArrayLike]], Quantity[ArrayLike]], order: InterpolationOptions, show_plots: bool): - original_points = NamedQuantity("x_base", np.linspace(-10,10, 31), units.meters) - test_points = NamedQuantity("x_test", np.linspace(-5, 5, 11), units.meters) - - - mapping, _ = calculate_interpolation_matrix_1d(original_points, test_points, order=order) - - y_original = fun(original_points) - y_test = y_original @ mapping - y_expected = fun(test_points) - - test_units = y_expected.units - - y_values_test = y_test.in_units_of(test_units) - y_values_expected = y_expected.in_units_of(test_units) - - if show_plots: - print(y_values_test) - print(y_values_expected) - - quantity_plot(original_points, y_original) - quantity_plot(test_points, y_test) - quantity_plot(test_points, y_expected) - plt.show() - - assert len(y_values_test) == len(y_values_expected) - - for t, e in zip(y_values_test, y_values_expected): - assert t == pytest.approx(e, abs=2) - - -@pytest.mark.parametrize("fun", test_functions) -@pytest.mark.parametrize("order", test_interpolation_orders) -def test_interpolate_different_units(fun: Callable[[Quantity[ArrayLike]], Quantity[ArrayLike]], order: InterpolationOptions, show_plots: bool): - original_points = NamedQuantity("x_base", np.linspace(-10,10, 107), units.meters) - test_points = NamedQuantity("x_test", np.linspace(-5000, 5000, 11), units.millimeters) - - mapping, _ = calculate_interpolation_matrix_1d(original_points, test_points, order=order) - - y_original = fun(original_points) - y_test = y_original @ mapping - y_expected = fun(test_points) - - test_units = y_expected.units - - y_values_test = y_test.in_units_of(test_units) - y_values_expected = y_expected.in_units_of(test_units) - - if show_plots: - print(y_values_test) - print(y_test.in_si()) - print(y_values_expected) - - plt.plot(original_points.in_si(), y_original.in_si()) - plt.plot(test_points.in_si(), y_test.in_si(), "x") - plt.plot(test_points.in_si(), y_expected.in_si(), "o") - plt.show() - - assert len(y_values_test) == len(y_values_expected) - - for t, e in zip(y_values_test, y_values_expected): - assert t == pytest.approx(e, rel=5e-2) - -@pytest.mark.parametrize("order", test_interpolation_orders) -def test_linear(order: InterpolationOptions): - """ Test linear interpolation between two points""" - x_and_y = NamedQuantity("x_base", np.linspace(-10, 10, 2), units.meters) - new_x = NamedQuantity("x_test", np.linspace(-5000, 5000, 101), units.millimeters) - - mapping, _ = calculate_interpolation_matrix_1d(x_and_y, new_x, order=order) - - linear_points = x_and_y @ mapping - - for t, e in zip(new_x.in_si(), linear_points.in_si()): - assert t == pytest.approx(e, rel=1e-3) +from collections.abc import Callable + +import numpy as np +import pytest +from matplotlib import pyplot as plt +from numpy.typing import ArrayLike + +from sasdata.quantities import units +from sasdata.quantities.plotting import quantity_plot +from sasdata.quantities.quantity import NamedQuantity, Quantity +from sasdata.transforms.rebinning import InterpolationOptions, calculate_interpolation_matrix_1d + +test_functions = [ + lambda x: x**2, + lambda x: 2*x, + lambda x: x**3 +] + +test_interpolation_orders = [ + InterpolationOptions.LINEAR, + InterpolationOptions.CUBIC +] + + +@pytest.mark.parametrize("fun", test_functions) +@pytest.mark.parametrize("order", test_interpolation_orders) +def test_interpolate_matrix_inside(fun: Callable[[Quantity[ArrayLike]], Quantity[ArrayLike]], order: InterpolationOptions, show_plots: bool): + original_points = NamedQuantity("x_base", np.linspace(-10,10, 31), units.meters) + test_points = NamedQuantity("x_test", np.linspace(-5, 5, 11), units.meters) + + + mapping, _ = calculate_interpolation_matrix_1d(original_points, test_points, order=order) + + y_original = fun(original_points) + y_test = y_original @ mapping + y_expected = fun(test_points) + + test_units = y_expected.units + + y_values_test = y_test.in_units_of(test_units) + y_values_expected = y_expected.in_units_of(test_units) + + if show_plots: + print(y_values_test) + print(y_values_expected) + + quantity_plot(original_points, y_original) + quantity_plot(test_points, y_test) + quantity_plot(test_points, y_expected) + plt.show() + + assert len(y_values_test) == len(y_values_expected) + + for t, e in zip(y_values_test, y_values_expected): + assert t == pytest.approx(e, abs=2) + + +@pytest.mark.parametrize("fun", test_functions) +@pytest.mark.parametrize("order", test_interpolation_orders) +def test_interpolate_different_units(fun: Callable[[Quantity[ArrayLike]], Quantity[ArrayLike]], order: InterpolationOptions, show_plots: bool): + original_points = NamedQuantity("x_base", np.linspace(-10,10, 107), units.meters) + test_points = NamedQuantity("x_test", np.linspace(-5000, 5000, 11), units.millimeters) + + mapping, _ = calculate_interpolation_matrix_1d(original_points, test_points, order=order) + + y_original = fun(original_points) + y_test = y_original @ mapping + y_expected = fun(test_points) + + test_units = y_expected.units + + y_values_test = y_test.in_units_of(test_units) + y_values_expected = y_expected.in_units_of(test_units) + + if show_plots: + print(y_values_test) + print(y_test.in_si()) + print(y_values_expected) + + plt.plot(original_points.in_si(), y_original.in_si()) + plt.plot(test_points.in_si(), y_test.in_si(), "x") + plt.plot(test_points.in_si(), y_expected.in_si(), "o") + plt.show() + + assert len(y_values_test) == len(y_values_expected) + + for t, e in zip(y_values_test, y_values_expected): + assert t == pytest.approx(e, rel=5e-2) + +@pytest.mark.parametrize("order", test_interpolation_orders) +def test_linear(order: InterpolationOptions): + """ Test linear interpolation between two points""" + x_and_y = NamedQuantity("x_base", np.linspace(-10, 10, 2), units.meters) + new_x = NamedQuantity("x_test", np.linspace(-5000, 5000, 101), units.millimeters) + + mapping, _ = calculate_interpolation_matrix_1d(x_and_y, new_x, order=order) + + linear_points = x_and_y @ mapping + + for t, e in zip(new_x.in_si(), linear_points.in_si()): + assert t == pytest.approx(e, rel=1e-3) diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv index 65305e2ab..8e9c70665 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/10_1000_1340_10.csv @@ -1,105 +1,105 @@ -3.624299999999999744e-02 7.295645247999999583e+01 1.637502872666669873e+01 -4.068929999999999769e-02 3.496757764333329987e+01 1.132330254166670080e+01 -4.510000000000000120e-02 2.871506291000000033e+01 8.366418418333330109e+00 -4.957960000000000145e-02 3.062621534000000167e+01 6.807088010000000189e+00 -5.414959999999999912e-02 1.698840335499999910e+01 5.315930135000000334e+00 -5.867460000000000037e-02 1.810732352000000134e+01 4.582343003333329889e+00 -6.313670000000000393e-02 1.758858145166669829e+01 3.753068668333329860e+00 -6.771770000000000567e-02 1.874808681500000063e+01 3.129801861666670071e+00 -7.237100000000000477e-02 1.219239694000000007e+01 2.701832888333330018e+00 -7.692330000000000001e-02 1.502033604000000011e+01 2.415586504999999828e+00 -8.164470000000000061e-02 1.051882241166670084e+01 2.003147743333329789e+00 -8.639470000000000482e-02 1.266539752666670005e+01 1.813845073333330005e+00 -9.106759999999999855e-02 1.164225125833329955e+01 1.590423455000000041e+00 -9.573710000000000553e-02 9.248378555000000389e+00 1.453449206666669991e+00 -1.004952999999999957e-01 1.082198768499999986e+01 1.296534581666670016e+00 -1.052397000000000055e-01 9.754544071666670035e+00 1.192202876666669908e+00 -1.099886000000000058e-01 9.770793396666670461e+00 1.074958141666670031e+00 -1.148422000000000054e-01 9.667035006666669261e+00 9.803857316666669819e-01 -1.197769999999999946e-01 8.381104240000000871e+00 8.964596183333329860e-01 -1.247698000000000002e-01 7.884219706666669936e+00 8.320707283333329540e-01 -1.298370000000000080e-01 8.175124921666670375e+00 7.497416000000000080e-01 -1.349077999999999944e-01 7.421197476666669957e+00 7.207336583333330271e-01 -1.399244000000000043e-01 8.545903931666670061e+00 6.648524133333330033e-01 -1.450733999999999913e-01 7.172791390000000433e+00 6.314494133333330428e-01 -1.502658000000000049e-01 6.110795001666669890e+00 5.924928833333330536e-01 -1.556062000000000001e-01 7.011488443333329990e+00 5.430119199999999813e-01 -1.572456999999999883e-01 7.121472013333329798e+00 1.740741033333330079e-01 -1.609471000000000096e-01 7.438929439999999893e+00 5.263131250000000483e-01 -1.661874999999999880e-01 6.540084590000000198e+00 4.946959550000000205e-01 -1.706292000000000086e-01 6.367655253333330378e+00 1.455746566666669961e-01 -1.715615000000000057e-01 6.476111691666670112e+00 4.707941449999999972e-01 -1.771270000000000067e-01 5.720913878333329983e+00 4.355610400000000104e-01 -1.827315999999999940e-01 6.117868691666670244e+00 4.186226383333330192e-01 -1.842428999999999872e-01 5.857041180000000402e+00 1.254778649999999940e-01 -1.883173999999999959e-01 5.849837826666670182e+00 4.069392433333329784e-01 -1.939794999999999991e-01 5.447672994999999574e+00 3.927526633333329742e-01 -1.982414999999999872e-01 5.391186461666669594e+00 1.085076650000000031e-01 -1.997663000000000078e-01 5.394637556666670442e+00 3.662608233333329855e-01 -2.055810999999999888e-01 5.784545713333329786e+00 3.603836316666669815e-01 -2.114655000000000007e-01 4.574601945000000391e+00 3.312713700000000094e-01 -2.120113000000000136e-01 5.084515549999999884e+00 9.927742500000000248e-02 -2.161903000000000019e-01 4.516358434999999893e+00 4.168106166666670220e-01 -2.259823999999999999e-01 4.782964421666670241e+00 8.791053666666670541e-02 -2.397845000000000115e-01 4.501217386666669817e+00 8.259429166666669431e-02 -2.537096999999999825e-01 4.179436571666670375e+00 7.562756833333329765e-02 -2.676275000000000182e-01 3.979478888333329856e+00 6.987285499999999761e-02 -2.817857999999999752e-01 3.702226940000000077e+00 6.482911333333329917e-02 -2.956398000000000081e-01 3.605992423333329810e+00 6.203536333333330155e-02 -3.099044000000000243e-01 3.377018353333329781e+00 5.670042833333330257e-02 -3.240645999999999805e-01 3.095807218333329836e+00 5.498817999999999762e-02 -3.388027000000000122e-01 2.841171323333330001e+00 4.897826333333329951e-02 -3.539140000000000064e-01 2.795649415000000193e+00 4.845330666666670255e-02 -3.687090000000000090e-01 2.622854690000000044e+00 4.475559833333329907e-02 -3.839813000000000254e-01 2.527809641666669993e+00 4.273165666666670082e-02 -3.988975000000000160e-01 2.232305030000000023e+00 4.094381166666669764e-02 -4.106734000000000218e-01 2.129986383333330124e+00 4.154637366666669857e-02 -4.136514000000000024e-01 2.084593566666669950e+00 3.891198166666669928e-02 -4.290628000000000219e-01 1.988620215000000080e+00 3.594587333333330165e-02 -4.295516999999999808e-01 1.964928603499999982e+00 3.519640899999999795e-02 -4.446014999999999828e-01 1.750614441666670018e+00 3.497378000000000292e-02 -4.466716000000000020e-01 1.709819834666669980e+00 3.112847050000000157e-02 -4.603325999999999807e-01 1.676685876666669905e+00 3.265084166666670090e-02 -4.685437000000000074e-01 1.638395569999999912e+00 3.101072850000000103e-02 -4.764860000000000206e-01 1.575855291666669933e+00 3.097528500000000171e-02 -4.834083000000000130e-01 1.443926158166670026e+00 2.913516383333330032e-02 -4.923204999999999942e-01 1.443778989999999984e+00 3.072023333333330150e-02 -5.046621000000000024e-01 1.382474827333330047e+00 2.709115466666670025e-02 -5.082708000000000226e-01 1.368563626666670086e+00 2.832584499999999880e-02 -5.230728999999999518e-01 1.117650907000000027e+00 2.515010599999999846e-02 -5.249162000000000550e-01 1.271594368333329950e+00 2.652784333333330080e-02 -5.416775999999999813e-01 1.132208539999999930e+00 2.601087833333329963e-02 -5.444001000000000534e-01 1.080469498666670081e+00 2.559191900000000117e-02 -5.583067999999999920e-01 1.032465565000000085e+00 2.510816333333330125e-02 -5.612614999999999688e-01 1.012286258500000091e+00 2.336018449999999885e-02 -5.753956999999999544e-01 9.763539783333330391e-01 2.332539999999999961e-02 -5.834072999999999620e-01 8.965217239999999643e-01 2.303063099999999933e-02 -5.927398999999999862e-01 9.096560916666670549e-01 2.248173499999999922e-02 -6.005747000000000169e-01 8.250965611666669641e-01 2.186496933333329992e-02 -6.099058000000000535e-01 8.168162183333329551e-01 2.170944500000000082e-02 -6.218546000000000351e-01 7.414260915000000507e-01 2.121375600000000028e-02 -6.275003000000000108e-01 7.444278466666669480e-01 2.046154333333330064e-02 -6.412082999999999533e-01 6.366966366666669819e-01 1.883217216666669899e-02 -6.447154999999999969e-01 6.422991433333330447e-01 2.075286000000000144e-02 -6.655497999999999692e-01 5.866493959999999896e-01 1.815403650000000160e-02 -6.843702000000000396e-01 5.515869356666670553e-01 2.025276583333330063e-02 -7.058105999999999547e-01 4.475886111666669831e-01 1.701240433333330027e-02 -7.258693999999999980e-01 4.775394179999999933e-01 1.840697383333329828e-02 -7.490480000000000471e-01 4.047520649999999942e-01 1.505153366666669990e-02 -7.720086999999999922e-01 3.731668894999999875e-01 1.706827766666670076e-02 -7.920989999999999975e-01 3.681129878333330163e-01 1.507231049999999996e-02 -8.155097999999999514e-01 3.208610430000000124e-01 1.529166149999999953e-02 -8.364475000000000104e-01 2.962226738333330056e-01 1.456896033333330079e-02 -8.619377000000000288e-01 2.765821119999999911e-01 1.371801400000000060e-02 -8.846403999999999934e-01 2.799105873333330163e-01 1.446314666666670065e-02 -9.081462000000000145e-01 2.318482950000000098e-01 1.260493333333330065e-02 -9.334447000000000161e-01 2.175556724999999914e-01 1.357374916666670081e-02 -9.551832000000000100e-01 1.903255399999999875e-01 1.273357800000000060e-02 -9.812971999999999806e-01 1.841620115000000002e-01 1.195187833333329931e-02 -1.006807800000000030e+00 1.608915558333330054e-01 1.233432733333329930e-02 -1.030406600000000061e+00 1.533644885000000069e-01 1.172346633333330029e-02 -1.057784300000000011e+00 1.661925581666670038e-01 1.091501716666670035e-02 -1.084600999999999926e+00 1.630933589999999933e-01 1.128103283333329980e-02 -1.109902299999999897e+00 1.327154809999999963e-01 1.088576583333330031e-02 -1.137751600000000085e+00 1.179623709999999964e-01 1.042595833333329926e-02 +3.624299999999999744e-02 7.295645247999999583e+01 1.637502872666669873e+01 +4.068929999999999769e-02 3.496757764333329987e+01 1.132330254166670080e+01 +4.510000000000000120e-02 2.871506291000000033e+01 8.366418418333330109e+00 +4.957960000000000145e-02 3.062621534000000167e+01 6.807088010000000189e+00 +5.414959999999999912e-02 1.698840335499999910e+01 5.315930135000000334e+00 +5.867460000000000037e-02 1.810732352000000134e+01 4.582343003333329889e+00 +6.313670000000000393e-02 1.758858145166669829e+01 3.753068668333329860e+00 +6.771770000000000567e-02 1.874808681500000063e+01 3.129801861666670071e+00 +7.237100000000000477e-02 1.219239694000000007e+01 2.701832888333330018e+00 +7.692330000000000001e-02 1.502033604000000011e+01 2.415586504999999828e+00 +8.164470000000000061e-02 1.051882241166670084e+01 2.003147743333329789e+00 +8.639470000000000482e-02 1.266539752666670005e+01 1.813845073333330005e+00 +9.106759999999999855e-02 1.164225125833329955e+01 1.590423455000000041e+00 +9.573710000000000553e-02 9.248378555000000389e+00 1.453449206666669991e+00 +1.004952999999999957e-01 1.082198768499999986e+01 1.296534581666670016e+00 +1.052397000000000055e-01 9.754544071666670035e+00 1.192202876666669908e+00 +1.099886000000000058e-01 9.770793396666670461e+00 1.074958141666670031e+00 +1.148422000000000054e-01 9.667035006666669261e+00 9.803857316666669819e-01 +1.197769999999999946e-01 8.381104240000000871e+00 8.964596183333329860e-01 +1.247698000000000002e-01 7.884219706666669936e+00 8.320707283333329540e-01 +1.298370000000000080e-01 8.175124921666670375e+00 7.497416000000000080e-01 +1.349077999999999944e-01 7.421197476666669957e+00 7.207336583333330271e-01 +1.399244000000000043e-01 8.545903931666670061e+00 6.648524133333330033e-01 +1.450733999999999913e-01 7.172791390000000433e+00 6.314494133333330428e-01 +1.502658000000000049e-01 6.110795001666669890e+00 5.924928833333330536e-01 +1.556062000000000001e-01 7.011488443333329990e+00 5.430119199999999813e-01 +1.572456999999999883e-01 7.121472013333329798e+00 1.740741033333330079e-01 +1.609471000000000096e-01 7.438929439999999893e+00 5.263131250000000483e-01 +1.661874999999999880e-01 6.540084590000000198e+00 4.946959550000000205e-01 +1.706292000000000086e-01 6.367655253333330378e+00 1.455746566666669961e-01 +1.715615000000000057e-01 6.476111691666670112e+00 4.707941449999999972e-01 +1.771270000000000067e-01 5.720913878333329983e+00 4.355610400000000104e-01 +1.827315999999999940e-01 6.117868691666670244e+00 4.186226383333330192e-01 +1.842428999999999872e-01 5.857041180000000402e+00 1.254778649999999940e-01 +1.883173999999999959e-01 5.849837826666670182e+00 4.069392433333329784e-01 +1.939794999999999991e-01 5.447672994999999574e+00 3.927526633333329742e-01 +1.982414999999999872e-01 5.391186461666669594e+00 1.085076650000000031e-01 +1.997663000000000078e-01 5.394637556666670442e+00 3.662608233333329855e-01 +2.055810999999999888e-01 5.784545713333329786e+00 3.603836316666669815e-01 +2.114655000000000007e-01 4.574601945000000391e+00 3.312713700000000094e-01 +2.120113000000000136e-01 5.084515549999999884e+00 9.927742500000000248e-02 +2.161903000000000019e-01 4.516358434999999893e+00 4.168106166666670220e-01 +2.259823999999999999e-01 4.782964421666670241e+00 8.791053666666670541e-02 +2.397845000000000115e-01 4.501217386666669817e+00 8.259429166666669431e-02 +2.537096999999999825e-01 4.179436571666670375e+00 7.562756833333329765e-02 +2.676275000000000182e-01 3.979478888333329856e+00 6.987285499999999761e-02 +2.817857999999999752e-01 3.702226940000000077e+00 6.482911333333329917e-02 +2.956398000000000081e-01 3.605992423333329810e+00 6.203536333333330155e-02 +3.099044000000000243e-01 3.377018353333329781e+00 5.670042833333330257e-02 +3.240645999999999805e-01 3.095807218333329836e+00 5.498817999999999762e-02 +3.388027000000000122e-01 2.841171323333330001e+00 4.897826333333329951e-02 +3.539140000000000064e-01 2.795649415000000193e+00 4.845330666666670255e-02 +3.687090000000000090e-01 2.622854690000000044e+00 4.475559833333329907e-02 +3.839813000000000254e-01 2.527809641666669993e+00 4.273165666666670082e-02 +3.988975000000000160e-01 2.232305030000000023e+00 4.094381166666669764e-02 +4.106734000000000218e-01 2.129986383333330124e+00 4.154637366666669857e-02 +4.136514000000000024e-01 2.084593566666669950e+00 3.891198166666669928e-02 +4.290628000000000219e-01 1.988620215000000080e+00 3.594587333333330165e-02 +4.295516999999999808e-01 1.964928603499999982e+00 3.519640899999999795e-02 +4.446014999999999828e-01 1.750614441666670018e+00 3.497378000000000292e-02 +4.466716000000000020e-01 1.709819834666669980e+00 3.112847050000000157e-02 +4.603325999999999807e-01 1.676685876666669905e+00 3.265084166666670090e-02 +4.685437000000000074e-01 1.638395569999999912e+00 3.101072850000000103e-02 +4.764860000000000206e-01 1.575855291666669933e+00 3.097528500000000171e-02 +4.834083000000000130e-01 1.443926158166670026e+00 2.913516383333330032e-02 +4.923204999999999942e-01 1.443778989999999984e+00 3.072023333333330150e-02 +5.046621000000000024e-01 1.382474827333330047e+00 2.709115466666670025e-02 +5.082708000000000226e-01 1.368563626666670086e+00 2.832584499999999880e-02 +5.230728999999999518e-01 1.117650907000000027e+00 2.515010599999999846e-02 +5.249162000000000550e-01 1.271594368333329950e+00 2.652784333333330080e-02 +5.416775999999999813e-01 1.132208539999999930e+00 2.601087833333329963e-02 +5.444001000000000534e-01 1.080469498666670081e+00 2.559191900000000117e-02 +5.583067999999999920e-01 1.032465565000000085e+00 2.510816333333330125e-02 +5.612614999999999688e-01 1.012286258500000091e+00 2.336018449999999885e-02 +5.753956999999999544e-01 9.763539783333330391e-01 2.332539999999999961e-02 +5.834072999999999620e-01 8.965217239999999643e-01 2.303063099999999933e-02 +5.927398999999999862e-01 9.096560916666670549e-01 2.248173499999999922e-02 +6.005747000000000169e-01 8.250965611666669641e-01 2.186496933333329992e-02 +6.099058000000000535e-01 8.168162183333329551e-01 2.170944500000000082e-02 +6.218546000000000351e-01 7.414260915000000507e-01 2.121375600000000028e-02 +6.275003000000000108e-01 7.444278466666669480e-01 2.046154333333330064e-02 +6.412082999999999533e-01 6.366966366666669819e-01 1.883217216666669899e-02 +6.447154999999999969e-01 6.422991433333330447e-01 2.075286000000000144e-02 +6.655497999999999692e-01 5.866493959999999896e-01 1.815403650000000160e-02 +6.843702000000000396e-01 5.515869356666670553e-01 2.025276583333330063e-02 +7.058105999999999547e-01 4.475886111666669831e-01 1.701240433333330027e-02 +7.258693999999999980e-01 4.775394179999999933e-01 1.840697383333329828e-02 +7.490480000000000471e-01 4.047520649999999942e-01 1.505153366666669990e-02 +7.720086999999999922e-01 3.731668894999999875e-01 1.706827766666670076e-02 +7.920989999999999975e-01 3.681129878333330163e-01 1.507231049999999996e-02 +8.155097999999999514e-01 3.208610430000000124e-01 1.529166149999999953e-02 +8.364475000000000104e-01 2.962226738333330056e-01 1.456896033333330079e-02 +8.619377000000000288e-01 2.765821119999999911e-01 1.371801400000000060e-02 +8.846403999999999934e-01 2.799105873333330163e-01 1.446314666666670065e-02 +9.081462000000000145e-01 2.318482950000000098e-01 1.260493333333330065e-02 +9.334447000000000161e-01 2.175556724999999914e-01 1.357374916666670081e-02 +9.551832000000000100e-01 1.903255399999999875e-01 1.273357800000000060e-02 +9.812971999999999806e-01 1.841620115000000002e-01 1.195187833333329931e-02 +1.006807800000000030e+00 1.608915558333330054e-01 1.233432733333329930e-02 +1.030406600000000061e+00 1.533644885000000069e-01 1.172346633333330029e-02 +1.057784300000000011e+00 1.661925581666670038e-01 1.091501716666670035e-02 +1.084600999999999926e+00 1.630933589999999933e-01 1.128103283333329980e-02 +1.109902299999999897e+00 1.327154809999999963e-01 1.088576583333330031e-02 +1.137751600000000085e+00 1.179623709999999964e-01 1.042595833333329926e-02 1.166036300000000026e+00 1.293750036666669878e-01 1.024355400000000020e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv index 96a87d0fe..bfbf36dcd 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/11_2000_1340_10.csv @@ -1,105 +1,105 @@ -3.625559999999999894e-02 4.452644707000000324e+01 1.628119149999999848e+01 -4.070349999999999663e-02 2.677295466333330154e+01 1.128515222166669929e+01 -4.511570000000000163e-02 2.350029203500000108e+01 8.338724138333329705e+00 -4.959680000000000338e-02 1.744413458166669884e+01 6.751264438333329565e+00 -5.416850000000000137e-02 9.909433441666669395e+00 5.280963783333329609e+00 -5.869510000000000005e-02 1.174714312999999954e+01 4.547423594999999708e+00 -6.315869999999999818e-02 1.312634901166670076e+01 3.725749208333330120e+00 -6.774130000000000429e-02 1.654730030333330149e+01 3.113655078333330106e+00 -7.239619999999999389e-02 7.792796271666669661e+00 2.672180411666670086e+00 -7.695009999999999351e-02 1.265325572666669984e+01 2.397233363333330036e+00 -8.167309999999999848e-02 6.069752713333330441e+00 1.971069876666670107e+00 -8.642469999999999319e-02 1.300927747833329917e+01 1.813635340000000040e+00 -9.109929999999999417e-02 9.757094948333330464e+00 1.573592551666670003e+00 -9.577040000000000552e-02 5.713518095000000407e+00 1.422093728333329921e+00 -1.005303000000000030e-01 7.313534973333330136e+00 1.265234731666670109e+00 -1.052763000000000032e-01 8.841184973333330532e+00 1.182077201666670074e+00 -1.100268999999999969e-01 7.404252198333329815e+00 1.051346621666670034e+00 -1.148821000000000009e-01 8.380590695000000423e+00 9.664303683333329564e-01 -1.198187000000000002e-01 7.413483668333330279e+00 8.855263516666670442e-01 -1.248133000000000020e-01 6.593134025000000342e+00 8.175650066666669824e-01 -1.298822000000000032e-01 6.731246111666670195e+00 7.333046399999999521e-01 -1.349548000000000136e-01 5.519098301666669926e+00 6.986229283333329487e-01 -1.399730999999999892e-01 7.581442331666670142e+00 6.528076566666669578e-01 -1.451239000000000001e-01 4.842304316666670161e+00 6.043489516666670225e-01 -1.503181000000000100e-01 5.135523888333329623e+00 5.802922499999999539e-01 -1.556604000000000043e-01 6.037988904999999740e+00 5.310080216666670516e-01 -1.573070000000000024e-01 6.020141886666669606e+00 1.700767950000000028e-01 -1.610031000000000101e-01 6.268605329999999753e+00 5.111983383333329467e-01 -1.662453999999999876e-01 5.536486726666669966e+00 4.815289200000000269e-01 -1.706957000000000058e-01 5.285752210000000062e+00 1.415798849999999887e-01 -1.716212000000000015e-01 5.016643598333329734e+00 4.522174083333330152e-01 -1.771887000000000045e-01 5.127789406666670047e+00 4.276572833333330270e-01 -1.827951999999999910e-01 5.311901800000000229e+00 4.077617766666670196e-01 -1.843146999999999980e-01 5.273006283333329769e+00 1.230909116666669967e-01 -1.883829999999999949e-01 4.028933333333330147e+00 3.832458766666669847e-01 -1.940469999999999973e-01 4.805727509999999647e+00 3.842635300000000198e-01 -1.983187999999999895e-01 4.783697818333330076e+00 1.059592133333329966e-01 -1.998358000000000079e-01 4.823453656666670142e+00 3.585670233333330126e-01 -2.056525999999999910e-01 4.659267076666670171e+00 3.454626916666669878e-01 -2.115392000000000106e-01 3.961550343333330115e+00 3.229926716666670083e-01 -2.120939000000000019e-01 4.350835990000000209e+00 9.606802500000000133e-02 -2.162656000000000023e-01 4.681036608333330129e+00 4.188060433333329891e-01 -2.260705000000000076e-01 4.224838659999999635e+00 8.541253666666670519e-02 -2.398779000000000050e-01 3.935926101666670007e+00 7.996145500000000073e-02 -2.538084999999999924e-01 3.694058728333330155e+00 7.335489833333329324e-02 -2.677318000000000198e-01 3.684019681666669932e+00 6.840629833333329579e-02 -2.818956000000000239e-01 3.452043701666669850e+00 6.355296333333329550e-02 -2.957549999999999901e-01 3.354666878333329993e+00 6.073878666666669701e-02 -3.100250999999999979e-01 3.092418856666669935e+00 5.527531000000000111e-02 -3.241909000000000041e-01 2.870290291666670157e+00 5.380070499999999728e-02 -3.389346999999999777e-01 2.729991994999999783e+00 4.836916333333329820e-02 -3.540519999999999778e-01 2.658729508333330216e+00 4.771163500000000224e-02 -3.688526999999999778e-01 2.488934241666670211e+00 4.403299000000000102e-02 -3.841308999999999974e-01 2.412009111666669980e+00 4.209804999999999797e-02 -3.990528999999999882e-01 2.203036439999999985e+00 4.070905166666669711e-02 -4.105667000000000066e-01 1.996977714666670067e+00 4.083280150000000164e-02 -4.138126999999999778e-01 2.043262161666670185e+00 3.862582833333329940e-02 -4.292300000000000004e-01 1.982205959999999934e+00 3.583282166666670182e-02 -4.294401999999999942e-01 1.834877223666669943e+00 3.458454216666669717e-02 -4.447747000000000228e-01 1.712660204999999936e+00 3.471672166666670001e-02 -4.465555999999999970e-01 1.615437673500000004e+00 3.068944266666669834e-02 -4.605119999999999769e-01 1.681440621666669966e+00 3.260043333333329657e-02 -4.684220000000000050e-01 1.529958281999999947e+00 3.049975383333329917e-02 -4.766716999999999760e-01 1.561241171666670091e+00 3.083583000000000157e-02 -4.832827000000000095e-01 1.369049060333330070e+00 2.875037449999999842e-02 -4.925123000000000140e-01 1.406416503333330015e+00 3.046807833333330107e-02 -5.045309999999999517e-01 1.316827885166669931e+00 2.677764066666669940e-02 -5.084689000000000014e-01 1.339987331666669945e+00 2.812536666666669988e-02 -5.229369999999999852e-01 1.082862526333330022e+00 2.496820599999999973e-02 -5.251208000000000542e-01 1.259172833333330077e+00 2.640966666666669932e-02 -5.418887000000000009e-01 1.134540908333329989e+00 2.596733000000000027e-02 -5.442586999999999842e-01 1.026980480500000015e+00 2.532101549999999854e-02 -5.585244000000000320e-01 1.057657990000000048e+00 2.518052499999999874e-02 -5.611156999999999950e-01 9.343203683333329845e-01 2.299225916666669881e-02 -5.756198999999999621e-01 9.598931866666670087e-01 2.319752666666670057e-02 -5.832557000000000436e-01 8.443178690000000541e-01 2.277228483333329848e-02 -5.929708999999999675e-01 9.115965033333329748e-01 2.244499833333329919e-02 -6.004186999999999719e-01 7.992612106666669991e-01 2.172028233333329894e-02 -6.101434999999999498e-01 8.528685350000000387e-01 2.184797833333329900e-02 -6.216930999999999985e-01 7.049236858333329803e-01 2.102741616666670144e-02 -6.277447999999999917e-01 7.853513183333330483e-01 2.062051499999999898e-02 -6.410417000000000476e-01 6.132204243333330140e-01 1.871036433333329863e-02 -6.449667999999999513e-01 7.011444599999999694e-01 2.101788333333329956e-02 -6.653769000000000489e-01 5.661603698333329548e-01 1.804829366666670099e-02 -6.841924999999999812e-01 5.085138883333329973e-01 2.002898349999999994e-02 -7.056272000000000100e-01 4.352650703333330040e-01 1.694186849999999855e-02 -7.256808000000000147e-01 4.355121908333329794e-01 1.820155999999999857e-02 -7.488534000000000024e-01 3.927147446666670039e-01 1.498729066666669961e-02 -7.718082000000000553e-01 3.535320510000000138e-01 1.696024266666670138e-02 -7.918933000000000222e-01 3.527103021666669891e-01 1.499266833333330086e-02 -8.152979999999999672e-01 3.240461856666669860e-01 1.528614783333329986e-02 -8.362302999999999820e-01 2.791947966666670222e-01 1.448550166666670060e-02 -8.617137999999999742e-01 2.463675190000000070e-01 1.359101549999999943e-02 -8.844106000000000467e-01 2.696912470000000228e-01 1.440389033333329925e-02 -9.079102999999999479e-01 2.246905299999999994e-01 1.256477649999999946e-02 -9.332021999999999817e-01 2.085629360000000043e-01 1.352310049999999944e-02 -9.549351000000000367e-01 1.738771078333329889e-01 1.265774100000000013e-02 -9.810423000000000338e-01 1.708308721666670082e-01 1.189189666666670003e-02 -1.006546299999999894e+00 1.505248680000000061e-01 1.228292216666669948e-02 -1.030138999999999916e+00 1.537520601666670095e-01 1.171224066666669977e-02 -1.057509599999999939e+00 1.534308791666670058e-01 1.086003916666669969e-02 -1.084319299999999986e+00 1.338797798333329903e-01 1.116524300000000004e-02 -1.109614000000000100e+00 1.189064603333330056e-01 1.082743033333329920e-02 -1.137456000000000023e+00 1.107916548333330031e-01 1.039160416666670000e-02 +3.625559999999999894e-02 4.452644707000000324e+01 1.628119149999999848e+01 +4.070349999999999663e-02 2.677295466333330154e+01 1.128515222166669929e+01 +4.511570000000000163e-02 2.350029203500000108e+01 8.338724138333329705e+00 +4.959680000000000338e-02 1.744413458166669884e+01 6.751264438333329565e+00 +5.416850000000000137e-02 9.909433441666669395e+00 5.280963783333329609e+00 +5.869510000000000005e-02 1.174714312999999954e+01 4.547423594999999708e+00 +6.315869999999999818e-02 1.312634901166670076e+01 3.725749208333330120e+00 +6.774130000000000429e-02 1.654730030333330149e+01 3.113655078333330106e+00 +7.239619999999999389e-02 7.792796271666669661e+00 2.672180411666670086e+00 +7.695009999999999351e-02 1.265325572666669984e+01 2.397233363333330036e+00 +8.167309999999999848e-02 6.069752713333330441e+00 1.971069876666670107e+00 +8.642469999999999319e-02 1.300927747833329917e+01 1.813635340000000040e+00 +9.109929999999999417e-02 9.757094948333330464e+00 1.573592551666670003e+00 +9.577040000000000552e-02 5.713518095000000407e+00 1.422093728333329921e+00 +1.005303000000000030e-01 7.313534973333330136e+00 1.265234731666670109e+00 +1.052763000000000032e-01 8.841184973333330532e+00 1.182077201666670074e+00 +1.100268999999999969e-01 7.404252198333329815e+00 1.051346621666670034e+00 +1.148821000000000009e-01 8.380590695000000423e+00 9.664303683333329564e-01 +1.198187000000000002e-01 7.413483668333330279e+00 8.855263516666670442e-01 +1.248133000000000020e-01 6.593134025000000342e+00 8.175650066666669824e-01 +1.298822000000000032e-01 6.731246111666670195e+00 7.333046399999999521e-01 +1.349548000000000136e-01 5.519098301666669926e+00 6.986229283333329487e-01 +1.399730999999999892e-01 7.581442331666670142e+00 6.528076566666669578e-01 +1.451239000000000001e-01 4.842304316666670161e+00 6.043489516666670225e-01 +1.503181000000000100e-01 5.135523888333329623e+00 5.802922499999999539e-01 +1.556604000000000043e-01 6.037988904999999740e+00 5.310080216666670516e-01 +1.573070000000000024e-01 6.020141886666669606e+00 1.700767950000000028e-01 +1.610031000000000101e-01 6.268605329999999753e+00 5.111983383333329467e-01 +1.662453999999999876e-01 5.536486726666669966e+00 4.815289200000000269e-01 +1.706957000000000058e-01 5.285752210000000062e+00 1.415798849999999887e-01 +1.716212000000000015e-01 5.016643598333329734e+00 4.522174083333330152e-01 +1.771887000000000045e-01 5.127789406666670047e+00 4.276572833333330270e-01 +1.827951999999999910e-01 5.311901800000000229e+00 4.077617766666670196e-01 +1.843146999999999980e-01 5.273006283333329769e+00 1.230909116666669967e-01 +1.883829999999999949e-01 4.028933333333330147e+00 3.832458766666669847e-01 +1.940469999999999973e-01 4.805727509999999647e+00 3.842635300000000198e-01 +1.983187999999999895e-01 4.783697818333330076e+00 1.059592133333329966e-01 +1.998358000000000079e-01 4.823453656666670142e+00 3.585670233333330126e-01 +2.056525999999999910e-01 4.659267076666670171e+00 3.454626916666669878e-01 +2.115392000000000106e-01 3.961550343333330115e+00 3.229926716666670083e-01 +2.120939000000000019e-01 4.350835990000000209e+00 9.606802500000000133e-02 +2.162656000000000023e-01 4.681036608333330129e+00 4.188060433333329891e-01 +2.260705000000000076e-01 4.224838659999999635e+00 8.541253666666670519e-02 +2.398779000000000050e-01 3.935926101666670007e+00 7.996145500000000073e-02 +2.538084999999999924e-01 3.694058728333330155e+00 7.335489833333329324e-02 +2.677318000000000198e-01 3.684019681666669932e+00 6.840629833333329579e-02 +2.818956000000000239e-01 3.452043701666669850e+00 6.355296333333329550e-02 +2.957549999999999901e-01 3.354666878333329993e+00 6.073878666666669701e-02 +3.100250999999999979e-01 3.092418856666669935e+00 5.527531000000000111e-02 +3.241909000000000041e-01 2.870290291666670157e+00 5.380070499999999728e-02 +3.389346999999999777e-01 2.729991994999999783e+00 4.836916333333329820e-02 +3.540519999999999778e-01 2.658729508333330216e+00 4.771163500000000224e-02 +3.688526999999999778e-01 2.488934241666670211e+00 4.403299000000000102e-02 +3.841308999999999974e-01 2.412009111666669980e+00 4.209804999999999797e-02 +3.990528999999999882e-01 2.203036439999999985e+00 4.070905166666669711e-02 +4.105667000000000066e-01 1.996977714666670067e+00 4.083280150000000164e-02 +4.138126999999999778e-01 2.043262161666670185e+00 3.862582833333329940e-02 +4.292300000000000004e-01 1.982205959999999934e+00 3.583282166666670182e-02 +4.294401999999999942e-01 1.834877223666669943e+00 3.458454216666669717e-02 +4.447747000000000228e-01 1.712660204999999936e+00 3.471672166666670001e-02 +4.465555999999999970e-01 1.615437673500000004e+00 3.068944266666669834e-02 +4.605119999999999769e-01 1.681440621666669966e+00 3.260043333333329657e-02 +4.684220000000000050e-01 1.529958281999999947e+00 3.049975383333329917e-02 +4.766716999999999760e-01 1.561241171666670091e+00 3.083583000000000157e-02 +4.832827000000000095e-01 1.369049060333330070e+00 2.875037449999999842e-02 +4.925123000000000140e-01 1.406416503333330015e+00 3.046807833333330107e-02 +5.045309999999999517e-01 1.316827885166669931e+00 2.677764066666669940e-02 +5.084689000000000014e-01 1.339987331666669945e+00 2.812536666666669988e-02 +5.229369999999999852e-01 1.082862526333330022e+00 2.496820599999999973e-02 +5.251208000000000542e-01 1.259172833333330077e+00 2.640966666666669932e-02 +5.418887000000000009e-01 1.134540908333329989e+00 2.596733000000000027e-02 +5.442586999999999842e-01 1.026980480500000015e+00 2.532101549999999854e-02 +5.585244000000000320e-01 1.057657990000000048e+00 2.518052499999999874e-02 +5.611156999999999950e-01 9.343203683333329845e-01 2.299225916666669881e-02 +5.756198999999999621e-01 9.598931866666670087e-01 2.319752666666670057e-02 +5.832557000000000436e-01 8.443178690000000541e-01 2.277228483333329848e-02 +5.929708999999999675e-01 9.115965033333329748e-01 2.244499833333329919e-02 +6.004186999999999719e-01 7.992612106666669991e-01 2.172028233333329894e-02 +6.101434999999999498e-01 8.528685350000000387e-01 2.184797833333329900e-02 +6.216930999999999985e-01 7.049236858333329803e-01 2.102741616666670144e-02 +6.277447999999999917e-01 7.853513183333330483e-01 2.062051499999999898e-02 +6.410417000000000476e-01 6.132204243333330140e-01 1.871036433333329863e-02 +6.449667999999999513e-01 7.011444599999999694e-01 2.101788333333329956e-02 +6.653769000000000489e-01 5.661603698333329548e-01 1.804829366666670099e-02 +6.841924999999999812e-01 5.085138883333329973e-01 2.002898349999999994e-02 +7.056272000000000100e-01 4.352650703333330040e-01 1.694186849999999855e-02 +7.256808000000000147e-01 4.355121908333329794e-01 1.820155999999999857e-02 +7.488534000000000024e-01 3.927147446666670039e-01 1.498729066666669961e-02 +7.718082000000000553e-01 3.535320510000000138e-01 1.696024266666670138e-02 +7.918933000000000222e-01 3.527103021666669891e-01 1.499266833333330086e-02 +8.152979999999999672e-01 3.240461856666669860e-01 1.528614783333329986e-02 +8.362302999999999820e-01 2.791947966666670222e-01 1.448550166666670060e-02 +8.617137999999999742e-01 2.463675190000000070e-01 1.359101549999999943e-02 +8.844106000000000467e-01 2.696912470000000228e-01 1.440389033333329925e-02 +9.079102999999999479e-01 2.246905299999999994e-01 1.256477649999999946e-02 +9.332021999999999817e-01 2.085629360000000043e-01 1.352310049999999944e-02 +9.549351000000000367e-01 1.738771078333329889e-01 1.265774100000000013e-02 +9.810423000000000338e-01 1.708308721666670082e-01 1.189189666666670003e-02 +1.006546299999999894e+00 1.505248680000000061e-01 1.228292216666669948e-02 +1.030138999999999916e+00 1.537520601666670095e-01 1.171224066666669977e-02 +1.057509599999999939e+00 1.534308791666670058e-01 1.086003916666669969e-02 +1.084319299999999986e+00 1.338797798333329903e-01 1.116524300000000004e-02 +1.109614000000000100e+00 1.189064603333330056e-01 1.082743033333329920e-02 +1.137456000000000023e+00 1.107916548333330031e-01 1.039160416666670000e-02 1.165733499999999978e+00 1.125385351666669947e-01 1.017680349999999963e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv index cb7796b60..9ae1c5f3e 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/12_3000_1340_10.csv @@ -1,105 +1,105 @@ -3.624610000000000332e-02 5.667029333499999666e+01 1.635708034166669833e+01 -4.069289999999999713e-02 2.663486052833329865e+01 1.131616966500000032e+01 -4.510390000000000232e-02 2.091145430999999988e+01 8.353784624999999409e+00 -4.958379999999999732e-02 1.655762528666669908e+01 6.766916158333329712e+00 -5.415430000000000244e-02 7.405398096666670149e+00 5.285856098333329811e+00 -5.867970000000000130e-02 1.609157327499999823e+01 4.579871853333330023e+00 -6.314219999999999555e-02 2.074624494500000083e+01 3.774208823333330187e+00 -6.772359999999999491e-02 1.622769223499999924e+01 3.121007619999999871e+00 -7.237720000000000264e-02 8.100976058333330343e+00 2.681633823333330113e+00 -7.692999999999999838e-02 7.297140411666670268e+00 2.370097993333330155e+00 -8.165179999999999660e-02 8.662000215000000836e+00 1.993900453333329992e+00 -8.640209999999999557e-02 1.195176863500000053e+01 1.811378463333330080e+00 -9.107550000000000368e-02 1.017929826333329935e+01 1.581605778333329937e+00 -9.574539999999999440e-02 8.299761948333330253e+00 1.447854706666670044e+00 -1.005039999999999961e-01 7.184010728333330320e+00 1.267957188333330043e+00 -1.052488000000000035e-01 7.705754226666670093e+00 1.175315996666669971e+00 -1.099981000000000014e-01 6.940137736666669888e+00 1.050239939999999983e+00 -1.148520999999999986e-01 7.227232895000000212e+00 9.582211533333330200e-01 -1.197872999999999993e-01 6.058664864999999899e+00 8.747766333333329980e-01 -1.247806000000000054e-01 5.235616768333329674e+00 8.060124016666669888e-01 -1.298481999999999970e-01 6.895559143333329644e+00 7.374701233333329498e-01 -1.349194999999999978e-01 5.596115646666669718e+00 7.017485283333330104e-01 -1.399364999999999915e-01 7.271002904999999572e+00 6.515097483333329720e-01 -1.450858999999999899e-01 5.001139740000000167e+00 6.081432883333329764e-01 -1.502787999999999902e-01 5.397041578333330314e+00 5.852662783333330010e-01 -1.556196999999999997e-01 5.201047356666670396e+00 5.230793849999999523e-01 -1.572660999999999920e-01 5.527525920000000426e+00 1.689539216666670063e-01 -1.609609999999999930e-01 6.050507654999999652e+00 5.103277550000000495e-01 -1.662019000000000135e-01 5.215723743333329665e+00 4.792083599999999999e-01 -1.706513000000000058e-01 5.031433279999999897e+00 1.411615750000000113e-01 -1.715762999999999872e-01 4.986483428333330359e+00 4.534299233333329848e-01 -1.771423000000000025e-01 5.106750501666669884e+00 4.289189133333329851e-01 -1.827474000000000043e-01 5.398633823333329751e+00 4.103611200000000236e-01 -1.842668000000000084e-01 4.914610723333329823e+00 1.221897900000000065e-01 -1.883336999999999928e-01 4.776135458333330419e+00 3.942386333333329773e-01 -1.939963000000000104e-01 4.310256373333330338e+00 3.794851616666670147e-01 -1.982673000000000074e-01 4.375084450000000125e+00 1.047416733333329936e-01 -1.997836000000000056e-01 4.425991520000000179e+00 3.548793383333330165e-01 -2.055989000000000011e-01 4.542295369999999721e+00 3.452195166666670034e-01 -2.114837999999999996e-01 4.392925553333330235e+00 3.296180283333329797e-01 -2.120387999999999995e-01 4.102498828333329683e+00 9.538819833333339604e-02 -2.162090000000000123e-01 4.067448908333330060e+00 4.099168333333330083e-01 -2.260118000000000127e-01 3.879140883333330070e+00 8.427184499999999800e-02 -2.398155999999999899e-01 3.717842756666669857e+00 7.930888666666670306e-02 -2.537425999999999848e-01 3.531988756666669893e+00 7.293178499999999898e-02 -2.676623000000000197e-01 3.501111030000000124e+00 6.786378666666670334e-02 -2.818223999999999729e-01 3.329498083333330083e+00 6.325724833333329356e-02 -2.956782000000000021e-01 3.079447669999999970e+00 5.969948499999999658e-02 -3.099446000000000145e-01 2.946954811666670171e+00 5.483356999999999815e-02 -3.241067000000000253e-01 2.705831398333330196e+00 5.323661166666669720e-02 -3.388467000000000007e-01 2.601996516666670090e+00 4.799289000000000333e-02 -3.539599999999999969e-01 2.517872383333330077e+00 4.725612833333329987e-02 -3.687568999999999986e-01 2.374362781666670141e+00 4.368410333333330037e-02 -3.840311000000000141e-01 2.195996148333330122e+00 4.125977166666670165e-02 -3.989493000000000067e-01 2.109030429999999789e+00 4.042385333333330111e-02 -4.107986000000000137e-01 1.888483604166669938e+00 4.043749766666669687e-02 -4.137051999999999952e-01 1.969810571666670063e+00 3.843483833333329741e-02 -4.291185000000000138e-01 1.859797011666669997e+00 3.539587999999999762e-02 -4.296826999999999730e-01 1.762954635166670059e+00 3.439219566666670141e-02 -4.446591999999999767e-01 1.624618943333330012e+00 3.443567000000000156e-02 -4.468077999999999772e-01 1.588049316333330019e+00 3.067751716666669917e-02 -4.603923999999999794e-01 1.585295316666669896e+00 3.227559333333329672e-02 -4.686866000000000088e-01 1.509168766666669992e+00 3.051112400000000058e-02 -4.765479000000000243e-01 1.429500135000000061e+00 3.031986666666669841e-02 -4.835556999999999772e-01 1.309360340500000053e+00 2.857159116666670162e-02 -4.923843999999999999e-01 1.363123808333329912e+00 3.037624166666669928e-02 -5.048160000000000425e-01 1.296483956833329954e+00 2.677855866666669846e-02 -5.083368000000000331e-01 1.254868451666669937e+00 2.782200166666669999e-02 -5.232324000000000419e-01 1.028253859833329953e+00 2.481625150000000071e-02 -5.249844000000000177e-01 1.223231273333329927e+00 2.634227000000000096e-02 -5.417480000000000073e-01 1.058531658333329961e+00 2.569255333333329838e-02 -5.445661000000000529e-01 1.022632484000000064e+00 2.537817800000000124e-02 -5.583793000000000228e-01 1.009770163333330029e+00 2.504100833333329848e-02 -5.614325999999999484e-01 9.522996788333329965e-01 2.313905700000000107e-02 -5.754704000000000486e-01 9.158985283333339611e-01 2.307270666666669939e-02 -5.835850999999999678e-01 8.544030651666669751e-01 2.288279616666670166e-02 -5.928168000000000326e-01 8.553651300000000290e-01 2.224781666666670113e-02 -6.007578000000000085e-01 7.747371155000000176e-01 2.167619850000000042e-02 -6.099849999999999994e-01 7.987110383333330121e-01 2.165553833333330042e-02 -6.220442000000000471e-01 6.615610463333330138e-01 2.089781950000000124e-02 -6.275817000000000201e-01 7.150054516666669580e-01 2.035196333333329916e-02 -6.414037999999999684e-01 6.088626698333330367e-01 1.874337833333329997e-02 -6.447992000000000168e-01 6.630811316666670452e-01 2.089752166666669977e-02 -6.657526999999999751e-01 5.716572943333330103e-01 1.811807299999999843e-02 -6.845788999999999902e-01 5.092866856666670161e-01 2.008440916666669879e-02 -7.060256999999999783e-01 4.113589818333330261e-01 1.688841199999999848e-02 -7.260906999999999778e-01 4.258370573333329911e-01 1.820484666666670123e-02 -7.492763000000000062e-01 3.814062795000000006e-01 1.498164383333329928e-02 -7.722440999999999889e-01 3.582434820000000020e-01 1.702263550000000097e-02 -7.923405000000000031e-01 3.290160251666670033e-01 1.493438950000000078e-02 -8.157583999999999946e-01 3.190799841666669967e-01 1.530228649999999975e-02 -8.367025000000000157e-01 2.762952625000000273e-01 1.450753649999999943e-02 -8.622005000000000363e-01 2.544186793333330088e-01 1.365137966666669922e-02 -8.849101000000000328e-01 2.424038613333329983e-01 1.432358516666669933e-02 -9.084231000000000389e-01 2.172930054999999971e-01 1.256612799999999933e-02 -9.337292000000000369e-01 2.202721591666670087e-01 1.359930866666670020e-02 -9.554743999999999460e-01 1.777866800000000025e-01 1.269970833333330072e-02 -9.815962999999999772e-01 1.676419470000000134e-01 1.190602366666669923e-02 -1.007114700000000029e+00 1.595580418333329975e-01 1.234223233333330005e-02 -1.030720700000000045e+00 1.541775503333329966e-01 1.173861049999999975e-02 -1.058106800000000014e+00 1.554276226666669869e-01 1.088984299999999975e-02 -1.084931700000000054e+00 1.440364893333329899e-01 1.122487333333329999e-02 -1.110240600000000022e+00 1.198653424999999995e-01 1.085281416666670010e-02 -1.138098400000000066e+00 1.211473946666670048e-01 1.044690799999999954e-02 +3.624610000000000332e-02 5.667029333499999666e+01 1.635708034166669833e+01 +4.069289999999999713e-02 2.663486052833329865e+01 1.131616966500000032e+01 +4.510390000000000232e-02 2.091145430999999988e+01 8.353784624999999409e+00 +4.958379999999999732e-02 1.655762528666669908e+01 6.766916158333329712e+00 +5.415430000000000244e-02 7.405398096666670149e+00 5.285856098333329811e+00 +5.867970000000000130e-02 1.609157327499999823e+01 4.579871853333330023e+00 +6.314219999999999555e-02 2.074624494500000083e+01 3.774208823333330187e+00 +6.772359999999999491e-02 1.622769223499999924e+01 3.121007619999999871e+00 +7.237720000000000264e-02 8.100976058333330343e+00 2.681633823333330113e+00 +7.692999999999999838e-02 7.297140411666670268e+00 2.370097993333330155e+00 +8.165179999999999660e-02 8.662000215000000836e+00 1.993900453333329992e+00 +8.640209999999999557e-02 1.195176863500000053e+01 1.811378463333330080e+00 +9.107550000000000368e-02 1.017929826333329935e+01 1.581605778333329937e+00 +9.574539999999999440e-02 8.299761948333330253e+00 1.447854706666670044e+00 +1.005039999999999961e-01 7.184010728333330320e+00 1.267957188333330043e+00 +1.052488000000000035e-01 7.705754226666670093e+00 1.175315996666669971e+00 +1.099981000000000014e-01 6.940137736666669888e+00 1.050239939999999983e+00 +1.148520999999999986e-01 7.227232895000000212e+00 9.582211533333330200e-01 +1.197872999999999993e-01 6.058664864999999899e+00 8.747766333333329980e-01 +1.247806000000000054e-01 5.235616768333329674e+00 8.060124016666669888e-01 +1.298481999999999970e-01 6.895559143333329644e+00 7.374701233333329498e-01 +1.349194999999999978e-01 5.596115646666669718e+00 7.017485283333330104e-01 +1.399364999999999915e-01 7.271002904999999572e+00 6.515097483333329720e-01 +1.450858999999999899e-01 5.001139740000000167e+00 6.081432883333329764e-01 +1.502787999999999902e-01 5.397041578333330314e+00 5.852662783333330010e-01 +1.556196999999999997e-01 5.201047356666670396e+00 5.230793849999999523e-01 +1.572660999999999920e-01 5.527525920000000426e+00 1.689539216666670063e-01 +1.609609999999999930e-01 6.050507654999999652e+00 5.103277550000000495e-01 +1.662019000000000135e-01 5.215723743333329665e+00 4.792083599999999999e-01 +1.706513000000000058e-01 5.031433279999999897e+00 1.411615750000000113e-01 +1.715762999999999872e-01 4.986483428333330359e+00 4.534299233333329848e-01 +1.771423000000000025e-01 5.106750501666669884e+00 4.289189133333329851e-01 +1.827474000000000043e-01 5.398633823333329751e+00 4.103611200000000236e-01 +1.842668000000000084e-01 4.914610723333329823e+00 1.221897900000000065e-01 +1.883336999999999928e-01 4.776135458333330419e+00 3.942386333333329773e-01 +1.939963000000000104e-01 4.310256373333330338e+00 3.794851616666670147e-01 +1.982673000000000074e-01 4.375084450000000125e+00 1.047416733333329936e-01 +1.997836000000000056e-01 4.425991520000000179e+00 3.548793383333330165e-01 +2.055989000000000011e-01 4.542295369999999721e+00 3.452195166666670034e-01 +2.114837999999999996e-01 4.392925553333330235e+00 3.296180283333329797e-01 +2.120387999999999995e-01 4.102498828333329683e+00 9.538819833333339604e-02 +2.162090000000000123e-01 4.067448908333330060e+00 4.099168333333330083e-01 +2.260118000000000127e-01 3.879140883333330070e+00 8.427184499999999800e-02 +2.398155999999999899e-01 3.717842756666669857e+00 7.930888666666670306e-02 +2.537425999999999848e-01 3.531988756666669893e+00 7.293178499999999898e-02 +2.676623000000000197e-01 3.501111030000000124e+00 6.786378666666670334e-02 +2.818223999999999729e-01 3.329498083333330083e+00 6.325724833333329356e-02 +2.956782000000000021e-01 3.079447669999999970e+00 5.969948499999999658e-02 +3.099446000000000145e-01 2.946954811666670171e+00 5.483356999999999815e-02 +3.241067000000000253e-01 2.705831398333330196e+00 5.323661166666669720e-02 +3.388467000000000007e-01 2.601996516666670090e+00 4.799289000000000333e-02 +3.539599999999999969e-01 2.517872383333330077e+00 4.725612833333329987e-02 +3.687568999999999986e-01 2.374362781666670141e+00 4.368410333333330037e-02 +3.840311000000000141e-01 2.195996148333330122e+00 4.125977166666670165e-02 +3.989493000000000067e-01 2.109030429999999789e+00 4.042385333333330111e-02 +4.107986000000000137e-01 1.888483604166669938e+00 4.043749766666669687e-02 +4.137051999999999952e-01 1.969810571666670063e+00 3.843483833333329741e-02 +4.291185000000000138e-01 1.859797011666669997e+00 3.539587999999999762e-02 +4.296826999999999730e-01 1.762954635166670059e+00 3.439219566666670141e-02 +4.446591999999999767e-01 1.624618943333330012e+00 3.443567000000000156e-02 +4.468077999999999772e-01 1.588049316333330019e+00 3.067751716666669917e-02 +4.603923999999999794e-01 1.585295316666669896e+00 3.227559333333329672e-02 +4.686866000000000088e-01 1.509168766666669992e+00 3.051112400000000058e-02 +4.765479000000000243e-01 1.429500135000000061e+00 3.031986666666669841e-02 +4.835556999999999772e-01 1.309360340500000053e+00 2.857159116666670162e-02 +4.923843999999999999e-01 1.363123808333329912e+00 3.037624166666669928e-02 +5.048160000000000425e-01 1.296483956833329954e+00 2.677855866666669846e-02 +5.083368000000000331e-01 1.254868451666669937e+00 2.782200166666669999e-02 +5.232324000000000419e-01 1.028253859833329953e+00 2.481625150000000071e-02 +5.249844000000000177e-01 1.223231273333329927e+00 2.634227000000000096e-02 +5.417480000000000073e-01 1.058531658333329961e+00 2.569255333333329838e-02 +5.445661000000000529e-01 1.022632484000000064e+00 2.537817800000000124e-02 +5.583793000000000228e-01 1.009770163333330029e+00 2.504100833333329848e-02 +5.614325999999999484e-01 9.522996788333329965e-01 2.313905700000000107e-02 +5.754704000000000486e-01 9.158985283333339611e-01 2.307270666666669939e-02 +5.835850999999999678e-01 8.544030651666669751e-01 2.288279616666670166e-02 +5.928168000000000326e-01 8.553651300000000290e-01 2.224781666666670113e-02 +6.007578000000000085e-01 7.747371155000000176e-01 2.167619850000000042e-02 +6.099849999999999994e-01 7.987110383333330121e-01 2.165553833333330042e-02 +6.220442000000000471e-01 6.615610463333330138e-01 2.089781950000000124e-02 +6.275817000000000201e-01 7.150054516666669580e-01 2.035196333333329916e-02 +6.414037999999999684e-01 6.088626698333330367e-01 1.874337833333329997e-02 +6.447992000000000168e-01 6.630811316666670452e-01 2.089752166666669977e-02 +6.657526999999999751e-01 5.716572943333330103e-01 1.811807299999999843e-02 +6.845788999999999902e-01 5.092866856666670161e-01 2.008440916666669879e-02 +7.060256999999999783e-01 4.113589818333330261e-01 1.688841199999999848e-02 +7.260906999999999778e-01 4.258370573333329911e-01 1.820484666666670123e-02 +7.492763000000000062e-01 3.814062795000000006e-01 1.498164383333329928e-02 +7.722440999999999889e-01 3.582434820000000020e-01 1.702263550000000097e-02 +7.923405000000000031e-01 3.290160251666670033e-01 1.493438950000000078e-02 +8.157583999999999946e-01 3.190799841666669967e-01 1.530228649999999975e-02 +8.367025000000000157e-01 2.762952625000000273e-01 1.450753649999999943e-02 +8.622005000000000363e-01 2.544186793333330088e-01 1.365137966666669922e-02 +8.849101000000000328e-01 2.424038613333329983e-01 1.432358516666669933e-02 +9.084231000000000389e-01 2.172930054999999971e-01 1.256612799999999933e-02 +9.337292000000000369e-01 2.202721591666670087e-01 1.359930866666670020e-02 +9.554743999999999460e-01 1.777866800000000025e-01 1.269970833333330072e-02 +9.815962999999999772e-01 1.676419470000000134e-01 1.190602366666669923e-02 +1.007114700000000029e+00 1.595580418333329975e-01 1.234223233333330005e-02 +1.030720700000000045e+00 1.541775503333329966e-01 1.173861049999999975e-02 +1.058106800000000014e+00 1.554276226666669869e-01 1.088984299999999975e-02 +1.084931700000000054e+00 1.440364893333329899e-01 1.122487333333329999e-02 +1.110240600000000022e+00 1.198653424999999995e-01 1.085281416666670010e-02 +1.138098400000000066e+00 1.211473946666670048e-01 1.044690799999999954e-02 1.166391799999999979e+00 1.189307901666669942e-01 1.021903716666669980e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv index 1161fab16..ee5f13e07 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/13_8000_1340_10.csv @@ -1,105 +1,105 @@ -3.625239999999999713e-02 6.302187949999999717e+01 1.635904319500000170e+01 -4.070000000000000007e-02 2.785521429499999968e+01 1.130956581166669928e+01 -4.511180000000000051e-02 1.008215536333329965e+01 8.312546360000000689e+00 -4.959249999999999770e-02 1.581932412333330085e+01 6.758513281666670203e+00 -5.416379999999999806e-02 7.750620351666669627e+00 5.282679641666669923e+00 -5.868999999999999911e-02 1.257659237500000060e+01 4.560014873333329888e+00 -6.315320000000000655e-02 1.891331758666670027e+01 3.761777425000000008e+00 -6.773540000000000116e-02 1.328150150333330082e+01 3.102479755000000061e+00 -7.238989999999999314e-02 9.795755306666670492e+00 2.689289660000000026e+00 -7.694339999999999513e-02 1.021541878833330053e+01 2.386645821666669942e+00 -8.166600000000000248e-02 7.264236756666670125e+00 1.982897978333330036e+00 -8.641719999999999957e-02 9.727612021666670827e+00 1.793249476666670006e+00 -9.109140000000000292e-02 9.940133039999999198e+00 1.578285125000000066e+00 -9.576210000000000278e-02 5.869161616666669801e+00 1.426304660000000002e+00 -1.005216000000000026e-01 6.271050506666670188e+00 1.258989316666669911e+00 -1.052672000000000052e-01 4.575212496666670070e+00 1.144957958333330028e+00 -1.100174000000000013e-01 6.675946670000000083e+00 1.046739891666669919e+00 -1.148721999999999938e-01 4.569861300000000348e+00 9.307519933333330275e-01 -1.198083000000000065e-01 4.073412075000000243e+00 8.536948699999999945e-01 -1.248023999999999939e-01 5.517398765000000260e+00 8.081908083333330106e-01 -1.298709000000000113e-01 6.055929844999999645e+00 7.277152516666669513e-01 -1.349431000000000103e-01 4.214499321666670184e+00 6.853886750000000028e-01 -1.399610000000000021e-01 4.711855326666669619e+00 6.206856016666669751e-01 -1.451112999999999986e-01 4.280988370000000209e+00 5.992362466666669718e-01 -1.503050999999999970e-01 3.350940026666669791e+00 5.604130616666670450e-01 -1.556469000000000047e-01 4.037392881666669986e+00 5.086757983333329847e-01 -1.572660999999999920e-01 4.116049464999999685e+00 1.639383783333329958e-01 -1.609891999999999990e-01 4.767404383333330387e+00 4.936060199999999787e-01 -1.662309999999999899e-01 4.092517224999999925e+00 4.643677516666669947e-01 -1.706513000000000058e-01 3.775210913333329810e+00 1.365719850000000068e-01 -1.716062999999999894e-01 4.067082121666669714e+00 4.413313999999999848e-01 -1.771733000000000058e-01 3.397890750000000182e+00 4.070909349999999871e-01 -1.827794000000000085e-01 4.061001236666670344e+00 3.925402433333329832e-01 -1.842668000000000084e-01 3.799252254999999856e+00 1.178310383333329991e-01 -1.883665999999999952e-01 3.208655455000000156e+00 3.733191000000000148e-01 -1.940302000000000138e-01 3.206445976666670195e+00 3.650098783333329822e-01 -1.982673000000000074e-01 3.425276903333330125e+00 1.008325449999999956e-01 -1.998185000000000100e-01 3.354815260000000077e+00 3.406662516666669749e-01 -2.056348000000000065e-01 3.721227830000000125e+00 3.339491649999999923e-01 -2.115208000000000088e-01 3.612948971666670062e+00 3.193275150000000062e-01 -2.120387999999999995e-01 3.205896688333329969e+00 9.145261000000000362e-02 -2.162467999999999890e-01 3.645113248333330169e+00 4.021025750000000176e-01 -2.260118000000000127e-01 3.104582965000000083e+00 8.081593333333329798e-02 -2.398155999999999899e-01 3.037513673333330111e+00 7.613482000000000582e-02 -2.537425999999999848e-01 2.836682165000000033e+00 6.969811833333329487e-02 -2.676623000000000197e-01 2.819590748333329788e+00 6.462849833333329796e-02 -2.818223999999999729e-01 2.721404538333330070e+00 6.033223166666670106e-02 -2.956782000000000021e-01 2.736251186666669888e+00 5.799425166666669768e-02 -3.099446000000000145e-01 2.543946483333329844e+00 5.286760000000000070e-02 -3.241067000000000253e-01 2.287160831666669836e+00 5.112056499999999976e-02 -3.388467000000000007e-01 2.288673078333329780e+00 4.649771999999999933e-02 -3.539599999999999969e-01 2.199149091666670053e+00 4.568711999999999773e-02 -3.687568999999999986e-01 2.068072668333329922e+00 4.217328666666669834e-02 -3.840311000000000141e-01 1.969221529999999998e+00 4.012745166666670249e-02 -3.989493000000000067e-01 1.908232941666669902e+00 3.938963333333329875e-02 -4.107629999999999892e-01 1.727702871333330004e+00 3.958386533333330126e-02 -4.137051999999999952e-01 1.726875600000000066e+00 3.720425833333330240e-02 -4.291185000000000138e-01 1.581841901666670047e+00 3.398506666666670228e-02 -4.296455000000000135e-01 1.691278518333330094e+00 3.404221949999999830e-02 -4.446591999999999767e-01 1.488087740000000103e+00 3.374035333333329917e-02 -4.467690999999999746e-01 1.413946998166669911e+00 2.991126200000000096e-02 -4.603923999999999794e-01 1.391984139999999925e+00 3.130147333333330173e-02 -4.686460000000000070e-01 1.392956528666670080e+00 2.997462383333330052e-02 -4.765479000000000243e-01 1.301627080000000047e+00 2.965699000000000113e-02 -4.835137999999999936e-01 1.193676802499999967e+00 2.800566683333330018e-02 -4.923843999999999999e-01 1.242278698333330045e+00 2.973970833333329858e-02 -5.047722000000000042e-01 1.149708217833329993e+00 2.613050733333329920e-02 -5.083368000000000331e-01 1.161310218333329924e+00 2.733334000000000111e-02 -5.231871000000000160e-01 9.503032668333329935e-01 2.446244750000000148e-02 -5.249844000000000177e-01 1.102167341666669964e+00 2.571981833333330039e-02 -5.417480000000000073e-01 9.754589783333329489e-01 2.525416166666670167e-02 -5.445189000000000279e-01 9.366835949999999800e-01 2.497178450000000008e-02 -5.583793000000000228e-01 8.831162099999999571e-01 2.438054666666670048e-02 -5.613839000000000468e-01 8.824506341666670250e-01 2.281443349999999828e-02 -5.754704000000000486e-01 8.100822066666669707e-01 2.253018666666670167e-02 -5.835346000000000144e-01 7.776236106666669645e-01 2.252483566666670101e-02 -5.928168000000000326e-01 7.764561633333330049e-01 2.182597999999999830e-02 -6.007057000000000091e-01 6.983251131666670108e-01 2.131793766666669962e-02 -6.099849999999999994e-01 7.099790583333329685e-01 2.117932666666669933e-02 -6.219902999999999960e-01 6.466382168333330016e-01 2.081252199999999997e-02 -6.275817000000000201e-01 6.603706066666670260e-01 2.006477833333330033e-02 -6.413482000000000349e-01 5.710830485000000234e-01 1.856948533333329862e-02 -6.447992000000000168e-01 5.732715750000000332e-01 2.040912500000000018e-02 -6.656950000000000367e-01 5.203726888333329859e-01 1.789587166666670170e-02 -6.845196000000000058e-01 4.749653629999999738e-01 1.990720683333329841e-02 -7.059646000000000532e-01 3.822856073333329996e-01 1.675657983333329881e-02 -7.260278000000000009e-01 3.886542691666670102e-01 1.802539466666670115e-02 -7.492113999999999718e-01 3.564554191666670091e-01 1.487377883333330063e-02 -7.721772000000000080e-01 3.333074428333330230e-01 1.689668533333330003e-02 -7.922717999999999705e-01 3.187338046666670088e-01 1.488059016666670037e-02 -8.156877999999999629e-01 3.010368924999999862e-01 1.521491216666670011e-02 -8.366301000000000432e-01 2.406595508333330136e-01 1.435568400000000050e-02 -8.621258000000000532e-01 2.223576200000000058e-01 1.352156766666669924e-02 -8.848333999999999921e-01 2.207387865000000060e-01 1.422139816666669922e-02 -9.083444000000000518e-01 2.134049949999999862e-01 1.254214099999999971e-02 -9.336484000000000449e-01 1.885945263333330124e-01 1.346345033333330027e-02 -9.553916000000000075e-01 1.698076676666669949e-01 1.265998783333329922e-02 -9.815112999999999754e-01 1.668850050000000029e-01 1.189438716666670059e-02 -1.007027499999999964e+00 1.441018685000000077e-01 1.227580483333329947e-02 -1.030631400000000086e+00 1.406578583333329968e-01 1.168073399999999991e-02 -1.058015099999999986e+00 1.399035711666669901e-01 1.082874783333329961e-02 -1.084837700000000016e+00 1.486492919999999884e-01 1.123307866666669978e-02 -1.110144500000000090e+00 1.008698655000000027e-01 1.077987283333329931e-02 -1.137999800000000006e+00 1.027075286666670056e-01 1.037853683333330064e-02 +3.625239999999999713e-02 6.302187949999999717e+01 1.635904319500000170e+01 +4.070000000000000007e-02 2.785521429499999968e+01 1.130956581166669928e+01 +4.511180000000000051e-02 1.008215536333329965e+01 8.312546360000000689e+00 +4.959249999999999770e-02 1.581932412333330085e+01 6.758513281666670203e+00 +5.416379999999999806e-02 7.750620351666669627e+00 5.282679641666669923e+00 +5.868999999999999911e-02 1.257659237500000060e+01 4.560014873333329888e+00 +6.315320000000000655e-02 1.891331758666670027e+01 3.761777425000000008e+00 +6.773540000000000116e-02 1.328150150333330082e+01 3.102479755000000061e+00 +7.238989999999999314e-02 9.795755306666670492e+00 2.689289660000000026e+00 +7.694339999999999513e-02 1.021541878833330053e+01 2.386645821666669942e+00 +8.166600000000000248e-02 7.264236756666670125e+00 1.982897978333330036e+00 +8.641719999999999957e-02 9.727612021666670827e+00 1.793249476666670006e+00 +9.109140000000000292e-02 9.940133039999999198e+00 1.578285125000000066e+00 +9.576210000000000278e-02 5.869161616666669801e+00 1.426304660000000002e+00 +1.005216000000000026e-01 6.271050506666670188e+00 1.258989316666669911e+00 +1.052672000000000052e-01 4.575212496666670070e+00 1.144957958333330028e+00 +1.100174000000000013e-01 6.675946670000000083e+00 1.046739891666669919e+00 +1.148721999999999938e-01 4.569861300000000348e+00 9.307519933333330275e-01 +1.198083000000000065e-01 4.073412075000000243e+00 8.536948699999999945e-01 +1.248023999999999939e-01 5.517398765000000260e+00 8.081908083333330106e-01 +1.298709000000000113e-01 6.055929844999999645e+00 7.277152516666669513e-01 +1.349431000000000103e-01 4.214499321666670184e+00 6.853886750000000028e-01 +1.399610000000000021e-01 4.711855326666669619e+00 6.206856016666669751e-01 +1.451112999999999986e-01 4.280988370000000209e+00 5.992362466666669718e-01 +1.503050999999999970e-01 3.350940026666669791e+00 5.604130616666670450e-01 +1.556469000000000047e-01 4.037392881666669986e+00 5.086757983333329847e-01 +1.572660999999999920e-01 4.116049464999999685e+00 1.639383783333329958e-01 +1.609891999999999990e-01 4.767404383333330387e+00 4.936060199999999787e-01 +1.662309999999999899e-01 4.092517224999999925e+00 4.643677516666669947e-01 +1.706513000000000058e-01 3.775210913333329810e+00 1.365719850000000068e-01 +1.716062999999999894e-01 4.067082121666669714e+00 4.413313999999999848e-01 +1.771733000000000058e-01 3.397890750000000182e+00 4.070909349999999871e-01 +1.827794000000000085e-01 4.061001236666670344e+00 3.925402433333329832e-01 +1.842668000000000084e-01 3.799252254999999856e+00 1.178310383333329991e-01 +1.883665999999999952e-01 3.208655455000000156e+00 3.733191000000000148e-01 +1.940302000000000138e-01 3.206445976666670195e+00 3.650098783333329822e-01 +1.982673000000000074e-01 3.425276903333330125e+00 1.008325449999999956e-01 +1.998185000000000100e-01 3.354815260000000077e+00 3.406662516666669749e-01 +2.056348000000000065e-01 3.721227830000000125e+00 3.339491649999999923e-01 +2.115208000000000088e-01 3.612948971666670062e+00 3.193275150000000062e-01 +2.120387999999999995e-01 3.205896688333329969e+00 9.145261000000000362e-02 +2.162467999999999890e-01 3.645113248333330169e+00 4.021025750000000176e-01 +2.260118000000000127e-01 3.104582965000000083e+00 8.081593333333329798e-02 +2.398155999999999899e-01 3.037513673333330111e+00 7.613482000000000582e-02 +2.537425999999999848e-01 2.836682165000000033e+00 6.969811833333329487e-02 +2.676623000000000197e-01 2.819590748333329788e+00 6.462849833333329796e-02 +2.818223999999999729e-01 2.721404538333330070e+00 6.033223166666670106e-02 +2.956782000000000021e-01 2.736251186666669888e+00 5.799425166666669768e-02 +3.099446000000000145e-01 2.543946483333329844e+00 5.286760000000000070e-02 +3.241067000000000253e-01 2.287160831666669836e+00 5.112056499999999976e-02 +3.388467000000000007e-01 2.288673078333329780e+00 4.649771999999999933e-02 +3.539599999999999969e-01 2.199149091666670053e+00 4.568711999999999773e-02 +3.687568999999999986e-01 2.068072668333329922e+00 4.217328666666669834e-02 +3.840311000000000141e-01 1.969221529999999998e+00 4.012745166666670249e-02 +3.989493000000000067e-01 1.908232941666669902e+00 3.938963333333329875e-02 +4.107629999999999892e-01 1.727702871333330004e+00 3.958386533333330126e-02 +4.137051999999999952e-01 1.726875600000000066e+00 3.720425833333330240e-02 +4.291185000000000138e-01 1.581841901666670047e+00 3.398506666666670228e-02 +4.296455000000000135e-01 1.691278518333330094e+00 3.404221949999999830e-02 +4.446591999999999767e-01 1.488087740000000103e+00 3.374035333333329917e-02 +4.467690999999999746e-01 1.413946998166669911e+00 2.991126200000000096e-02 +4.603923999999999794e-01 1.391984139999999925e+00 3.130147333333330173e-02 +4.686460000000000070e-01 1.392956528666670080e+00 2.997462383333330052e-02 +4.765479000000000243e-01 1.301627080000000047e+00 2.965699000000000113e-02 +4.835137999999999936e-01 1.193676802499999967e+00 2.800566683333330018e-02 +4.923843999999999999e-01 1.242278698333330045e+00 2.973970833333329858e-02 +5.047722000000000042e-01 1.149708217833329993e+00 2.613050733333329920e-02 +5.083368000000000331e-01 1.161310218333329924e+00 2.733334000000000111e-02 +5.231871000000000160e-01 9.503032668333329935e-01 2.446244750000000148e-02 +5.249844000000000177e-01 1.102167341666669964e+00 2.571981833333330039e-02 +5.417480000000000073e-01 9.754589783333329489e-01 2.525416166666670167e-02 +5.445189000000000279e-01 9.366835949999999800e-01 2.497178450000000008e-02 +5.583793000000000228e-01 8.831162099999999571e-01 2.438054666666670048e-02 +5.613839000000000468e-01 8.824506341666670250e-01 2.281443349999999828e-02 +5.754704000000000486e-01 8.100822066666669707e-01 2.253018666666670167e-02 +5.835346000000000144e-01 7.776236106666669645e-01 2.252483566666670101e-02 +5.928168000000000326e-01 7.764561633333330049e-01 2.182597999999999830e-02 +6.007057000000000091e-01 6.983251131666670108e-01 2.131793766666669962e-02 +6.099849999999999994e-01 7.099790583333329685e-01 2.117932666666669933e-02 +6.219902999999999960e-01 6.466382168333330016e-01 2.081252199999999997e-02 +6.275817000000000201e-01 6.603706066666670260e-01 2.006477833333330033e-02 +6.413482000000000349e-01 5.710830485000000234e-01 1.856948533333329862e-02 +6.447992000000000168e-01 5.732715750000000332e-01 2.040912500000000018e-02 +6.656950000000000367e-01 5.203726888333329859e-01 1.789587166666670170e-02 +6.845196000000000058e-01 4.749653629999999738e-01 1.990720683333329841e-02 +7.059646000000000532e-01 3.822856073333329996e-01 1.675657983333329881e-02 +7.260278000000000009e-01 3.886542691666670102e-01 1.802539466666670115e-02 +7.492113999999999718e-01 3.564554191666670091e-01 1.487377883333330063e-02 +7.721772000000000080e-01 3.333074428333330230e-01 1.689668533333330003e-02 +7.922717999999999705e-01 3.187338046666670088e-01 1.488059016666670037e-02 +8.156877999999999629e-01 3.010368924999999862e-01 1.521491216666670011e-02 +8.366301000000000432e-01 2.406595508333330136e-01 1.435568400000000050e-02 +8.621258000000000532e-01 2.223576200000000058e-01 1.352156766666669924e-02 +8.848333999999999921e-01 2.207387865000000060e-01 1.422139816666669922e-02 +9.083444000000000518e-01 2.134049949999999862e-01 1.254214099999999971e-02 +9.336484000000000449e-01 1.885945263333330124e-01 1.346345033333330027e-02 +9.553916000000000075e-01 1.698076676666669949e-01 1.265998783333329922e-02 +9.815112999999999754e-01 1.668850050000000029e-01 1.189438716666670059e-02 +1.007027499999999964e+00 1.441018685000000077e-01 1.227580483333329947e-02 +1.030631400000000086e+00 1.406578583333329968e-01 1.168073399999999991e-02 +1.058015099999999986e+00 1.399035711666669901e-01 1.082874783333329961e-02 +1.084837700000000016e+00 1.486492919999999884e-01 1.123307866666669978e-02 +1.110144500000000090e+00 1.008698655000000027e-01 1.077987283333329931e-02 +1.137999800000000006e+00 1.027075286666670056e-01 1.037853683333330064e-02 1.166290800000000072e+00 1.157098001666670012e-01 1.020088966666670045e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv index 741887c08..1c5c261ee 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/1_0_1340_10.csv @@ -1,105 +1,105 @@ -3.625239999999999713e-02 2.859171986188329811e+03 2.282233352000000082e+01 -4.070000000000000007e-02 1.037695935384999984e+03 1.390765389166669941e+01 -4.511180000000000051e-02 4.617414862783330136e+02 9.644274246666670436e+00 -4.959249999999999770e-02 2.830472148050000101e+02 7.651757100000000200e+00 -5.416379999999999806e-02 1.737180786733329967e+02 5.901133003333329796e+00 -5.868999999999999911e-02 1.284318533800000068e+02 5.055296333333330061e+00 -6.315320000000000655e-02 1.083304533916670067e+02 4.179970964999999872e+00 -6.773540000000000116e-02 8.164665742500000079e+01 3.449109084999999908e+00 -7.238989999999999314e-02 6.842710629666669320e+01 3.015091889999999886e+00 -7.694339999999999513e-02 6.503887503333329789e+01 2.712566869999999852e+00 -8.166600000000000248e-02 5.768616606333330310e+01 2.292022508333329878e+00 -8.641719999999999957e-02 4.726633163000000337e+01 2.052834279999999900e+00 -9.109140000000000292e-02 4.170182763166670270e+01 1.806841736666670029e+00 -9.576210000000000278e-02 3.278791741500000256e+01 1.635979810000000034e+00 -1.005216000000000026e-01 3.137094696333329935e+01 1.457612156666669989e+00 -1.052672000000000052e-01 2.858316747499999977e+01 1.352856671666669897e+00 -1.100174000000000013e-01 2.685582243333330155e+01 1.222659363333330029e+00 -1.148721999999999938e-01 2.463809722666670154e+01 1.115379456666669933e+00 -1.198083000000000065e-01 1.979913578000000030e+01 1.002652691666670037e+00 -1.248023999999999939e-01 1.884005529499999909e+01 9.371682333333329895e-01 -1.298709000000000113e-01 2.011378014833330141e+01 8.660532583333330203e-01 -1.349431000000000103e-01 1.548196221999999977e+01 8.040137483333329449e-01 -1.399610000000000021e-01 1.553817986500000004e+01 7.396018783333330182e-01 -1.451112999999999986e-01 1.380290046833330031e+01 7.008050850000000498e-01 -1.503050999999999970e-01 1.290957537833329916e+01 6.659874700000000258e-01 -1.556469000000000047e-01 1.188963399333329995e+01 5.958023666666669715e-01 -1.572456999999999883e-01 1.305280697499999931e+01 1.930089849999999940e-01 -1.609891999999999990e-01 1.134609165166670053e+01 5.714861916666670316e-01 -1.662309999999999899e-01 1.103891432833330022e+01 5.468199316666669807e-01 -1.706292000000000086e-01 1.121912493499999997e+01 1.614639983333329976e-01 -1.716062999999999894e-01 1.098087770333330049e+01 5.221648316666670508e-01 -1.771733000000000058e-01 9.846715853333330770e+00 4.826313150000000052e-01 -1.827794000000000085e-01 1.030369242166669963e+01 4.679303400000000002e-01 -1.842428999999999872e-01 9.629214631666670243e+00 1.387244099999999924e-01 -1.883665999999999952e-01 9.108624106666670883e+00 4.454082083333330000e-01 -1.940302000000000138e-01 8.056377178333329780e+00 4.232006716666670276e-01 -1.982414999999999872e-01 8.605072379999999299e+00 1.202604099999999981e-01 -1.998185000000000100e-01 8.229729869999999892e+00 3.995894999999999864e-01 -2.056348000000000065e-01 8.070094290000000115e+00 3.879820366666669740e-01 -2.115208000000000088e-01 7.741634115000000094e+00 3.686955350000000187e-01 -2.120113000000000136e-01 7.664225765000000301e+00 1.093220133333329958e-01 -2.162467999999999890e-01 7.363320653333330412e+00 4.626756216666669808e-01 -2.259823999999999999e-01 6.848802841666669750e+00 9.609777999999999376e-02 -2.397845000000000115e-01 6.337189861666669977e+00 9.020952999999999611e-02 -2.537096999999999825e-01 5.738702153333330003e+00 8.211384833333329469e-02 -2.676275000000000182e-01 5.346591223333329701e+00 7.572218666666670484e-02 -2.817857999999999752e-01 5.009933698333330021e+00 7.051459333333330581e-02 -2.956398000000000081e-01 4.597692046666669974e+00 6.646157833333329878e-02 -3.099044000000000243e-01 4.193400725000000051e+00 6.031815000000000093e-02 -3.240645999999999805e-01 3.804645918333330101e+00 5.825413166666670167e-02 -3.388027000000000122e-01 3.560888523333329836e+00 5.213344166666669666e-02 -3.539140000000000064e-01 3.375211385000000064e+00 5.107971833333330158e-02 -3.687090000000000090e-01 3.188264295000000192e+00 4.732182333333329743e-02 -3.839813000000000254e-01 2.892990108333330035e+00 4.441047333333329739e-02 -3.988975000000000160e-01 2.640608908333330174e+00 4.290645666666669661e-02 -4.106379000000000001e-01 2.501690660833329805e+00 4.331324033333330131e-02 -4.136514000000000024e-01 2.477246653333330162e+00 4.077528500000000139e-02 -4.290628000000000219e-01 2.358423203333329887e+00 3.769917166666669761e-02 -4.295145000000000213e-01 2.266923564999999918e+00 3.645828216666670285e-02 -4.446014999999999828e-01 2.023246533333329822e+00 3.627248666666670063e-02 -4.466328999999999994e-01 2.032174506166669836e+00 3.243397416666669864e-02 -4.603325999999999807e-01 1.951935533333329920e+00 3.395880333333330114e-02 -4.685032000000000085e-01 1.797322475499999905e+00 3.168831166666669780e-02 -4.764860000000000206e-01 1.814704324999999896e+00 3.212894000000000166e-02 -4.833663999999999739e-01 1.722621554333330085e+00 3.037123383333329915e-02 -4.923204999999999942e-01 1.658358661666669898e+00 3.178619500000000320e-02 -5.046184000000000225e-01 1.539108265666669917e+00 2.774163983333330016e-02 -5.082708000000000226e-01 1.547966548333330028e+00 2.920229666666670013e-02 -5.230276000000000369e-01 1.345057283333330078e+00 2.608127533333329945e-02 -5.249162000000000550e-01 1.417396718333330030e+00 2.724554333333329900e-02 -5.416775999999999813e-01 1.270799306666670070e+00 2.670250999999999875e-02 -5.443529999999999758e-01 1.250087865666670073e+00 2.633086933333329827e-02 -5.583067999999999920e-01 1.165305416666670091e+00 2.577655499999999961e-02 -5.612129000000000145e-01 1.147836548999999984e+00 2.393862083333329893e-02 -5.753956999999999544e-01 1.115183805000000028e+00 2.400332833333329932e-02 -5.833568000000000087e-01 1.044019996999999922e+00 2.366755300000000090e-02 -5.927398999999999862e-01 1.004017331666670065e+00 2.296542000000000028e-02 -6.005226999999999649e-01 9.482225546666670501e-01 2.240195116666670108e-02 -6.099058000000000535e-01 9.388455449999999480e-01 2.233828499999999939e-02 -6.218008000000000424e-01 8.511757086666670302e-01 2.168908733333330119e-02 -6.275003000000000108e-01 8.553386066666669452e-01 2.101305833333329959e-02 -6.411527999999999672e-01 7.761240236666669956e-01 1.940277716666670080e-02 -6.447154999999999969e-01 7.270576883333329521e-01 2.120466833333330137e-02 -6.654921999999999782e-01 7.007768106666669716e-01 1.861042133333330045e-02 -6.843110000000000026e-01 6.466361541666669766e-01 2.069310833333330019e-02 -7.057493999999999712e-01 5.771519323333329510e-01 1.752841666666669906e-02 -7.258065000000000211e-01 5.204018098333329512e-01 1.860044799999999859e-02 -7.489831000000000127e-01 4.984340896666670240e-01 1.540761000000000040e-02 -7.719418000000000113e-01 4.436713720000000083e-01 1.738589999999999927e-02 -7.920304000000000233e-01 4.316635041666669892e-01 1.532890283333330009e-02 -8.154392000000000307e-01 3.868879691666670118e-01 1.556857449999999969e-02 -8.363751000000000380e-01 3.670109628333330098e-01 1.484866983333330004e-02 -8.618630000000000457e-01 3.329731463333330255e-01 1.392995016666669951e-02 -8.845638000000000112e-01 3.302565831666670060e-01 1.467645416666669977e-02 -9.080675999999999748e-01 2.757098590000000016e-01 1.276754683333329934e-02 -9.333637999999999657e-01 2.804865558333329845e-01 1.382540016666669938e-02 -9.551005000000000189e-01 2.398962168333330092e-01 1.292395533333329932e-02 -9.812121999999999788e-01 2.360268241666670097e-01 1.213837400000000039e-02 -1.006720599999999965e+00 2.134167958333330062e-01 1.253179649999999930e-02 -1.030317399999999939e+00 2.102511210000000130e-01 1.193319533333330081e-02 -1.057692700000000041e+00 2.135461601666669984e-01 1.107935333333330032e-02 -1.084507099999999946e+00 1.969431385000000034e-01 1.140526600000000071e-02 -1.109806099999999907e+00 1.561050018333330069e-01 1.096976283333329916e-02 -1.137653000000000025e+00 1.629041234999999976e-01 1.057719600000000051e-02 +3.625239999999999713e-02 2.859171986188329811e+03 2.282233352000000082e+01 +4.070000000000000007e-02 1.037695935384999984e+03 1.390765389166669941e+01 +4.511180000000000051e-02 4.617414862783330136e+02 9.644274246666670436e+00 +4.959249999999999770e-02 2.830472148050000101e+02 7.651757100000000200e+00 +5.416379999999999806e-02 1.737180786733329967e+02 5.901133003333329796e+00 +5.868999999999999911e-02 1.284318533800000068e+02 5.055296333333330061e+00 +6.315320000000000655e-02 1.083304533916670067e+02 4.179970964999999872e+00 +6.773540000000000116e-02 8.164665742500000079e+01 3.449109084999999908e+00 +7.238989999999999314e-02 6.842710629666669320e+01 3.015091889999999886e+00 +7.694339999999999513e-02 6.503887503333329789e+01 2.712566869999999852e+00 +8.166600000000000248e-02 5.768616606333330310e+01 2.292022508333329878e+00 +8.641719999999999957e-02 4.726633163000000337e+01 2.052834279999999900e+00 +9.109140000000000292e-02 4.170182763166670270e+01 1.806841736666670029e+00 +9.576210000000000278e-02 3.278791741500000256e+01 1.635979810000000034e+00 +1.005216000000000026e-01 3.137094696333329935e+01 1.457612156666669989e+00 +1.052672000000000052e-01 2.858316747499999977e+01 1.352856671666669897e+00 +1.100174000000000013e-01 2.685582243333330155e+01 1.222659363333330029e+00 +1.148721999999999938e-01 2.463809722666670154e+01 1.115379456666669933e+00 +1.198083000000000065e-01 1.979913578000000030e+01 1.002652691666670037e+00 +1.248023999999999939e-01 1.884005529499999909e+01 9.371682333333329895e-01 +1.298709000000000113e-01 2.011378014833330141e+01 8.660532583333330203e-01 +1.349431000000000103e-01 1.548196221999999977e+01 8.040137483333329449e-01 +1.399610000000000021e-01 1.553817986500000004e+01 7.396018783333330182e-01 +1.451112999999999986e-01 1.380290046833330031e+01 7.008050850000000498e-01 +1.503050999999999970e-01 1.290957537833329916e+01 6.659874700000000258e-01 +1.556469000000000047e-01 1.188963399333329995e+01 5.958023666666669715e-01 +1.572456999999999883e-01 1.305280697499999931e+01 1.930089849999999940e-01 +1.609891999999999990e-01 1.134609165166670053e+01 5.714861916666670316e-01 +1.662309999999999899e-01 1.103891432833330022e+01 5.468199316666669807e-01 +1.706292000000000086e-01 1.121912493499999997e+01 1.614639983333329976e-01 +1.716062999999999894e-01 1.098087770333330049e+01 5.221648316666670508e-01 +1.771733000000000058e-01 9.846715853333330770e+00 4.826313150000000052e-01 +1.827794000000000085e-01 1.030369242166669963e+01 4.679303400000000002e-01 +1.842428999999999872e-01 9.629214631666670243e+00 1.387244099999999924e-01 +1.883665999999999952e-01 9.108624106666670883e+00 4.454082083333330000e-01 +1.940302000000000138e-01 8.056377178333329780e+00 4.232006716666670276e-01 +1.982414999999999872e-01 8.605072379999999299e+00 1.202604099999999981e-01 +1.998185000000000100e-01 8.229729869999999892e+00 3.995894999999999864e-01 +2.056348000000000065e-01 8.070094290000000115e+00 3.879820366666669740e-01 +2.115208000000000088e-01 7.741634115000000094e+00 3.686955350000000187e-01 +2.120113000000000136e-01 7.664225765000000301e+00 1.093220133333329958e-01 +2.162467999999999890e-01 7.363320653333330412e+00 4.626756216666669808e-01 +2.259823999999999999e-01 6.848802841666669750e+00 9.609777999999999376e-02 +2.397845000000000115e-01 6.337189861666669977e+00 9.020952999999999611e-02 +2.537096999999999825e-01 5.738702153333330003e+00 8.211384833333329469e-02 +2.676275000000000182e-01 5.346591223333329701e+00 7.572218666666670484e-02 +2.817857999999999752e-01 5.009933698333330021e+00 7.051459333333330581e-02 +2.956398000000000081e-01 4.597692046666669974e+00 6.646157833333329878e-02 +3.099044000000000243e-01 4.193400725000000051e+00 6.031815000000000093e-02 +3.240645999999999805e-01 3.804645918333330101e+00 5.825413166666670167e-02 +3.388027000000000122e-01 3.560888523333329836e+00 5.213344166666669666e-02 +3.539140000000000064e-01 3.375211385000000064e+00 5.107971833333330158e-02 +3.687090000000000090e-01 3.188264295000000192e+00 4.732182333333329743e-02 +3.839813000000000254e-01 2.892990108333330035e+00 4.441047333333329739e-02 +3.988975000000000160e-01 2.640608908333330174e+00 4.290645666666669661e-02 +4.106379000000000001e-01 2.501690660833329805e+00 4.331324033333330131e-02 +4.136514000000000024e-01 2.477246653333330162e+00 4.077528500000000139e-02 +4.290628000000000219e-01 2.358423203333329887e+00 3.769917166666669761e-02 +4.295145000000000213e-01 2.266923564999999918e+00 3.645828216666670285e-02 +4.446014999999999828e-01 2.023246533333329822e+00 3.627248666666670063e-02 +4.466328999999999994e-01 2.032174506166669836e+00 3.243397416666669864e-02 +4.603325999999999807e-01 1.951935533333329920e+00 3.395880333333330114e-02 +4.685032000000000085e-01 1.797322475499999905e+00 3.168831166666669780e-02 +4.764860000000000206e-01 1.814704324999999896e+00 3.212894000000000166e-02 +4.833663999999999739e-01 1.722621554333330085e+00 3.037123383333329915e-02 +4.923204999999999942e-01 1.658358661666669898e+00 3.178619500000000320e-02 +5.046184000000000225e-01 1.539108265666669917e+00 2.774163983333330016e-02 +5.082708000000000226e-01 1.547966548333330028e+00 2.920229666666670013e-02 +5.230276000000000369e-01 1.345057283333330078e+00 2.608127533333329945e-02 +5.249162000000000550e-01 1.417396718333330030e+00 2.724554333333329900e-02 +5.416775999999999813e-01 1.270799306666670070e+00 2.670250999999999875e-02 +5.443529999999999758e-01 1.250087865666670073e+00 2.633086933333329827e-02 +5.583067999999999920e-01 1.165305416666670091e+00 2.577655499999999961e-02 +5.612129000000000145e-01 1.147836548999999984e+00 2.393862083333329893e-02 +5.753956999999999544e-01 1.115183805000000028e+00 2.400332833333329932e-02 +5.833568000000000087e-01 1.044019996999999922e+00 2.366755300000000090e-02 +5.927398999999999862e-01 1.004017331666670065e+00 2.296542000000000028e-02 +6.005226999999999649e-01 9.482225546666670501e-01 2.240195116666670108e-02 +6.099058000000000535e-01 9.388455449999999480e-01 2.233828499999999939e-02 +6.218008000000000424e-01 8.511757086666670302e-01 2.168908733333330119e-02 +6.275003000000000108e-01 8.553386066666669452e-01 2.101305833333329959e-02 +6.411527999999999672e-01 7.761240236666669956e-01 1.940277716666670080e-02 +6.447154999999999969e-01 7.270576883333329521e-01 2.120466833333330137e-02 +6.654921999999999782e-01 7.007768106666669716e-01 1.861042133333330045e-02 +6.843110000000000026e-01 6.466361541666669766e-01 2.069310833333330019e-02 +7.057493999999999712e-01 5.771519323333329510e-01 1.752841666666669906e-02 +7.258065000000000211e-01 5.204018098333329512e-01 1.860044799999999859e-02 +7.489831000000000127e-01 4.984340896666670240e-01 1.540761000000000040e-02 +7.719418000000000113e-01 4.436713720000000083e-01 1.738589999999999927e-02 +7.920304000000000233e-01 4.316635041666669892e-01 1.532890283333330009e-02 +8.154392000000000307e-01 3.868879691666670118e-01 1.556857449999999969e-02 +8.363751000000000380e-01 3.670109628333330098e-01 1.484866983333330004e-02 +8.618630000000000457e-01 3.329731463333330255e-01 1.392995016666669951e-02 +8.845638000000000112e-01 3.302565831666670060e-01 1.467645416666669977e-02 +9.080675999999999748e-01 2.757098590000000016e-01 1.276754683333329934e-02 +9.333637999999999657e-01 2.804865558333329845e-01 1.382540016666669938e-02 +9.551005000000000189e-01 2.398962168333330092e-01 1.292395533333329932e-02 +9.812121999999999788e-01 2.360268241666670097e-01 1.213837400000000039e-02 +1.006720599999999965e+00 2.134167958333330062e-01 1.253179649999999930e-02 +1.030317399999999939e+00 2.102511210000000130e-01 1.193319533333330081e-02 +1.057692700000000041e+00 2.135461601666669984e-01 1.107935333333330032e-02 +1.084507099999999946e+00 1.969431385000000034e-01 1.140526600000000071e-02 +1.109806099999999907e+00 1.561050018333330069e-01 1.096976283333329916e-02 +1.137653000000000025e+00 1.629041234999999976e-01 1.057719600000000051e-02 1.165935399999999955e+00 1.774132069999999894e-01 1.040658966666670009e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv index a4e026fba..3fc895617 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/2_20_1340_10.csv @@ -1,105 +1,105 @@ -3.623980000000000257e-02 4.717095203250000282e+02 1.736400694499999986e+01 -4.068580000000000113e-02 2.786014172683330230e+02 1.198827076999999974e+01 -4.509610000000000007e-02 1.807710803516669955e+02 8.834240069999999889e+00 -4.957530000000000270e-02 1.404167299050000111e+02 7.187393765000000379e+00 -5.414490000000000275e-02 1.070548824566670021e+02 5.660295944999999662e+00 -5.866960000000000230e-02 9.429733434666670178e+01 4.914365443333330141e+00 -6.313130000000000130e-02 8.753748113499999306e+01 4.086659178333330367e+00 -6.771190000000000542e-02 8.007891920833330346e+01 3.441741584999999937e+00 -7.236470000000000402e-02 5.999202779333329971e+01 2.970499293333329849e+00 -7.691660000000000164e-02 5.902839900166669906e+01 2.678938321666669786e+00 -8.163760000000000461e-02 4.960764509333330352e+01 2.245417474999999996e+00 -8.638719999999999732e-02 4.414010876166670272e+01 2.032560301666670011e+00 -9.105969999999999342e-02 4.256424763833329905e+01 1.812761751666670085e+00 -9.572880000000000278e-02 3.308233848333330229e+01 1.638201501666670001e+00 -1.004865999999999954e-01 2.810971494833329842e+01 1.433384486666670066e+00 -1.052305999999999936e-01 2.588485028666670118e+01 1.331128581666670030e+00 -1.099790999999999963e-01 2.266535039333329848e+01 1.188278135000000013e+00 -1.148321999999999954e-01 2.068870146000000076e+01 1.081535063333330049e+00 -1.197666000000000008e-01 1.976825064833330003e+01 1.002416109999999971e+00 -1.247589999999999949e-01 1.708519936000000072e+01 9.212166283333329542e-01 -1.298257999999999912e-01 1.961539944500000132e+01 8.615532866666669731e-01 -1.348960999999999910e-01 1.509279464499999968e+01 8.002327049999999886e-01 -1.399122999999999895e-01 1.461401991333329953e+01 7.302237983333329518e-01 -1.450607999999999898e-01 1.234817605166669985e+01 6.862621599999999544e-01 -1.502527999999999919e-01 1.236984282499999921e+01 6.604921383333329787e-01 -1.555927000000000004e-01 1.196552256666669933e+01 5.966093183333329719e-01 -1.572660999999999920e-01 1.278021405166670021e+01 1.919547649999999994e-01 -1.609331999999999985e-01 1.153752966666669977e+01 5.736198133333330063e-01 -1.661730999999999903e-01 1.078861117833329963e+01 5.440816866666670082e-01 -1.706513000000000058e-01 1.087118622666669943e+01 1.601861350000000073e-01 -1.715465999999999935e-01 9.877732214999999982e+00 5.101304616666669789e-01 -1.771117000000000108e-01 1.016148657499999963e+01 4.860413033333330080e-01 -1.827158000000000115e-01 1.012859923499999937e+01 4.659961616666670192e-01 -1.842668000000000084e-01 9.892309961666670759e+00 1.394281016666669981e-01 -1.883010999999999990e-01 9.370592901666670471e+00 4.483600366666670167e-01 -1.939626999999999879e-01 7.953713988333330320e+00 4.220674716666670268e-01 -1.982673000000000074e-01 8.536490116666669792e+00 1.198682733333329975e-01 -1.997490000000000099e-01 8.016174306666670191e+00 3.972042266666669930e-01 -2.055633000000000044e-01 7.936747634999999690e+00 3.864501066666670148e-01 -2.114472000000000018e-01 7.092097319999999705e+00 3.613801233333330254e-01 -2.120387999999999995e-01 7.719984431666669700e+00 1.093860133333330042e-01 -2.161715999999999915e-01 7.279911723333330364e+00 4.614210216666669861e-01 -2.260118000000000127e-01 6.899103116666670310e+00 9.616077666666669743e-02 -2.398155999999999899e-01 6.131303501666669931e+00 8.927448999999999801e-02 -2.537425999999999848e-01 5.657937448333330011e+00 8.168489666666670090e-02 -2.676623000000000197e-01 5.142021448333330191e+00 7.478100833333330144e-02 -2.818223999999999729e-01 4.914665098333330207e+00 7.002304500000000598e-02 -2.956782000000000021e-01 4.446721935000000236e+00 6.572301166666670580e-02 -3.099446000000000145e-01 4.282954679999999570e+00 6.061547666666670248e-02 -3.241067000000000253e-01 3.767117071666670203e+00 5.800978500000000121e-02 -3.388467000000000007e-01 3.499952983333329826e+00 5.180699999999999888e-02 -3.539599999999999969e-01 3.303444670000000194e+00 5.069738166666670071e-02 -3.687568999999999986e-01 2.950319708333330126e+00 4.620904333333329672e-02 -3.840311000000000141e-01 2.864367984999999894e+00 4.422433499999999656e-02 -3.989493000000000067e-01 2.552979848333329915e+00 4.244176999999999672e-02 -4.107629999999999892e-01 2.431688859833330163e+00 4.295243233333329719e-02 -4.137051999999999952e-01 2.340746346666669808e+00 4.009275166666669693e-02 -4.291185000000000138e-01 2.236674611666670032e+00 3.708904500000000104e-02 -4.296455000000000135e-01 2.145105044333329936e+00 3.592934700000000037e-02 -4.446591999999999767e-01 1.951663006666670030e+00 3.589577499999999782e-02 -4.467690999999999746e-01 1.941018092166669984e+00 3.204738566666669869e-02 -4.603923999999999794e-01 1.841567858333329921e+00 3.340552499999999841e-02 -4.686460000000000070e-01 1.795296687500000044e+00 3.165418133333330192e-02 -4.765479000000000243e-01 1.725552725000000009e+00 3.166947999999999985e-02 -4.835137999999999936e-01 1.648896234833330032e+00 3.002704050000000111e-02 -4.923843999999999999e-01 1.592235150000000043e+00 3.142748499999999806e-02 -5.047722000000000042e-01 1.524318554666669989e+00 2.765916716666669967e-02 -5.083368000000000331e-01 1.470192684999999999e+00 2.879683666666670028e-02 -5.231871000000000160e-01 1.276008043333330066e+00 2.578494833333330044e-02 -5.249844000000000177e-01 1.335736669999999959e+00 2.682150333333329847e-02 -5.417480000000000073e-01 1.255200871666670048e+00 2.659473333333330081e-02 -5.445189000000000279e-01 1.181751707666669926e+00 2.602010650000000092e-02 -5.583793000000000228e-01 1.119981195000000040e+00 2.552491833333329907e-02 -5.613839000000000468e-01 1.109540133333329903e+00 2.376074416666670158e-02 -5.754704000000000486e-01 1.035568078333330089e+00 2.359670999999999991e-02 -5.835346000000000144e-01 1.009673415166669974e+00 2.350527950000000019e-02 -5.928168000000000326e-01 9.958746566666669686e-01 2.289775833333329916e-02 -6.007057000000000091e-01 9.162153768333329840e-01 2.224946400000000005e-02 -6.099849999999999994e-01 8.912180400000000446e-01 2.207391333333329902e-02 -6.219902999999999960e-01 8.127960751666669648e-01 2.151158183333330004e-02 -6.275817000000000201e-01 8.004247816666669735e-01 2.072389499999999912e-02 -6.413482000000000349e-01 7.426332359999999744e-01 1.925514349999999861e-02 -6.447992000000000168e-01 7.076525866666669717e-01 2.108122000000000121e-02 -6.656950000000000367e-01 6.442563610000000551e-01 1.837696600000000152e-02 -6.845196000000000058e-01 6.085390748333330269e-01 2.050695833333330068e-02 -7.059646000000000532e-01 5.280073378333329792e-01 1.732566899999999840e-02 -7.260278000000000009e-01 5.220653703333330009e-01 1.859470200000000115e-02 -7.492113999999999718e-01 4.598426163333330097e-01 1.525465250000000023e-02 -7.721772000000000080e-01 4.332637708333330062e-01 1.732895283333329983e-02 -7.922717999999999705e-01 4.105990393333330268e-01 1.523655316666669944e-02 -8.156877999999999629e-01 3.602943534999999975e-01 1.545041316666669919e-02 -8.366301000000000432e-01 3.406887861666669792e-01 1.473824349999999957e-02 -8.621258000000000532e-01 3.067601776666670221e-01 1.382606316666670082e-02 -8.848333999999999921e-01 3.015524316666670090e-01 1.454982116666670051e-02 -9.083444000000000518e-01 2.607474308333330160e-01 1.270642616666669937e-02 -9.336484000000000449e-01 2.588003018333330241e-01 1.373286349999999940e-02 -9.553916000000000075e-01 2.226530176666670080e-01 1.285228899999999938e-02 -9.815112999999999754e-01 2.127235584999999929e-01 1.205009299999999957e-02 -1.007027499999999964e+00 2.082924603333330127e-01 1.250585733333330063e-02 -1.030631400000000086e+00 1.912464838333330086e-01 1.185822249999999960e-02 -1.058015099999999986e+00 1.948314409999999941e-01 1.101004149999999966e-02 -1.084837700000000016e+00 1.896849941666670092e-01 1.137308499999999979e-02 -1.110144500000000090e+00 1.497566153333330097e-01 1.094208966666669960e-02 -1.137999800000000006e+00 1.454676966666670068e-01 1.051448583333330043e-02 +3.623980000000000257e-02 4.717095203250000282e+02 1.736400694499999986e+01 +4.068580000000000113e-02 2.786014172683330230e+02 1.198827076999999974e+01 +4.509610000000000007e-02 1.807710803516669955e+02 8.834240069999999889e+00 +4.957530000000000270e-02 1.404167299050000111e+02 7.187393765000000379e+00 +5.414490000000000275e-02 1.070548824566670021e+02 5.660295944999999662e+00 +5.866960000000000230e-02 9.429733434666670178e+01 4.914365443333330141e+00 +6.313130000000000130e-02 8.753748113499999306e+01 4.086659178333330367e+00 +6.771190000000000542e-02 8.007891920833330346e+01 3.441741584999999937e+00 +7.236470000000000402e-02 5.999202779333329971e+01 2.970499293333329849e+00 +7.691660000000000164e-02 5.902839900166669906e+01 2.678938321666669786e+00 +8.163760000000000461e-02 4.960764509333330352e+01 2.245417474999999996e+00 +8.638719999999999732e-02 4.414010876166670272e+01 2.032560301666670011e+00 +9.105969999999999342e-02 4.256424763833329905e+01 1.812761751666670085e+00 +9.572880000000000278e-02 3.308233848333330229e+01 1.638201501666670001e+00 +1.004865999999999954e-01 2.810971494833329842e+01 1.433384486666670066e+00 +1.052305999999999936e-01 2.588485028666670118e+01 1.331128581666670030e+00 +1.099790999999999963e-01 2.266535039333329848e+01 1.188278135000000013e+00 +1.148321999999999954e-01 2.068870146000000076e+01 1.081535063333330049e+00 +1.197666000000000008e-01 1.976825064833330003e+01 1.002416109999999971e+00 +1.247589999999999949e-01 1.708519936000000072e+01 9.212166283333329542e-01 +1.298257999999999912e-01 1.961539944500000132e+01 8.615532866666669731e-01 +1.348960999999999910e-01 1.509279464499999968e+01 8.002327049999999886e-01 +1.399122999999999895e-01 1.461401991333329953e+01 7.302237983333329518e-01 +1.450607999999999898e-01 1.234817605166669985e+01 6.862621599999999544e-01 +1.502527999999999919e-01 1.236984282499999921e+01 6.604921383333329787e-01 +1.555927000000000004e-01 1.196552256666669933e+01 5.966093183333329719e-01 +1.572660999999999920e-01 1.278021405166670021e+01 1.919547649999999994e-01 +1.609331999999999985e-01 1.153752966666669977e+01 5.736198133333330063e-01 +1.661730999999999903e-01 1.078861117833329963e+01 5.440816866666670082e-01 +1.706513000000000058e-01 1.087118622666669943e+01 1.601861350000000073e-01 +1.715465999999999935e-01 9.877732214999999982e+00 5.101304616666669789e-01 +1.771117000000000108e-01 1.016148657499999963e+01 4.860413033333330080e-01 +1.827158000000000115e-01 1.012859923499999937e+01 4.659961616666670192e-01 +1.842668000000000084e-01 9.892309961666670759e+00 1.394281016666669981e-01 +1.883010999999999990e-01 9.370592901666670471e+00 4.483600366666670167e-01 +1.939626999999999879e-01 7.953713988333330320e+00 4.220674716666670268e-01 +1.982673000000000074e-01 8.536490116666669792e+00 1.198682733333329975e-01 +1.997490000000000099e-01 8.016174306666670191e+00 3.972042266666669930e-01 +2.055633000000000044e-01 7.936747634999999690e+00 3.864501066666670148e-01 +2.114472000000000018e-01 7.092097319999999705e+00 3.613801233333330254e-01 +2.120387999999999995e-01 7.719984431666669700e+00 1.093860133333330042e-01 +2.161715999999999915e-01 7.279911723333330364e+00 4.614210216666669861e-01 +2.260118000000000127e-01 6.899103116666670310e+00 9.616077666666669743e-02 +2.398155999999999899e-01 6.131303501666669931e+00 8.927448999999999801e-02 +2.537425999999999848e-01 5.657937448333330011e+00 8.168489666666670090e-02 +2.676623000000000197e-01 5.142021448333330191e+00 7.478100833333330144e-02 +2.818223999999999729e-01 4.914665098333330207e+00 7.002304500000000598e-02 +2.956782000000000021e-01 4.446721935000000236e+00 6.572301166666670580e-02 +3.099446000000000145e-01 4.282954679999999570e+00 6.061547666666670248e-02 +3.241067000000000253e-01 3.767117071666670203e+00 5.800978500000000121e-02 +3.388467000000000007e-01 3.499952983333329826e+00 5.180699999999999888e-02 +3.539599999999999969e-01 3.303444670000000194e+00 5.069738166666670071e-02 +3.687568999999999986e-01 2.950319708333330126e+00 4.620904333333329672e-02 +3.840311000000000141e-01 2.864367984999999894e+00 4.422433499999999656e-02 +3.989493000000000067e-01 2.552979848333329915e+00 4.244176999999999672e-02 +4.107629999999999892e-01 2.431688859833330163e+00 4.295243233333329719e-02 +4.137051999999999952e-01 2.340746346666669808e+00 4.009275166666669693e-02 +4.291185000000000138e-01 2.236674611666670032e+00 3.708904500000000104e-02 +4.296455000000000135e-01 2.145105044333329936e+00 3.592934700000000037e-02 +4.446591999999999767e-01 1.951663006666670030e+00 3.589577499999999782e-02 +4.467690999999999746e-01 1.941018092166669984e+00 3.204738566666669869e-02 +4.603923999999999794e-01 1.841567858333329921e+00 3.340552499999999841e-02 +4.686460000000000070e-01 1.795296687500000044e+00 3.165418133333330192e-02 +4.765479000000000243e-01 1.725552725000000009e+00 3.166947999999999985e-02 +4.835137999999999936e-01 1.648896234833330032e+00 3.002704050000000111e-02 +4.923843999999999999e-01 1.592235150000000043e+00 3.142748499999999806e-02 +5.047722000000000042e-01 1.524318554666669989e+00 2.765916716666669967e-02 +5.083368000000000331e-01 1.470192684999999999e+00 2.879683666666670028e-02 +5.231871000000000160e-01 1.276008043333330066e+00 2.578494833333330044e-02 +5.249844000000000177e-01 1.335736669999999959e+00 2.682150333333329847e-02 +5.417480000000000073e-01 1.255200871666670048e+00 2.659473333333330081e-02 +5.445189000000000279e-01 1.181751707666669926e+00 2.602010650000000092e-02 +5.583793000000000228e-01 1.119981195000000040e+00 2.552491833333329907e-02 +5.613839000000000468e-01 1.109540133333329903e+00 2.376074416666670158e-02 +5.754704000000000486e-01 1.035568078333330089e+00 2.359670999999999991e-02 +5.835346000000000144e-01 1.009673415166669974e+00 2.350527950000000019e-02 +5.928168000000000326e-01 9.958746566666669686e-01 2.289775833333329916e-02 +6.007057000000000091e-01 9.162153768333329840e-01 2.224946400000000005e-02 +6.099849999999999994e-01 8.912180400000000446e-01 2.207391333333329902e-02 +6.219902999999999960e-01 8.127960751666669648e-01 2.151158183333330004e-02 +6.275817000000000201e-01 8.004247816666669735e-01 2.072389499999999912e-02 +6.413482000000000349e-01 7.426332359999999744e-01 1.925514349999999861e-02 +6.447992000000000168e-01 7.076525866666669717e-01 2.108122000000000121e-02 +6.656950000000000367e-01 6.442563610000000551e-01 1.837696600000000152e-02 +6.845196000000000058e-01 6.085390748333330269e-01 2.050695833333330068e-02 +7.059646000000000532e-01 5.280073378333329792e-01 1.732566899999999840e-02 +7.260278000000000009e-01 5.220653703333330009e-01 1.859470200000000115e-02 +7.492113999999999718e-01 4.598426163333330097e-01 1.525465250000000023e-02 +7.721772000000000080e-01 4.332637708333330062e-01 1.732895283333329983e-02 +7.922717999999999705e-01 4.105990393333330268e-01 1.523655316666669944e-02 +8.156877999999999629e-01 3.602943534999999975e-01 1.545041316666669919e-02 +8.366301000000000432e-01 3.406887861666669792e-01 1.473824349999999957e-02 +8.621258000000000532e-01 3.067601776666670221e-01 1.382606316666670082e-02 +8.848333999999999921e-01 3.015524316666670090e-01 1.454982116666670051e-02 +9.083444000000000518e-01 2.607474308333330160e-01 1.270642616666669937e-02 +9.336484000000000449e-01 2.588003018333330241e-01 1.373286349999999940e-02 +9.553916000000000075e-01 2.226530176666670080e-01 1.285228899999999938e-02 +9.815112999999999754e-01 2.127235584999999929e-01 1.205009299999999957e-02 +1.007027499999999964e+00 2.082924603333330127e-01 1.250585733333330063e-02 +1.030631400000000086e+00 1.912464838333330086e-01 1.185822249999999960e-02 +1.058015099999999986e+00 1.948314409999999941e-01 1.101004149999999966e-02 +1.084837700000000016e+00 1.896849941666670092e-01 1.137308499999999979e-02 +1.110144500000000090e+00 1.497566153333330097e-01 1.094208966666669960e-02 +1.137999800000000006e+00 1.454676966666670068e-01 1.051448583333330043e-02 1.166290800000000072e+00 1.467227160000000030e-01 1.029956333333329963e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv index 98341d530..5ef6a3266 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/3_35_1340_10.csv @@ -1,105 +1,105 @@ -3.625239999999999713e-02 2.531792558183329902e+02 1.680830338499999854e+01 -4.070000000000000007e-02 1.901177223299999923e+02 1.173664666500000031e+01 -4.511180000000000051e-02 1.217924648083329942e+02 8.645296186666669769e+00 -4.959249999999999770e-02 1.094275780066670052e+02 7.073034475000000043e+00 -5.416379999999999806e-02 8.791320813333329909e+01 5.581711248333330211e+00 -5.868999999999999911e-02 8.309104453833330695e+01 4.860535583333329690e+00 -6.315320000000000655e-02 7.081360745666670198e+01 4.003961999999999577e+00 -6.773540000000000116e-02 6.343291181166669901e+01 3.355398363333330192e+00 -7.238989999999999314e-02 4.842191466166669755e+01 2.903796691666669982e+00 -7.694339999999999513e-02 4.694420552666669977e+01 2.605583116666669863e+00 -8.166600000000000248e-02 4.367521950333330238e+01 2.207077676666670207e+00 -8.641719999999999957e-02 3.957930205499999943e+01 1.999356729999999915e+00 -9.109140000000000292e-02 3.553857484166670133e+01 1.762052579999999979e+00 -9.576210000000000278e-02 2.783675838666669833e+01 1.597004463333330015e+00 -1.005216000000000026e-01 2.705964543666669897e+01 1.423240978333329965e+00 -1.052672000000000052e-01 2.262947438833329983e+01 1.302317253333330038e+00 -1.100174000000000013e-01 2.182584247666670052e+01 1.179366926666669979e+00 -1.148721999999999938e-01 2.121788853500000016e+01 1.084366495000000041e+00 -1.198083000000000065e-01 1.779511935000000022e+01 9.833421683333329888e-01 -1.248023999999999939e-01 1.651748253666670152e+01 9.145048883333329881e-01 -1.298709000000000113e-01 1.721928703000000027e+01 8.380137100000000228e-01 -1.349431000000000103e-01 1.436323046666669967e+01 7.917284633333330213e-01 -1.399610000000000021e-01 1.550343697666670018e+01 7.379972516666669646e-01 -1.451112999999999986e-01 1.303663926666670037e+01 6.920347900000000108e-01 -1.503050999999999970e-01 1.200503839166669984e+01 6.556345366666670449e-01 -1.556469000000000047e-01 1.229304255666670009e+01 5.989305183333329952e-01 -1.573070000000000024e-01 1.257057899666670053e+01 1.910309249999999903e-01 -1.609891999999999990e-01 1.193592632666669928e+01 5.769697900000000379e-01 -1.662309999999999899e-01 1.125234698666669964e+01 5.482133000000000145e-01 -1.706957000000000058e-01 1.058112505166669948e+01 1.590339783333329926e-01 -1.716062999999999894e-01 1.070644689999999954e+01 5.183003699999999547e-01 -1.771733000000000058e-01 9.479454351666669609e+00 4.778282466666670114e-01 -1.827794000000000085e-01 9.400985496666670826e+00 4.569814249999999967e-01 -1.843146999999999980e-01 9.549487438333329692e+00 1.380682866666670117e-01 -1.883665999999999952e-01 8.342261173333330504e+00 4.359566316666669827e-01 -1.940302000000000138e-01 8.124126898333329905e+00 4.232381216666670221e-01 -1.983187999999999895e-01 8.328415036666669380e+00 1.189532799999999946e-01 -1.998185000000000100e-01 8.328210934999999537e+00 3.999954083333330246e-01 -2.056348000000000065e-01 8.350671104999999983e+00 3.905236483333329733e-01 -2.115208000000000088e-01 6.929636241666670138e+00 3.588886250000000167e-01 -2.120939000000000019e-01 7.535892504999999630e+00 1.085254183333329986e-01 -2.162467999999999890e-01 7.407988318333329936e+00 4.625349066666670228e-01 -2.260705000000000076e-01 6.743451298333329902e+00 9.541167166666669752e-02 -2.398779000000000050e-01 6.099490819999999758e+00 8.899463999999999986e-02 -2.538084999999999924e-01 5.555039073333330357e+00 8.113394833333330280e-02 -2.677318000000000198e-01 5.152730110000000252e+00 7.469547999999999466e-02 -2.818956000000000239e-01 4.837557096666669665e+00 6.957829666666670576e-02 -2.957549999999999901e-01 4.369791838333330070e+00 6.527595833333330044e-02 -3.100250999999999979e-01 4.110463069999999774e+00 5.977720166666670304e-02 -3.241909000000000041e-01 3.813721606666669928e+00 5.811357666666670113e-02 -3.389346999999999777e-01 3.461479851666669827e+00 5.155417166666669687e-02 -3.540519999999999778e-01 3.230298750000000219e+00 5.028755499999999767e-02 -3.688526999999999778e-01 2.998165658333329819e+00 4.634052999999999783e-02 -3.841308999999999974e-01 2.784144708333330165e+00 4.378963833333329725e-02 -3.990528999999999882e-01 2.595613363333329815e+00 4.256657166666669850e-02 -4.108341999999999827e-01 2.335089765499999803e+00 4.258898366666669794e-02 -4.138126999999999778e-01 2.324415418333329875e+00 3.994880166666670007e-02 -4.292300000000000004e-01 2.216248561666669836e+00 3.693022666666669757e-02 -4.297198999999999880e-01 2.134554158666670087e+00 3.596130699999999791e-02 -4.447747000000000228e-01 1.890609146666669904e+00 3.555346833333330320e-02 -4.468464999999999798e-01 1.908117816499999897e+00 3.198120466666670020e-02 -4.605119999999999769e-01 1.871098863333330087e+00 3.348654166666670262e-02 -4.687272000000000105e-01 1.810652348333330108e+00 3.178039216666669886e-02 -4.766716999999999760e-01 1.698277889999999957e+00 3.148857166666670093e-02 -4.835976000000000163e-01 1.613169754500000108e+00 2.993151466666670035e-02 -4.925123000000000140e-01 1.548358499999999971e+00 3.116390166666669834e-02 -5.048597000000000223e-01 1.494630669833330039e+00 2.759253283333330115e-02 -5.084689000000000014e-01 1.491590500000000041e+00 2.885127333333329866e-02 -5.232776999999999568e-01 1.248566430833329965e+00 2.572220416666669979e-02 -5.251208000000000542e-01 1.383180581666670017e+00 2.700447666666670049e-02 -5.418887000000000009e-01 1.221960488333329931e+00 2.639246833333330072e-02 -5.446132999999999669e-01 1.208971178333329899e+00 2.618446533333329898e-02 -5.585244000000000320e-01 1.107120358333330001e+00 2.542247833333330029e-02 -5.614812000000000136e-01 1.085889866500000078e+00 2.370511449999999909e-02 -5.756198999999999621e-01 1.024119451666670066e+00 2.350574000000000066e-02 -5.836356999999999795e-01 9.666399098333330331e-01 2.336446566666669847e-02 -5.929708999999999675e-01 9.753983600000000198e-01 2.276144833333329856e-02 -6.008097999999999494e-01 8.857038164999999630e-01 2.215761016666669900e-02 -6.101434999999999498e-01 9.144217283333330171e-01 2.215592499999999992e-02 -6.220980999999999872e-01 8.054969749999999484e-01 2.151697083333330152e-02 -6.277447999999999917e-01 7.972735800000000372e-01 2.067797666666670170e-02 -6.414592999999999545e-01 7.033510668333330385e-01 1.912904316666669963e-02 -6.449667999999999513e-01 7.010848466666670387e-01 2.101707333333329916e-02 -6.658104000000000244e-01 6.363828563333330246e-01 1.837497983333330129e-02 -6.846381999999999746e-01 5.758642446666669690e-01 2.039069533333329881e-02 -7.060868999999999618e-01 5.109788090000000338e-01 1.728495966666670006e-02 -7.261535999999999547e-01 4.885223020000000194e-01 1.847847583333329935e-02 -7.493412999999999879e-01 4.387949984999999775e-01 1.519840233333329994e-02 -7.723109999999999697e-01 3.923397161666670185e-01 1.717436333333329998e-02 -7.924090999999999774e-01 3.993512075000000272e-01 1.521433699999999965e-02 -8.158290999999999737e-01 3.564691013333329828e-01 1.545670316666669999e-02 -8.367750000000000465e-01 3.230009236666669947e-01 1.469029500000000078e-02 -8.622752000000000194e-01 2.878051181666669844e-01 1.377513966666669976e-02 -8.849867000000000150e-01 2.848005155000000177e-01 1.450056933333329981e-02 -9.085018000000000260e-01 2.630901753333330095e-01 1.273161166666669959e-02 -9.338100999999999763e-01 2.556641304999999753e-01 1.373873700000000087e-02 -9.555571000000000481e-01 2.110106781666669928e-01 1.282516266666670034e-02 -9.816814000000000373e-01 1.989191335000000116e-01 1.201689483333330012e-02 -1.007201999999999931e+00 1.798726026666669919e-01 1.241756500000000020e-02 -1.030810000000000004e+00 1.697684260000000001e-01 1.179553216666670047e-02 -1.058198500000000042e+00 1.911874938333329998e-01 1.101163099999999916e-02 -1.085025700000000093e+00 1.546144220000000014e-01 1.126302133333329999e-02 -1.110336800000000013e+00 1.274498698333330071e-01 1.087918116666669946e-02 -1.138196999999999903e+00 1.312019681666669879e-01 1.048030450000000079e-02 +3.625239999999999713e-02 2.531792558183329902e+02 1.680830338499999854e+01 +4.070000000000000007e-02 1.901177223299999923e+02 1.173664666500000031e+01 +4.511180000000000051e-02 1.217924648083329942e+02 8.645296186666669769e+00 +4.959249999999999770e-02 1.094275780066670052e+02 7.073034475000000043e+00 +5.416379999999999806e-02 8.791320813333329909e+01 5.581711248333330211e+00 +5.868999999999999911e-02 8.309104453833330695e+01 4.860535583333329690e+00 +6.315320000000000655e-02 7.081360745666670198e+01 4.003961999999999577e+00 +6.773540000000000116e-02 6.343291181166669901e+01 3.355398363333330192e+00 +7.238989999999999314e-02 4.842191466166669755e+01 2.903796691666669982e+00 +7.694339999999999513e-02 4.694420552666669977e+01 2.605583116666669863e+00 +8.166600000000000248e-02 4.367521950333330238e+01 2.207077676666670207e+00 +8.641719999999999957e-02 3.957930205499999943e+01 1.999356729999999915e+00 +9.109140000000000292e-02 3.553857484166670133e+01 1.762052579999999979e+00 +9.576210000000000278e-02 2.783675838666669833e+01 1.597004463333330015e+00 +1.005216000000000026e-01 2.705964543666669897e+01 1.423240978333329965e+00 +1.052672000000000052e-01 2.262947438833329983e+01 1.302317253333330038e+00 +1.100174000000000013e-01 2.182584247666670052e+01 1.179366926666669979e+00 +1.148721999999999938e-01 2.121788853500000016e+01 1.084366495000000041e+00 +1.198083000000000065e-01 1.779511935000000022e+01 9.833421683333329888e-01 +1.248023999999999939e-01 1.651748253666670152e+01 9.145048883333329881e-01 +1.298709000000000113e-01 1.721928703000000027e+01 8.380137100000000228e-01 +1.349431000000000103e-01 1.436323046666669967e+01 7.917284633333330213e-01 +1.399610000000000021e-01 1.550343697666670018e+01 7.379972516666669646e-01 +1.451112999999999986e-01 1.303663926666670037e+01 6.920347900000000108e-01 +1.503050999999999970e-01 1.200503839166669984e+01 6.556345366666670449e-01 +1.556469000000000047e-01 1.229304255666670009e+01 5.989305183333329952e-01 +1.573070000000000024e-01 1.257057899666670053e+01 1.910309249999999903e-01 +1.609891999999999990e-01 1.193592632666669928e+01 5.769697900000000379e-01 +1.662309999999999899e-01 1.125234698666669964e+01 5.482133000000000145e-01 +1.706957000000000058e-01 1.058112505166669948e+01 1.590339783333329926e-01 +1.716062999999999894e-01 1.070644689999999954e+01 5.183003699999999547e-01 +1.771733000000000058e-01 9.479454351666669609e+00 4.778282466666670114e-01 +1.827794000000000085e-01 9.400985496666670826e+00 4.569814249999999967e-01 +1.843146999999999980e-01 9.549487438333329692e+00 1.380682866666670117e-01 +1.883665999999999952e-01 8.342261173333330504e+00 4.359566316666669827e-01 +1.940302000000000138e-01 8.124126898333329905e+00 4.232381216666670221e-01 +1.983187999999999895e-01 8.328415036666669380e+00 1.189532799999999946e-01 +1.998185000000000100e-01 8.328210934999999537e+00 3.999954083333330246e-01 +2.056348000000000065e-01 8.350671104999999983e+00 3.905236483333329733e-01 +2.115208000000000088e-01 6.929636241666670138e+00 3.588886250000000167e-01 +2.120939000000000019e-01 7.535892504999999630e+00 1.085254183333329986e-01 +2.162467999999999890e-01 7.407988318333329936e+00 4.625349066666670228e-01 +2.260705000000000076e-01 6.743451298333329902e+00 9.541167166666669752e-02 +2.398779000000000050e-01 6.099490819999999758e+00 8.899463999999999986e-02 +2.538084999999999924e-01 5.555039073333330357e+00 8.113394833333330280e-02 +2.677318000000000198e-01 5.152730110000000252e+00 7.469547999999999466e-02 +2.818956000000000239e-01 4.837557096666669665e+00 6.957829666666670576e-02 +2.957549999999999901e-01 4.369791838333330070e+00 6.527595833333330044e-02 +3.100250999999999979e-01 4.110463069999999774e+00 5.977720166666670304e-02 +3.241909000000000041e-01 3.813721606666669928e+00 5.811357666666670113e-02 +3.389346999999999777e-01 3.461479851666669827e+00 5.155417166666669687e-02 +3.540519999999999778e-01 3.230298750000000219e+00 5.028755499999999767e-02 +3.688526999999999778e-01 2.998165658333329819e+00 4.634052999999999783e-02 +3.841308999999999974e-01 2.784144708333330165e+00 4.378963833333329725e-02 +3.990528999999999882e-01 2.595613363333329815e+00 4.256657166666669850e-02 +4.108341999999999827e-01 2.335089765499999803e+00 4.258898366666669794e-02 +4.138126999999999778e-01 2.324415418333329875e+00 3.994880166666670007e-02 +4.292300000000000004e-01 2.216248561666669836e+00 3.693022666666669757e-02 +4.297198999999999880e-01 2.134554158666670087e+00 3.596130699999999791e-02 +4.447747000000000228e-01 1.890609146666669904e+00 3.555346833333330320e-02 +4.468464999999999798e-01 1.908117816499999897e+00 3.198120466666670020e-02 +4.605119999999999769e-01 1.871098863333330087e+00 3.348654166666670262e-02 +4.687272000000000105e-01 1.810652348333330108e+00 3.178039216666669886e-02 +4.766716999999999760e-01 1.698277889999999957e+00 3.148857166666670093e-02 +4.835976000000000163e-01 1.613169754500000108e+00 2.993151466666670035e-02 +4.925123000000000140e-01 1.548358499999999971e+00 3.116390166666669834e-02 +5.048597000000000223e-01 1.494630669833330039e+00 2.759253283333330115e-02 +5.084689000000000014e-01 1.491590500000000041e+00 2.885127333333329866e-02 +5.232776999999999568e-01 1.248566430833329965e+00 2.572220416666669979e-02 +5.251208000000000542e-01 1.383180581666670017e+00 2.700447666666670049e-02 +5.418887000000000009e-01 1.221960488333329931e+00 2.639246833333330072e-02 +5.446132999999999669e-01 1.208971178333329899e+00 2.618446533333329898e-02 +5.585244000000000320e-01 1.107120358333330001e+00 2.542247833333330029e-02 +5.614812000000000136e-01 1.085889866500000078e+00 2.370511449999999909e-02 +5.756198999999999621e-01 1.024119451666670066e+00 2.350574000000000066e-02 +5.836356999999999795e-01 9.666399098333330331e-01 2.336446566666669847e-02 +5.929708999999999675e-01 9.753983600000000198e-01 2.276144833333329856e-02 +6.008097999999999494e-01 8.857038164999999630e-01 2.215761016666669900e-02 +6.101434999999999498e-01 9.144217283333330171e-01 2.215592499999999992e-02 +6.220980999999999872e-01 8.054969749999999484e-01 2.151697083333330152e-02 +6.277447999999999917e-01 7.972735800000000372e-01 2.067797666666670170e-02 +6.414592999999999545e-01 7.033510668333330385e-01 1.912904316666669963e-02 +6.449667999999999513e-01 7.010848466666670387e-01 2.101707333333329916e-02 +6.658104000000000244e-01 6.363828563333330246e-01 1.837497983333330129e-02 +6.846381999999999746e-01 5.758642446666669690e-01 2.039069533333329881e-02 +7.060868999999999618e-01 5.109788090000000338e-01 1.728495966666670006e-02 +7.261535999999999547e-01 4.885223020000000194e-01 1.847847583333329935e-02 +7.493412999999999879e-01 4.387949984999999775e-01 1.519840233333329994e-02 +7.723109999999999697e-01 3.923397161666670185e-01 1.717436333333329998e-02 +7.924090999999999774e-01 3.993512075000000272e-01 1.521433699999999965e-02 +8.158290999999999737e-01 3.564691013333329828e-01 1.545670316666669999e-02 +8.367750000000000465e-01 3.230009236666669947e-01 1.469029500000000078e-02 +8.622752000000000194e-01 2.878051181666669844e-01 1.377513966666669976e-02 +8.849867000000000150e-01 2.848005155000000177e-01 1.450056933333329981e-02 +9.085018000000000260e-01 2.630901753333330095e-01 1.273161166666669959e-02 +9.338100999999999763e-01 2.556641304999999753e-01 1.373873700000000087e-02 +9.555571000000000481e-01 2.110106781666669928e-01 1.282516266666670034e-02 +9.816814000000000373e-01 1.989191335000000116e-01 1.201689483333330012e-02 +1.007201999999999931e+00 1.798726026666669919e-01 1.241756500000000020e-02 +1.030810000000000004e+00 1.697684260000000001e-01 1.179553216666670047e-02 +1.058198500000000042e+00 1.911874938333329998e-01 1.101163099999999916e-02 +1.085025700000000093e+00 1.546144220000000014e-01 1.126302133333329999e-02 +1.110336800000000013e+00 1.274498698333330071e-01 1.087918116666669946e-02 +1.138196999999999903e+00 1.312019681666669879e-01 1.048030450000000079e-02 1.166492899999999944e+00 1.202452754999999984e-01 1.022370933333329943e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv index 2dcce686f..51227d3b8 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/4_50_1340_10.csv @@ -1,105 +1,105 @@ -3.624299999999999744e-02 2.421839941750000094e+02 1.681259771499999900e+01 -4.068929999999999769e-02 1.253477160583330061e+02 1.158261931833330038e+01 -4.510000000000000120e-02 1.038159109083329952e+02 8.606540843333329249e+00 -4.957960000000000145e-02 9.508877155000000414e+01 7.037626288333330038e+00 -5.414959999999999912e-02 7.142443308833330207e+01 5.530319266666669620e+00 -5.867460000000000037e-02 6.747951957166669956e+01 4.803320423333330424e+00 -6.313670000000000393e-02 6.491403129500000091e+01 3.984481885000000112e+00 -6.771770000000000567e-02 5.688806046833330043e+01 3.329560004999999823e+00 -7.237100000000000477e-02 4.031379161166670144e+01 2.864987329999999943e+00 -7.692330000000000001e-02 4.363721252500000247e+01 2.591659659999999921e+00 -8.164470000000000061e-02 3.499940050499999700e+01 2.159604903333330217e+00 -8.639470000000000482e-02 3.331168452000000002e+01 1.961486934999999932e+00 -9.106759999999999855e-02 3.141853618500000067e+01 1.737193953333330043e+00 -9.573710000000000553e-02 2.514925802833329982e+01 1.580249494999999893e+00 -1.004952999999999957e-01 2.418445705499999931e+01 1.404480071666670105e+00 -1.052397000000000055e-01 2.311071394833329862e+01 1.309208076666670051e+00 -1.099886000000000058e-01 2.234431306333329914e+01 1.186371084999999992e+00 -1.148422000000000054e-01 2.015011891333330141e+01 1.077548355000000013e+00 -1.197769999999999946e-01 1.762490517499999854e+01 9.840672733333329925e-01 -1.247698000000000002e-01 1.703488854000000075e+01 9.213895800000000413e-01 -1.298370000000000080e-01 1.644401272166669870e+01 8.327218266666670532e-01 -1.349077999999999944e-01 1.614025673666670002e+01 8.110203433333329492e-01 -1.399244000000000043e-01 1.432045983666669997e+01 7.277294366666670067e-01 -1.450733999999999913e-01 1.348007003166670081e+01 6.981156733333330200e-01 -1.502658000000000049e-01 1.217057146500000009e+01 6.589065133333330548e-01 -1.556062000000000001e-01 1.311354035333330081e+01 6.087518283333329672e-01 -1.573412999999999895e-01 1.262766263333329952e+01 1.918068450000000036e-01 -1.609471000000000096e-01 1.195521582166669994e+01 5.786270049999999721e-01 -1.661874999999999880e-01 1.070419187999999977e+01 5.435432616666669992e-01 -1.707328999999999930e-01 1.060603477499999947e+01 1.596232366666670011e-01 -1.715615000000000057e-01 1.106375028666669991e+01 5.234683166666670440e-01 -1.771270000000000067e-01 9.097135046666670277e+00 4.748174949999999783e-01 -1.827315999999999940e-01 9.232441778333329907e+00 4.562185283333329844e-01 -1.843548999999999882e-01 9.582483613333330652e+00 1.386399050000000077e-01 -1.883173999999999959e-01 9.681451038333330317e+00 4.521609416666669823e-01 -1.939794999999999991e-01 8.227612430000000643e+00 4.254379616666669750e-01 -1.983621000000000134e-01 8.295318078333329126e+00 1.192443799999999970e-01 -1.997663000000000078e-01 8.131970284999999521e+00 3.988034016666670012e-01 -2.055810999999999888e-01 7.142658796666670362e+00 3.773835349999999922e-01 -2.114655000000000007e-01 7.164933761666669731e+00 3.624743966666669759e-01 -2.121402000000000010e-01 7.387669431666670228e+00 1.083523799999999981e-01 -2.161903000000000019e-01 6.864321103333329788e+00 4.553583783333329804e-01 -2.261198000000000097e-01 6.847039901666669870e+00 9.614554833333330275e-02 -2.399302000000000101e-01 6.151464958333329847e+00 8.952354166666670610e-02 -2.538638999999999757e-01 5.563245829999999614e+00 8.146051666666670465e-02 -2.677901999999999783e-01 5.162996156666669556e+00 7.501275500000000040e-02 -2.819571000000000160e-01 4.731078383333329640e+00 6.938886333333330048e-02 -2.958196000000000159e-01 4.470382223333330352e+00 6.595420000000000449e-02 -3.100928000000000018e-01 4.071269568333329758e+00 5.983178000000000107e-02 -3.242616999999999861e-01 3.818289136666670025e+00 5.835058500000000342e-02 -3.390086999999999962e-01 3.464278166666669989e+00 5.175618166666669934e-02 -3.541291999999999773e-01 3.297458013333330218e+00 5.076983000000000190e-02 -3.689332000000000167e-01 3.070901008333330129e+00 4.683460500000000137e-02 -3.842147000000000201e-01 2.769801061666670172e+00 4.388707166666670073e-02 -3.991399999999999948e-01 2.510583560000000158e+00 4.232430333333329908e-02 -4.106022999999999756e-01 2.374815773499999949e+00 4.286182233333329927e-02 -4.139030000000000209e-01 2.373871081666670158e+00 4.032223833333330176e-02 -4.293236999999999748e-01 2.231085370000000179e+00 3.713437166666670036e-02 -4.294773000000000063e-01 2.156539414333329852e+00 3.612328016666670194e-02 -4.448717999999999839e-01 1.876962131666670031e+00 3.561285166666670193e-02 -4.465942999999999996e-01 1.963582529333329996e+00 3.226501116666669750e-02 -4.606124999999999803e-01 1.886281606666670108e+00 3.367513833333329876e-02 -4.684626000000000068e-01 1.795604685000000034e+00 3.177854483333329705e-02 -4.767757000000000245e-01 1.729912848333329922e+00 3.174894833333329752e-02 -4.833245999999999931e-01 1.643333701666670033e+00 3.012282700000000132e-02 -4.926197999999999966e-01 1.601281793333330095e+00 3.152871666666669931e-02 -5.045747000000000426e-01 1.513868059666670041e+00 2.772222300000000070e-02 -5.085798000000000263e-01 1.480025179999999940e+00 2.889593166666670071e-02 -5.229823000000000111e-01 1.292098316666669966e+00 2.594417883333329997e-02 -5.252354000000000189e-01 1.389690103333329985e+00 2.712855999999999948e-02 -5.420070000000000165e-01 1.207626951666670001e+00 2.641061333333330138e-02 -5.443057999999999508e-01 1.171074812333330106e+00 2.606778300000000062e-02 -5.586463000000000401e-01 1.131968480000000055e+00 2.562754666666669859e-02 -5.611642999999999493e-01 1.119771183833329964e+00 2.388942000000000149e-02 -5.757455000000000211e-01 1.050324178333329916e+00 2.370775166666670014e-02 -5.833063000000000553e-01 9.890430198333329814e-01 2.349970633333330061e-02 -5.931003000000000247e-01 9.529422783333330038e-01 2.272385333333330065e-02 -6.004707000000000239e-01 9.087951714999999986e-01 2.229426183333330092e-02 -6.102765999999999469e-01 8.968441200000000224e-01 2.213925333333329956e-02 -6.217470000000000496e-01 8.116193323333330545e-01 2.157820200000000119e-02 -6.278818000000000454e-01 7.745292049999999984e-01 2.063141833333330052e-02 -6.410972000000000337e-01 7.304547335000000086e-01 1.926881999999999900e-02 -6.451074999999999449e-01 7.030634049999999746e-01 2.109099333333330079e-02 -6.654345000000000399e-01 6.451808323333330097e-01 1.843812350000000044e-02 -6.842517000000000182e-01 5.969281796666670026e-01 2.051784966666669874e-02 -7.056883000000000461e-01 4.875458616666670242e-01 1.721726566666669997e-02 -7.257436999999999916e-01 5.206052460000000215e-01 1.864389433333329960e-02 -7.489183000000000368e-01 4.716855048333329914e-01 1.534349166666670004e-02 -7.718749999999999778e-01 3.996116843333329949e-01 1.723059933333330115e-02 -7.919618000000000491e-01 3.949704010000000265e-01 1.521841983333330033e-02 -8.153685999999999989e-01 3.711572033333330189e-01 1.553813883333329988e-02 -8.363026999999999544e-01 3.373120053333329982e-01 1.476541233333330053e-02 -8.617884000000000100e-01 3.012111169999999727e-01 1.384248800000000001e-02 -8.844872000000000289e-01 3.093801609999999869e-01 1.462152149999999991e-02 -9.079890000000000461e-01 2.725293346666670113e-01 1.278188633333329945e-02 -9.332829999999999737e-01 2.562172424999999976e-01 1.375849099999999943e-02 -9.550178000000000278e-01 2.195073688333329942e-01 1.287299783333330054e-02 -9.811271999999999771e-01 1.993873673333330099e-01 1.203331399999999982e-02 -1.006633399999999900e+00 1.965978770000000042e-01 1.249421516666670076e-02 -1.030228200000000038e+00 1.888581198333330047e-01 1.187900783333330039e-02 -1.057601100000000072e+00 2.019180355000000093e-01 1.106158266666669963e-02 -1.084413199999999966e+00 1.710308969999999873e-01 1.133507299999999933e-02 -1.109710100000000033e+00 1.385269876666669897e-01 1.092970799999999978e-02 -1.137554500000000024e+00 1.323425321666669985e-01 1.049619949999999920e-02 +3.624299999999999744e-02 2.421839941750000094e+02 1.681259771499999900e+01 +4.068929999999999769e-02 1.253477160583330061e+02 1.158261931833330038e+01 +4.510000000000000120e-02 1.038159109083329952e+02 8.606540843333329249e+00 +4.957960000000000145e-02 9.508877155000000414e+01 7.037626288333330038e+00 +5.414959999999999912e-02 7.142443308833330207e+01 5.530319266666669620e+00 +5.867460000000000037e-02 6.747951957166669956e+01 4.803320423333330424e+00 +6.313670000000000393e-02 6.491403129500000091e+01 3.984481885000000112e+00 +6.771770000000000567e-02 5.688806046833330043e+01 3.329560004999999823e+00 +7.237100000000000477e-02 4.031379161166670144e+01 2.864987329999999943e+00 +7.692330000000000001e-02 4.363721252500000247e+01 2.591659659999999921e+00 +8.164470000000000061e-02 3.499940050499999700e+01 2.159604903333330217e+00 +8.639470000000000482e-02 3.331168452000000002e+01 1.961486934999999932e+00 +9.106759999999999855e-02 3.141853618500000067e+01 1.737193953333330043e+00 +9.573710000000000553e-02 2.514925802833329982e+01 1.580249494999999893e+00 +1.004952999999999957e-01 2.418445705499999931e+01 1.404480071666670105e+00 +1.052397000000000055e-01 2.311071394833329862e+01 1.309208076666670051e+00 +1.099886000000000058e-01 2.234431306333329914e+01 1.186371084999999992e+00 +1.148422000000000054e-01 2.015011891333330141e+01 1.077548355000000013e+00 +1.197769999999999946e-01 1.762490517499999854e+01 9.840672733333329925e-01 +1.247698000000000002e-01 1.703488854000000075e+01 9.213895800000000413e-01 +1.298370000000000080e-01 1.644401272166669870e+01 8.327218266666670532e-01 +1.349077999999999944e-01 1.614025673666670002e+01 8.110203433333329492e-01 +1.399244000000000043e-01 1.432045983666669997e+01 7.277294366666670067e-01 +1.450733999999999913e-01 1.348007003166670081e+01 6.981156733333330200e-01 +1.502658000000000049e-01 1.217057146500000009e+01 6.589065133333330548e-01 +1.556062000000000001e-01 1.311354035333330081e+01 6.087518283333329672e-01 +1.573412999999999895e-01 1.262766263333329952e+01 1.918068450000000036e-01 +1.609471000000000096e-01 1.195521582166669994e+01 5.786270049999999721e-01 +1.661874999999999880e-01 1.070419187999999977e+01 5.435432616666669992e-01 +1.707328999999999930e-01 1.060603477499999947e+01 1.596232366666670011e-01 +1.715615000000000057e-01 1.106375028666669991e+01 5.234683166666670440e-01 +1.771270000000000067e-01 9.097135046666670277e+00 4.748174949999999783e-01 +1.827315999999999940e-01 9.232441778333329907e+00 4.562185283333329844e-01 +1.843548999999999882e-01 9.582483613333330652e+00 1.386399050000000077e-01 +1.883173999999999959e-01 9.681451038333330317e+00 4.521609416666669823e-01 +1.939794999999999991e-01 8.227612430000000643e+00 4.254379616666669750e-01 +1.983621000000000134e-01 8.295318078333329126e+00 1.192443799999999970e-01 +1.997663000000000078e-01 8.131970284999999521e+00 3.988034016666670012e-01 +2.055810999999999888e-01 7.142658796666670362e+00 3.773835349999999922e-01 +2.114655000000000007e-01 7.164933761666669731e+00 3.624743966666669759e-01 +2.121402000000000010e-01 7.387669431666670228e+00 1.083523799999999981e-01 +2.161903000000000019e-01 6.864321103333329788e+00 4.553583783333329804e-01 +2.261198000000000097e-01 6.847039901666669870e+00 9.614554833333330275e-02 +2.399302000000000101e-01 6.151464958333329847e+00 8.952354166666670610e-02 +2.538638999999999757e-01 5.563245829999999614e+00 8.146051666666670465e-02 +2.677901999999999783e-01 5.162996156666669556e+00 7.501275500000000040e-02 +2.819571000000000160e-01 4.731078383333329640e+00 6.938886333333330048e-02 +2.958196000000000159e-01 4.470382223333330352e+00 6.595420000000000449e-02 +3.100928000000000018e-01 4.071269568333329758e+00 5.983178000000000107e-02 +3.242616999999999861e-01 3.818289136666670025e+00 5.835058500000000342e-02 +3.390086999999999962e-01 3.464278166666669989e+00 5.175618166666669934e-02 +3.541291999999999773e-01 3.297458013333330218e+00 5.076983000000000190e-02 +3.689332000000000167e-01 3.070901008333330129e+00 4.683460500000000137e-02 +3.842147000000000201e-01 2.769801061666670172e+00 4.388707166666670073e-02 +3.991399999999999948e-01 2.510583560000000158e+00 4.232430333333329908e-02 +4.106022999999999756e-01 2.374815773499999949e+00 4.286182233333329927e-02 +4.139030000000000209e-01 2.373871081666670158e+00 4.032223833333330176e-02 +4.293236999999999748e-01 2.231085370000000179e+00 3.713437166666670036e-02 +4.294773000000000063e-01 2.156539414333329852e+00 3.612328016666670194e-02 +4.448717999999999839e-01 1.876962131666670031e+00 3.561285166666670193e-02 +4.465942999999999996e-01 1.963582529333329996e+00 3.226501116666669750e-02 +4.606124999999999803e-01 1.886281606666670108e+00 3.367513833333329876e-02 +4.684626000000000068e-01 1.795604685000000034e+00 3.177854483333329705e-02 +4.767757000000000245e-01 1.729912848333329922e+00 3.174894833333329752e-02 +4.833245999999999931e-01 1.643333701666670033e+00 3.012282700000000132e-02 +4.926197999999999966e-01 1.601281793333330095e+00 3.152871666666669931e-02 +5.045747000000000426e-01 1.513868059666670041e+00 2.772222300000000070e-02 +5.085798000000000263e-01 1.480025179999999940e+00 2.889593166666670071e-02 +5.229823000000000111e-01 1.292098316666669966e+00 2.594417883333329997e-02 +5.252354000000000189e-01 1.389690103333329985e+00 2.712855999999999948e-02 +5.420070000000000165e-01 1.207626951666670001e+00 2.641061333333330138e-02 +5.443057999999999508e-01 1.171074812333330106e+00 2.606778300000000062e-02 +5.586463000000000401e-01 1.131968480000000055e+00 2.562754666666669859e-02 +5.611642999999999493e-01 1.119771183833329964e+00 2.388942000000000149e-02 +5.757455000000000211e-01 1.050324178333329916e+00 2.370775166666670014e-02 +5.833063000000000553e-01 9.890430198333329814e-01 2.349970633333330061e-02 +5.931003000000000247e-01 9.529422783333330038e-01 2.272385333333330065e-02 +6.004707000000000239e-01 9.087951714999999986e-01 2.229426183333330092e-02 +6.102765999999999469e-01 8.968441200000000224e-01 2.213925333333329956e-02 +6.217470000000000496e-01 8.116193323333330545e-01 2.157820200000000119e-02 +6.278818000000000454e-01 7.745292049999999984e-01 2.063141833333330052e-02 +6.410972000000000337e-01 7.304547335000000086e-01 1.926881999999999900e-02 +6.451074999999999449e-01 7.030634049999999746e-01 2.109099333333330079e-02 +6.654345000000000399e-01 6.451808323333330097e-01 1.843812350000000044e-02 +6.842517000000000182e-01 5.969281796666670026e-01 2.051784966666669874e-02 +7.056883000000000461e-01 4.875458616666670242e-01 1.721726566666669997e-02 +7.257436999999999916e-01 5.206052460000000215e-01 1.864389433333329960e-02 +7.489183000000000368e-01 4.716855048333329914e-01 1.534349166666670004e-02 +7.718749999999999778e-01 3.996116843333329949e-01 1.723059933333330115e-02 +7.919618000000000491e-01 3.949704010000000265e-01 1.521841983333330033e-02 +8.153685999999999989e-01 3.711572033333330189e-01 1.553813883333329988e-02 +8.363026999999999544e-01 3.373120053333329982e-01 1.476541233333330053e-02 +8.617884000000000100e-01 3.012111169999999727e-01 1.384248800000000001e-02 +8.844872000000000289e-01 3.093801609999999869e-01 1.462152149999999991e-02 +9.079890000000000461e-01 2.725293346666670113e-01 1.278188633333329945e-02 +9.332829999999999737e-01 2.562172424999999976e-01 1.375849099999999943e-02 +9.550178000000000278e-01 2.195073688333329942e-01 1.287299783333330054e-02 +9.811271999999999771e-01 1.993873673333330099e-01 1.203331399999999982e-02 +1.006633399999999900e+00 1.965978770000000042e-01 1.249421516666670076e-02 +1.030228200000000038e+00 1.888581198333330047e-01 1.187900783333330039e-02 +1.057601100000000072e+00 2.019180355000000093e-01 1.106158266666669963e-02 +1.084413199999999966e+00 1.710308969999999873e-01 1.133507299999999933e-02 +1.109710100000000033e+00 1.385269876666669897e-01 1.092970799999999978e-02 +1.137554500000000024e+00 1.323425321666669985e-01 1.049619949999999920e-02 1.165834400000000048e+00 1.352444690000000060e-01 1.028587266666670073e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv index 8ef596703..e4a5c8ff1 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/5_75_1340_10.csv @@ -1,105 +1,105 @@ -3.623830000000000107e-02 1.262534512933330006e+02 1.649893105666669868e+01 -4.068399999999999794e-02 1.096408472683330046e+02 1.152156481833329948e+01 -4.509420000000000095e-02 6.843298548666669490e+01 8.484508865000000455e+00 -4.957310000000000189e-02 5.337196919333329959e+01 6.882409771666670117e+00 -5.414259999999999906e-02 4.824018401499999698e+01 5.433445991666670416e+00 -5.866699999999999693e-02 4.665372951666670076e+01 4.705492196666670068e+00 -6.312850000000000406e-02 5.221271013999999866e+01 3.917987768333329957e+00 -6.770890000000000242e-02 4.827582027833329903e+01 3.280544881666669799e+00 -7.236159999999999815e-02 3.618855914666669804e+01 2.837183351666670017e+00 -7.691330000000000389e-02 3.079150051333330040e+01 2.510836073333329921e+00 -8.163410000000000111e-02 3.296728457500000076e+01 2.143401925000000041e+00 -8.638339999999999907e-02 3.069841431000000043e+01 1.940150145000000048e+00 -9.105580000000000618e-02 2.710592771666669876e+01 1.703459686666670025e+00 -9.572469999999999590e-02 2.329590637833329936e+01 1.563327263333329942e+00 -1.004822999999999966e-01 2.091072460333329985e+01 1.376591528333330094e+00 -1.052260000000000001e-01 1.912562908333330114e+01 1.273402691666670083e+00 -1.099742999999999971e-01 1.787115249333330169e+01 1.146192773333329917e+00 -1.148272999999999933e-01 1.794118791666669921e+01 1.055988855000000060e+00 -1.197614000000000040e-01 1.653599519333329937e+01 9.723875616666669552e-01 -1.247536000000000062e-01 1.582743532666670028e+01 9.084356083333330334e-01 -1.298200999999999938e-01 1.478155951166669979e+01 8.152435350000000192e-01 -1.348902999999999908e-01 1.334408521333329922e+01 7.818770066666670404e-01 -1.399062000000000083e-01 1.377281605666670039e+01 7.205883533333330426e-01 -1.450545000000000029e-01 1.181691977333330001e+01 6.799812333333330461e-01 -1.502462999999999993e-01 1.213584320000000005e+01 6.572146300000000219e-01 -1.555860000000000021e-01 1.192358865166669979e+01 5.953690533333330093e-01 -1.572933999999999999e-01 1.181612013833330010e+01 1.889312700000000123e-01 -1.609261999999999915e-01 1.175466066000000076e+01 5.752044899999999572e-01 -1.661659000000000053e-01 1.042143580833329963e+01 5.392668716666669804e-01 -1.706808999999999965e-01 1.011778497999999971e+01 1.577585016666669948e-01 -1.715392000000000028e-01 9.758357795000000223e+00 5.081139666666669719e-01 -1.771040000000000114e-01 8.903400566666670457e+00 4.716962699999999731e-01 -1.827079000000000064e-01 9.178007346666669619e+00 4.546196783333329994e-01 -1.842987000000000097e-01 9.009516103333330861e+00 1.364224366666670074e-01 -1.882929000000000130e-01 8.406366826666669567e+00 4.368516150000000264e-01 -1.939542999999999962e-01 7.892936534999999587e+00 4.208100816666670019e-01 -1.983015999999999945e-01 7.968528981666669786e+00 1.178380566666669960e-01 -1.997403000000000095e-01 7.734987613333330181e+00 3.934730833333329736e-01 -2.055543999999999982e-01 7.979108915000000302e+00 3.863922049999999886e-01 -2.114380999999999899e-01 6.834691483333330098e+00 3.579354766666669740e-01 -2.120755000000000001e-01 7.473622876666669690e+00 1.084324933333330049e-01 -2.161621999999999988e-01 6.843431601666670083e+00 4.540542233333330069e-01 -2.260508999999999991e-01 6.624537448333329692e+00 9.508442500000000019e-02 -2.398570999999999898e-01 6.030806045000000282e+00 8.883706333333329930e-02 -2.537865999999999733e-01 5.548485336666669987e+00 8.121552666666670417e-02 -2.677086000000000188e-01 5.056279183333329819e+00 7.439664999999999473e-02 -2.818711999999999884e-01 4.746517688333329765e+00 6.929181333333329917e-02 -2.957293999999999756e-01 4.360488485000000303e+00 6.532353000000000465e-02 -3.099983000000000044e-01 4.042259101666670240e+00 5.956615500000000257e-02 -3.241628999999999761e-01 3.667612291666670021e+00 5.754424666666670130e-02 -3.389054000000000233e-01 3.392261260000000167e+00 5.132888666666669819e-02 -3.540212999999999832e-01 3.153369070000000107e+00 5.001504333333330055e-02 -3.688208000000000042e-01 2.957433689999999782e+00 4.622241666666670329e-02 -3.840975999999999835e-01 2.782086464999999897e+00 4.383930500000000202e-02 -3.990183999999999953e-01 2.497954614999999823e+00 4.216718166666669904e-02 -4.106379000000000001e-01 2.347253106833329994e+00 4.254085666666670290e-02 -4.137768000000000002e-01 2.313526113333329803e+00 3.995030166666670157e-02 -4.291927999999999854e-01 2.205677500000000180e+00 3.693004333333330114e-02 -4.295145000000000213e-01 2.125140473833329935e+00 3.583346700000000079e-02 -4.447362000000000259e-01 1.900926653333329996e+00 3.564656666666669860e-02 -4.466328999999999994e-01 1.939722618500000051e+00 3.202840516666669718e-02 -4.604721999999999982e-01 1.890633683333329929e+00 3.361991000000000285e-02 -4.685032000000000085e-01 1.753475375666670111e+00 3.146806816666670309e-02 -4.766304000000000096e-01 1.692544018333330014e+00 3.150160500000000197e-02 -4.833663999999999739e-01 1.571138671166669942e+00 2.967553150000000126e-02 -4.924697000000000102e-01 1.562743266666670072e+00 3.127265833333330025e-02 -5.046184000000000225e-01 1.517538195333330009e+00 2.762060549999999920e-02 -5.084248000000000101e-01 1.452519751666669912e+00 2.870172666666670133e-02 -5.230276000000000369e-01 1.280607860833330003e+00 2.579378549999999937e-02 -5.250753000000000226e-01 1.364635400000000054e+00 2.694985833333329861e-02 -5.418418000000000401e-01 1.180339848333330055e+00 2.622176999999999841e-02 -5.443529999999999758e-01 1.172893769833329936e+00 2.597214383333330129e-02 -5.584759999999999724e-01 1.116791568333330043e+00 2.550004666666669945e-02 -5.612129000000000145e-01 1.071752901666670033e+00 2.359418099999999879e-02 -5.755700000000000260e-01 1.003165499999999932e+00 2.343291166666670172e-02 -5.833568000000000087e-01 9.490407108333329678e-01 2.324037416666669895e-02 -5.929195000000000437e-01 9.286979850000000036e-01 2.255620333333329883e-02 -6.005226999999999649e-01 8.938147573333330431e-01 2.214501316666669939e-02 -6.100906000000000384e-01 8.779068549999999860e-01 2.199904499999999832e-02 -6.218008000000000424e-01 8.078191183333329750e-01 2.148254866666670163e-02 -6.276903999999999817e-01 7.890844949999999969e-01 2.066168499999999908e-02 -6.411527999999999672e-01 6.990414535000000207e-01 1.907308200000000162e-02 -6.449108999999999536e-01 7.027759316666669642e-01 2.104888333333329933e-02 -6.654921999999999782e-01 6.693195063333330364e-01 1.846815400000000051e-02 -6.843110000000000026e-01 5.654079498333329790e-01 2.030432683333329921e-02 -7.057493999999999712e-01 4.733216641666669888e-01 1.710506283333329894e-02 -7.258065000000000211e-01 4.881572298333329840e-01 1.844279849999999957e-02 -7.489831000000000127e-01 4.439720878333329734e-01 1.519038399999999948e-02 -7.719418000000000113e-01 4.063687451666669892e-01 1.720554133333329974e-02 -7.920304000000000233e-01 4.025809184999999957e-01 1.519988700000000047e-02 -8.154392000000000307e-01 3.522328571666670238e-01 1.541253149999999988e-02 -8.363751000000000380e-01 3.005755748333330257e-01 1.457862766666669953e-02 -8.618630000000000457e-01 2.801856756666670223e-01 1.372444566666669932e-02 -8.845638000000000112e-01 3.046253318333330129e-01 1.455751649999999925e-02 -9.080675999999999748e-01 2.540008221666669730e-01 1.267830250000000041e-02 -9.333637999999999657e-01 2.481020686666670083e-01 1.368678783333330054e-02 -9.551005000000000189e-01 1.938199579999999866e-01 1.274076333333330063e-02 -9.812121999999999788e-01 1.905731619999999904e-01 1.196892649999999926e-02 -1.006720599999999965e+00 1.784818836666670072e-01 1.239337400000000040e-02 -1.030317399999999939e+00 1.750911911666669929e-01 1.179671083333330012e-02 -1.057692700000000041e+00 1.705610396666669970e-01 1.092493383333329945e-02 -1.084507099999999946e+00 1.719191243333330066e-01 1.130716749999999965e-02 -1.109806099999999907e+00 1.366376699999999889e-01 1.089438483333329995e-02 -1.137653000000000025e+00 1.239800338333330032e-01 1.044124700000000072e-02 +3.623830000000000107e-02 1.262534512933330006e+02 1.649893105666669868e+01 +4.068399999999999794e-02 1.096408472683330046e+02 1.152156481833329948e+01 +4.509420000000000095e-02 6.843298548666669490e+01 8.484508865000000455e+00 +4.957310000000000189e-02 5.337196919333329959e+01 6.882409771666670117e+00 +5.414259999999999906e-02 4.824018401499999698e+01 5.433445991666670416e+00 +5.866699999999999693e-02 4.665372951666670076e+01 4.705492196666670068e+00 +6.312850000000000406e-02 5.221271013999999866e+01 3.917987768333329957e+00 +6.770890000000000242e-02 4.827582027833329903e+01 3.280544881666669799e+00 +7.236159999999999815e-02 3.618855914666669804e+01 2.837183351666670017e+00 +7.691330000000000389e-02 3.079150051333330040e+01 2.510836073333329921e+00 +8.163410000000000111e-02 3.296728457500000076e+01 2.143401925000000041e+00 +8.638339999999999907e-02 3.069841431000000043e+01 1.940150145000000048e+00 +9.105580000000000618e-02 2.710592771666669876e+01 1.703459686666670025e+00 +9.572469999999999590e-02 2.329590637833329936e+01 1.563327263333329942e+00 +1.004822999999999966e-01 2.091072460333329985e+01 1.376591528333330094e+00 +1.052260000000000001e-01 1.912562908333330114e+01 1.273402691666670083e+00 +1.099742999999999971e-01 1.787115249333330169e+01 1.146192773333329917e+00 +1.148272999999999933e-01 1.794118791666669921e+01 1.055988855000000060e+00 +1.197614000000000040e-01 1.653599519333329937e+01 9.723875616666669552e-01 +1.247536000000000062e-01 1.582743532666670028e+01 9.084356083333330334e-01 +1.298200999999999938e-01 1.478155951166669979e+01 8.152435350000000192e-01 +1.348902999999999908e-01 1.334408521333329922e+01 7.818770066666670404e-01 +1.399062000000000083e-01 1.377281605666670039e+01 7.205883533333330426e-01 +1.450545000000000029e-01 1.181691977333330001e+01 6.799812333333330461e-01 +1.502462999999999993e-01 1.213584320000000005e+01 6.572146300000000219e-01 +1.555860000000000021e-01 1.192358865166669979e+01 5.953690533333330093e-01 +1.572933999999999999e-01 1.181612013833330010e+01 1.889312700000000123e-01 +1.609261999999999915e-01 1.175466066000000076e+01 5.752044899999999572e-01 +1.661659000000000053e-01 1.042143580833329963e+01 5.392668716666669804e-01 +1.706808999999999965e-01 1.011778497999999971e+01 1.577585016666669948e-01 +1.715392000000000028e-01 9.758357795000000223e+00 5.081139666666669719e-01 +1.771040000000000114e-01 8.903400566666670457e+00 4.716962699999999731e-01 +1.827079000000000064e-01 9.178007346666669619e+00 4.546196783333329994e-01 +1.842987000000000097e-01 9.009516103333330861e+00 1.364224366666670074e-01 +1.882929000000000130e-01 8.406366826666669567e+00 4.368516150000000264e-01 +1.939542999999999962e-01 7.892936534999999587e+00 4.208100816666670019e-01 +1.983015999999999945e-01 7.968528981666669786e+00 1.178380566666669960e-01 +1.997403000000000095e-01 7.734987613333330181e+00 3.934730833333329736e-01 +2.055543999999999982e-01 7.979108915000000302e+00 3.863922049999999886e-01 +2.114380999999999899e-01 6.834691483333330098e+00 3.579354766666669740e-01 +2.120755000000000001e-01 7.473622876666669690e+00 1.084324933333330049e-01 +2.161621999999999988e-01 6.843431601666670083e+00 4.540542233333330069e-01 +2.260508999999999991e-01 6.624537448333329692e+00 9.508442500000000019e-02 +2.398570999999999898e-01 6.030806045000000282e+00 8.883706333333329930e-02 +2.537865999999999733e-01 5.548485336666669987e+00 8.121552666666670417e-02 +2.677086000000000188e-01 5.056279183333329819e+00 7.439664999999999473e-02 +2.818711999999999884e-01 4.746517688333329765e+00 6.929181333333329917e-02 +2.957293999999999756e-01 4.360488485000000303e+00 6.532353000000000465e-02 +3.099983000000000044e-01 4.042259101666670240e+00 5.956615500000000257e-02 +3.241628999999999761e-01 3.667612291666670021e+00 5.754424666666670130e-02 +3.389054000000000233e-01 3.392261260000000167e+00 5.132888666666669819e-02 +3.540212999999999832e-01 3.153369070000000107e+00 5.001504333333330055e-02 +3.688208000000000042e-01 2.957433689999999782e+00 4.622241666666670329e-02 +3.840975999999999835e-01 2.782086464999999897e+00 4.383930500000000202e-02 +3.990183999999999953e-01 2.497954614999999823e+00 4.216718166666669904e-02 +4.106379000000000001e-01 2.347253106833329994e+00 4.254085666666670290e-02 +4.137768000000000002e-01 2.313526113333329803e+00 3.995030166666670157e-02 +4.291927999999999854e-01 2.205677500000000180e+00 3.693004333333330114e-02 +4.295145000000000213e-01 2.125140473833329935e+00 3.583346700000000079e-02 +4.447362000000000259e-01 1.900926653333329996e+00 3.564656666666669860e-02 +4.466328999999999994e-01 1.939722618500000051e+00 3.202840516666669718e-02 +4.604721999999999982e-01 1.890633683333329929e+00 3.361991000000000285e-02 +4.685032000000000085e-01 1.753475375666670111e+00 3.146806816666670309e-02 +4.766304000000000096e-01 1.692544018333330014e+00 3.150160500000000197e-02 +4.833663999999999739e-01 1.571138671166669942e+00 2.967553150000000126e-02 +4.924697000000000102e-01 1.562743266666670072e+00 3.127265833333330025e-02 +5.046184000000000225e-01 1.517538195333330009e+00 2.762060549999999920e-02 +5.084248000000000101e-01 1.452519751666669912e+00 2.870172666666670133e-02 +5.230276000000000369e-01 1.280607860833330003e+00 2.579378549999999937e-02 +5.250753000000000226e-01 1.364635400000000054e+00 2.694985833333329861e-02 +5.418418000000000401e-01 1.180339848333330055e+00 2.622176999999999841e-02 +5.443529999999999758e-01 1.172893769833329936e+00 2.597214383333330129e-02 +5.584759999999999724e-01 1.116791568333330043e+00 2.550004666666669945e-02 +5.612129000000000145e-01 1.071752901666670033e+00 2.359418099999999879e-02 +5.755700000000000260e-01 1.003165499999999932e+00 2.343291166666670172e-02 +5.833568000000000087e-01 9.490407108333329678e-01 2.324037416666669895e-02 +5.929195000000000437e-01 9.286979850000000036e-01 2.255620333333329883e-02 +6.005226999999999649e-01 8.938147573333330431e-01 2.214501316666669939e-02 +6.100906000000000384e-01 8.779068549999999860e-01 2.199904499999999832e-02 +6.218008000000000424e-01 8.078191183333329750e-01 2.148254866666670163e-02 +6.276903999999999817e-01 7.890844949999999969e-01 2.066168499999999908e-02 +6.411527999999999672e-01 6.990414535000000207e-01 1.907308200000000162e-02 +6.449108999999999536e-01 7.027759316666669642e-01 2.104888333333329933e-02 +6.654921999999999782e-01 6.693195063333330364e-01 1.846815400000000051e-02 +6.843110000000000026e-01 5.654079498333329790e-01 2.030432683333329921e-02 +7.057493999999999712e-01 4.733216641666669888e-01 1.710506283333329894e-02 +7.258065000000000211e-01 4.881572298333329840e-01 1.844279849999999957e-02 +7.489831000000000127e-01 4.439720878333329734e-01 1.519038399999999948e-02 +7.719418000000000113e-01 4.063687451666669892e-01 1.720554133333329974e-02 +7.920304000000000233e-01 4.025809184999999957e-01 1.519988700000000047e-02 +8.154392000000000307e-01 3.522328571666670238e-01 1.541253149999999988e-02 +8.363751000000000380e-01 3.005755748333330257e-01 1.457862766666669953e-02 +8.618630000000000457e-01 2.801856756666670223e-01 1.372444566666669932e-02 +8.845638000000000112e-01 3.046253318333330129e-01 1.455751649999999925e-02 +9.080675999999999748e-01 2.540008221666669730e-01 1.267830250000000041e-02 +9.333637999999999657e-01 2.481020686666670083e-01 1.368678783333330054e-02 +9.551005000000000189e-01 1.938199579999999866e-01 1.274076333333330063e-02 +9.812121999999999788e-01 1.905731619999999904e-01 1.196892649999999926e-02 +1.006720599999999965e+00 1.784818836666670072e-01 1.239337400000000040e-02 +1.030317399999999939e+00 1.750911911666669929e-01 1.179671083333330012e-02 +1.057692700000000041e+00 1.705610396666669970e-01 1.092493383333329945e-02 +1.084507099999999946e+00 1.719191243333330066e-01 1.130716749999999965e-02 +1.109806099999999907e+00 1.366376699999999889e-01 1.089438483333329995e-02 +1.137653000000000025e+00 1.239800338333330032e-01 1.044124700000000072e-02 1.165935399999999955e+00 1.310211675000000076e-01 1.024458533333330069e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv index 4f571dd57..2b03b80a5 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/6_100_1340_10.csv @@ -1,105 +1,105 @@ -3.625239999999999713e-02 1.213206534416670053e+02 1.651067908166670151e+01 -4.070000000000000007e-02 8.158564289333330066e+01 1.146150313666669973e+01 -4.511180000000000051e-02 6.728303165833330013e+01 8.493610868333329122e+00 -4.959249999999999770e-02 5.609321657833329766e+01 6.902234358333330100e+00 -5.416379999999999806e-02 4.208391674666670212e+01 5.417946521666669568e+00 -5.868999999999999911e-02 4.572918046833329697e+01 4.708583066666670369e+00 -6.315320000000000655e-02 4.506950746166670285e+01 3.890110903333329873e+00 -6.773540000000000116e-02 3.932771859999999720e+01 3.240109296666669803e+00 -7.238989999999999314e-02 3.425092975666670014e+01 2.830867521666669884e+00 -7.694339999999999513e-02 2.785716006499999864e+01 2.497106951666669961e+00 -8.166600000000000248e-02 2.647316349333329910e+01 2.106834523333330100e+00 -8.641719999999999957e-02 2.865549820000000025e+01 1.929370503333329934e+00 -9.109140000000000292e-02 2.617781355833329826e+01 1.699746431666669944e+00 -9.576210000000000278e-02 2.262414874833330103e+01 1.560889624999999947e+00 -1.005216000000000026e-01 2.072404344833330114e+01 1.377539340000000001e+00 -1.052672000000000052e-01 1.924028949499999896e+01 1.276625569999999987e+00 -1.100174000000000013e-01 1.836748323999999855e+01 1.152518286666670111e+00 -1.148721999999999938e-01 1.699007782666669897e+01 1.049408108333329981e+00 -1.198083000000000065e-01 1.493712180833330017e+01 9.595881783333329862e-01 -1.248023999999999939e-01 1.484142020166670051e+01 9.009069050000000356e-01 -1.298709000000000113e-01 1.473895257666669956e+01 8.163899350000000110e-01 -1.349431000000000103e-01 1.308340819666669930e+01 7.807371766666669766e-01 -1.399610000000000021e-01 1.350568340499999920e+01 7.192249033333329988e-01 -1.451112999999999986e-01 1.173611615333330072e+01 6.804578466666669767e-01 -1.503050999999999970e-01 1.154060497666669960e+01 6.523238550000000080e-01 -1.556469000000000047e-01 1.191625231333330071e+01 5.964806683333330195e-01 -1.573344999999999883e-01 1.139197852166670089e+01 1.879402166666669927e-01 -1.609891999999999990e-01 1.125507998666670062e+01 5.708663616666670437e-01 -1.662309999999999899e-01 1.041113468166670053e+01 5.402433599999999503e-01 -1.707255000000000023e-01 1.013307594333329931e+01 1.580824633333330065e-01 -1.716062999999999894e-01 9.500610554999999735e+00 5.062648633333329817e-01 -1.771733000000000058e-01 8.706795813333329193e+00 4.704599616666669815e-01 -1.827794000000000085e-01 9.156035623333330875e+00 4.553047450000000107e-01 -1.843469000000000080e-01 9.118870355000000316e+00 1.370399833333330042e-01 -1.883665999999999952e-01 7.952454938333329615e+00 4.325042000000000053e-01 -1.940302000000000138e-01 8.034647969999999972e+00 4.232443883333329993e-01 -1.983534999999999882e-01 8.119139649999999264e+00 1.185909816666669975e-01 -1.998185000000000100e-01 7.527596430000000005e+00 3.919050766666670182e-01 -2.056348000000000065e-01 7.553855535000000287e+00 3.822255366666669762e-01 -2.115208000000000088e-01 6.617426820000000376e+00 3.561540533333329983e-01 -2.121309999999999862e-01 7.390867828333330003e+00 1.083323783333329932e-01 -2.162467999999999890e-01 6.635593964999999983e+00 4.517541333333329745e-01 -2.261101000000000083e-01 6.488236141666670065e+00 9.474941333333329607e-02 -2.399198999999999915e-01 5.939089416666670118e+00 8.864513000000000253e-02 -2.538528999999999924e-01 5.445706584999999933e+00 8.096326333333329905e-02 -2.677785999999999778e-01 5.020975218333330048e+00 7.440106833333330616e-02 -2.819448999999999983e-01 4.782109235000000069e+00 6.958310166666670238e-02 -2.958067999999999809e-01 4.377367741666669865e+00 6.553075166666670615e-02 -3.100794000000000050e-01 4.070373518333330054e+00 5.980910666666670178e-02 -3.242476000000000247e-01 3.688249826666670117e+00 5.775312500000000238e-02 -3.389940000000000175e-01 3.411490240000000007e+00 5.151532000000000333e-02 -3.541138999999999815e-01 3.221007965000000084e+00 5.041618500000000225e-02 -3.689172000000000007e-01 2.942401639999999929e+00 4.624927499999999941e-02 -3.841980999999999868e-01 2.767105533333329870e+00 4.386071833333329839e-02 -3.991226999999999969e-01 2.564823933333329808e+00 4.256582833333329846e-02 -4.106734000000000218e-01 2.300881685499999829e+00 4.238948299999999864e-02 -4.138850000000000029e-01 2.413576710000000070e+00 4.049426666666670199e-02 -4.293050999999999950e-01 2.233726248333329778e+00 3.713503166666669991e-02 -4.295516999999999808e-01 2.156876818999999834e+00 3.601888033333330158e-02 -4.448524999999999840e-01 1.902652508333330106e+00 3.572283666666670188e-02 -4.466716000000000020e-01 1.934442038833330102e+00 3.205653166666670023e-02 -4.605926000000000187e-01 1.874115690000000001e+00 3.360869833333329781e-02 -4.685437000000000074e-01 1.737730488500000003e+00 3.144913299999999717e-02 -4.767550999999999872e-01 1.772107871666670054e+00 3.193823833333329920e-02 -4.834083000000000130e-01 1.581873448666669901e+00 2.976716433333330067e-02 -4.925984999999999947e-01 1.570737606666670061e+00 3.137136000000000091e-02 -5.046621000000000024e-01 1.492830698499999942e+00 2.756047650000000016e-02 -5.085577999999999488e-01 1.485373084999999982e+00 2.891283166666670096e-02 -5.230728999999999518e-01 1.159546245333330061e+00 2.533816566666670031e-02 -5.252126000000000294e-01 1.354185358333330091e+00 2.695080999999999866e-02 -5.419834999999999514e-01 1.186315898333329955e+00 2.629908666666670031e-02 -5.444001000000000534e-01 1.201936935333330014e+00 2.613158683333329999e-02 -5.586221000000000103e-01 1.109243371666670086e+00 2.550917499999999852e-02 -5.612614999999999688e-01 1.098874749833330000e+00 2.373973216666670077e-02 -5.757206000000000268e-01 1.029040688333330067e+00 2.359920000000000073e-02 -5.834072999999999620e-01 9.811238644999999980e-01 2.340685516666669852e-02 -5.930746000000000073e-01 9.534806916666670462e-01 2.272023833333329870e-02 -6.005747000000000169e-01 8.956047156666669951e-01 2.218217800000000031e-02 -6.102501999999999649e-01 8.805252883333329894e-01 2.205115333333329888e-02 -6.218546000000000351e-01 8.076579554999999688e-01 2.150926133333330020e-02 -6.278546000000000404e-01 8.143317416666669972e-01 2.081983000000000097e-02 -6.412082999999999533e-01 7.185076576666670212e-01 1.917512450000000146e-02 -6.450795999999999752e-01 7.187583950000000499e-01 2.116659499999999985e-02 -6.655497999999999692e-01 6.417931828333329758e-01 1.838261283333330123e-02 -6.843702000000000396e-01 5.677104609999999996e-01 2.033867249999999835e-02 -7.058105999999999547e-01 5.146355146666670155e-01 1.728668516666670082e-02 -7.258693999999999980e-01 5.183306771666670310e-01 1.859332783333330144e-02 -7.490480000000000471e-01 4.413184218333329745e-01 1.519721516666669957e-02 -7.720086999999999922e-01 4.069291728333330194e-01 1.722663266666669968e-02 -7.920989999999999975e-01 3.912903401666669723e-01 1.517220816666670080e-02 -8.155097999999999514e-01 3.620392363333330144e-01 1.546880433333329939e-02 -8.364475000000000104e-01 3.218374210000000124e-01 1.467598383333330002e-02 -8.619377000000000288e-01 2.793489951666670024e-01 1.373524349999999915e-02 -8.846403999999999934e-01 2.729738648333330242e-01 1.444214883333330007e-02 -9.081462000000000145e-01 2.731246803333329809e-01 1.275928200000000026e-02 -9.334447000000000161e-01 2.513956430000000020e-01 1.371339566666670076e-02 -9.551832000000000100e-01 2.075616728333329886e-01 1.280443116666669934e-02 -9.812971999999999806e-01 2.026315226666670077e-01 1.202260966666669935e-02 -1.006807800000000030e+00 1.715856353333329865e-01 1.237966916666670067e-02 -1.030406600000000061e+00 1.813217336666670121e-01 1.183022066666669994e-02 -1.057784300000000011e+00 1.874246033333329953e-01 1.099227083333330010e-02 -1.084600999999999926e+00 1.682342156666669919e-01 1.130467983333329970e-02 -1.109902299999999897e+00 1.305937931666669993e-01 1.088363799999999930e-02 -1.137751600000000085e+00 1.264251891666670069e-01 1.045857849999999936e-02 +3.625239999999999713e-02 1.213206534416670053e+02 1.651067908166670151e+01 +4.070000000000000007e-02 8.158564289333330066e+01 1.146150313666669973e+01 +4.511180000000000051e-02 6.728303165833330013e+01 8.493610868333329122e+00 +4.959249999999999770e-02 5.609321657833329766e+01 6.902234358333330100e+00 +5.416379999999999806e-02 4.208391674666670212e+01 5.417946521666669568e+00 +5.868999999999999911e-02 4.572918046833329697e+01 4.708583066666670369e+00 +6.315320000000000655e-02 4.506950746166670285e+01 3.890110903333329873e+00 +6.773540000000000116e-02 3.932771859999999720e+01 3.240109296666669803e+00 +7.238989999999999314e-02 3.425092975666670014e+01 2.830867521666669884e+00 +7.694339999999999513e-02 2.785716006499999864e+01 2.497106951666669961e+00 +8.166600000000000248e-02 2.647316349333329910e+01 2.106834523333330100e+00 +8.641719999999999957e-02 2.865549820000000025e+01 1.929370503333329934e+00 +9.109140000000000292e-02 2.617781355833329826e+01 1.699746431666669944e+00 +9.576210000000000278e-02 2.262414874833330103e+01 1.560889624999999947e+00 +1.005216000000000026e-01 2.072404344833330114e+01 1.377539340000000001e+00 +1.052672000000000052e-01 1.924028949499999896e+01 1.276625569999999987e+00 +1.100174000000000013e-01 1.836748323999999855e+01 1.152518286666670111e+00 +1.148721999999999938e-01 1.699007782666669897e+01 1.049408108333329981e+00 +1.198083000000000065e-01 1.493712180833330017e+01 9.595881783333329862e-01 +1.248023999999999939e-01 1.484142020166670051e+01 9.009069050000000356e-01 +1.298709000000000113e-01 1.473895257666669956e+01 8.163899350000000110e-01 +1.349431000000000103e-01 1.308340819666669930e+01 7.807371766666669766e-01 +1.399610000000000021e-01 1.350568340499999920e+01 7.192249033333329988e-01 +1.451112999999999986e-01 1.173611615333330072e+01 6.804578466666669767e-01 +1.503050999999999970e-01 1.154060497666669960e+01 6.523238550000000080e-01 +1.556469000000000047e-01 1.191625231333330071e+01 5.964806683333330195e-01 +1.573344999999999883e-01 1.139197852166670089e+01 1.879402166666669927e-01 +1.609891999999999990e-01 1.125507998666670062e+01 5.708663616666670437e-01 +1.662309999999999899e-01 1.041113468166670053e+01 5.402433599999999503e-01 +1.707255000000000023e-01 1.013307594333329931e+01 1.580824633333330065e-01 +1.716062999999999894e-01 9.500610554999999735e+00 5.062648633333329817e-01 +1.771733000000000058e-01 8.706795813333329193e+00 4.704599616666669815e-01 +1.827794000000000085e-01 9.156035623333330875e+00 4.553047450000000107e-01 +1.843469000000000080e-01 9.118870355000000316e+00 1.370399833333330042e-01 +1.883665999999999952e-01 7.952454938333329615e+00 4.325042000000000053e-01 +1.940302000000000138e-01 8.034647969999999972e+00 4.232443883333329993e-01 +1.983534999999999882e-01 8.119139649999999264e+00 1.185909816666669975e-01 +1.998185000000000100e-01 7.527596430000000005e+00 3.919050766666670182e-01 +2.056348000000000065e-01 7.553855535000000287e+00 3.822255366666669762e-01 +2.115208000000000088e-01 6.617426820000000376e+00 3.561540533333329983e-01 +2.121309999999999862e-01 7.390867828333330003e+00 1.083323783333329932e-01 +2.162467999999999890e-01 6.635593964999999983e+00 4.517541333333329745e-01 +2.261101000000000083e-01 6.488236141666670065e+00 9.474941333333329607e-02 +2.399198999999999915e-01 5.939089416666670118e+00 8.864513000000000253e-02 +2.538528999999999924e-01 5.445706584999999933e+00 8.096326333333329905e-02 +2.677785999999999778e-01 5.020975218333330048e+00 7.440106833333330616e-02 +2.819448999999999983e-01 4.782109235000000069e+00 6.958310166666670238e-02 +2.958067999999999809e-01 4.377367741666669865e+00 6.553075166666670615e-02 +3.100794000000000050e-01 4.070373518333330054e+00 5.980910666666670178e-02 +3.242476000000000247e-01 3.688249826666670117e+00 5.775312500000000238e-02 +3.389940000000000175e-01 3.411490240000000007e+00 5.151532000000000333e-02 +3.541138999999999815e-01 3.221007965000000084e+00 5.041618500000000225e-02 +3.689172000000000007e-01 2.942401639999999929e+00 4.624927499999999941e-02 +3.841980999999999868e-01 2.767105533333329870e+00 4.386071833333329839e-02 +3.991226999999999969e-01 2.564823933333329808e+00 4.256582833333329846e-02 +4.106734000000000218e-01 2.300881685499999829e+00 4.238948299999999864e-02 +4.138850000000000029e-01 2.413576710000000070e+00 4.049426666666670199e-02 +4.293050999999999950e-01 2.233726248333329778e+00 3.713503166666669991e-02 +4.295516999999999808e-01 2.156876818999999834e+00 3.601888033333330158e-02 +4.448524999999999840e-01 1.902652508333330106e+00 3.572283666666670188e-02 +4.466716000000000020e-01 1.934442038833330102e+00 3.205653166666670023e-02 +4.605926000000000187e-01 1.874115690000000001e+00 3.360869833333329781e-02 +4.685437000000000074e-01 1.737730488500000003e+00 3.144913299999999717e-02 +4.767550999999999872e-01 1.772107871666670054e+00 3.193823833333329920e-02 +4.834083000000000130e-01 1.581873448666669901e+00 2.976716433333330067e-02 +4.925984999999999947e-01 1.570737606666670061e+00 3.137136000000000091e-02 +5.046621000000000024e-01 1.492830698499999942e+00 2.756047650000000016e-02 +5.085577999999999488e-01 1.485373084999999982e+00 2.891283166666670096e-02 +5.230728999999999518e-01 1.159546245333330061e+00 2.533816566666670031e-02 +5.252126000000000294e-01 1.354185358333330091e+00 2.695080999999999866e-02 +5.419834999999999514e-01 1.186315898333329955e+00 2.629908666666670031e-02 +5.444001000000000534e-01 1.201936935333330014e+00 2.613158683333329999e-02 +5.586221000000000103e-01 1.109243371666670086e+00 2.550917499999999852e-02 +5.612614999999999688e-01 1.098874749833330000e+00 2.373973216666670077e-02 +5.757206000000000268e-01 1.029040688333330067e+00 2.359920000000000073e-02 +5.834072999999999620e-01 9.811238644999999980e-01 2.340685516666669852e-02 +5.930746000000000073e-01 9.534806916666670462e-01 2.272023833333329870e-02 +6.005747000000000169e-01 8.956047156666669951e-01 2.218217800000000031e-02 +6.102501999999999649e-01 8.805252883333329894e-01 2.205115333333329888e-02 +6.218546000000000351e-01 8.076579554999999688e-01 2.150926133333330020e-02 +6.278546000000000404e-01 8.143317416666669972e-01 2.081983000000000097e-02 +6.412082999999999533e-01 7.185076576666670212e-01 1.917512450000000146e-02 +6.450795999999999752e-01 7.187583950000000499e-01 2.116659499999999985e-02 +6.655497999999999692e-01 6.417931828333329758e-01 1.838261283333330123e-02 +6.843702000000000396e-01 5.677104609999999996e-01 2.033867249999999835e-02 +7.058105999999999547e-01 5.146355146666670155e-01 1.728668516666670082e-02 +7.258693999999999980e-01 5.183306771666670310e-01 1.859332783333330144e-02 +7.490480000000000471e-01 4.413184218333329745e-01 1.519721516666669957e-02 +7.720086999999999922e-01 4.069291728333330194e-01 1.722663266666669968e-02 +7.920989999999999975e-01 3.912903401666669723e-01 1.517220816666670080e-02 +8.155097999999999514e-01 3.620392363333330144e-01 1.546880433333329939e-02 +8.364475000000000104e-01 3.218374210000000124e-01 1.467598383333330002e-02 +8.619377000000000288e-01 2.793489951666670024e-01 1.373524349999999915e-02 +8.846403999999999934e-01 2.729738648333330242e-01 1.444214883333330007e-02 +9.081462000000000145e-01 2.731246803333329809e-01 1.275928200000000026e-02 +9.334447000000000161e-01 2.513956430000000020e-01 1.371339566666670076e-02 +9.551832000000000100e-01 2.075616728333329886e-01 1.280443116666669934e-02 +9.812971999999999806e-01 2.026315226666670077e-01 1.202260966666669935e-02 +1.006807800000000030e+00 1.715856353333329865e-01 1.237966916666670067e-02 +1.030406600000000061e+00 1.813217336666670121e-01 1.183022066666669994e-02 +1.057784300000000011e+00 1.874246033333329953e-01 1.099227083333330010e-02 +1.084600999999999926e+00 1.682342156666669919e-01 1.130467983333329970e-02 +1.109902299999999897e+00 1.305937931666669993e-01 1.088363799999999930e-02 +1.137751600000000085e+00 1.264251891666670069e-01 1.045857849999999936e-02 1.166036300000000026e+00 1.206125236666669986e-01 1.021913349999999977e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv index 69ff8c3df..e8e9c9a0b 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/7_200_1340_10.csv @@ -1,105 +1,105 @@ -3.625239999999999713e-02 8.265676436333329491e+01 1.638320715333329858e+01 -4.070000000000000007e-02 5.464383480166669926e+01 1.136626790833330070e+01 -4.511180000000000051e-02 2.996549328500000087e+01 8.362137733333330658e+00 -4.959249999999999770e-02 3.902000664833330035e+01 6.829579628333330099e+00 -5.416379999999999806e-02 2.960868386499999971e+01 5.359635035000000158e+00 -5.868999999999999911e-02 2.775202533166670094e+01 4.620562245000000345e+00 -6.315320000000000655e-02 2.923420741833329828e+01 3.806268636666669813e+00 -6.773540000000000116e-02 2.925570898666670061e+01 3.181662941666670186e+00 -7.238989999999999314e-02 2.438109743166669929e+01 2.769415394999999780e+00 -7.694339999999999513e-02 2.082174377999999848e+01 2.449056793333329818e+00 -8.166600000000000248e-02 2.093264007666670068e+01 2.067833788333329981e+00 -8.641719999999999957e-02 2.065156679166669917e+01 1.869354308333329939e+00 -9.109140000000000292e-02 2.096371475999999845e+01 1.658336066666669995e+00 -9.576210000000000278e-02 1.686565956500000141e+01 1.512923419999999908e+00 -1.005216000000000026e-01 1.674424940666670025e+01 1.343149441666670052e+00 -1.052672000000000052e-01 1.453594207833329932e+01 1.233355748333329949e+00 -1.100174000000000013e-01 1.743436942499999986e+01 1.141890178333329953e+00 -1.148721999999999938e-01 1.514907325499999935e+01 1.030380964999999982e+00 -1.198083000000000065e-01 1.335097668833330076e+01 9.427780516666669497e-01 -1.248023999999999939e-01 1.334016233833330034e+01 8.846290449999999472e-01 -1.298709000000000113e-01 1.370878951499999943e+01 8.044898483333330352e-01 -1.349431000000000103e-01 1.169732300833329930e+01 7.648545733333329544e-01 -1.399610000000000021e-01 1.178831958166670013e+01 6.994071549999999471e-01 -1.451112999999999986e-01 1.065116290166669977e+01 6.676857533333330208e-01 -1.503050999999999970e-01 9.325193926666669242e+00 6.273500633333329857e-01 -1.556469000000000047e-01 1.029459589333329994e+01 5.781039766666670188e-01 -1.572456999999999883e-01 1.000640059000000015e+01 1.830944850000000013e-01 -1.609891999999999990e-01 1.045812633999999974e+01 5.605480683333330383e-01 -1.662309999999999899e-01 9.379805284999999770e+00 5.273011283333329802e-01 -1.706292000000000086e-01 9.152038171666669442e+00 1.545153300000000063e-01 -1.716062999999999894e-01 9.072271783333329509e+00 5.002084749999999858e-01 -1.771733000000000058e-01 8.299759079999999400e+00 4.647556766666670058e-01 -1.827794000000000085e-01 8.918414625000000484e+00 4.514085349999999996e-01 -1.842428999999999872e-01 8.303275895000000517e+00 1.338776349999999948e-01 -1.883665999999999952e-01 8.087114149999999668e+00 4.329608600000000029e-01 -1.940302000000000138e-01 6.940626968333329927e+00 4.097805333333329747e-01 -1.982414999999999872e-01 7.399220633333330355e+00 1.156899150000000043e-01 -1.998185000000000100e-01 7.671813116666670318e+00 3.925434549999999856e-01 -2.056348000000000065e-01 7.058416683333329722e+00 3.753756766666669908e-01 -2.115208000000000088e-01 6.186979153333330039e+00 3.502447450000000240e-01 -2.120113000000000136e-01 6.509825833333329648e+00 1.046767516666669978e-01 -2.162467999999999890e-01 6.237968744999999871e+00 4.443455150000000242e-01 -2.259823999999999999e-01 6.054194650000000344e+00 9.278840666666669790e-02 -2.397845000000000115e-01 5.564811654999999746e+00 8.685724833333340056e-02 -2.537096999999999825e-01 5.167096618333330227e+00 7.958348833333329930e-02 -2.676275000000000182e-01 4.857346653333330266e+00 7.348198000000000230e-02 -2.817857999999999752e-01 4.540460176666670122e+00 6.833893833333329337e-02 -2.956398000000000081e-01 4.237780543333330208e+00 6.471250666666669704e-02 -3.099044000000000243e-01 3.935048769999999863e+00 5.903304000000000190e-02 -3.240645999999999805e-01 3.478254921666669830e+00 5.662396666666669881e-02 -3.388027000000000122e-01 3.303115776666670111e+00 5.088800999999999741e-02 -3.539140000000000064e-01 3.111107356666670043e+00 4.976782999999999901e-02 -3.687090000000000090e-01 2.860701315000000022e+00 4.573441000000000312e-02 -3.839813000000000254e-01 2.699693565000000017e+00 4.341666500000000012e-02 -3.988975000000000160e-01 2.495346641666670084e+00 4.210437499999999944e-02 -4.106734000000000218e-01 2.304978501333330154e+00 4.227540733333329942e-02 -4.136514000000000024e-01 2.281161938333330141e+00 3.975256666666669714e-02 -4.290628000000000219e-01 2.190969609999999790e+00 3.681797500000000278e-02 -4.295516999999999808e-01 2.110397390999999789e+00 3.571657216666670326e-02 -4.446014999999999828e-01 1.879588453333330023e+00 3.550642500000000118e-02 -4.466716000000000020e-01 1.816268564666670082e+00 3.148649049999999866e-02 -4.603325999999999807e-01 1.793649588333330103e+00 3.313105499999999953e-02 -4.685437000000000074e-01 1.770170460833329962e+00 3.148902633333330175e-02 -4.764860000000000206e-01 1.682140176666669928e+00 3.141608500000000331e-02 -4.834083000000000130e-01 1.536765404999999918e+00 2.947832866666669910e-02 -4.923204999999999942e-01 1.511959243333329983e+00 3.099057499999999937e-02 -5.046621000000000024e-01 1.465441131499999994e+00 2.736933133333329868e-02 -5.082708000000000226e-01 1.365583310000000106e+00 2.825172333333330135e-02 -5.230728999999999518e-01 1.154780808166669948e+00 2.524863800000000033e-02 -5.249162000000000550e-01 1.329800611666670074e+00 2.675280666666670151e-02 -5.416775999999999813e-01 1.188958583333330044e+00 2.623523499999999911e-02 -5.444001000000000534e-01 1.154485974333330001e+00 2.585743066666670170e-02 -5.583067999999999920e-01 1.077189841666670089e+00 2.527868166666669830e-02 -5.612614999999999688e-01 1.051792144833330056e+00 2.347724083333330158e-02 -5.753956999999999544e-01 1.014095294999999952e+00 2.346036166666670003e-02 -5.834072999999999620e-01 9.588631039999999661e-01 2.325032483333330097e-02 -5.927398999999999862e-01 9.388917833333330076e-01 2.258296499999999998e-02 -6.005747000000000169e-01 8.756694673333329515e-01 2.203778849999999886e-02 -6.099058000000000535e-01 8.473022983333330371e-01 2.182166666666670099e-02 -6.218546000000000351e-01 7.881510335000000422e-01 2.137202599999999883e-02 -6.275003000000000108e-01 7.785123416666670515e-01 2.058900166666670015e-02 -6.412082999999999533e-01 7.088910750000000371e-01 1.908878433333329946e-02 -6.447154999999999969e-01 6.898300916666669780e-01 2.096122833333330035e-02 -6.655497999999999692e-01 6.325061706666670336e-01 1.830133016666669887e-02 -6.843702000000000396e-01 5.535274884999999978e-01 2.022582083333330019e-02 -7.058105999999999547e-01 4.772884753333330177e-01 1.710068249999999873e-02 -7.258693999999999980e-01 4.794482545000000040e-01 1.838371499999999839e-02 -7.490480000000000471e-01 4.303608649999999813e-01 1.512209783333329921e-02 -7.720086999999999922e-01 3.958678310000000033e-01 1.713988450000000080e-02 -7.920989999999999975e-01 3.804415833333329999e-01 1.509590366666670007e-02 -8.155097999999999514e-01 3.391658666666669819e-01 1.534219399999999997e-02 -8.364475000000000104e-01 2.920511656666670008e-01 1.453006433333330072e-02 -8.619377000000000288e-01 2.768105268333330149e-01 1.369777266666669970e-02 -8.846403999999999934e-01 2.773741731666670152e-01 1.443021766666669967e-02 -9.081462000000000145e-01 2.284839270000000033e-01 1.257401600000000036e-02 -9.334447000000000161e-01 2.262680790000000108e-01 1.358766933333330033e-02 -9.551832000000000100e-01 2.014745451666669906e-01 1.275664699999999943e-02 -9.812971999999999806e-01 1.828399243333329871e-01 1.193000216666669985e-02 -1.006807800000000030e+00 1.768480391666669982e-01 1.237525766666669989e-02 -1.030406600000000061e+00 1.607457411666670111e-01 1.173357283333329934e-02 -1.057784300000000011e+00 1.603443938333329877e-01 1.087976483333330004e-02 -1.084600999999999926e+00 1.672401265000000026e-01 1.127955949999999950e-02 -1.109902299999999897e+00 1.308651896666669923e-01 1.086452716666670010e-02 -1.137751600000000085e+00 1.208445169999999985e-01 1.042120399999999988e-02 +3.625239999999999713e-02 8.265676436333329491e+01 1.638320715333329858e+01 +4.070000000000000007e-02 5.464383480166669926e+01 1.136626790833330070e+01 +4.511180000000000051e-02 2.996549328500000087e+01 8.362137733333330658e+00 +4.959249999999999770e-02 3.902000664833330035e+01 6.829579628333330099e+00 +5.416379999999999806e-02 2.960868386499999971e+01 5.359635035000000158e+00 +5.868999999999999911e-02 2.775202533166670094e+01 4.620562245000000345e+00 +6.315320000000000655e-02 2.923420741833329828e+01 3.806268636666669813e+00 +6.773540000000000116e-02 2.925570898666670061e+01 3.181662941666670186e+00 +7.238989999999999314e-02 2.438109743166669929e+01 2.769415394999999780e+00 +7.694339999999999513e-02 2.082174377999999848e+01 2.449056793333329818e+00 +8.166600000000000248e-02 2.093264007666670068e+01 2.067833788333329981e+00 +8.641719999999999957e-02 2.065156679166669917e+01 1.869354308333329939e+00 +9.109140000000000292e-02 2.096371475999999845e+01 1.658336066666669995e+00 +9.576210000000000278e-02 1.686565956500000141e+01 1.512923419999999908e+00 +1.005216000000000026e-01 1.674424940666670025e+01 1.343149441666670052e+00 +1.052672000000000052e-01 1.453594207833329932e+01 1.233355748333329949e+00 +1.100174000000000013e-01 1.743436942499999986e+01 1.141890178333329953e+00 +1.148721999999999938e-01 1.514907325499999935e+01 1.030380964999999982e+00 +1.198083000000000065e-01 1.335097668833330076e+01 9.427780516666669497e-01 +1.248023999999999939e-01 1.334016233833330034e+01 8.846290449999999472e-01 +1.298709000000000113e-01 1.370878951499999943e+01 8.044898483333330352e-01 +1.349431000000000103e-01 1.169732300833329930e+01 7.648545733333329544e-01 +1.399610000000000021e-01 1.178831958166670013e+01 6.994071549999999471e-01 +1.451112999999999986e-01 1.065116290166669977e+01 6.676857533333330208e-01 +1.503050999999999970e-01 9.325193926666669242e+00 6.273500633333329857e-01 +1.556469000000000047e-01 1.029459589333329994e+01 5.781039766666670188e-01 +1.572456999999999883e-01 1.000640059000000015e+01 1.830944850000000013e-01 +1.609891999999999990e-01 1.045812633999999974e+01 5.605480683333330383e-01 +1.662309999999999899e-01 9.379805284999999770e+00 5.273011283333329802e-01 +1.706292000000000086e-01 9.152038171666669442e+00 1.545153300000000063e-01 +1.716062999999999894e-01 9.072271783333329509e+00 5.002084749999999858e-01 +1.771733000000000058e-01 8.299759079999999400e+00 4.647556766666670058e-01 +1.827794000000000085e-01 8.918414625000000484e+00 4.514085349999999996e-01 +1.842428999999999872e-01 8.303275895000000517e+00 1.338776349999999948e-01 +1.883665999999999952e-01 8.087114149999999668e+00 4.329608600000000029e-01 +1.940302000000000138e-01 6.940626968333329927e+00 4.097805333333329747e-01 +1.982414999999999872e-01 7.399220633333330355e+00 1.156899150000000043e-01 +1.998185000000000100e-01 7.671813116666670318e+00 3.925434549999999856e-01 +2.056348000000000065e-01 7.058416683333329722e+00 3.753756766666669908e-01 +2.115208000000000088e-01 6.186979153333330039e+00 3.502447450000000240e-01 +2.120113000000000136e-01 6.509825833333329648e+00 1.046767516666669978e-01 +2.162467999999999890e-01 6.237968744999999871e+00 4.443455150000000242e-01 +2.259823999999999999e-01 6.054194650000000344e+00 9.278840666666669790e-02 +2.397845000000000115e-01 5.564811654999999746e+00 8.685724833333340056e-02 +2.537096999999999825e-01 5.167096618333330227e+00 7.958348833333329930e-02 +2.676275000000000182e-01 4.857346653333330266e+00 7.348198000000000230e-02 +2.817857999999999752e-01 4.540460176666670122e+00 6.833893833333329337e-02 +2.956398000000000081e-01 4.237780543333330208e+00 6.471250666666669704e-02 +3.099044000000000243e-01 3.935048769999999863e+00 5.903304000000000190e-02 +3.240645999999999805e-01 3.478254921666669830e+00 5.662396666666669881e-02 +3.388027000000000122e-01 3.303115776666670111e+00 5.088800999999999741e-02 +3.539140000000000064e-01 3.111107356666670043e+00 4.976782999999999901e-02 +3.687090000000000090e-01 2.860701315000000022e+00 4.573441000000000312e-02 +3.839813000000000254e-01 2.699693565000000017e+00 4.341666500000000012e-02 +3.988975000000000160e-01 2.495346641666670084e+00 4.210437499999999944e-02 +4.106734000000000218e-01 2.304978501333330154e+00 4.227540733333329942e-02 +4.136514000000000024e-01 2.281161938333330141e+00 3.975256666666669714e-02 +4.290628000000000219e-01 2.190969609999999790e+00 3.681797500000000278e-02 +4.295516999999999808e-01 2.110397390999999789e+00 3.571657216666670326e-02 +4.446014999999999828e-01 1.879588453333330023e+00 3.550642500000000118e-02 +4.466716000000000020e-01 1.816268564666670082e+00 3.148649049999999866e-02 +4.603325999999999807e-01 1.793649588333330103e+00 3.313105499999999953e-02 +4.685437000000000074e-01 1.770170460833329962e+00 3.148902633333330175e-02 +4.764860000000000206e-01 1.682140176666669928e+00 3.141608500000000331e-02 +4.834083000000000130e-01 1.536765404999999918e+00 2.947832866666669910e-02 +4.923204999999999942e-01 1.511959243333329983e+00 3.099057499999999937e-02 +5.046621000000000024e-01 1.465441131499999994e+00 2.736933133333329868e-02 +5.082708000000000226e-01 1.365583310000000106e+00 2.825172333333330135e-02 +5.230728999999999518e-01 1.154780808166669948e+00 2.524863800000000033e-02 +5.249162000000000550e-01 1.329800611666670074e+00 2.675280666666670151e-02 +5.416775999999999813e-01 1.188958583333330044e+00 2.623523499999999911e-02 +5.444001000000000534e-01 1.154485974333330001e+00 2.585743066666670170e-02 +5.583067999999999920e-01 1.077189841666670089e+00 2.527868166666669830e-02 +5.612614999999999688e-01 1.051792144833330056e+00 2.347724083333330158e-02 +5.753956999999999544e-01 1.014095294999999952e+00 2.346036166666670003e-02 +5.834072999999999620e-01 9.588631039999999661e-01 2.325032483333330097e-02 +5.927398999999999862e-01 9.388917833333330076e-01 2.258296499999999998e-02 +6.005747000000000169e-01 8.756694673333329515e-01 2.203778849999999886e-02 +6.099058000000000535e-01 8.473022983333330371e-01 2.182166666666670099e-02 +6.218546000000000351e-01 7.881510335000000422e-01 2.137202599999999883e-02 +6.275003000000000108e-01 7.785123416666670515e-01 2.058900166666670015e-02 +6.412082999999999533e-01 7.088910750000000371e-01 1.908878433333329946e-02 +6.447154999999999969e-01 6.898300916666669780e-01 2.096122833333330035e-02 +6.655497999999999692e-01 6.325061706666670336e-01 1.830133016666669887e-02 +6.843702000000000396e-01 5.535274884999999978e-01 2.022582083333330019e-02 +7.058105999999999547e-01 4.772884753333330177e-01 1.710068249999999873e-02 +7.258693999999999980e-01 4.794482545000000040e-01 1.838371499999999839e-02 +7.490480000000000471e-01 4.303608649999999813e-01 1.512209783333329921e-02 +7.720086999999999922e-01 3.958678310000000033e-01 1.713988450000000080e-02 +7.920989999999999975e-01 3.804415833333329999e-01 1.509590366666670007e-02 +8.155097999999999514e-01 3.391658666666669819e-01 1.534219399999999997e-02 +8.364475000000000104e-01 2.920511656666670008e-01 1.453006433333330072e-02 +8.619377000000000288e-01 2.768105268333330149e-01 1.369777266666669970e-02 +8.846403999999999934e-01 2.773741731666670152e-01 1.443021766666669967e-02 +9.081462000000000145e-01 2.284839270000000033e-01 1.257401600000000036e-02 +9.334447000000000161e-01 2.262680790000000108e-01 1.358766933333330033e-02 +9.551832000000000100e-01 2.014745451666669906e-01 1.275664699999999943e-02 +9.812971999999999806e-01 1.828399243333329871e-01 1.193000216666669985e-02 +1.006807800000000030e+00 1.768480391666669982e-01 1.237525766666669989e-02 +1.030406600000000061e+00 1.607457411666670111e-01 1.173357283333329934e-02 +1.057784300000000011e+00 1.603443938333329877e-01 1.087976483333330004e-02 +1.084600999999999926e+00 1.672401265000000026e-01 1.127955949999999950e-02 +1.109902299999999897e+00 1.308651896666669923e-01 1.086452716666670010e-02 +1.137751600000000085e+00 1.208445169999999985e-01 1.042120399999999988e-02 1.166036300000000026e+00 1.219414448333329959e-01 1.020481383333330001e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv index c61ec5437..c576fb9ba 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/8_300_1340_10.csv @@ -1,105 +1,105 @@ -3.625710000000000044e-02 7.586499487000000386e+01 1.637401323166670153e+01 -4.070529999999999982e-02 4.481643682666670259e+01 1.134473448500000003e+01 -4.511769999999999670e-02 3.187475403666670104e+01 8.372120233333330219e+00 -4.959899999999999726e-02 2.997679580000000144e+01 6.801308398333329563e+00 -5.417079999999999812e-02 2.394855565499999983e+01 5.340431286666669664e+00 -5.869760000000000255e-02 2.142582576833330066e+01 4.594792676666670239e+00 -6.316149999999999542e-02 3.089957102166669856e+01 3.816311058333329953e+00 -6.774429999999999341e-02 2.654007947166670078e+01 3.169185818333330129e+00 -7.239929999999999977e-02 1.943375908333329960e+01 2.742530958333329938e+00 -7.695340000000000513e-02 1.976728253666669843e+01 2.443851029999999813e+00 -8.167670000000000485e-02 1.925900297000000094e+01 2.058348746666669893e+00 -8.642850000000000532e-02 1.891829230833329945e+01 1.858069830000000033e+00 -9.110319999999999530e-02 1.827805419833330092e+01 1.639507476666669961e+00 -9.577460000000000140e-02 1.569160155166670023e+01 1.504524439999999963e+00 -1.005346000000000017e-01 1.326347007166669911e+01 1.315847523333329994e+00 -1.052808999999999967e-01 1.528716061000000082e+01 1.240626203333329958e+00 -1.100316999999999962e-01 1.357029930000000029e+01 1.108701733333329997e+00 -1.148871000000000059e-01 1.268526336333330029e+01 1.008324261666670107e+00 -1.198237999999999942e-01 1.157206131499999913e+01 9.266636050000000013e-01 -1.248187000000000046e-01 1.139260776499999928e+01 8.664271866666669597e-01 -1.298877999999999977e-01 1.288652256499999993e+01 7.969746983333330093e-01 -1.349605999999999861e-01 1.079102049499999971e+01 7.560191466666670301e-01 -1.399791999999999981e-01 1.105679143000000053e+01 6.920319183333329960e-01 -1.451301000000000119e-01 1.044385611833330074e+01 6.659680816666669889e-01 -1.503246000000000027e-01 9.389620521666669717e+00 6.284466633333329888e-01 -1.556671000000000027e-01 9.365269319999999453e+00 5.685768949999999711e-01 -1.572933999999999999e-01 9.202126339999999516e+00 1.807199866666669985e-01 -1.610100999999999893e-01 9.725111731666670423e+00 5.526473100000000027e-01 -1.662526000000000004e-01 8.453553321666669618e+00 5.170390433333329483e-01 -1.706808999999999965e-01 8.508661829999999426e+00 1.525917300000000087e-01 -1.716285999999999923e-01 8.248625778333330771e+00 4.912094450000000223e-01 -1.771963000000000010e-01 7.860151886666669974e+00 4.601271083333329792e-01 -1.828030999999999962e-01 8.179063558333330874e+00 4.431557566666670112e-01 -1.842987000000000097e-01 7.789301021666670266e+00 1.322509683333329966e-01 -1.883911000000000058e-01 7.284922560000000047e+00 4.239183200000000151e-01 -1.940553999999999890e-01 6.860865920000000173e+00 4.091373166666669725e-01 -1.983015999999999945e-01 6.984366938333329777e+00 1.143283233333329957e-01 -1.998445000000000082e-01 7.321059296666669880e+00 3.888106266666669919e-01 -2.056614999999999971e-01 6.516638536666669701e+00 3.691254600000000163e-01 -2.115482999999999947e-01 5.813378858333329902e+00 3.460794933333329881e-01 -2.120755000000000001e-01 6.410695145000000039e+00 1.044179233333329959e-01 -2.162748999999999922e-01 6.046752721666670105e+00 4.416217800000000193e-01 -2.260508999999999991e-01 5.970100884999999913e+00 9.257100833333330170e-02 -2.398570999999999898e-01 5.328183368333330172e+00 8.599138666666669706e-02 -2.537865999999999733e-01 5.025059630000000332e+00 7.909936500000000481e-02 -2.677086000000000188e-01 4.638679231666669622e+00 7.265197833333329747e-02 -2.818711999999999884e-01 4.320586221666670390e+00 6.748263000000000178e-02 -2.957293999999999756e-01 4.003143766666670267e+00 6.376038000000000538e-02 -3.099983000000000044e-01 3.820362695000000031e+00 5.861029000000000239e-02 -3.241628999999999761e-01 3.476478435000000200e+00 5.668581000000000314e-02 -3.389054000000000233e-01 3.203212216666670109e+00 5.052067666666670148e-02 -3.540212999999999832e-01 3.082675891666669887e+00 4.970334166666669912e-02 -3.688208000000000042e-01 2.852994409999999981e+00 4.575685000000000169e-02 -3.840975999999999835e-01 2.619206445000000105e+00 4.310591500000000159e-02 -3.990183999999999953e-01 2.447015261666670050e+00 4.192961333333330293e-02 -4.106022999999999756e-01 2.250148667666670210e+00 4.208387400000000028e-02 -4.137768000000000002e-01 2.199470903333330174e+00 3.941821333333329902e-02 -4.291927999999999854e-01 2.152990283333330090e+00 3.668624166666670239e-02 -4.294773000000000063e-01 2.066339865166670009e+00 3.559078633333329772e-02 -4.447362000000000259e-01 1.856158275000000080e+00 3.543832166666670280e-02 -4.465942999999999996e-01 1.863514126000000104e+00 3.172593550000000345e-02 -4.604721999999999982e-01 1.785743791666670077e+00 3.313367500000000132e-02 -4.684626000000000068e-01 1.701883971166670007e+00 3.125393900000000141e-02 -4.766304000000000096e-01 1.673134868333330028e+00 3.141082333333330284e-02 -4.833245999999999931e-01 1.561424375333329895e+00 2.963426116666669982e-02 -4.924697000000000102e-01 1.528741043333329941e+00 3.110879000000000075e-02 -5.045747000000000426e-01 1.440318964999999896e+00 2.730927600000000038e-02 -5.084248000000000101e-01 1.414442154999999923e+00 2.852017166666670142e-02 -5.229823000000000111e-01 1.195010044500000035e+00 2.544837383333330150e-02 -5.250753000000000226e-01 1.305492214999999900e+00 2.666661666666670163e-02 -5.418418000000000401e-01 1.152673440000000049e+00 2.608773333333330030e-02 -5.443057999999999508e-01 1.145610492499999911e+00 2.585580999999999990e-02 -5.584759999999999724e-01 1.067225758333329999e+00 2.525753999999999846e-02 -5.611642999999999493e-01 1.067666433166670092e+00 2.357715833333329930e-02 -5.755700000000000260e-01 1.029394661666670041e+00 2.355942499999999842e-02 -5.833063000000000553e-01 9.377488744999999959e-01 2.319254466666669998e-02 -5.929195000000000437e-01 9.657185166666669707e-01 2.274125999999999925e-02 -6.004707000000000239e-01 8.602252591666670334e-01 2.200228683333330104e-02 -6.100906000000000384e-01 8.435776883333330201e-01 2.182633499999999879e-02 -6.217470000000000496e-01 7.760975660000000165e-01 2.134885499999999992e-02 -6.276903999999999817e-01 7.741666183333330009e-01 2.058969000000000077e-02 -6.410972000000000337e-01 7.019246166666669451e-01 1.908517183333329967e-02 -6.449108999999999536e-01 6.851353900000000108e-01 2.095862666666669857e-02 -6.654345000000000399e-01 5.961630181666669470e-01 1.818150283333330036e-02 -6.842517000000000182e-01 5.507593983333329835e-01 2.023759049999999948e-02 -7.056883000000000461e-01 4.903288296666670210e-01 1.717216466666670119e-02 -7.257436999999999916e-01 4.865799499999999833e-01 1.843612033333329875e-02 -7.489183000000000368e-01 4.252237993333329857e-01 1.512044316666670031e-02 -7.718749999999999778e-01 3.910920323333330062e-01 1.713838283333329882e-02 -7.919618000000000491e-01 3.921714671666670093e-01 1.515910683333330025e-02 -8.153685999999999989e-01 3.357406613333330236e-01 1.534501599999999952e-02 -8.363026999999999544e-01 3.075498956666670169e-01 1.460560383333329992e-02 -8.617884000000000100e-01 2.857851470000000171e-01 1.374501849999999921e-02 -8.844872000000000289e-01 2.740424961666669823e-01 1.443190633333329975e-02 -9.079890000000000461e-01 2.574230581666669959e-01 1.269050000000000039e-02 -9.332829999999999737e-01 2.258197691666669893e-01 1.359980449999999980e-02 -9.550178000000000278e-01 1.934376846666669980e-01 1.273933533333329940e-02 -9.811271999999999771e-01 1.665732448333329951e-01 1.188447333333329976e-02 -1.006633399999999900e+00 1.640185443333329884e-01 1.234030849999999922e-02 -1.030228200000000038e+00 1.357939996666669979e-01 1.165456533333330061e-02 -1.057601100000000072e+00 1.607766528333330058e-01 1.089187166666670016e-02 -1.084413199999999966e+00 1.505459054999999935e-01 1.123158833333329915e-02 -1.109710100000000033e+00 1.282342724999999961e-01 1.086581349999999994e-02 -1.137554500000000024e+00 1.161345933333329944e-01 1.041549200000000015e-02 +3.625710000000000044e-02 7.586499487000000386e+01 1.637401323166670153e+01 +4.070529999999999982e-02 4.481643682666670259e+01 1.134473448500000003e+01 +4.511769999999999670e-02 3.187475403666670104e+01 8.372120233333330219e+00 +4.959899999999999726e-02 2.997679580000000144e+01 6.801308398333329563e+00 +5.417079999999999812e-02 2.394855565499999983e+01 5.340431286666669664e+00 +5.869760000000000255e-02 2.142582576833330066e+01 4.594792676666670239e+00 +6.316149999999999542e-02 3.089957102166669856e+01 3.816311058333329953e+00 +6.774429999999999341e-02 2.654007947166670078e+01 3.169185818333330129e+00 +7.239929999999999977e-02 1.943375908333329960e+01 2.742530958333329938e+00 +7.695340000000000513e-02 1.976728253666669843e+01 2.443851029999999813e+00 +8.167670000000000485e-02 1.925900297000000094e+01 2.058348746666669893e+00 +8.642850000000000532e-02 1.891829230833329945e+01 1.858069830000000033e+00 +9.110319999999999530e-02 1.827805419833330092e+01 1.639507476666669961e+00 +9.577460000000000140e-02 1.569160155166670023e+01 1.504524439999999963e+00 +1.005346000000000017e-01 1.326347007166669911e+01 1.315847523333329994e+00 +1.052808999999999967e-01 1.528716061000000082e+01 1.240626203333329958e+00 +1.100316999999999962e-01 1.357029930000000029e+01 1.108701733333329997e+00 +1.148871000000000059e-01 1.268526336333330029e+01 1.008324261666670107e+00 +1.198237999999999942e-01 1.157206131499999913e+01 9.266636050000000013e-01 +1.248187000000000046e-01 1.139260776499999928e+01 8.664271866666669597e-01 +1.298877999999999977e-01 1.288652256499999993e+01 7.969746983333330093e-01 +1.349605999999999861e-01 1.079102049499999971e+01 7.560191466666670301e-01 +1.399791999999999981e-01 1.105679143000000053e+01 6.920319183333329960e-01 +1.451301000000000119e-01 1.044385611833330074e+01 6.659680816666669889e-01 +1.503246000000000027e-01 9.389620521666669717e+00 6.284466633333329888e-01 +1.556671000000000027e-01 9.365269319999999453e+00 5.685768949999999711e-01 +1.572933999999999999e-01 9.202126339999999516e+00 1.807199866666669985e-01 +1.610100999999999893e-01 9.725111731666670423e+00 5.526473100000000027e-01 +1.662526000000000004e-01 8.453553321666669618e+00 5.170390433333329483e-01 +1.706808999999999965e-01 8.508661829999999426e+00 1.525917300000000087e-01 +1.716285999999999923e-01 8.248625778333330771e+00 4.912094450000000223e-01 +1.771963000000000010e-01 7.860151886666669974e+00 4.601271083333329792e-01 +1.828030999999999962e-01 8.179063558333330874e+00 4.431557566666670112e-01 +1.842987000000000097e-01 7.789301021666670266e+00 1.322509683333329966e-01 +1.883911000000000058e-01 7.284922560000000047e+00 4.239183200000000151e-01 +1.940553999999999890e-01 6.860865920000000173e+00 4.091373166666669725e-01 +1.983015999999999945e-01 6.984366938333329777e+00 1.143283233333329957e-01 +1.998445000000000082e-01 7.321059296666669880e+00 3.888106266666669919e-01 +2.056614999999999971e-01 6.516638536666669701e+00 3.691254600000000163e-01 +2.115482999999999947e-01 5.813378858333329902e+00 3.460794933333329881e-01 +2.120755000000000001e-01 6.410695145000000039e+00 1.044179233333329959e-01 +2.162748999999999922e-01 6.046752721666670105e+00 4.416217800000000193e-01 +2.260508999999999991e-01 5.970100884999999913e+00 9.257100833333330170e-02 +2.398570999999999898e-01 5.328183368333330172e+00 8.599138666666669706e-02 +2.537865999999999733e-01 5.025059630000000332e+00 7.909936500000000481e-02 +2.677086000000000188e-01 4.638679231666669622e+00 7.265197833333329747e-02 +2.818711999999999884e-01 4.320586221666670390e+00 6.748263000000000178e-02 +2.957293999999999756e-01 4.003143766666670267e+00 6.376038000000000538e-02 +3.099983000000000044e-01 3.820362695000000031e+00 5.861029000000000239e-02 +3.241628999999999761e-01 3.476478435000000200e+00 5.668581000000000314e-02 +3.389054000000000233e-01 3.203212216666670109e+00 5.052067666666670148e-02 +3.540212999999999832e-01 3.082675891666669887e+00 4.970334166666669912e-02 +3.688208000000000042e-01 2.852994409999999981e+00 4.575685000000000169e-02 +3.840975999999999835e-01 2.619206445000000105e+00 4.310591500000000159e-02 +3.990183999999999953e-01 2.447015261666670050e+00 4.192961333333330293e-02 +4.106022999999999756e-01 2.250148667666670210e+00 4.208387400000000028e-02 +4.137768000000000002e-01 2.199470903333330174e+00 3.941821333333329902e-02 +4.291927999999999854e-01 2.152990283333330090e+00 3.668624166666670239e-02 +4.294773000000000063e-01 2.066339865166670009e+00 3.559078633333329772e-02 +4.447362000000000259e-01 1.856158275000000080e+00 3.543832166666670280e-02 +4.465942999999999996e-01 1.863514126000000104e+00 3.172593550000000345e-02 +4.604721999999999982e-01 1.785743791666670077e+00 3.313367500000000132e-02 +4.684626000000000068e-01 1.701883971166670007e+00 3.125393900000000141e-02 +4.766304000000000096e-01 1.673134868333330028e+00 3.141082333333330284e-02 +4.833245999999999931e-01 1.561424375333329895e+00 2.963426116666669982e-02 +4.924697000000000102e-01 1.528741043333329941e+00 3.110879000000000075e-02 +5.045747000000000426e-01 1.440318964999999896e+00 2.730927600000000038e-02 +5.084248000000000101e-01 1.414442154999999923e+00 2.852017166666670142e-02 +5.229823000000000111e-01 1.195010044500000035e+00 2.544837383333330150e-02 +5.250753000000000226e-01 1.305492214999999900e+00 2.666661666666670163e-02 +5.418418000000000401e-01 1.152673440000000049e+00 2.608773333333330030e-02 +5.443057999999999508e-01 1.145610492499999911e+00 2.585580999999999990e-02 +5.584759999999999724e-01 1.067225758333329999e+00 2.525753999999999846e-02 +5.611642999999999493e-01 1.067666433166670092e+00 2.357715833333329930e-02 +5.755700000000000260e-01 1.029394661666670041e+00 2.355942499999999842e-02 +5.833063000000000553e-01 9.377488744999999959e-01 2.319254466666669998e-02 +5.929195000000000437e-01 9.657185166666669707e-01 2.274125999999999925e-02 +6.004707000000000239e-01 8.602252591666670334e-01 2.200228683333330104e-02 +6.100906000000000384e-01 8.435776883333330201e-01 2.182633499999999879e-02 +6.217470000000000496e-01 7.760975660000000165e-01 2.134885499999999992e-02 +6.276903999999999817e-01 7.741666183333330009e-01 2.058969000000000077e-02 +6.410972000000000337e-01 7.019246166666669451e-01 1.908517183333329967e-02 +6.449108999999999536e-01 6.851353900000000108e-01 2.095862666666669857e-02 +6.654345000000000399e-01 5.961630181666669470e-01 1.818150283333330036e-02 +6.842517000000000182e-01 5.507593983333329835e-01 2.023759049999999948e-02 +7.056883000000000461e-01 4.903288296666670210e-01 1.717216466666670119e-02 +7.257436999999999916e-01 4.865799499999999833e-01 1.843612033333329875e-02 +7.489183000000000368e-01 4.252237993333329857e-01 1.512044316666670031e-02 +7.718749999999999778e-01 3.910920323333330062e-01 1.713838283333329882e-02 +7.919618000000000491e-01 3.921714671666670093e-01 1.515910683333330025e-02 +8.153685999999999989e-01 3.357406613333330236e-01 1.534501599999999952e-02 +8.363026999999999544e-01 3.075498956666670169e-01 1.460560383333329992e-02 +8.617884000000000100e-01 2.857851470000000171e-01 1.374501849999999921e-02 +8.844872000000000289e-01 2.740424961666669823e-01 1.443190633333329975e-02 +9.079890000000000461e-01 2.574230581666669959e-01 1.269050000000000039e-02 +9.332829999999999737e-01 2.258197691666669893e-01 1.359980449999999980e-02 +9.550178000000000278e-01 1.934376846666669980e-01 1.273933533333329940e-02 +9.811271999999999771e-01 1.665732448333329951e-01 1.188447333333329976e-02 +1.006633399999999900e+00 1.640185443333329884e-01 1.234030849999999922e-02 +1.030228200000000038e+00 1.357939996666669979e-01 1.165456533333330061e-02 +1.057601100000000072e+00 1.607766528333330058e-01 1.089187166666670016e-02 +1.084413199999999966e+00 1.505459054999999935e-01 1.123158833333329915e-02 +1.109710100000000033e+00 1.282342724999999961e-01 1.086581349999999994e-02 +1.137554500000000024e+00 1.161345933333329944e-01 1.041549200000000015e-02 1.165834400000000048e+00 1.239725849999999963e-01 1.022116500000000081e-02 \ No newline at end of file diff --git a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv index c04b643c3..c869ca7de 100644 --- a/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv +++ b/test/trend_test_data/FeNiB_perpendicular_Bersweiler_et_al/9_600_1340_10.csv @@ -1,105 +1,105 @@ -3.625239999999999713e-02 5.114892415500000311e+01 1.631213251166670020e+01 -4.070000000000000007e-02 4.576787608166669941e+01 1.134772132833330005e+01 -4.511180000000000051e-02 4.331816215999999997e+01 8.407984515000000769e+00 -4.959249999999999770e-02 2.519454865000000154e+01 6.784784965000000057e+00 -5.416379999999999806e-02 1.407789967999999980e+01 5.302135776666670353e+00 -5.868999999999999911e-02 1.337527417166669963e+01 4.558895663333330184e+00 -6.315320000000000655e-02 2.088227957833329995e+01 3.767553325000000175e+00 -6.773540000000000116e-02 2.352067832833330030e+01 3.153463791666669902e+00 -7.238989999999999314e-02 1.459065788833330046e+01 2.714546644999999980e+00 -7.694339999999999513e-02 1.643097480333329941e+01 2.423213508333330157e+00 -8.166600000000000248e-02 1.564276924666670077e+01 2.035339249999999822e+00 -8.641719999999999957e-02 1.609254856500000130e+01 1.837833853333330048e+00 -9.109140000000000292e-02 1.279946007166670086e+01 1.598433549999999981e+00 -9.576210000000000278e-02 1.168004799999999932e+01 1.472505774999999906e+00 -1.005216000000000026e-01 1.239115217500000021e+01 1.308776653333330042e+00 -1.052672000000000052e-01 1.104442360666669920e+01 1.203200884999999998e+00 -1.100174000000000013e-01 1.264824788499999997e+01 1.100505863333330003e+00 -1.148721999999999938e-01 1.068150069333329988e+01 9.895295950000000396e-01 -1.198083000000000065e-01 1.062919121333329997e+01 9.177280949999999660e-01 -1.248023999999999939e-01 8.480228023333330256e+00 8.376397483333329896e-01 -1.298709000000000113e-01 1.054387282333330056e+01 7.736622133333329598e-01 -1.349431000000000103e-01 8.823326103333329229e+00 7.353996000000000421e-01 -1.399610000000000021e-01 9.107303678333330765e+00 6.707318450000000487e-01 -1.451112999999999986e-01 7.568946575000000010e+00 6.354211899999999691e-01 -1.503050999999999970e-01 7.486937655000000191e+00 6.076642716666670330e-01 -1.556469000000000047e-01 8.316071640000000542e+00 5.572019216666670438e-01 -1.572933999999999999e-01 8.082806423333330770e+00 1.772221983333329975e-01 -1.609891999999999990e-01 8.406204656666670161e+00 5.374420016666670019e-01 -1.662309999999999899e-01 7.305961626666669595e+00 5.035922400000000243e-01 -1.706808999999999965e-01 7.409980823333330413e+00 1.490785450000000067e-01 -1.716062999999999894e-01 7.126663556666669841e+00 4.782201200000000263e-01 -1.771733000000000058e-01 6.104670323333330373e+00 4.398585833333329975e-01 -1.827794000000000085e-01 6.314649313333330127e+00 4.207942599999999755e-01 -1.842987000000000097e-01 6.985669296666669581e+00 1.295300000000000062e-01 -1.883665999999999952e-01 7.196837438333330006e+00 4.229003000000000068e-01 -1.940302000000000138e-01 5.456149725000000394e+00 3.926154199999999928e-01 -1.983015999999999945e-01 6.101519538333329606e+00 1.111746183333330029e-01 -1.998185000000000100e-01 6.715507050000000255e+00 3.818104066666669905e-01 -2.056348000000000065e-01 5.954089436666669677e+00 3.622545733333329965e-01 -2.115208000000000088e-01 5.823000606666670187e+00 3.462099583333330122e-01 -2.120755000000000001e-01 5.689073146666670411e+00 1.016859966666670001e-01 -2.162467999999999890e-01 5.274567024999999632e+00 4.291691899999999782e-01 -2.260508999999999991e-01 5.306054011666669901e+00 9.002336499999999408e-02 -2.398570999999999898e-01 4.872989734999999989e+00 8.416759833333330165e-02 -2.537865999999999733e-01 4.590923198333330291e+00 7.736351666666670124e-02 -2.677086000000000188e-01 4.288802803333330083e+00 7.121471833333330170e-02 -2.818711999999999884e-01 4.093612151666669696e+00 6.655526166666669852e-02 -2.957293999999999756e-01 3.790488160000000217e+00 6.286535166666669394e-02 -3.099983000000000044e-01 3.646502630000000078e+00 5.789795166666669712e-02 -3.241628999999999761e-01 3.269809508333330061e+00 5.578990999999999811e-02 -3.389054000000000233e-01 3.057003066666669877e+00 4.992672166666670130e-02 -3.540212999999999832e-01 3.010102380000000188e+00 4.942106333333329965e-02 -3.688208000000000042e-01 2.669906414999999811e+00 4.496581333333329877e-02 -3.840975999999999835e-01 2.619258584999999862e+00 4.314465499999999704e-02 -3.990183999999999953e-01 2.335828473333330102e+00 4.143680999999999753e-02 -4.106379000000000001e-01 2.148179208166669962e+00 4.160297799999999879e-02 -4.137768000000000002e-01 2.129094906666670006e+00 3.911823833333329808e-02 -4.291927999999999854e-01 2.070782439999999891e+00 3.633175833333329718e-02 -4.295145000000000213e-01 2.006558257333329820e+00 3.534480766666669993e-02 -4.447362000000000259e-01 1.796411879999999961e+00 3.518650999999999723e-02 -4.466328999999999994e-01 1.795892682000000073e+00 3.145603500000000025e-02 -4.604721999999999982e-01 1.744876515000000072e+00 3.296921333333330262e-02 -4.685032000000000085e-01 1.640983006833329982e+00 3.099933850000000102e-02 -4.766304000000000096e-01 1.643527214999999986e+00 3.129624333333329983e-02 -4.833663999999999739e-01 1.494623838666669924e+00 2.933965966666670158e-02 -4.924697000000000102e-01 1.485128543333330109e+00 3.092004166666669981e-02 -5.046184000000000225e-01 1.428664912499999939e+00 2.726148050000000087e-02 -5.084248000000000101e-01 1.392996424999999983e+00 2.844018666666670025e-02 -5.230276000000000369e-01 1.160762609500000098e+00 2.531033383333329903e-02 -5.250753000000000226e-01 1.272159111666669951e+00 2.652694499999999969e-02 -5.418418000000000401e-01 1.157124196666670102e+00 2.613007999999999997e-02 -5.443529999999999758e-01 1.137421045666670016e+00 2.582160033333329857e-02 -5.584759999999999724e-01 1.068463686666669910e+00 2.528335666666670090e-02 -5.612129000000000145e-01 1.030207043666669930e+00 2.342105016666670009e-02 -5.755700000000000260e-01 9.590708749999999894e-01 2.323855999999999838e-02 -5.833568000000000087e-01 9.226566683333330410e-01 2.312843766666669923e-02 -5.929195000000000437e-01 9.361494049999999900e-01 2.261169999999999847e-02 -6.005226999999999649e-01 8.377321681666669573e-01 2.190618299999999921e-02 -6.100906000000000384e-01 8.074355933333330348e-01 2.165867833333329912e-02 -6.218008000000000424e-01 7.338905468333329907e-01 2.116956166666670094e-02 -6.276903999999999817e-01 7.588048750000000453e-01 2.052974999999999939e-02 -6.411527999999999672e-01 6.602236648333329461e-01 1.891721183333330142e-02 -6.449108999999999536e-01 6.976061483333330093e-01 2.103810166666670103e-02 -6.654921999999999782e-01 5.868389913333329488e-01 1.814479133333329886e-02 -6.843110000000000026e-01 5.442379206666669855e-01 2.020865366666670104e-02 -7.057493999999999712e-01 4.561023925000000090e-01 1.703726683333330050e-02 -7.258065000000000211e-01 4.680557555000000036e-01 1.835656600000000124e-02 -7.489831000000000127e-01 4.286472281666670048e-01 1.513358700000000043e-02 -7.719418000000000113e-01 3.942902281666669784e-01 1.715291783333329836e-02 -7.920304000000000233e-01 3.917498161666669865e-01 1.515774683333329965e-02 -8.154392000000000307e-01 3.437863165000000221e-01 1.537817166666670052e-02 -8.363751000000000380e-01 2.882515494999999817e-01 1.453092849999999998e-02 -8.618630000000000457e-01 2.511196196666670155e-01 1.361783299999999933e-02 -8.845638000000000112e-01 2.644882184999999830e-01 1.439263916666670001e-02 -9.080675999999999748e-01 2.444909116666670046e-01 1.264447816666670020e-02 -9.333637999999999657e-01 2.291532736666669900e-01 1.361314100000000048e-02 -9.551005000000000189e-01 1.942403736666669933e-01 1.274254833333329957e-02 -9.812121999999999788e-01 1.854263468333330056e-01 1.195107366666670057e-02 -1.006720599999999965e+00 1.833105325000000119e-01 1.241118433333330065e-02 -1.030317399999999939e+00 1.560276093333330116e-01 1.172809033333330024e-02 -1.057692700000000041e+00 1.687616888333330067e-01 1.091902633333330028e-02 -1.084507099999999946e+00 1.609880563333329906e-01 1.126864266666669986e-02 -1.109806099999999907e+00 1.237764021666669934e-01 1.085079116666669979e-02 -1.137653000000000025e+00 1.252411816666670064e-01 1.044549983333330039e-02 +3.625239999999999713e-02 5.114892415500000311e+01 1.631213251166670020e+01 +4.070000000000000007e-02 4.576787608166669941e+01 1.134772132833330005e+01 +4.511180000000000051e-02 4.331816215999999997e+01 8.407984515000000769e+00 +4.959249999999999770e-02 2.519454865000000154e+01 6.784784965000000057e+00 +5.416379999999999806e-02 1.407789967999999980e+01 5.302135776666670353e+00 +5.868999999999999911e-02 1.337527417166669963e+01 4.558895663333330184e+00 +6.315320000000000655e-02 2.088227957833329995e+01 3.767553325000000175e+00 +6.773540000000000116e-02 2.352067832833330030e+01 3.153463791666669902e+00 +7.238989999999999314e-02 1.459065788833330046e+01 2.714546644999999980e+00 +7.694339999999999513e-02 1.643097480333329941e+01 2.423213508333330157e+00 +8.166600000000000248e-02 1.564276924666670077e+01 2.035339249999999822e+00 +8.641719999999999957e-02 1.609254856500000130e+01 1.837833853333330048e+00 +9.109140000000000292e-02 1.279946007166670086e+01 1.598433549999999981e+00 +9.576210000000000278e-02 1.168004799999999932e+01 1.472505774999999906e+00 +1.005216000000000026e-01 1.239115217500000021e+01 1.308776653333330042e+00 +1.052672000000000052e-01 1.104442360666669920e+01 1.203200884999999998e+00 +1.100174000000000013e-01 1.264824788499999997e+01 1.100505863333330003e+00 +1.148721999999999938e-01 1.068150069333329988e+01 9.895295950000000396e-01 +1.198083000000000065e-01 1.062919121333329997e+01 9.177280949999999660e-01 +1.248023999999999939e-01 8.480228023333330256e+00 8.376397483333329896e-01 +1.298709000000000113e-01 1.054387282333330056e+01 7.736622133333329598e-01 +1.349431000000000103e-01 8.823326103333329229e+00 7.353996000000000421e-01 +1.399610000000000021e-01 9.107303678333330765e+00 6.707318450000000487e-01 +1.451112999999999986e-01 7.568946575000000010e+00 6.354211899999999691e-01 +1.503050999999999970e-01 7.486937655000000191e+00 6.076642716666670330e-01 +1.556469000000000047e-01 8.316071640000000542e+00 5.572019216666670438e-01 +1.572933999999999999e-01 8.082806423333330770e+00 1.772221983333329975e-01 +1.609891999999999990e-01 8.406204656666670161e+00 5.374420016666670019e-01 +1.662309999999999899e-01 7.305961626666669595e+00 5.035922400000000243e-01 +1.706808999999999965e-01 7.409980823333330413e+00 1.490785450000000067e-01 +1.716062999999999894e-01 7.126663556666669841e+00 4.782201200000000263e-01 +1.771733000000000058e-01 6.104670323333330373e+00 4.398585833333329975e-01 +1.827794000000000085e-01 6.314649313333330127e+00 4.207942599999999755e-01 +1.842987000000000097e-01 6.985669296666669581e+00 1.295300000000000062e-01 +1.883665999999999952e-01 7.196837438333330006e+00 4.229003000000000068e-01 +1.940302000000000138e-01 5.456149725000000394e+00 3.926154199999999928e-01 +1.983015999999999945e-01 6.101519538333329606e+00 1.111746183333330029e-01 +1.998185000000000100e-01 6.715507050000000255e+00 3.818104066666669905e-01 +2.056348000000000065e-01 5.954089436666669677e+00 3.622545733333329965e-01 +2.115208000000000088e-01 5.823000606666670187e+00 3.462099583333330122e-01 +2.120755000000000001e-01 5.689073146666670411e+00 1.016859966666670001e-01 +2.162467999999999890e-01 5.274567024999999632e+00 4.291691899999999782e-01 +2.260508999999999991e-01 5.306054011666669901e+00 9.002336499999999408e-02 +2.398570999999999898e-01 4.872989734999999989e+00 8.416759833333330165e-02 +2.537865999999999733e-01 4.590923198333330291e+00 7.736351666666670124e-02 +2.677086000000000188e-01 4.288802803333330083e+00 7.121471833333330170e-02 +2.818711999999999884e-01 4.093612151666669696e+00 6.655526166666669852e-02 +2.957293999999999756e-01 3.790488160000000217e+00 6.286535166666669394e-02 +3.099983000000000044e-01 3.646502630000000078e+00 5.789795166666669712e-02 +3.241628999999999761e-01 3.269809508333330061e+00 5.578990999999999811e-02 +3.389054000000000233e-01 3.057003066666669877e+00 4.992672166666670130e-02 +3.540212999999999832e-01 3.010102380000000188e+00 4.942106333333329965e-02 +3.688208000000000042e-01 2.669906414999999811e+00 4.496581333333329877e-02 +3.840975999999999835e-01 2.619258584999999862e+00 4.314465499999999704e-02 +3.990183999999999953e-01 2.335828473333330102e+00 4.143680999999999753e-02 +4.106379000000000001e-01 2.148179208166669962e+00 4.160297799999999879e-02 +4.137768000000000002e-01 2.129094906666670006e+00 3.911823833333329808e-02 +4.291927999999999854e-01 2.070782439999999891e+00 3.633175833333329718e-02 +4.295145000000000213e-01 2.006558257333329820e+00 3.534480766666669993e-02 +4.447362000000000259e-01 1.796411879999999961e+00 3.518650999999999723e-02 +4.466328999999999994e-01 1.795892682000000073e+00 3.145603500000000025e-02 +4.604721999999999982e-01 1.744876515000000072e+00 3.296921333333330262e-02 +4.685032000000000085e-01 1.640983006833329982e+00 3.099933850000000102e-02 +4.766304000000000096e-01 1.643527214999999986e+00 3.129624333333329983e-02 +4.833663999999999739e-01 1.494623838666669924e+00 2.933965966666670158e-02 +4.924697000000000102e-01 1.485128543333330109e+00 3.092004166666669981e-02 +5.046184000000000225e-01 1.428664912499999939e+00 2.726148050000000087e-02 +5.084248000000000101e-01 1.392996424999999983e+00 2.844018666666670025e-02 +5.230276000000000369e-01 1.160762609500000098e+00 2.531033383333329903e-02 +5.250753000000000226e-01 1.272159111666669951e+00 2.652694499999999969e-02 +5.418418000000000401e-01 1.157124196666670102e+00 2.613007999999999997e-02 +5.443529999999999758e-01 1.137421045666670016e+00 2.582160033333329857e-02 +5.584759999999999724e-01 1.068463686666669910e+00 2.528335666666670090e-02 +5.612129000000000145e-01 1.030207043666669930e+00 2.342105016666670009e-02 +5.755700000000000260e-01 9.590708749999999894e-01 2.323855999999999838e-02 +5.833568000000000087e-01 9.226566683333330410e-01 2.312843766666669923e-02 +5.929195000000000437e-01 9.361494049999999900e-01 2.261169999999999847e-02 +6.005226999999999649e-01 8.377321681666669573e-01 2.190618299999999921e-02 +6.100906000000000384e-01 8.074355933333330348e-01 2.165867833333329912e-02 +6.218008000000000424e-01 7.338905468333329907e-01 2.116956166666670094e-02 +6.276903999999999817e-01 7.588048750000000453e-01 2.052974999999999939e-02 +6.411527999999999672e-01 6.602236648333329461e-01 1.891721183333330142e-02 +6.449108999999999536e-01 6.976061483333330093e-01 2.103810166666670103e-02 +6.654921999999999782e-01 5.868389913333329488e-01 1.814479133333329886e-02 +6.843110000000000026e-01 5.442379206666669855e-01 2.020865366666670104e-02 +7.057493999999999712e-01 4.561023925000000090e-01 1.703726683333330050e-02 +7.258065000000000211e-01 4.680557555000000036e-01 1.835656600000000124e-02 +7.489831000000000127e-01 4.286472281666670048e-01 1.513358700000000043e-02 +7.719418000000000113e-01 3.942902281666669784e-01 1.715291783333329836e-02 +7.920304000000000233e-01 3.917498161666669865e-01 1.515774683333329965e-02 +8.154392000000000307e-01 3.437863165000000221e-01 1.537817166666670052e-02 +8.363751000000000380e-01 2.882515494999999817e-01 1.453092849999999998e-02 +8.618630000000000457e-01 2.511196196666670155e-01 1.361783299999999933e-02 +8.845638000000000112e-01 2.644882184999999830e-01 1.439263916666670001e-02 +9.080675999999999748e-01 2.444909116666670046e-01 1.264447816666670020e-02 +9.333637999999999657e-01 2.291532736666669900e-01 1.361314100000000048e-02 +9.551005000000000189e-01 1.942403736666669933e-01 1.274254833333329957e-02 +9.812121999999999788e-01 1.854263468333330056e-01 1.195107366666670057e-02 +1.006720599999999965e+00 1.833105325000000119e-01 1.241118433333330065e-02 +1.030317399999999939e+00 1.560276093333330116e-01 1.172809033333330024e-02 +1.057692700000000041e+00 1.687616888333330067e-01 1.091902633333330028e-02 +1.084507099999999946e+00 1.609880563333329906e-01 1.126864266666669986e-02 +1.109806099999999907e+00 1.237764021666669934e-01 1.085079116666669979e-02 +1.137653000000000025e+00 1.252411816666670064e-01 1.044549983333330039e-02 1.165935399999999955e+00 1.143170270000000016e-01 1.018908599999999998e-02 \ No newline at end of file diff --git a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv index 92b38bcf5..160f11da2 100644 --- a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv +++ b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/1_33_1640_22.874115.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 5.247581629999999677e+03 5.122294999999999732e+01 -3.090999999999999998e-02 3.911350339999999960e+03 4.422301999999999822e+01 -3.452999999999999819e-02 2.897911560000000009e+03 3.806515000000000271e+01 -3.812999999999999723e-02 2.151411560000000009e+03 3.279795000000000016e+01 -4.173999999999999932e-02 1.629610879999999952e+03 2.854479999999999862e+01 -4.542999999999999816e-02 1.229812930000000051e+03 2.479730999999999952e+01 -4.646000000000000130e-02 1.191418850000000020e+03 2.440716000000000108e+01 -4.909000000000000169e-02 9.198557799999999816e+02 2.144593000000000060e+01 -5.254999999999999949e-02 7.981839199999999437e+02 1.997728999999999999e+01 -5.270999999999999991e-02 7.205761899999999969e+02 1.898125999999999891e+01 -5.630999999999999894e-02 5.509914999999999736e+02 1.659806000000000026e+01 -5.870999999999999830e-02 5.012570499999999925e+02 1.583125000000000071e+01 -5.988000000000000267e-02 4.332142900000000054e+02 1.471757999999999988e+01 -6.353999999999999926e-02 3.420333299999999781e+02 1.307732999999999990e+01 -6.482999999999999874e-02 3.398080699999999865e+02 1.303472000000000008e+01 -6.716999999999999360e-02 2.726683699999999817e+02 1.167622000000000071e+01 -7.073000000000000120e-02 2.204248299999999858e+02 1.049821000000000026e+01 -7.095999999999999530e-02 2.235476199999999949e+02 1.057230999999999987e+01 -7.434999999999999942e-02 1.760958799999999940e+02 9.383390000000000342e+00 -7.724000000000000310e-02 1.542382200000000125e+02 8.781750000000000611e+00 -7.799999999999999989e-02 1.457825499999999863e+02 8.537639999999999674e+00 -8.164000000000000423e-02 1.201677600000000012e+02 7.751380000000000159e+00 -8.346000000000000640e-02 1.089934400000000068e+02 7.382189999999999586e+00 -8.525000000000000633e-02 9.836262000000000683e+01 7.012940000000000396e+00 -8.881999999999999618e-02 8.192439000000000249e+01 6.400170000000000137e+00 -8.962000000000000521e-02 7.733648999999999774e+01 6.218379999999999797e+00 -9.572999999999999565e-02 5.882012000000000285e+01 5.423099999999999810e+00 -1.018000000000000016e-01 4.406902000000000186e+01 4.694090000000000096e+00 -1.080300000000000010e-01 3.487624000000000279e+01 4.175900000000000389e+00 -1.141999999999999960e-01 2.769241999999999848e+01 3.721049999999999969e+00 -1.202399999999999997e-01 2.227824000000000026e+01 3.337530000000000108e+00 -1.263900000000000023e-01 1.858717000000000041e+01 3.048540000000000028e+00 -1.325999999999999956e-01 1.587791999999999959e+01 2.817619999999999791e+00 -1.388199999999999990e-01 1.416899000000000086e+01 2.661669999999999980e+00 -1.449499999999999955e-01 1.174597999999999942e+01 2.423430000000000195e+00 -1.509900000000000131e-01 1.047161000000000008e+01 2.288190000000000168e+00 -1.571599999999999941e-01 9.681599999999999540e+00 2.200180000000000025e+00 -1.633799999999999975e-01 8.894579999999999487e+00 2.108859999999999957e+00 -1.695599999999999885e-01 8.317479999999999762e+00 2.039299999999999891e+00 -1.756800000000000028e-01 7.913870000000000182e+00 1.989200000000000079e+00 -1.818599999999999939e-01 7.771530000000000271e+00 1.971230000000000038e+00 -1.880699999999999872e-01 7.882909999999999862e+00 1.985309999999999908e+00 -1.941799999999999915e-01 7.707720000000000127e+00 1.963130000000000042e+00 -2.002800000000000136e-01 7.676859999999999573e+00 1.959189999999999987e+00 -2.064199999999999924e-01 7.872259999999999813e+00 1.983970000000000011e+00 -2.126000000000000112e-01 7.870400000000000063e+00 1.983729999999999993e+00 -2.187500000000000000e-01 7.977940000000000254e+00 1.997239999999999904e+00 -2.248699999999999866e-01 8.152039999999999509e+00 2.018920000000000048e+00 -2.310500000000000054e-01 8.298420000000000130e+00 2.036960000000000104e+00 -2.372700000000000087e-01 8.716689999999999827e+00 2.087660000000000071e+00 -2.434399999999999897e-01 8.782600000000000406e+00 2.095540000000000180e+00 -2.495600000000000041e-01 8.933479999999999421e+00 2.113469999999999960e+00 -2.556899999999999729e-01 9.374109999999999943e+00 2.164960000000000218e+00 -2.618500000000000272e-01 9.457430000000000447e+00 2.174560000000000048e+00 -2.680500000000000105e-01 9.702469999999999928e+00 2.202550000000000008e+00 -2.742100000000000093e-01 9.923930000000000362e+00 2.227549999999999919e+00 -2.802999999999999936e-01 1.008966000000000030e+01 2.246070000000000011e+00 -2.864599999999999924e-01 1.031367999999999974e+01 2.270869999999999944e+00 -2.926699999999999857e-01 1.058960000000000079e+01 2.301039999999999974e+00 +2.732000000000000053e-02 5.247581629999999677e+03 5.122294999999999732e+01 +3.090999999999999998e-02 3.911350339999999960e+03 4.422301999999999822e+01 +3.452999999999999819e-02 2.897911560000000009e+03 3.806515000000000271e+01 +3.812999999999999723e-02 2.151411560000000009e+03 3.279795000000000016e+01 +4.173999999999999932e-02 1.629610879999999952e+03 2.854479999999999862e+01 +4.542999999999999816e-02 1.229812930000000051e+03 2.479730999999999952e+01 +4.646000000000000130e-02 1.191418850000000020e+03 2.440716000000000108e+01 +4.909000000000000169e-02 9.198557799999999816e+02 2.144593000000000060e+01 +5.254999999999999949e-02 7.981839199999999437e+02 1.997728999999999999e+01 +5.270999999999999991e-02 7.205761899999999969e+02 1.898125999999999891e+01 +5.630999999999999894e-02 5.509914999999999736e+02 1.659806000000000026e+01 +5.870999999999999830e-02 5.012570499999999925e+02 1.583125000000000071e+01 +5.988000000000000267e-02 4.332142900000000054e+02 1.471757999999999988e+01 +6.353999999999999926e-02 3.420333299999999781e+02 1.307732999999999990e+01 +6.482999999999999874e-02 3.398080699999999865e+02 1.303472000000000008e+01 +6.716999999999999360e-02 2.726683699999999817e+02 1.167622000000000071e+01 +7.073000000000000120e-02 2.204248299999999858e+02 1.049821000000000026e+01 +7.095999999999999530e-02 2.235476199999999949e+02 1.057230999999999987e+01 +7.434999999999999942e-02 1.760958799999999940e+02 9.383390000000000342e+00 +7.724000000000000310e-02 1.542382200000000125e+02 8.781750000000000611e+00 +7.799999999999999989e-02 1.457825499999999863e+02 8.537639999999999674e+00 +8.164000000000000423e-02 1.201677600000000012e+02 7.751380000000000159e+00 +8.346000000000000640e-02 1.089934400000000068e+02 7.382189999999999586e+00 +8.525000000000000633e-02 9.836262000000000683e+01 7.012940000000000396e+00 +8.881999999999999618e-02 8.192439000000000249e+01 6.400170000000000137e+00 +8.962000000000000521e-02 7.733648999999999774e+01 6.218379999999999797e+00 +9.572999999999999565e-02 5.882012000000000285e+01 5.423099999999999810e+00 +1.018000000000000016e-01 4.406902000000000186e+01 4.694090000000000096e+00 +1.080300000000000010e-01 3.487624000000000279e+01 4.175900000000000389e+00 +1.141999999999999960e-01 2.769241999999999848e+01 3.721049999999999969e+00 +1.202399999999999997e-01 2.227824000000000026e+01 3.337530000000000108e+00 +1.263900000000000023e-01 1.858717000000000041e+01 3.048540000000000028e+00 +1.325999999999999956e-01 1.587791999999999959e+01 2.817619999999999791e+00 +1.388199999999999990e-01 1.416899000000000086e+01 2.661669999999999980e+00 +1.449499999999999955e-01 1.174597999999999942e+01 2.423430000000000195e+00 +1.509900000000000131e-01 1.047161000000000008e+01 2.288190000000000168e+00 +1.571599999999999941e-01 9.681599999999999540e+00 2.200180000000000025e+00 +1.633799999999999975e-01 8.894579999999999487e+00 2.108859999999999957e+00 +1.695599999999999885e-01 8.317479999999999762e+00 2.039299999999999891e+00 +1.756800000000000028e-01 7.913870000000000182e+00 1.989200000000000079e+00 +1.818599999999999939e-01 7.771530000000000271e+00 1.971230000000000038e+00 +1.880699999999999872e-01 7.882909999999999862e+00 1.985309999999999908e+00 +1.941799999999999915e-01 7.707720000000000127e+00 1.963130000000000042e+00 +2.002800000000000136e-01 7.676859999999999573e+00 1.959189999999999987e+00 +2.064199999999999924e-01 7.872259999999999813e+00 1.983970000000000011e+00 +2.126000000000000112e-01 7.870400000000000063e+00 1.983729999999999993e+00 +2.187500000000000000e-01 7.977940000000000254e+00 1.997239999999999904e+00 +2.248699999999999866e-01 8.152039999999999509e+00 2.018920000000000048e+00 +2.310500000000000054e-01 8.298420000000000130e+00 2.036960000000000104e+00 +2.372700000000000087e-01 8.716689999999999827e+00 2.087660000000000071e+00 +2.434399999999999897e-01 8.782600000000000406e+00 2.095540000000000180e+00 +2.495600000000000041e-01 8.933479999999999421e+00 2.113469999999999960e+00 +2.556899999999999729e-01 9.374109999999999943e+00 2.164960000000000218e+00 +2.618500000000000272e-01 9.457430000000000447e+00 2.174560000000000048e+00 +2.680500000000000105e-01 9.702469999999999928e+00 2.202550000000000008e+00 +2.742100000000000093e-01 9.923930000000000362e+00 2.227549999999999919e+00 +2.802999999999999936e-01 1.008966000000000030e+01 2.246070000000000011e+00 +2.864599999999999924e-01 1.031367999999999974e+01 2.270869999999999944e+00 +2.926699999999999857e-01 1.058960000000000079e+01 2.301039999999999974e+00 2.988199999999999745e-01 1.062256999999999962e+01 2.304619999999999891e+00 \ No newline at end of file diff --git a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv index 831fa6a9d..80562dff5 100644 --- a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv +++ b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/2_42_1640_23.456895.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 3.883615650000000187e+03 4.406595000000000084e+01 -3.090000000000000038e-02 3.072013609999999971e+03 3.919192000000000320e+01 -3.452999999999999819e-02 2.355659860000000208e+03 3.431953000000000031e+01 -3.812999999999999723e-02 1.806985030000000052e+03 3.005815000000000126e+01 -4.173999999999999932e-02 1.389839799999999968e+03 2.636132999999999882e+01 -4.542000000000000204e-02 1.072684349999999995e+03 2.315906000000000020e+01 -4.644000000000000211e-02 9.624380499999999756e+02 2.193669999999999831e+01 -4.907999999999999863e-02 8.065360500000000457e+02 2.008153000000000077e+01 -5.253000000000000030e-02 6.666923000000000457e+02 1.825777000000000072e+01 -5.270999999999999991e-02 6.432540800000000445e+02 1.793395999999999901e+01 -5.630000000000000282e-02 4.985809499999999730e+02 1.578894000000000020e+01 -5.868999999999999911e-02 4.290448299999999904e+02 1.464658000000000015e+01 -5.986999999999999961e-02 3.918163299999999936e+02 1.399671999999999983e+01 -6.353000000000000314e-02 3.098850299999999720e+02 1.244758999999999993e+01 -6.481000000000000649e-02 2.946982499999999732e+02 1.213874000000000031e+01 -6.715999999999999748e-02 2.516384400000000028e+02 1.121692000000000000e+01 -7.072000000000000508e-02 2.028407500000000141e+02 1.007076999999999956e+01 -7.094000000000000306e-02 1.948358800000000031e+02 9.870050000000000878e+00 -7.434000000000000330e-02 1.633427599999999984e+02 9.037219999999999587e+00 -7.721000000000000085e-02 1.371933899999999937e+02 8.282310000000000727e+00 -7.799000000000000377e-02 1.347819700000000012e+02 8.209199999999999164e+00 -8.162999999999999423e-02 1.123165999999999940e+02 7.493879999999999875e+00 -8.343000000000000416e-02 9.602442000000000633e+01 6.929079999999999906e+00 -8.523999999999999633e-02 9.249591999999999814e+01 6.800589999999999691e+00 -8.880000000000000393e-02 7.934887999999999408e+01 6.298759999999999692e+00 -8.959000000000000297e-02 7.016214999999999691e+01 5.922930000000000028e+00 -9.568999999999999728e-02 5.357988000000000284e+01 5.175900000000000389e+00 -1.017699999999999994e-01 4.050641000000000247e+01 4.500359999999999694e+00 -1.079900000000000027e-01 3.194395000000000095e+01 3.996500000000000163e+00 -1.141599999999999976e-01 2.563089000000000084e+01 3.579870000000000108e+00 -1.202000000000000013e-01 2.144641999999999982e+01 3.274630000000000152e+00 -1.263499999999999901e-01 1.696240999999999843e+01 2.912249999999999783e+00 -1.325600000000000112e-01 1.453672000000000075e+01 2.695990000000000109e+00 -1.387700000000000045e-01 1.265718999999999994e+01 2.515670000000000073e+00 -1.449000000000000010e-01 1.114897000000000027e+01 2.361029999999999962e+00 -1.509399999999999908e-01 1.005156999999999989e+01 2.241830000000000211e+00 -1.571099999999999997e-01 9.313710000000000377e+00 2.157970000000000166e+00 -1.633300000000000030e-01 8.668530000000000513e+00 2.081890000000000018e+00 -1.695099999999999940e-01 7.810069999999999624e+00 1.976120000000000099e+00 -1.756300000000000083e-01 7.695079999999999920e+00 1.961519999999999930e+00 -1.817999999999999894e-01 7.222220000000000084e+00 1.900290000000000035e+00 -1.880100000000000104e-01 7.386999999999999567e+00 1.921850000000000058e+00 -1.941199999999999870e-01 7.239320000000000199e+00 1.902539999999999898e+00 -2.002200000000000091e-01 7.279099999999999682e+00 1.907759999999999900e+00 -2.063500000000000056e-01 7.406340000000000146e+00 1.924360000000000070e+00 -2.125299999999999967e-01 7.439199999999999591e+00 1.928630000000000067e+00 -2.186800000000000133e-01 7.556879999999999598e+00 1.943820000000000103e+00 -2.247899999999999898e-01 7.730520000000000280e+00 1.966029999999999944e+00 -2.309799999999999909e-01 8.106099999999999639e+00 2.013220000000000010e+00 -2.371999999999999942e-01 8.398609999999999687e+00 2.049220000000000041e+00 -2.433599999999999930e-01 8.171440000000000481e+00 2.021319999999999784e+00 -2.494800000000000073e-01 8.478289999999999438e+00 2.058920000000000083e+00 -2.556100000000000039e-01 8.796279999999999433e+00 2.097170000000000201e+00 -2.617700000000000027e-01 8.973420000000000840e+00 2.118189999999999795e+00 -2.679699999999999860e-01 9.270730000000000359e+00 2.152989999999999959e+00 -2.741299999999999848e-01 9.463879999999999626e+00 2.175300000000000011e+00 -2.802100000000000146e-01 9.409150000000000347e+00 2.169000000000000039e+00 -2.863700000000000134e-01 9.709509999999999863e+00 2.203349999999999920e+00 -2.925800000000000067e-01 9.851300000000000168e+00 2.219380000000000130e+00 +2.732000000000000053e-02 3.883615650000000187e+03 4.406595000000000084e+01 +3.090000000000000038e-02 3.072013609999999971e+03 3.919192000000000320e+01 +3.452999999999999819e-02 2.355659860000000208e+03 3.431953000000000031e+01 +3.812999999999999723e-02 1.806985030000000052e+03 3.005815000000000126e+01 +4.173999999999999932e-02 1.389839799999999968e+03 2.636132999999999882e+01 +4.542000000000000204e-02 1.072684349999999995e+03 2.315906000000000020e+01 +4.644000000000000211e-02 9.624380499999999756e+02 2.193669999999999831e+01 +4.907999999999999863e-02 8.065360500000000457e+02 2.008153000000000077e+01 +5.253000000000000030e-02 6.666923000000000457e+02 1.825777000000000072e+01 +5.270999999999999991e-02 6.432540800000000445e+02 1.793395999999999901e+01 +5.630000000000000282e-02 4.985809499999999730e+02 1.578894000000000020e+01 +5.868999999999999911e-02 4.290448299999999904e+02 1.464658000000000015e+01 +5.986999999999999961e-02 3.918163299999999936e+02 1.399671999999999983e+01 +6.353000000000000314e-02 3.098850299999999720e+02 1.244758999999999993e+01 +6.481000000000000649e-02 2.946982499999999732e+02 1.213874000000000031e+01 +6.715999999999999748e-02 2.516384400000000028e+02 1.121692000000000000e+01 +7.072000000000000508e-02 2.028407500000000141e+02 1.007076999999999956e+01 +7.094000000000000306e-02 1.948358800000000031e+02 9.870050000000000878e+00 +7.434000000000000330e-02 1.633427599999999984e+02 9.037219999999999587e+00 +7.721000000000000085e-02 1.371933899999999937e+02 8.282310000000000727e+00 +7.799000000000000377e-02 1.347819700000000012e+02 8.209199999999999164e+00 +8.162999999999999423e-02 1.123165999999999940e+02 7.493879999999999875e+00 +8.343000000000000416e-02 9.602442000000000633e+01 6.929079999999999906e+00 +8.523999999999999633e-02 9.249591999999999814e+01 6.800589999999999691e+00 +8.880000000000000393e-02 7.934887999999999408e+01 6.298759999999999692e+00 +8.959000000000000297e-02 7.016214999999999691e+01 5.922930000000000028e+00 +9.568999999999999728e-02 5.357988000000000284e+01 5.175900000000000389e+00 +1.017699999999999994e-01 4.050641000000000247e+01 4.500359999999999694e+00 +1.079900000000000027e-01 3.194395000000000095e+01 3.996500000000000163e+00 +1.141599999999999976e-01 2.563089000000000084e+01 3.579870000000000108e+00 +1.202000000000000013e-01 2.144641999999999982e+01 3.274630000000000152e+00 +1.263499999999999901e-01 1.696240999999999843e+01 2.912249999999999783e+00 +1.325600000000000112e-01 1.453672000000000075e+01 2.695990000000000109e+00 +1.387700000000000045e-01 1.265718999999999994e+01 2.515670000000000073e+00 +1.449000000000000010e-01 1.114897000000000027e+01 2.361029999999999962e+00 +1.509399999999999908e-01 1.005156999999999989e+01 2.241830000000000211e+00 +1.571099999999999997e-01 9.313710000000000377e+00 2.157970000000000166e+00 +1.633300000000000030e-01 8.668530000000000513e+00 2.081890000000000018e+00 +1.695099999999999940e-01 7.810069999999999624e+00 1.976120000000000099e+00 +1.756300000000000083e-01 7.695079999999999920e+00 1.961519999999999930e+00 +1.817999999999999894e-01 7.222220000000000084e+00 1.900290000000000035e+00 +1.880100000000000104e-01 7.386999999999999567e+00 1.921850000000000058e+00 +1.941199999999999870e-01 7.239320000000000199e+00 1.902539999999999898e+00 +2.002200000000000091e-01 7.279099999999999682e+00 1.907759999999999900e+00 +2.063500000000000056e-01 7.406340000000000146e+00 1.924360000000000070e+00 +2.125299999999999967e-01 7.439199999999999591e+00 1.928630000000000067e+00 +2.186800000000000133e-01 7.556879999999999598e+00 1.943820000000000103e+00 +2.247899999999999898e-01 7.730520000000000280e+00 1.966029999999999944e+00 +2.309799999999999909e-01 8.106099999999999639e+00 2.013220000000000010e+00 +2.371999999999999942e-01 8.398609999999999687e+00 2.049220000000000041e+00 +2.433599999999999930e-01 8.171440000000000481e+00 2.021319999999999784e+00 +2.494800000000000073e-01 8.478289999999999438e+00 2.058920000000000083e+00 +2.556100000000000039e-01 8.796279999999999433e+00 2.097170000000000201e+00 +2.617700000000000027e-01 8.973420000000000840e+00 2.118189999999999795e+00 +2.679699999999999860e-01 9.270730000000000359e+00 2.152989999999999959e+00 +2.741299999999999848e-01 9.463879999999999626e+00 2.175300000000000011e+00 +2.802100000000000146e-01 9.409150000000000347e+00 2.169000000000000039e+00 +2.863700000000000134e-01 9.709509999999999863e+00 2.203349999999999920e+00 +2.925800000000000067e-01 9.851300000000000168e+00 2.219380000000000130e+00 2.987299999999999955e-01 9.904920000000000613e+00 2.225410000000000110e+00 \ No newline at end of file diff --git a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv index 59e4cde42..6e68726d8 100644 --- a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv +++ b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/3_61_1640_23.748285.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 2.792353740000000016e+03 3.736545000000000272e+01 -3.090000000000000038e-02 2.271702040000000125e+03 3.370239000000000118e+01 -3.452000000000000207e-02 1.788897279999999910e+03 2.990733000000000175e+01 -3.812000000000000111e-02 1.407023470000000088e+03 2.652380000000000138e+01 -4.173000000000000320e-02 1.095009520000000066e+03 2.339882000000000062e+01 -4.542000000000000204e-02 8.376734699999999521e+02 2.046549999999999869e+01 -4.644000000000000211e-02 7.836296200000000454e+02 1.979430999999999941e+01 -4.907000000000000250e-02 6.414952399999999670e+02 1.790943000000000040e+01 -5.253000000000000030e-02 5.516777200000000221e+02 1.660839999999999961e+01 -5.269999999999999685e-02 5.141714299999999866e+02 1.603388999999999953e+01 -5.628999999999999976e-02 3.988418399999999906e+02 1.412165000000000070e+01 -5.868999999999999911e-02 3.579082799999999907e+02 1.337737000000000087e+01 -5.985999999999999654e-02 3.164397999999999911e+02 1.257854999999999990e+01 -6.351999999999999313e-02 2.486343500000000120e+02 1.114976000000000056e+01 -6.481000000000000649e-02 2.482066299999999899e+02 1.114016999999999946e+01 -6.715000000000000135e-02 2.006787799999999891e+02 1.001695999999999920e+01 -7.070999999999999508e-02 1.657927200000000028e+02 9.104739999999999611e+00 -7.094000000000000306e-02 1.667760000000000105e+02 9.131700000000000372e+00 -7.431999999999999718e-02 1.326982299999999952e+02 8.145500000000000185e+00 -7.721000000000000085e-02 1.181177100000000024e+02 7.684980000000000366e+00 -7.796999999999999764e-02 1.108474499999999949e+02 7.444709999999999717e+00 -8.161999999999999811e-02 9.087302999999999997e+01 6.740660000000000096e+00 -8.343000000000000416e-02 8.290343000000000018e+01 6.438299999999999912e+00 -8.522000000000000408e-02 7.588799000000000206e+01 6.159869999999999735e+00 -8.878999999999999393e-02 6.486343999999999710e+01 5.694890000000000008e+00 -8.959000000000000297e-02 6.133471999999999724e+01 5.537810000000000343e+00 -9.568999999999999728e-02 4.711737999999999715e+01 4.853729999999999656e+00 -1.017699999999999994e-01 3.554666000000000281e+01 4.215840000000000032e+00 -1.079900000000000027e-01 2.833098000000000027e+01 3.763710000000000111e+00 -1.141599999999999976e-01 2.318925000000000125e+01 3.405089999999999950e+00 -1.202000000000000013e-01 1.876435000000000031e+01 3.063029999999999919e+00 -1.263499999999999901e-01 1.568601999999999919e+01 2.800539999999999807e+00 -1.325600000000000112e-01 1.346410000000000018e+01 2.594619999999999926e+00 -1.387700000000000045e-01 1.173840000000000039e+01 2.422639999999999905e+00 -1.449000000000000010e-01 1.054757999999999996e+01 2.296469999999999789e+00 -1.509399999999999908e-01 9.084839999999999804e+00 2.131299999999999972e+00 -1.571099999999999997e-01 8.239589999999999748e+00 2.029729999999999812e+00 -1.633300000000000030e-01 7.767660000000000231e+00 1.970739999999999936e+00 -1.695099999999999940e-01 7.631929999999999659e+00 1.953449999999999909e+00 -1.756300000000000083e-01 7.253739999999999633e+00 1.904430000000000067e+00 -1.817999999999999894e-01 6.968580000000000219e+00 1.866630000000000011e+00 -1.880100000000000104e-01 7.029829999999999579e+00 1.874810000000000088e+00 -1.941199999999999870e-01 6.805609999999999715e+00 1.844670000000000032e+00 -2.002200000000000091e-01 7.007130000000000081e+00 1.871779999999999999e+00 -2.063500000000000056e-01 7.083709999999999951e+00 1.881979999999999986e+00 -2.125299999999999967e-01 6.971890000000000143e+00 1.867070000000000007e+00 -2.186800000000000133e-01 7.549360000000000070e+00 1.942849999999999966e+00 -2.247899999999999898e-01 7.451310000000000322e+00 1.930199999999999916e+00 -2.309799999999999909e-01 7.449589999999999712e+00 1.929969999999999963e+00 -2.371999999999999942e-01 7.776720000000000077e+00 1.971889999999999921e+00 -2.433599999999999930e-01 8.157130000000000436e+00 2.019550000000000178e+00 -2.494800000000000073e-01 8.339280000000000470e+00 2.041970000000000063e+00 -2.556100000000000039e-01 8.448100000000000165e+00 2.055250000000000021e+00 -2.617700000000000027e-01 8.746420000000000528e+00 2.091219999999999857e+00 -2.679699999999999860e-01 9.040720000000000312e+00 2.126110000000000166e+00 -2.741299999999999848e-01 9.130409999999999471e+00 2.136629999999999807e+00 -2.802100000000000146e-01 9.247719999999999274e+00 2.150319999999999787e+00 -2.863700000000000134e-01 9.291150000000000020e+00 2.155359999999999943e+00 -2.925800000000000067e-01 9.640140000000000597e+00 2.195469999999999811e+00 +2.732000000000000053e-02 2.792353740000000016e+03 3.736545000000000272e+01 +3.090000000000000038e-02 2.271702040000000125e+03 3.370239000000000118e+01 +3.452000000000000207e-02 1.788897279999999910e+03 2.990733000000000175e+01 +3.812000000000000111e-02 1.407023470000000088e+03 2.652380000000000138e+01 +4.173000000000000320e-02 1.095009520000000066e+03 2.339882000000000062e+01 +4.542000000000000204e-02 8.376734699999999521e+02 2.046549999999999869e+01 +4.644000000000000211e-02 7.836296200000000454e+02 1.979430999999999941e+01 +4.907000000000000250e-02 6.414952399999999670e+02 1.790943000000000040e+01 +5.253000000000000030e-02 5.516777200000000221e+02 1.660839999999999961e+01 +5.269999999999999685e-02 5.141714299999999866e+02 1.603388999999999953e+01 +5.628999999999999976e-02 3.988418399999999906e+02 1.412165000000000070e+01 +5.868999999999999911e-02 3.579082799999999907e+02 1.337737000000000087e+01 +5.985999999999999654e-02 3.164397999999999911e+02 1.257854999999999990e+01 +6.351999999999999313e-02 2.486343500000000120e+02 1.114976000000000056e+01 +6.481000000000000649e-02 2.482066299999999899e+02 1.114016999999999946e+01 +6.715000000000000135e-02 2.006787799999999891e+02 1.001695999999999920e+01 +7.070999999999999508e-02 1.657927200000000028e+02 9.104739999999999611e+00 +7.094000000000000306e-02 1.667760000000000105e+02 9.131700000000000372e+00 +7.431999999999999718e-02 1.326982299999999952e+02 8.145500000000000185e+00 +7.721000000000000085e-02 1.181177100000000024e+02 7.684980000000000366e+00 +7.796999999999999764e-02 1.108474499999999949e+02 7.444709999999999717e+00 +8.161999999999999811e-02 9.087302999999999997e+01 6.740660000000000096e+00 +8.343000000000000416e-02 8.290343000000000018e+01 6.438299999999999912e+00 +8.522000000000000408e-02 7.588799000000000206e+01 6.159869999999999735e+00 +8.878999999999999393e-02 6.486343999999999710e+01 5.694890000000000008e+00 +8.959000000000000297e-02 6.133471999999999724e+01 5.537810000000000343e+00 +9.568999999999999728e-02 4.711737999999999715e+01 4.853729999999999656e+00 +1.017699999999999994e-01 3.554666000000000281e+01 4.215840000000000032e+00 +1.079900000000000027e-01 2.833098000000000027e+01 3.763710000000000111e+00 +1.141599999999999976e-01 2.318925000000000125e+01 3.405089999999999950e+00 +1.202000000000000013e-01 1.876435000000000031e+01 3.063029999999999919e+00 +1.263499999999999901e-01 1.568601999999999919e+01 2.800539999999999807e+00 +1.325600000000000112e-01 1.346410000000000018e+01 2.594619999999999926e+00 +1.387700000000000045e-01 1.173840000000000039e+01 2.422639999999999905e+00 +1.449000000000000010e-01 1.054757999999999996e+01 2.296469999999999789e+00 +1.509399999999999908e-01 9.084839999999999804e+00 2.131299999999999972e+00 +1.571099999999999997e-01 8.239589999999999748e+00 2.029729999999999812e+00 +1.633300000000000030e-01 7.767660000000000231e+00 1.970739999999999936e+00 +1.695099999999999940e-01 7.631929999999999659e+00 1.953449999999999909e+00 +1.756300000000000083e-01 7.253739999999999633e+00 1.904430000000000067e+00 +1.817999999999999894e-01 6.968580000000000219e+00 1.866630000000000011e+00 +1.880100000000000104e-01 7.029829999999999579e+00 1.874810000000000088e+00 +1.941199999999999870e-01 6.805609999999999715e+00 1.844670000000000032e+00 +2.002200000000000091e-01 7.007130000000000081e+00 1.871779999999999999e+00 +2.063500000000000056e-01 7.083709999999999951e+00 1.881979999999999986e+00 +2.125299999999999967e-01 6.971890000000000143e+00 1.867070000000000007e+00 +2.186800000000000133e-01 7.549360000000000070e+00 1.942849999999999966e+00 +2.247899999999999898e-01 7.451310000000000322e+00 1.930199999999999916e+00 +2.309799999999999909e-01 7.449589999999999712e+00 1.929969999999999963e+00 +2.371999999999999942e-01 7.776720000000000077e+00 1.971889999999999921e+00 +2.433599999999999930e-01 8.157130000000000436e+00 2.019550000000000178e+00 +2.494800000000000073e-01 8.339280000000000470e+00 2.041970000000000063e+00 +2.556100000000000039e-01 8.448100000000000165e+00 2.055250000000000021e+00 +2.617700000000000027e-01 8.746420000000000528e+00 2.091219999999999857e+00 +2.679699999999999860e-01 9.040720000000000312e+00 2.126110000000000166e+00 +2.741299999999999848e-01 9.130409999999999471e+00 2.136629999999999807e+00 +2.802100000000000146e-01 9.247719999999999274e+00 2.150319999999999787e+00 +2.863700000000000134e-01 9.291150000000000020e+00 2.155359999999999943e+00 +2.925800000000000067e-01 9.640140000000000597e+00 2.195469999999999811e+00 2.987299999999999955e-01 9.537290000000000489e+00 2.183720000000000105e+00 \ No newline at end of file diff --git a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv index daf8f80a8..c33506202 100644 --- a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv +++ b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/4_103_1640_24.039675.csv @@ -1,60 +1,60 @@ -2.733000000000000013e-02 2.320909860000000208e+03 3.406544999999999845e+01 -3.090999999999999998e-02 1.910828909999999951e+03 3.090978000000000137e+01 -3.454000000000000126e-02 1.519815650000000005e+03 2.756643000000000043e+01 -3.814000000000000029e-02 1.188850680000000011e+03 2.438083999999999918e+01 -4.175000000000000239e-02 9.312768700000000308e+02 2.157865999999999929e+01 -4.544000000000000122e-02 7.201697299999999586e+02 1.897589999999999932e+01 -4.646000000000000130e-02 6.728012599999999566e+02 1.834122999999999948e+01 -4.909999999999999781e-02 5.453608799999999519e+02 1.651304000000000016e+01 -5.256000000000000255e-02 4.724414499999999748e+02 1.536946999999999974e+01 -5.272000000000000297e-02 4.318700699999999983e+02 1.469472999999999985e+01 -5.632000000000000201e-02 3.382353699999999890e+02 1.300453000000000081e+01 -5.870999999999999830e-02 3.073326000000000136e+02 1.239621999999999957e+01 -5.988999999999999879e-02 2.634156100000000151e+02 1.147639999999999993e+01 -6.356000000000000538e-02 2.076918699999999944e+02 1.019048000000000087e+01 -6.483999999999999486e-02 2.125336499999999944e+02 1.030857999999999919e+01 -6.718999999999999972e-02 1.688028199999999970e+02 9.187020000000000408e+00 -7.073999999999999733e-02 1.362696899999999971e+02 8.254379999999999384e+00 -7.097000000000000530e-02 1.410024300000000039e+02 8.396499999999999631e+00 -7.435999999999999555e-02 1.127603699999999947e+02 7.508670000000000400e+00 -7.724999999999999922e-02 9.965560999999999581e+01 7.058880000000000265e+00 -7.800999999999999601e-02 9.194693999999999789e+01 6.780369999999999564e+00 -8.165999999999999648e-02 7.522768999999999551e+01 6.133009999999999629e+00 -8.347000000000000253e-02 7.049939999999999429e+01 5.937149999999999928e+00 -8.526000000000000245e-02 6.411020000000000607e+01 5.661719999999999864e+00 -8.883000000000000618e-02 5.376234999999999786e+01 5.184709999999999930e+00 -8.963000000000000134e-02 5.217504000000000275e+01 5.107590000000000074e+00 -9.574000000000000565e-02 4.054399999999999693e+01 4.502439999999999998e+00 -1.018199999999999938e-01 3.096013999999999911e+01 3.934470000000000134e+00 -1.080399999999999971e-01 2.426012000000000057e+01 3.482819999999999805e+00 -1.142200000000000021e-01 1.991522000000000148e+01 3.155569999999999986e+00 -1.202600000000000058e-01 1.696463999999999928e+01 2.912440000000000140e+00 -1.264099999999999946e-01 1.406012999999999913e+01 2.651429999999999954e+00 -1.326199999999999879e-01 1.186475000000000080e+01 2.435649999999999871e+00 -1.388300000000000090e-01 1.075843000000000060e+01 2.319310000000000205e+00 -1.449699999999999878e-01 9.447770000000000223e+00 2.173449999999999882e+00 -1.510100000000000053e-01 8.521739999999999426e+00 2.064189999999999969e+00 -1.571799999999999864e-01 7.782460000000000377e+00 1.972620000000000040e+00 -1.634099999999999997e-01 7.576889999999999681e+00 1.946390000000000065e+00 -1.695800000000000085e-01 7.175270000000000259e+00 1.894109999999999960e+00 -1.756999999999999951e-01 6.609770000000000145e+00 1.817930000000000046e+00 -1.818799999999999861e-01 6.690150000000000041e+00 1.828950000000000076e+00 -1.880999999999999894e-01 6.763010000000000410e+00 1.838889999999999914e+00 -1.942000000000000115e-01 6.479930000000000412e+00 1.799989999999999979e+00 -2.003099999999999881e-01 6.931930000000000369e+00 1.861709999999999976e+00 -2.064499999999999946e-01 7.058690000000000353e+00 1.878649999999999931e+00 -2.126300000000000134e-01 6.966739999999999711e+00 1.866379999999999928e+00 -2.187699999999999922e-01 7.155350000000000321e+00 1.891469999999999985e+00 -2.248999999999999888e-01 7.328820000000000334e+00 1.914260000000000073e+00 -2.310800000000000076e-01 7.623789999999999623e+00 1.952409999999999979e+00 -2.373000000000000109e-01 7.870739999999999625e+00 1.983780000000000099e+00 -2.434699999999999920e-01 7.865639999999999965e+00 1.983130000000000059e+00 -2.495900000000000063e-01 8.081390000000000740e+00 2.010149999999999881e+00 -2.557300000000000129e-01 8.480309999999999349e+00 2.059159999999999879e+00 -2.618900000000000117e-01 8.708700000000000330e+00 2.086710000000000065e+00 -2.680899999999999950e-01 8.823320000000000718e+00 2.100389999999999979e+00 -2.742499999999999938e-01 9.030450000000000088e+00 2.124909999999999854e+00 -2.803300000000000236e-01 9.222670000000000812e+00 2.147400000000000198e+00 -2.864999999999999769e-01 9.345430000000000348e+00 2.161649999999999849e+00 -2.927100000000000257e-01 9.660539999999999239e+00 2.197789999999999910e+00 +2.733000000000000013e-02 2.320909860000000208e+03 3.406544999999999845e+01 +3.090999999999999998e-02 1.910828909999999951e+03 3.090978000000000137e+01 +3.454000000000000126e-02 1.519815650000000005e+03 2.756643000000000043e+01 +3.814000000000000029e-02 1.188850680000000011e+03 2.438083999999999918e+01 +4.175000000000000239e-02 9.312768700000000308e+02 2.157865999999999929e+01 +4.544000000000000122e-02 7.201697299999999586e+02 1.897589999999999932e+01 +4.646000000000000130e-02 6.728012599999999566e+02 1.834122999999999948e+01 +4.909999999999999781e-02 5.453608799999999519e+02 1.651304000000000016e+01 +5.256000000000000255e-02 4.724414499999999748e+02 1.536946999999999974e+01 +5.272000000000000297e-02 4.318700699999999983e+02 1.469472999999999985e+01 +5.632000000000000201e-02 3.382353699999999890e+02 1.300453000000000081e+01 +5.870999999999999830e-02 3.073326000000000136e+02 1.239621999999999957e+01 +5.988999999999999879e-02 2.634156100000000151e+02 1.147639999999999993e+01 +6.356000000000000538e-02 2.076918699999999944e+02 1.019048000000000087e+01 +6.483999999999999486e-02 2.125336499999999944e+02 1.030857999999999919e+01 +6.718999999999999972e-02 1.688028199999999970e+02 9.187020000000000408e+00 +7.073999999999999733e-02 1.362696899999999971e+02 8.254379999999999384e+00 +7.097000000000000530e-02 1.410024300000000039e+02 8.396499999999999631e+00 +7.435999999999999555e-02 1.127603699999999947e+02 7.508670000000000400e+00 +7.724999999999999922e-02 9.965560999999999581e+01 7.058880000000000265e+00 +7.800999999999999601e-02 9.194693999999999789e+01 6.780369999999999564e+00 +8.165999999999999648e-02 7.522768999999999551e+01 6.133009999999999629e+00 +8.347000000000000253e-02 7.049939999999999429e+01 5.937149999999999928e+00 +8.526000000000000245e-02 6.411020000000000607e+01 5.661719999999999864e+00 +8.883000000000000618e-02 5.376234999999999786e+01 5.184709999999999930e+00 +8.963000000000000134e-02 5.217504000000000275e+01 5.107590000000000074e+00 +9.574000000000000565e-02 4.054399999999999693e+01 4.502439999999999998e+00 +1.018199999999999938e-01 3.096013999999999911e+01 3.934470000000000134e+00 +1.080399999999999971e-01 2.426012000000000057e+01 3.482819999999999805e+00 +1.142200000000000021e-01 1.991522000000000148e+01 3.155569999999999986e+00 +1.202600000000000058e-01 1.696463999999999928e+01 2.912440000000000140e+00 +1.264099999999999946e-01 1.406012999999999913e+01 2.651429999999999954e+00 +1.326199999999999879e-01 1.186475000000000080e+01 2.435649999999999871e+00 +1.388300000000000090e-01 1.075843000000000060e+01 2.319310000000000205e+00 +1.449699999999999878e-01 9.447770000000000223e+00 2.173449999999999882e+00 +1.510100000000000053e-01 8.521739999999999426e+00 2.064189999999999969e+00 +1.571799999999999864e-01 7.782460000000000377e+00 1.972620000000000040e+00 +1.634099999999999997e-01 7.576889999999999681e+00 1.946390000000000065e+00 +1.695800000000000085e-01 7.175270000000000259e+00 1.894109999999999960e+00 +1.756999999999999951e-01 6.609770000000000145e+00 1.817930000000000046e+00 +1.818799999999999861e-01 6.690150000000000041e+00 1.828950000000000076e+00 +1.880999999999999894e-01 6.763010000000000410e+00 1.838889999999999914e+00 +1.942000000000000115e-01 6.479930000000000412e+00 1.799989999999999979e+00 +2.003099999999999881e-01 6.931930000000000369e+00 1.861709999999999976e+00 +2.064499999999999946e-01 7.058690000000000353e+00 1.878649999999999931e+00 +2.126300000000000134e-01 6.966739999999999711e+00 1.866379999999999928e+00 +2.187699999999999922e-01 7.155350000000000321e+00 1.891469999999999985e+00 +2.248999999999999888e-01 7.328820000000000334e+00 1.914260000000000073e+00 +2.310800000000000076e-01 7.623789999999999623e+00 1.952409999999999979e+00 +2.373000000000000109e-01 7.870739999999999625e+00 1.983780000000000099e+00 +2.434699999999999920e-01 7.865639999999999965e+00 1.983130000000000059e+00 +2.495900000000000063e-01 8.081390000000000740e+00 2.010149999999999881e+00 +2.557300000000000129e-01 8.480309999999999349e+00 2.059159999999999879e+00 +2.618900000000000117e-01 8.708700000000000330e+00 2.086710000000000065e+00 +2.680899999999999950e-01 8.823320000000000718e+00 2.100389999999999979e+00 +2.742499999999999938e-01 9.030450000000000088e+00 2.124909999999999854e+00 +2.803300000000000236e-01 9.222670000000000812e+00 2.147400000000000198e+00 +2.864999999999999769e-01 9.345430000000000348e+00 2.161649999999999849e+00 +2.927100000000000257e-01 9.660539999999999239e+00 2.197789999999999910e+00 2.988600000000000145e-01 9.559969999999999857e+00 2.186319999999999819e+00 \ No newline at end of file diff --git a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv index 2f696f3b5..17968ec9e 100644 --- a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv +++ b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/5_312_1640_24.331065.csv @@ -1,60 +1,60 @@ -2.733000000000000013e-02 1.791495509999999967e+03 2.992905000000000015e+01 -3.091999999999999957e-02 1.477992469999999912e+03 2.718449000000000026e+01 -3.454000000000000126e-02 1.172791189999999915e+03 2.421561000000000163e+01 -3.814000000000000029e-02 9.196233300000000099e+02 2.144322000000000017e+01 -4.175000000000000239e-02 7.160111200000000053e+02 1.892102999999999824e+01 -4.544000000000000122e-02 5.391461900000000469e+02 1.641867999999999839e+01 -4.646000000000000130e-02 4.929036699999999769e+02 1.569877999999999929e+01 -4.909999999999999781e-02 4.129331099999999992e+02 1.436894000000000027e+01 -5.256000000000000255e-02 3.482022600000000239e+02 1.319473999999999947e+01 -5.272999999999999909e-02 3.242194700000000012e+02 1.273222999999999949e+01 -5.632000000000000201e-02 2.454095199999999863e+02 1.107722000000000051e+01 -5.870999999999999830e-02 2.218204599999999971e+02 1.053139000000000003e+01 -5.990000000000000185e-02 1.931666899999999885e+02 9.827680000000000859e+00 -6.356000000000000538e-02 1.505020900000000097e+02 8.674739999999999895e+00 -6.483999999999999486e-02 1.511605900000000133e+02 8.693690000000000140e+00 -6.718999999999999972e-02 1.202856799999999993e+02 7.755180000000000184e+00 -7.074999999999999345e-02 9.616129999999999711e+01 6.934020000000000294e+00 -7.097000000000000530e-02 9.870516999999999541e+01 7.025140000000000384e+00 -7.435999999999999555e-02 7.818730999999999653e+01 6.252489999999999881e+00 -7.724999999999999922e-02 6.837958000000000425e+01 5.847199999999999953e+00 -7.802000000000000601e-02 6.371482000000000312e+01 5.644239999999999924e+00 -8.165999999999999648e-02 5.179379999999999740e+01 5.088899999999999757e+00 -8.347000000000000253e-02 4.836007000000000033e+01 4.917320000000000135e+00 -8.526999999999999857e-02 4.457972000000000179e+01 4.721210000000000129e+00 -8.884000000000000230e-02 3.751116999999999990e+01 4.330770000000000231e+00 -8.963000000000000134e-02 3.544118999999999886e+01 4.209579999999999878e+00 -9.574000000000000565e-02 2.739192999999999856e+01 3.700810000000000155e+00 -1.018199999999999938e-01 2.084316000000000102e+01 3.228250000000000064e+00 -1.080399999999999971e-01 1.702296000000000120e+01 2.917440000000000033e+00 -1.142200000000000021e-01 1.391883999999999943e+01 2.638069999999999915e+00 -1.202600000000000058e-01 1.148202000000000034e+01 2.396040000000000170e+00 -1.264099999999999946e-01 9.887589999999999435e+00 2.223460000000000214e+00 -1.326199999999999879e-01 8.618710000000000093e+00 2.075899999999999856e+00 -1.388300000000000090e-01 7.875820000000000043e+00 1.984420000000000073e+00 -1.449699999999999878e-01 7.119869999999999699e+00 1.886779999999999902e+00 -1.510100000000000053e-01 6.691399999999999793e+00 1.829129999999999923e+00 -1.571799999999999864e-01 6.133020000000000138e+00 1.751139999999999919e+00 -1.634099999999999997e-01 5.984770000000000145e+00 1.729850000000000110e+00 -1.695800000000000085e-01 5.802669999999999995e+00 1.703330000000000011e+00 -1.756999999999999951e-01 5.772070000000000256e+00 1.698830000000000062e+00 -1.818799999999999861e-01 5.866640000000000299e+00 1.712690000000000046e+00 -1.880999999999999894e-01 5.880740000000000300e+00 1.714749999999999996e+00 -1.942000000000000115e-01 5.856810000000000294e+00 1.711260000000000003e+00 -2.003099999999999881e-01 6.138060000000000294e+00 1.751870000000000038e+00 -2.064499999999999946e-01 6.406990000000000407e+00 1.789830000000000032e+00 -2.126300000000000134e-01 6.462060000000000137e+00 1.797509999999999941e+00 -2.187699999999999922e-01 6.501079999999999970e+00 1.802929999999999922e+00 -2.248999999999999888e-01 6.991179999999999950e+00 1.869650000000000034e+00 -2.310800000000000076e-01 7.014639999999999986e+00 1.872779999999999889e+00 -2.373000000000000109e-01 7.136879999999999669e+00 1.889029999999999987e+00 -2.434699999999999920e-01 7.547889999999999766e+00 1.942660000000000053e+00 -2.495900000000000063e-01 7.608620000000000161e+00 1.950460000000000083e+00 -2.557300000000000129e-01 7.913459999999999717e+00 1.989149999999999974e+00 -2.618900000000000117e-01 8.245919999999999916e+00 2.030510000000000037e+00 -2.680899999999999950e-01 8.604509999999999437e+00 2.074190000000000200e+00 -2.742499999999999938e-01 8.711750000000000327e+00 2.087070000000000203e+00 -2.803300000000000236e-01 8.863739999999999952e+00 2.105199999999999960e+00 -2.864999999999999769e-01 8.911099999999999355e+00 2.110819999999999919e+00 -2.927100000000000257e-01 9.338430000000000675e+00 2.160839999999999872e+00 +2.733000000000000013e-02 1.791495509999999967e+03 2.992905000000000015e+01 +3.091999999999999957e-02 1.477992469999999912e+03 2.718449000000000026e+01 +3.454000000000000126e-02 1.172791189999999915e+03 2.421561000000000163e+01 +3.814000000000000029e-02 9.196233300000000099e+02 2.144322000000000017e+01 +4.175000000000000239e-02 7.160111200000000053e+02 1.892102999999999824e+01 +4.544000000000000122e-02 5.391461900000000469e+02 1.641867999999999839e+01 +4.646000000000000130e-02 4.929036699999999769e+02 1.569877999999999929e+01 +4.909999999999999781e-02 4.129331099999999992e+02 1.436894000000000027e+01 +5.256000000000000255e-02 3.482022600000000239e+02 1.319473999999999947e+01 +5.272999999999999909e-02 3.242194700000000012e+02 1.273222999999999949e+01 +5.632000000000000201e-02 2.454095199999999863e+02 1.107722000000000051e+01 +5.870999999999999830e-02 2.218204599999999971e+02 1.053139000000000003e+01 +5.990000000000000185e-02 1.931666899999999885e+02 9.827680000000000859e+00 +6.356000000000000538e-02 1.505020900000000097e+02 8.674739999999999895e+00 +6.483999999999999486e-02 1.511605900000000133e+02 8.693690000000000140e+00 +6.718999999999999972e-02 1.202856799999999993e+02 7.755180000000000184e+00 +7.074999999999999345e-02 9.616129999999999711e+01 6.934020000000000294e+00 +7.097000000000000530e-02 9.870516999999999541e+01 7.025140000000000384e+00 +7.435999999999999555e-02 7.818730999999999653e+01 6.252489999999999881e+00 +7.724999999999999922e-02 6.837958000000000425e+01 5.847199999999999953e+00 +7.802000000000000601e-02 6.371482000000000312e+01 5.644239999999999924e+00 +8.165999999999999648e-02 5.179379999999999740e+01 5.088899999999999757e+00 +8.347000000000000253e-02 4.836007000000000033e+01 4.917320000000000135e+00 +8.526999999999999857e-02 4.457972000000000179e+01 4.721210000000000129e+00 +8.884000000000000230e-02 3.751116999999999990e+01 4.330770000000000231e+00 +8.963000000000000134e-02 3.544118999999999886e+01 4.209579999999999878e+00 +9.574000000000000565e-02 2.739192999999999856e+01 3.700810000000000155e+00 +1.018199999999999938e-01 2.084316000000000102e+01 3.228250000000000064e+00 +1.080399999999999971e-01 1.702296000000000120e+01 2.917440000000000033e+00 +1.142200000000000021e-01 1.391883999999999943e+01 2.638069999999999915e+00 +1.202600000000000058e-01 1.148202000000000034e+01 2.396040000000000170e+00 +1.264099999999999946e-01 9.887589999999999435e+00 2.223460000000000214e+00 +1.326199999999999879e-01 8.618710000000000093e+00 2.075899999999999856e+00 +1.388300000000000090e-01 7.875820000000000043e+00 1.984420000000000073e+00 +1.449699999999999878e-01 7.119869999999999699e+00 1.886779999999999902e+00 +1.510100000000000053e-01 6.691399999999999793e+00 1.829129999999999923e+00 +1.571799999999999864e-01 6.133020000000000138e+00 1.751139999999999919e+00 +1.634099999999999997e-01 5.984770000000000145e+00 1.729850000000000110e+00 +1.695800000000000085e-01 5.802669999999999995e+00 1.703330000000000011e+00 +1.756999999999999951e-01 5.772070000000000256e+00 1.698830000000000062e+00 +1.818799999999999861e-01 5.866640000000000299e+00 1.712690000000000046e+00 +1.880999999999999894e-01 5.880740000000000300e+00 1.714749999999999996e+00 +1.942000000000000115e-01 5.856810000000000294e+00 1.711260000000000003e+00 +2.003099999999999881e-01 6.138060000000000294e+00 1.751870000000000038e+00 +2.064499999999999946e-01 6.406990000000000407e+00 1.789830000000000032e+00 +2.126300000000000134e-01 6.462060000000000137e+00 1.797509999999999941e+00 +2.187699999999999922e-01 6.501079999999999970e+00 1.802929999999999922e+00 +2.248999999999999888e-01 6.991179999999999950e+00 1.869650000000000034e+00 +2.310800000000000076e-01 7.014639999999999986e+00 1.872779999999999889e+00 +2.373000000000000109e-01 7.136879999999999669e+00 1.889029999999999987e+00 +2.434699999999999920e-01 7.547889999999999766e+00 1.942660000000000053e+00 +2.495900000000000063e-01 7.608620000000000161e+00 1.950460000000000083e+00 +2.557300000000000129e-01 7.913459999999999717e+00 1.989149999999999974e+00 +2.618900000000000117e-01 8.245919999999999916e+00 2.030510000000000037e+00 +2.680899999999999950e-01 8.604509999999999437e+00 2.074190000000000200e+00 +2.742499999999999938e-01 8.711750000000000327e+00 2.087070000000000203e+00 +2.803300000000000236e-01 8.863739999999999952e+00 2.105199999999999960e+00 +2.864999999999999769e-01 8.911099999999999355e+00 2.110819999999999919e+00 +2.927100000000000257e-01 9.338430000000000675e+00 2.160839999999999872e+00 2.988600000000000145e-01 9.385640000000000427e+00 2.166290000000000049e+00 \ No newline at end of file diff --git a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv index e7dfab999..72272ed89 100644 --- a/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv +++ b/test/trend_test_data/Nanoperm_perpendicular_Honecker_et_al/6_1270_1640_24.331065.csv @@ -1,60 +1,60 @@ -2.732000000000000053e-02 1.517870979999999918e+03 2.754878000000000071e+01 -3.090999999999999998e-02 1.252144950000000108e+03 2.502143999999999835e+01 -3.452999999999999819e-02 9.849326300000000174e+02 2.219157999999999831e+01 -3.812999999999999723e-02 7.635778900000000249e+02 1.953941999999999979e+01 -4.173999999999999932e-02 5.910564900000000534e+02 1.719093000000000160e+01 -4.542999999999999816e-02 4.454160299999999779e+02 1.492340000000000089e+01 -4.644000000000000211e-02 4.097451399999999921e+02 1.431337000000000081e+01 -4.907999999999999863e-02 3.412573399999999992e+02 1.306249000000000038e+01 -5.254000000000000337e-02 2.833860500000000116e+02 1.190348999999999968e+01 -5.270999999999999991e-02 2.587516299999999774e+02 1.137434999999999974e+01 -5.630000000000000282e-02 1.972410900000000140e+02 9.930790000000000006e+00 -5.868999999999999911e-02 1.820288400000000024e+02 9.540150000000000574e+00 -5.988000000000000267e-02 1.548462399999999946e+02 8.799039999999999750e+00 -6.353999999999999926e-02 1.208091600000000057e+02 7.772039999999999615e+00 -6.481000000000000649e-02 1.228846300000000014e+02 7.838510000000000311e+00 -6.716999999999999360e-02 9.485747999999999536e+01 6.886849999999999916e+00 -7.072000000000000508e-02 7.616365000000000407e+01 6.171050000000000146e+00 -7.094999999999999918e-02 7.959243999999999630e+01 6.308419999999999916e+00 -7.434000000000000330e-02 6.139544999999999675e+01 5.540549999999999642e+00 -7.721999999999999698e-02 5.528307999999999822e+01 5.257520000000000415e+00 -7.799000000000000377e-02 5.105310999999999666e+01 5.052380000000000315e+00 -8.164000000000000423e-02 4.131436000000000064e+01 4.545020000000000060e+00 -8.343000000000000416e-02 3.883191999999999666e+01 4.406349999999999767e+00 -8.523999999999999633e-02 3.386838999999999800e+01 4.115120000000000111e+00 -8.881000000000000005e-02 2.873742000000000019e+01 3.790610000000000035e+00 -8.959999999999999909e-02 2.744166999999999845e+01 3.704159999999999897e+00 -9.569999999999999341e-02 2.114314999999999856e+01 3.251399999999999846e+00 -1.017799999999999955e-01 1.639198000000000022e+01 2.862859999999999960e+00 -1.079999999999999988e-01 1.302345000000000041e+01 2.551810000000000134e+00 -1.141699999999999937e-01 1.067233000000000054e+01 2.310010000000000119e+00 -1.202099999999999974e-01 8.927680000000000504e+00 2.112779999999999880e+00 -1.263600000000000001e-01 7.691300000000000026e+00 1.961030000000000051e+00 -1.325600000000000112e-01 6.633219999999999672e+00 1.821159999999999890e+00 -1.387799999999999867e-01 6.187759999999999927e+00 1.758939999999999948e+00 -1.449100000000000110e-01 5.397269999999999790e+00 1.642749999999999932e+00 -1.509500000000000008e-01 5.127299999999999969e+00 1.601140000000000008e+00 -1.571200000000000097e-01 4.947350000000000136e+00 1.572789999999999910e+00 -1.633400000000000130e-01 4.791970000000000063e+00 1.547900000000000054e+00 -1.695200000000000040e-01 4.839830000000000076e+00 1.555609999999999937e+00 -1.756399999999999906e-01 4.855599999999999916e+00 1.558140000000000081e+00 -1.818099999999999994e-01 4.971189999999999998e+00 1.576580000000000092e+00 -1.880199999999999927e-01 4.996179999999999843e+00 1.580540000000000056e+00 -1.941299999999999970e-01 5.231489999999999974e+00 1.617329999999999934e+00 -2.002299999999999913e-01 5.461660000000000181e+00 1.652519999999999989e+00 -2.063699999999999979e-01 5.566430000000000433e+00 1.668299999999999894e+00 -2.125400000000000067e-01 5.749649999999999928e+00 1.695529999999999982e+00 -2.186899999999999955e-01 5.962720000000000020e+00 1.726660000000000084e+00 -2.248100000000000098e-01 6.366220000000000212e+00 1.784129999999999994e+00 -2.309900000000000009e-01 6.576419999999999710e+00 1.813339999999999952e+00 -2.372100000000000042e-01 6.993730000000000224e+00 1.869990000000000041e+00 -2.433800000000000130e-01 7.112300000000000288e+00 1.885780000000000012e+00 -2.494999999999999996e-01 7.346860000000000390e+00 1.916619999999999990e+00 -2.556300000000000239e-01 7.629410000000000025e+00 1.953130000000000033e+00 -2.617900000000000227e-01 7.827810000000000379e+00 1.978359999999999896e+00 -2.679900000000000060e-01 8.252810000000000201e+00 2.031359999999999832e+00 -2.741399999999999948e-01 8.304840000000000444e+00 2.037749999999999950e+00 -2.802200000000000246e-01 8.705450000000000799e+00 2.086320000000000174e+00 -2.863899999999999779e-01 8.881330000000000169e+00 2.107289999999999885e+00 -2.926000000000000267e-01 9.112230000000000274e+00 2.134510000000000129e+00 -2.987500000000000155e-01 9.303969999999999629e+00 2.156849999999999934e+00 +2.732000000000000053e-02 1.517870979999999918e+03 2.754878000000000071e+01 +3.090999999999999998e-02 1.252144950000000108e+03 2.502143999999999835e+01 +3.452999999999999819e-02 9.849326300000000174e+02 2.219157999999999831e+01 +3.812999999999999723e-02 7.635778900000000249e+02 1.953941999999999979e+01 +4.173999999999999932e-02 5.910564900000000534e+02 1.719093000000000160e+01 +4.542999999999999816e-02 4.454160299999999779e+02 1.492340000000000089e+01 +4.644000000000000211e-02 4.097451399999999921e+02 1.431337000000000081e+01 +4.907999999999999863e-02 3.412573399999999992e+02 1.306249000000000038e+01 +5.254000000000000337e-02 2.833860500000000116e+02 1.190348999999999968e+01 +5.270999999999999991e-02 2.587516299999999774e+02 1.137434999999999974e+01 +5.630000000000000282e-02 1.972410900000000140e+02 9.930790000000000006e+00 +5.868999999999999911e-02 1.820288400000000024e+02 9.540150000000000574e+00 +5.988000000000000267e-02 1.548462399999999946e+02 8.799039999999999750e+00 +6.353999999999999926e-02 1.208091600000000057e+02 7.772039999999999615e+00 +6.481000000000000649e-02 1.228846300000000014e+02 7.838510000000000311e+00 +6.716999999999999360e-02 9.485747999999999536e+01 6.886849999999999916e+00 +7.072000000000000508e-02 7.616365000000000407e+01 6.171050000000000146e+00 +7.094999999999999918e-02 7.959243999999999630e+01 6.308419999999999916e+00 +7.434000000000000330e-02 6.139544999999999675e+01 5.540549999999999642e+00 +7.721999999999999698e-02 5.528307999999999822e+01 5.257520000000000415e+00 +7.799000000000000377e-02 5.105310999999999666e+01 5.052380000000000315e+00 +8.164000000000000423e-02 4.131436000000000064e+01 4.545020000000000060e+00 +8.343000000000000416e-02 3.883191999999999666e+01 4.406349999999999767e+00 +8.523999999999999633e-02 3.386838999999999800e+01 4.115120000000000111e+00 +8.881000000000000005e-02 2.873742000000000019e+01 3.790610000000000035e+00 +8.959999999999999909e-02 2.744166999999999845e+01 3.704159999999999897e+00 +9.569999999999999341e-02 2.114314999999999856e+01 3.251399999999999846e+00 +1.017799999999999955e-01 1.639198000000000022e+01 2.862859999999999960e+00 +1.079999999999999988e-01 1.302345000000000041e+01 2.551810000000000134e+00 +1.141699999999999937e-01 1.067233000000000054e+01 2.310010000000000119e+00 +1.202099999999999974e-01 8.927680000000000504e+00 2.112779999999999880e+00 +1.263600000000000001e-01 7.691300000000000026e+00 1.961030000000000051e+00 +1.325600000000000112e-01 6.633219999999999672e+00 1.821159999999999890e+00 +1.387799999999999867e-01 6.187759999999999927e+00 1.758939999999999948e+00 +1.449100000000000110e-01 5.397269999999999790e+00 1.642749999999999932e+00 +1.509500000000000008e-01 5.127299999999999969e+00 1.601140000000000008e+00 +1.571200000000000097e-01 4.947350000000000136e+00 1.572789999999999910e+00 +1.633400000000000130e-01 4.791970000000000063e+00 1.547900000000000054e+00 +1.695200000000000040e-01 4.839830000000000076e+00 1.555609999999999937e+00 +1.756399999999999906e-01 4.855599999999999916e+00 1.558140000000000081e+00 +1.818099999999999994e-01 4.971189999999999998e+00 1.576580000000000092e+00 +1.880199999999999927e-01 4.996179999999999843e+00 1.580540000000000056e+00 +1.941299999999999970e-01 5.231489999999999974e+00 1.617329999999999934e+00 +2.002299999999999913e-01 5.461660000000000181e+00 1.652519999999999989e+00 +2.063699999999999979e-01 5.566430000000000433e+00 1.668299999999999894e+00 +2.125400000000000067e-01 5.749649999999999928e+00 1.695529999999999982e+00 +2.186899999999999955e-01 5.962720000000000020e+00 1.726660000000000084e+00 +2.248100000000000098e-01 6.366220000000000212e+00 1.784129999999999994e+00 +2.309900000000000009e-01 6.576419999999999710e+00 1.813339999999999952e+00 +2.372100000000000042e-01 6.993730000000000224e+00 1.869990000000000041e+00 +2.433800000000000130e-01 7.112300000000000288e+00 1.885780000000000012e+00 +2.494999999999999996e-01 7.346860000000000390e+00 1.916619999999999990e+00 +2.556300000000000239e-01 7.629410000000000025e+00 1.953130000000000033e+00 +2.617900000000000227e-01 7.827810000000000379e+00 1.978359999999999896e+00 +2.679900000000000060e-01 8.252810000000000201e+00 2.031359999999999832e+00 +2.741399999999999948e-01 8.304840000000000444e+00 2.037749999999999950e+00 +2.802200000000000246e-01 8.705450000000000799e+00 2.086320000000000174e+00 +2.863899999999999779e-01 8.881330000000000169e+00 2.107289999999999885e+00 +2.926000000000000267e-01 9.112230000000000274e+00 2.134510000000000129e+00 +2.987500000000000155e-01 9.303969999999999629e+00 2.156849999999999934e+00 diff --git a/test/trend_test_data/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv b/test/trend_test_data/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv index 48bb9bce9..efaf03f7e 100644 --- a/test/trend_test_data/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv +++ b/test/trend_test_data/NdFeB_parallel_Bick_et_al/1_8000_1600_1070.csv @@ -1,53 +1,53 @@ -0.02466 11161.7 105.066 -0.02779 8582.24 78.8702 -0.03118 6929.14 63.4309 -0.03472 5567.83 52.0489 -0.03798 4896.87 48.9428 -0.04103 4301.45 44.2537 -0.04439 3931.56 35.32 -0.04789 3532.24 33.8506 -0.05145 3225.93 29.1479 -0.05487 3001.52 30.0366 -0.05809 2808.67 26.8966 -0.06147 2656.59 24.6464 -0.06487 2544.49 24.3544 -0.06823 2417.04 22.1946 -0.07159 2285.04 21.753 -0.07491 2209.24 20.4624 -0.07817 2057.47 19.703 -0.08149 2022.7 18.6311 -0.08492 1895.55 17.4353 -0.08832 1842.28 17.2068 -0.09171 1764.56 16.4013 -0.09497 1702.47 16.2564 -0.09818 1650.68 15.7993 -0.10176 1598.61 13.5448 -0.10537 1517.07 14.6455 -0.10864 1470.19 13.6872 -0.11191 1422.64 13.7771 -0.11529 1373.82 12.5952 -0.11874 1333.67 12.468 -0.12204 1309.38 12.7116 -0.1253 1256.04 11.6755 -0.12868 1224.03 11.535 -0.13213 1180.94 10.9145 -0.13557 1163.16 10.9427 -0.13878 1135.89 11.2995 -0.14204 1129.91 10.3422 -0.14544 1101.7 10.3463 -0.14888 1050.46 9.68171 -0.1523 1034.3 9.79525 -0.15558 1022.51 9.86417 -0.15895 1003.15 9.06883 -0.16231 984.02 9.61305 -0.16567 956.076 8.69603 -0.16916 941.039 8.81872 -0.17256 914.22 8.5457 -0.1759 903.557 8.49062 -0.1792 862.822 8.49027 -0.18246 857.39 8.12443 -0.18596 822.372 7.58423 -0.18945 803.539 7.77639 -0.19275 787.933 7.6279 -0.19605 759.06 7.64242 -0.1993 746.444 7.32989 +0.02466 11161.7 105.066 +0.02779 8582.24 78.8702 +0.03118 6929.14 63.4309 +0.03472 5567.83 52.0489 +0.03798 4896.87 48.9428 +0.04103 4301.45 44.2537 +0.04439 3931.56 35.32 +0.04789 3532.24 33.8506 +0.05145 3225.93 29.1479 +0.05487 3001.52 30.0366 +0.05809 2808.67 26.8966 +0.06147 2656.59 24.6464 +0.06487 2544.49 24.3544 +0.06823 2417.04 22.1946 +0.07159 2285.04 21.753 +0.07491 2209.24 20.4624 +0.07817 2057.47 19.703 +0.08149 2022.7 18.6311 +0.08492 1895.55 17.4353 +0.08832 1842.28 17.2068 +0.09171 1764.56 16.4013 +0.09497 1702.47 16.2564 +0.09818 1650.68 15.7993 +0.10176 1598.61 13.5448 +0.10537 1517.07 14.6455 +0.10864 1470.19 13.6872 +0.11191 1422.64 13.7771 +0.11529 1373.82 12.5952 +0.11874 1333.67 12.468 +0.12204 1309.38 12.7116 +0.1253 1256.04 11.6755 +0.12868 1224.03 11.535 +0.13213 1180.94 10.9145 +0.13557 1163.16 10.9427 +0.13878 1135.89 11.2995 +0.14204 1129.91 10.3422 +0.14544 1101.7 10.3463 +0.14888 1050.46 9.68171 +0.1523 1034.3 9.79525 +0.15558 1022.51 9.86417 +0.15895 1003.15 9.06883 +0.16231 984.02 9.61305 +0.16567 956.076 8.69603 +0.16916 941.039 8.81872 +0.17256 914.22 8.5457 +0.1759 903.557 8.49062 +0.1792 862.822 8.49027 +0.18246 857.39 8.12443 +0.18596 822.372 7.58423 +0.18945 803.539 7.77639 +0.19275 787.933 7.6279 +0.19605 759.06 7.64242 +0.1993 746.444 7.32989 diff --git a/test/trend_test_data/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv b/test/trend_test_data/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv index 2464d9ffa..ede4f8121 100644 --- a/test/trend_test_data/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv +++ b/test/trend_test_data/NdFeB_parallel_Bick_et_al/2_10000_1600_1070.csv @@ -1,53 +1,53 @@ -0.02466 9785.87 100.498 -0.02779 7387.61 74.8808 -0.03118 5638.9 58.6706 -0.03472 4473.77 47.7572 -0.03797 3723.19 43.7134 -0.04102 3256.4 39.3915 -0.04439 2850.7 30.7019 -0.04789 2561.59 29.3595 -0.05145 2280.01 24.9612 -0.05487 2158.85 25.8372 -0.05809 1997.24 23.0262 -0.06147 1891.61 21.0832 -0.06486 1796.03 20.6896 -0.06823 1698.02 18.8045 -0.07158 1613.84 18.4277 -0.0749 1560.07 17.3367 -0.07817 1481.58 16.8421 -0.08149 1400.5 15.6189 -0.08492 1362.71 14.8771 -0.08832 1326.21 14.6884 -0.09171 1308.1 14.1935 -0.09497 1238.48 13.9232 -0.09817 1217.12 13.6217 -0.10176 1182.01 11.7148 -0.10536 1125.29 12.6688 -0.10863 1086.39 11.8029 -0.1119 1069.27 11.9783 -0.11528 1037.53 10.9946 -0.11874 1000.25 10.8391 -0.12203 1030.21 11.3207 -0.12529 996.562 10.4091 -0.12867 937.635 10.1418 -0.13213 932.787 9.7458 -0.13557 936.093 9.83598 -0.13878 902.903 10.118 -0.14204 895.331 9.2379 -0.14544 894.523 9.3444 -0.14887 873.213 8.84172 -0.15229 870.028 8.99453 -0.15558 846.466 8.9992 -0.15895 842.358 8.32813 -0.1623 809.53 8.74144 -0.16566 822.783 8.08431 -0.16915 792.943 8.10552 -0.17255 774.308 7.87783 -0.1759 781.539 7.90816 -0.17919 756.562 7.97296 -0.18245 745.925 7.59066 -0.18596 725.982 7.13904 -0.18944 711.483 7.3287 -0.19275 709.157 7.24903 -0.19604 677.704 7.2411 -0.19929 659.648 6.90112 +0.02466 9785.87 100.498 +0.02779 7387.61 74.8808 +0.03118 5638.9 58.6706 +0.03472 4473.77 47.7572 +0.03797 3723.19 43.7134 +0.04102 3256.4 39.3915 +0.04439 2850.7 30.7019 +0.04789 2561.59 29.3595 +0.05145 2280.01 24.9612 +0.05487 2158.85 25.8372 +0.05809 1997.24 23.0262 +0.06147 1891.61 21.0832 +0.06486 1796.03 20.6896 +0.06823 1698.02 18.8045 +0.07158 1613.84 18.4277 +0.0749 1560.07 17.3367 +0.07817 1481.58 16.8421 +0.08149 1400.5 15.6189 +0.08492 1362.71 14.8771 +0.08832 1326.21 14.6884 +0.09171 1308.1 14.1935 +0.09497 1238.48 13.9232 +0.09817 1217.12 13.6217 +0.10176 1182.01 11.7148 +0.10536 1125.29 12.6688 +0.10863 1086.39 11.8029 +0.1119 1069.27 11.9783 +0.11528 1037.53 10.9946 +0.11874 1000.25 10.8391 +0.12203 1030.21 11.3207 +0.12529 996.562 10.4091 +0.12867 937.635 10.1418 +0.13213 932.787 9.7458 +0.13557 936.093 9.83598 +0.13878 902.903 10.118 +0.14204 895.331 9.2379 +0.14544 894.523 9.3444 +0.14887 873.213 8.84172 +0.15229 870.028 8.99453 +0.15558 846.466 8.9992 +0.15895 842.358 8.32813 +0.1623 809.53 8.74144 +0.16566 822.783 8.08431 +0.16915 792.943 8.10552 +0.17255 774.308 7.87783 +0.1759 781.539 7.90816 +0.17919 756.562 7.97296 +0.18245 745.925 7.59066 +0.18596 725.982 7.13904 +0.18944 711.483 7.3287 +0.19275 709.157 7.24903 +0.19604 677.704 7.2411 +0.19929 659.648 6.90112 diff --git a/test/trend_test_data/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv b/test/trend_test_data/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv index 517a96859..1c96f3d5f 100644 --- a/test/trend_test_data/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv +++ b/test/trend_test_data/NdFeB_parallel_Bick_et_al/3_12000_1600_1070.csv @@ -1,53 +1,53 @@ -0.02467 9119.79 98.2483 -0.02779 6716.34 72.6007 -0.03118 4992.66 56.2161 -0.03472 3831.98 45.1388 -0.03798 3145.6 40.9924 -0.04103 2635.02 36.2785 -0.0444 2353.33 28.4064 -0.04789 2051.02 26.7601 -0.05146 1820.51 22.7202 -0.05487 1702.5 23.3101 -0.0581 1582.43 20.8224 -0.06148 1455.78 18.7977 -0.06487 1396.8 18.5029 -0.06824 1347.58 16.9495 -0.07159 1258.02 16.4371 -0.07491 1231.28 15.5554 -0.07818 1164.47 15.0776 -0.0815 1146.97 14.2378 -0.08493 1109.77 13.533 -0.08833 1040.08 13.1167 -0.09172 1030.03 12.6919 -0.09498 996.502 12.5769 -0.09819 973.153 12.2625 -0.10178 933.855 10.4847 -0.10538 941.324 11.6421 -0.10865 891.14 10.747 -0.11192 890.927 10.9919 -0.1153 863.999 10.0862 -0.11876 860.652 10.1051 -0.12205 833.905 10.2392 -0.12531 831.414 9.54046 -0.12869 796.354 9.38666 -0.13215 809.376 9.11842 -0.13559 805.133 9.14629 -0.1388 791.474 9.50691 -0.14205 787.287 8.69915 -0.14546 761.22 8.65866 -0.1489 779.201 8.38098 -0.15232 771.323 8.50152 -0.1556 748.08 8.49235 -0.15897 748.238 7.8713 -0.16233 756.864 8.48551 -0.16569 723.545 7.61209 -0.16918 723.039 7.76626 -0.17258 714.249 7.58349 -0.17592 707.068 7.55031 -0.17922 695.999 7.67253 -0.18248 687.854 7.31121 -0.18599 672.503 6.89206 -0.18947 656.046 7.05985 -0.19277 644.64 6.93548 -0.19607 633.62 7.0287 -0.19932 617.369 6.7009 +0.02467 9119.79 98.2483 +0.02779 6716.34 72.6007 +0.03118 4992.66 56.2161 +0.03472 3831.98 45.1388 +0.03798 3145.6 40.9924 +0.04103 2635.02 36.2785 +0.0444 2353.33 28.4064 +0.04789 2051.02 26.7601 +0.05146 1820.51 22.7202 +0.05487 1702.5 23.3101 +0.0581 1582.43 20.8224 +0.06148 1455.78 18.7977 +0.06487 1396.8 18.5029 +0.06824 1347.58 16.9495 +0.07159 1258.02 16.4371 +0.07491 1231.28 15.5554 +0.07818 1164.47 15.0776 +0.0815 1146.97 14.2378 +0.08493 1109.77 13.533 +0.08833 1040.08 13.1167 +0.09172 1030.03 12.6919 +0.09498 996.502 12.5769 +0.09819 973.153 12.2625 +0.10178 933.855 10.4847 +0.10538 941.324 11.6421 +0.10865 891.14 10.747 +0.11192 890.927 10.9919 +0.1153 863.999 10.0862 +0.11876 860.652 10.1051 +0.12205 833.905 10.2392 +0.12531 831.414 9.54046 +0.12869 796.354 9.38666 +0.13215 809.376 9.11842 +0.13559 805.133 9.14629 +0.1388 791.474 9.50691 +0.14205 787.287 8.69915 +0.14546 761.22 8.65866 +0.1489 779.201 8.38098 +0.15232 771.323 8.50152 +0.1556 748.08 8.49235 +0.15897 748.238 7.8713 +0.16233 756.864 8.48551 +0.16569 723.545 7.61209 +0.16918 723.039 7.76626 +0.17258 714.249 7.58349 +0.17592 707.068 7.55031 +0.17922 695.999 7.67253 +0.18248 687.854 7.31121 +0.18599 672.503 6.89206 +0.18947 656.046 7.05985 +0.19277 644.64 6.93548 +0.19607 633.62 7.0287 +0.19932 617.369 6.7009 diff --git a/test/trend_test_data/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv b/test/trend_test_data/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv index 838f64e5b..e349acefe 100644 --- a/test/trend_test_data/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv +++ b/test/trend_test_data/NdFeB_parallel_Bick_et_al/4_14000_1600_1070.csv @@ -1,53 +1,53 @@ -0.02466 8578.27 96.3713 -0.02778 6201.5 70.6884 -0.03117 4666.55 54.9081 -0.03471 3532.71 43.8556 -0.03797 2779.72 39.1195 -0.04102 2401.14 35.0436 -0.04438 2010.93 26.6446 -0.04788 1789.13 25.3004 -0.05144 1629 21.7057 -0.05485 1414.39 21.5471 -0.05808 1338.47 19.3969 -0.06145 1255.55 17.6425 -0.06485 1194.78 17.2789 -0.06822 1131.88 15.6792 -0.07157 1093.29 15.4062 -0.07489 1076.75 14.6325 -0.07815 990.83 13.9891 -0.08147 993.984 13.3123 -0.0849 949.429 12.5828 -0.0883 906.082 12.3081 -0.09169 901.543 11.9196 -0.09495 883.023 11.8721 -0.09815 842.784 11.4424 -0.10174 819.526 9.8676 -0.10534 802.736 10.7893 -0.10861 795.767 10.1828 -0.11188 791.163 10.3837 -0.11526 783.07 9.63416 -0.11872 771.734 9.59199 -0.12201 755.014 9.75865 -0.12527 763.25 9.14929 -0.12865 738.983 9.05459 -0.1321 735.65 8.71334 -0.13554 713.743 8.62175 -0.13875 720.548 9.08471 -0.142 726.975 8.37203 -0.14541 705.893 8.34698 -0.14884 717.099 8.0504 -0.15226 709.825 8.16294 -0.15554 709.595 8.27884 -0.15891 699.293 7.61937 -0.16227 704.678 8.19256 -0.16563 698.926 7.48706 -0.16912 685.563 7.56396 -0.17251 673.043 7.36594 -0.17586 671.398 7.36238 -0.17915 664.082 7.50135 -0.18241 667.157 7.20373 -0.18592 646.099 6.75787 -0.1894 640.973 6.98357 -0.1927 634.489 6.88246 -0.196 608.639 6.89728 -0.19924 599.163 6.60299 +0.02466 8578.27 96.3713 +0.02778 6201.5 70.6884 +0.03117 4666.55 54.9081 +0.03471 3532.71 43.8556 +0.03797 2779.72 39.1195 +0.04102 2401.14 35.0436 +0.04438 2010.93 26.6446 +0.04788 1789.13 25.3004 +0.05144 1629 21.7057 +0.05485 1414.39 21.5471 +0.05808 1338.47 19.3969 +0.06145 1255.55 17.6425 +0.06485 1194.78 17.2789 +0.06822 1131.88 15.6792 +0.07157 1093.29 15.4062 +0.07489 1076.75 14.6325 +0.07815 990.83 13.9891 +0.08147 993.984 13.3123 +0.0849 949.429 12.5828 +0.0883 906.082 12.3081 +0.09169 901.543 11.9196 +0.09495 883.023 11.8721 +0.09815 842.784 11.4424 +0.10174 819.526 9.8676 +0.10534 802.736 10.7893 +0.10861 795.767 10.1828 +0.11188 791.163 10.3837 +0.11526 783.07 9.63416 +0.11872 771.734 9.59199 +0.12201 755.014 9.75865 +0.12527 763.25 9.14929 +0.12865 738.983 9.05459 +0.1321 735.65 8.71334 +0.13554 713.743 8.62175 +0.13875 720.548 9.08471 +0.142 726.975 8.37203 +0.14541 705.893 8.34698 +0.14884 717.099 8.0504 +0.15226 709.825 8.16294 +0.15554 709.595 8.27884 +0.15891 699.293 7.61937 +0.16227 704.678 8.19256 +0.16563 698.926 7.48706 +0.16912 685.563 7.56396 +0.17251 673.043 7.36594 +0.17586 671.398 7.36238 +0.17915 664.082 7.50135 +0.18241 667.157 7.20373 +0.18592 646.099 6.75787 +0.1894 640.973 6.98357 +0.1927 634.489 6.88246 +0.196 608.639 6.89728 +0.19924 599.163 6.60299 diff --git a/test/trend_test_data/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv b/test/trend_test_data/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv index ebbe41831..03d157c58 100644 --- a/test/trend_test_data/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv +++ b/test/trend_test_data/NdFeB_parallel_Bick_et_al/5_16000_1600_1070.csv @@ -1,53 +1,53 @@ -0.02466 8403.24 95.8365 -0.02779 5866.26 69.5434 -0.03118 4356.78 53.6923 -0.03472 3299.25 42.8649 -0.03798 2597.38 38.2386 -0.04103 2129.79 33.557 -0.04439 1878.69 25.9888 -0.04789 1624.61 24.3861 -0.05145 1439.52 20.6737 -0.05487 1263.65 20.5759 -0.05809 1171.99 18.386 -0.06147 1079.56 16.577 -0.06487 1041.15 16.3129 -0.06823 1001.7 14.8847 -0.07159 961.645 14.563 -0.07491 923.442 13.6706 -0.07817 896.915 13.3973 -0.08149 883.652 12.6286 -0.08492 862.753 12.0581 -0.08832 824.722 11.795 -0.09171 784.35 11.1756 -0.09497 769.294 11.1579 -0.09818 755.349 10.8901 -0.10176 749.016 9.48228 -0.10537 742.393 10.4072 -0.10864 731.812 9.80011 -0.11191 725.902 9.97489 -0.11529 687.755 9.06119 -0.11874 695.826 9.13917 -0.12204 706.826 9.47552 -0.1253 686.062 8.69528 -0.12868 672.907 8.67583 -0.13213 693.14 8.48682 -0.13557 670.728 8.38538 -0.13878 665.705 8.76139 -0.14204 671.833 8.08011 -0.14544 675.608 8.18129 -0.14888 672.094 7.81614 -0.1523 674.683 7.97469 -0.15558 656.506 7.99112 -0.15895 676.236 7.50792 -0.16231 665.98 7.99164 -0.16567 649.237 7.2359 -0.16916 663.887 7.46039 -0.17256 654.732 7.28088 -0.1759 649.138 7.26044 -0.1792 637.918 7.36805 -0.18246 634.954 7.04588 -0.18596 615.952 6.61209 -0.18945 606.075 6.80618 -0.19275 602.38 6.72418 -0.19605 583.877 6.77081 -0.1993 592.832 6.58159 +0.02466 8403.24 95.8365 +0.02779 5866.26 69.5434 +0.03118 4356.78 53.6923 +0.03472 3299.25 42.8649 +0.03798 2597.38 38.2386 +0.04103 2129.79 33.557 +0.04439 1878.69 25.9888 +0.04789 1624.61 24.3861 +0.05145 1439.52 20.6737 +0.05487 1263.65 20.5759 +0.05809 1171.99 18.386 +0.06147 1079.56 16.577 +0.06487 1041.15 16.3129 +0.06823 1001.7 14.8847 +0.07159 961.645 14.563 +0.07491 923.442 13.6706 +0.07817 896.915 13.3973 +0.08149 883.652 12.6286 +0.08492 862.753 12.0581 +0.08832 824.722 11.795 +0.09171 784.35 11.1756 +0.09497 769.294 11.1579 +0.09818 755.349 10.8901 +0.10176 749.016 9.48228 +0.10537 742.393 10.4072 +0.10864 731.812 9.80011 +0.11191 725.902 9.97489 +0.11529 687.755 9.06119 +0.11874 695.826 9.13917 +0.12204 706.826 9.47552 +0.1253 686.062 8.69528 +0.12868 672.907 8.67583 +0.13213 693.14 8.48682 +0.13557 670.728 8.38538 +0.13878 665.705 8.76139 +0.14204 671.833 8.08011 +0.14544 675.608 8.18129 +0.14888 672.094 7.81614 +0.1523 674.683 7.97469 +0.15558 656.506 7.99112 +0.15895 676.236 7.50792 +0.16231 665.98 7.99164 +0.16567 649.237 7.2359 +0.16916 663.887 7.46039 +0.17256 654.732 7.28088 +0.1759 649.138 7.26044 +0.1792 637.918 7.36805 +0.18246 634.954 7.04588 +0.18596 615.952 6.61209 +0.18945 606.075 6.80618 +0.19275 602.38 6.72418 +0.19605 583.877 6.77081 +0.1993 592.832 6.58159 diff --git a/test/utest_new_sasdata.py b/test/utest_new_sasdata.py index 16665c20f..62e5e4ab7 100644 --- a/test/utest_new_sasdata.py +++ b/test/utest_new_sasdata.py @@ -2,7 +2,7 @@ from sasdata.data import SasData from sasdata.data_backing import Group -from sasdata.dataset_types import one_dim, two_dim +from sasdata.dataset_types import one_dim from sasdata.quantities.quantity import Quantity from sasdata.quantities.units import per_angstrom, per_centimeter @@ -21,28 +21,5 @@ def test_1d(): data = SasData('TestData', data_contents, one_dim, Group('root', {}), True) - assert all(data.abscissae.value == np.array(q)) - assert all(data.ordinate.value == np.array(i)) - - -def test_2d(): - # This could be autogenerated but I am hard coding to reduce the logic in - # the test. - qx = [1, 1, 1, 2, 2, 2, 3, 3, 3] - qy = [1, 2, 3, 1, 2, 3, 1, 2, 3] - i = [1, 2, 3] - - qx_quantity = Quantity(np.array(qx), per_angstrom) - qy_quantity = Quantity(np.array(qy), per_angstrom) - i_quantity = Quantity(np.array(i), per_centimeter) - - data_contents = { - 'Qx': qx_quantity, - 'Qy': qy_quantity, - 'I': i_quantity - } - - data = SasData('TestData', data_contents, two_dim, Group('root', {}), True) - - assert all(data.ordinate.value == np.array(i)) - assert (data.abscissae.value == np.array([[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [3, 1], [3, 2], [3, 3]])).all().all() + assert all(data.abscissae == np.array(q_quantity)) + assert all(data.ordinate == np.array(i_quantity)) diff --git a/test/utest_sasdata.py b/test/utest_sasdata.py index cebc748e2..391768382 100644 --- a/test/utest_sasdata.py +++ b/test/utest_sasdata.py @@ -9,6 +9,13 @@ logging.config.fileConfig(LOGGER_CONFIG_FILE) logger = logging.getLogger(__name__) +try: + pass +except: + logger.error("xmlrunner needs to be installed to run these tests") + logger.error("Try easy_install unittest-xml-reporting") + sys.exit(1) + # Check whether we have matplotlib installed HAS_MPL_WX = True try: diff --git a/test/utest_temp_ascii_reader.py b/test/utest_temp_ascii_reader.py index 0361ca342..8ae481ac8 100644 --- a/test/utest_temp_ascii_reader.py +++ b/test/utest_temp_ascii_reader.py @@ -1,3 +1,4 @@ +import pytest import os from typing import Literal @@ -20,24 +21,11 @@ # TODO: Look into parameterizing this, although its not trivial due to the setup, and tests being a bit different. -def find(filename: str, locations: Literal["sasdataloader", "mumag"]) -> str: - # This match statement is here in case we want to pull data out of other locations. - match locations: - case "sasdataloader": - return os.path.join( - os.path.dirname(__file__), "sasdataloader", "data", filename - ) - case "mumag": - return os.path.join( - os.path.dirname(__file__), - "mumag", - "Nanoperm_perpendicular_Honecker_et_al", - filename, - ) - +def find(filename: str) -> str: + return os.path.join(os.path.dirname(__file__), 'sasdataloader', 'data', filename) def test_ascii_1(): - filename = find("ascii_test_1.txt", "sasdataloader") + filename = 'ascii_test_1.txt' params = guess_params_from_filename(filename, one_dim) # Need to change the columns as they won't be right. # TODO: unitless @@ -63,6 +51,7 @@ def test_ascii_1(): case "dI": assert datum.value[0] == pytest.approx(0.002704) assert datum.value[-1] == pytest.approx(0.191) +<<<<<<< HEAD def test_ascii_2(): @@ -152,3 +141,23 @@ def test_mumag_metadata(): assert datum.metadata.raw.filter("applied_magnetic_field") == ["1270"] assert datum.metadata.raw.filter("saturation_magnetization") == ["1640"] assert datum.metadata.raw.filter("demagnetizing_field") == ["24"] +||||||| parent of f7982fb1 (Wrote a test for the ASCII reader.) + +def test_ascii_2(): + filename = find('test_3_columns.txt', 'sasdataloader') + params = guess_params_from_filename(filename, one_dim) + loaded_data = load_data(params)[0] + + for datum in loaded_data._data_contents: + match datum.name: + case 'Q': + assert datum.value[0] == pytest.approx(0) + assert datum.value[-1] == pytest.approx(1.22449) + case 'I': + assert datum.value[0] == pytest.approx(2.83954) + assert datum.value[-1] == pytest.approx(7.47487) + case 'dI': + assert datum.value[0] == pytest.approx(0.6) + assert datum.value[-1] == pytest.approx(1.05918) +======= +>>>>>>> f7982fb1 (Wrote a test for the ASCII reader.) diff --git a/test/utest_trend.py b/test/utest_trend.py index b079bf53c..cae81131a 100644 --- a/test/utest_trend.py +++ b/test/utest_trend.py @@ -4,34 +4,24 @@ import sasdata.temp_ascii_reader as ascii_reader from sasdata.ascii_reader_metadata import AsciiMetadataCategory -from sasdata.quantities.units import per_angstrom, per_nanometer +from sasdata.quantities.units import per_nanometer from sasdata.temp_ascii_reader import AsciiReaderParams from sasdata.trend import Trend -mumag_test_directories = [ +test_directories = [ 'FeNiB_perpendicular_Bersweiler_et_al', 'Nanoperm_perpendicular_Honecker_et_al', 'NdFeB_parallel_Bick_et_al' ] -custom_test_directory = 'custom_test' +@pytest.mark.parametrize('directory_name', test_directories) +def test_trend_build(directory_name: str): + """Try to build a trend object on the MuMag datasets, and see if all the Q items match (as they should).""" + load_from = path.join(path.dirname(__file__), directory_name) + files_to_load = listdir(load_from) -def get_files_to_load(directory_name: str) -> list[str]: - load_from = path.join(path.dirname(__file__), 'trend_test_data', directory_name) - base_filenames_to_load = listdir(load_from) - files_to_load = [path.join(load_from, basename) for basename in base_filenames_to_load] - return files_to_load - -@pytest.mark.parametrize('directory_name', mumag_test_directories) -def test_trend_build_interpolate(directory_name: str): - """Try to build a trend object on the MuMag datasets""" - files_to_load = get_files_to_load(directory_name) - params = AsciiReaderParams( - filenames=files_to_load, - columns=[('Q', per_nanometer), ('I', per_nanometer), ('dI', per_nanometer)], - ) - params.separator_dict['Whitespace'] = True - params.metadata.master_metadata['magnetic'] = AsciiMetadataCategory( + metadata = AsciiReaderMetadata() + metadata.master_metadata['magnetic'] = AsciiMetadataCategory( values={ 'counting_index': 0, 'applied_magnetic_field': 1, @@ -39,31 +29,18 @@ def test_trend_build_interpolate(directory_name: str): 'demagnetizing_field': 3 } ) - data = ascii_reader.load_data(params) - trend = Trend( - data=data, - trend_axis=['magnetic', 'applied_magnetic_field'] - ) - # Initially, the q axes in this date don't exactly match - to_interpolate_on = 'Q' - assert not trend.all_axis_match(to_interpolate_on) - interpolated_trend = trend.interpolate(to_interpolate_on) - assert interpolated_trend.all_axis_match(to_interpolate_on) -def test_trend_q_axis_match(): - files_to_load = get_files_to_load(custom_test_directory) params = AsciiReaderParams( filenames=files_to_load, - columns=[('Q', per_angstrom), ('I', per_angstrom)] - ) - params.metadata.master_metadata['magnetic'] = AsciiMetadataCategory( - values={ - 'counting_index': 0, - } + starting_line=0, + columns=[('Q', per_nanometer), ('I', per_nanometer), ('dI', per_nanometer)], + excluded_lines=set(), + separator_dict={'Whitespace': True, 'Comma': False, 'Tab': False}, + metadata=metadata, ) data = ascii_reader.load_data(params) trend = Trend( data=data, - trend_axis=['magnetic', 'counting_index'] + trend_axis=['magnetic', 'applied_magnetic_field'] ) assert trend.all_axis_match('Q') diff --git a/test/utest_unit_parser.py b/test/utest_unit_parser.py index e757a0220..7bdcf997f 100644 --- a/test/utest_unit_parser.py +++ b/test/utest_unit_parser.py @@ -1,5 +1,3 @@ -import re - import pytest from sasdata.quantities import units @@ -7,75 +5,57 @@ from sasdata.quantities.units import Unit named_units_for_testing = [ - ("m", units.meters), - ("A-1", units.per_angstrom), - ("1/A", units.per_angstrom), - ("1/angstroms", units.per_angstrom), - ("micrometer", units.micrometers), - ("micron", units.micrometers), - ("kmh-2", units.kilometers_per_square_hour), - ("km/h2", units.kilometers_per_square_hour), - ("kgm/s2", units.newtons), - ("m m", units.square_meters), - ("mm", units.millimeters), - ("A^-1", units.per_angstrom), - ("V/Amps", units.ohms), - ("Ω", units.ohms), - ("Å", units.angstroms), - ("%", units.percent), - ("per_centimeter", units.per_centimeter), + ('m', units.meters), + ('A-1', units.per_angstrom), + ('1/A', units.per_angstrom), + ('kmh-2', units.kilometers_per_square_hour), + ('km/h2', units.kilometers_per_square_hour), + ('kgm/s2', units.newtons), + ('m m', units.square_meters), + ('mm', units.millimeters), + ('A^-1', units.per_angstrom), + ('V/Amps', units.ohms), + ('Ω', units.ohms), + ('Å', units.angstroms), + ('%', units.percent) ] -latex_units_for_testing = [ - (r"\Omega", units.ohms), # Test omega is Ω - (r"\AA", units.angstroms), # Test angstrom is Å - (r"\%", units.percent), # Test percent is NOT a comment - (r"{\mu}A", units.microamperes), # Test µ with an ASCII unit - (r"{\mu}\Omega", units.microohms), # Test µ with LaTeX unit - (r"mm", units.millimeters), # Test that most units just use ASCII in LaTeX +unnamed_units_for_testing = [ + ('m13', units.meters**13), + ('kW/sr', units.kilowatts/units.stradians) ] -unnamed_units_for_testing = [("m13", units.meters**13), ("kW/sr", units.kilowatts / units.stradians)] - - @pytest.mark.parametrize("string, expected_units", named_units_for_testing) def test_name_parse(string: str, expected_units: Unit): - """Test basic parsing""" + """ Test basic parsing""" assert parse_named_unit(string) == expected_units - @pytest.mark.parametrize("string, expected_units", named_units_for_testing + unnamed_units_for_testing) def test_equivalent(string: str, expected_units: Unit): - """Check dimensions of parsed units""" + """ Check dimensions of parsed units""" assert parse_unit(string).equivalent(expected_units) @pytest.mark.parametrize("string, expected_units", named_units_for_testing + unnamed_units_for_testing) def test_scale_same(string: str, expected_units: Unit): - """Test basic parsing""" + """ Test basic parsing""" assert parse_unit(string).scale == pytest.approx(expected_units.scale, rel=1e-14) -@pytest.mark.parametrize("latex_string, units", latex_units_for_testing) -def test_latex_parse(latex_string: str, units: Unit): - """Test that proper LaTeX formats for units are being generated""" - assert units.latex_symbol == latex_string - - def test_parse_from_group(): - """Test group based disambiguation""" - parsed_metres_per_second = parse_named_unit_from_group("ms-1", units.speed) + """ Test group based disambiguation""" + parsed_metres_per_second = parse_named_unit_from_group('ms-1', units.speed) assert parsed_metres_per_second == units.meters_per_second def test_parse_errors(): # Fails because the unit is not in that specific group. - with pytest.raises(ValueError, match="That unit cannot be parsed from the specified group."): - parse_named_unit_from_group("km", units.speed) + with pytest.raises(ValueError, match='That unit cannot be parsed from the specified group.'): + parse_named_unit_from_group('km', units.speed) # Fails because part of the unit matches but there is an unknown unit '@' - with pytest.raises(ValueError, match=re.escape("unit_str (km@-1) contains forbidden characters.")): - parse_unit("km@-1") + with pytest.raises(ValueError, match='unit_str contains forbidden characters.'): + parse_unit('km@-1') # Fails because 'da' is not a unit. - with pytest.raises(ValueError, match="Unit string contains an unrecognised pattern."): - parse_unit("mmda2") + with pytest.raises(ValueError, match='Unit string contains an unrecognised pattern.'): + parse_unit('mmda2') diff --git a/tox.ini b/tox.ini new file mode 100644 index 000000000..54dfeb507 --- /dev/null +++ b/tox.ini @@ -0,0 +1,3 @@ +[pycodestyle] +max-line-length = 120 +ignore = E501,W503 \ No newline at end of file