From c7c31377fedd3446066ab8f9daeb9857d1a9847b Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 09:41:35 +0200 Subject: [PATCH 01/12] Apply latest templates --- .copier-answers.yml | 2 +- .github/workflows/issues-labels.yml | 9 + .github/workflows/lint-format.yml | 8 - .gitignore | 1 + .pre-commit-config.yaml | 7 - .prettierignore | 17 +- CONTRIBUTING.md | 1 - docs/mkdocs.yml | 3 +- pixi.toml | 47 +- pyproject.toml | 67 +-- tools/add_license_headers.py | 151 ------- tools/check_license_headers.py | 45 -- tools/license_headers.py | 315 +++++++++++++ tools/param_consistency.py | 677 ++++++++++++++++++++++++++++ tools/remove_license_headers.py | 41 -- 15 files changed, 1082 insertions(+), 309 deletions(-) delete mode 100644 tools/add_license_headers.py delete mode 100644 tools/check_license_headers.py create mode 100644 tools/license_headers.py create mode 100644 tools/param_consistency.py delete mode 100644 tools/remove_license_headers.py diff --git a/.copier-answers.yml b/.copier-answers.yml index 7b414c16..d9076626 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,6 +1,6 @@ # WARNING: Do not edit this file manually. # Any changes will be overwritten by Copier. -_commit: v0.10.1-25-ga5301e9 +_commit: v0.10.1-34-gd2bd5b6 _src_path: gh:easyscience/templates app_docs_url: https://easyscience.github.io/dynamics-app app_doi: 10.5281/zenodo.18877180 diff --git a/.github/workflows/issues-labels.yml b/.github/workflows/issues-labels.yml index 3a60cdd7..df3c55f1 100644 --- a/.github/workflows/issues-labels.yml +++ b/.github/workflows/issues-labels.yml @@ -13,9 +13,18 @@ permissions: jobs: check-labels: + if: github.actor != 'easyscience[bot]' + runs-on: ubuntu-latest + concurrency: + group: issue-labels-${{ github.event.issue.number }} + cancel-in-progress: true + steps: + - name: Checkout repository + uses: actions/checkout@v5 + - name: Setup easyscience[bot] id: bot uses: ./.github/actions/setup-easyscience-bot diff --git a/.github/workflows/lint-format.yml b/.github/workflows/lint-format.yml index 457d67f4..f1135fa5 100644 --- a/.github/workflows/lint-format.yml +++ b/.github/workflows/lint-format.yml @@ -79,12 +79,6 @@ jobs: shell: bash run: pixi run docstring-lint-check - - name: Check formatting of docstrings in Python code - id: docstring_format - continue-on-error: true - shell: bash - run: pixi run docstring-format-check - - name: Check formatting of non-Python files (md, toml, etc.) id: nonpy_format continue-on-error: true @@ -112,7 +106,6 @@ jobs: echo "| py lint | ${{ steps.py_lint.outcome == 'success' && '✅' || '❌' }} |" echo "| py format | ${{ steps.py_format.outcome == 'success' && '✅' || '❌' }} |" echo "| docstring lint | ${{ steps.docstring_lint.outcome == 'success' && '✅' || '❌' }} |" - echo "| docstring format | ${{ steps.docstring_format.outcome == 'success' && '✅' || '❌' }} |" echo "| nonpy format | ${{ steps.nonpy_format.outcome == 'success' && '✅' || '❌' }} |" echo "| notebooks lint | ${{ steps.notebook_lint.outcome == 'success' && '✅' || '❌' }} |" } >> "$GITHUB_STEP_SUMMARY" @@ -125,7 +118,6 @@ jobs: || steps.py_lint.outcome == 'failure' || steps.py_format.outcome == 'failure' || steps.docstring_lint.outcome == 'failure' - || steps.docstring_format.outcome == 'failure' || steps.nonpy_format.outcome == 'failure' || steps.notebook_lint.outcome == 'failure' shell: bash diff --git a/.gitignore b/.gitignore index 0500ede3..6dc595c7 100644 --- a/.gitignore +++ b/.gitignore @@ -41,5 +41,6 @@ CMakeLists.txt.user* *.dmg # Misc +.cache/ *.log *.zip diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5fa0c2cb..9a3855f4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,13 +39,6 @@ repos: pass_filenames: false stages: [manual] - - id: pixi-docstring-format-check - name: pixi run docstring-format-check - entry: pixi run docstring-format-check - language: system - pass_filenames: false - stages: [manual] - - id: pixi-nonpy-format-check name: pixi run nonpy-format-check entry: pixi run nonpy-format-check diff --git a/.prettierignore b/.prettierignore index 788ec8fa..a08c3c48 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,6 @@ +# Git +.git/ + # Copier .copier-answers*.yml @@ -14,4 +17,16 @@ docs/docs/assets/ .pytest_cache/ # MyPy -.mypy_cache +.mypy_cache/ + +# Ruff +.ruff_cache/ + +# Node +node_modules + +# Misc +.benchmarks +.cache +deps/ +tmp/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 85365779..168c5d97 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -230,7 +230,6 @@ pixi run license-check.........................Passed pixi run py-lint-check.........................Passed pixi run py-format-check.......................Passed pixi run docstring-lint-check..................Passed -pixi run docstring-format-check................Passed pixi run nonpy-format-check....................Passed pixi run notebook-lint-check...................Passed pixi run unit-tests............................Passed diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index bd73822e..cfde9673 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -148,8 +148,7 @@ plugins: python: paths: ['src'] # Change 'src' to your actual sources directory options: - docstring_style: google - render_markdown: true + docstring_style: numpy group_by_category: false heading_level: 1 show_root_heading: true diff --git a/pixi.toml b/pixi.toml index ab15262f..b3250ce0 100644 --- a/pixi.toml +++ b/pixi.toml @@ -5,7 +5,7 @@ # Platform-independent [activation.env] -PYTHONIOENCODING = "utf-8" +PYTHONIOENCODING = 'utf-8' # Platform-specific @@ -35,7 +35,7 @@ platforms = ['win-64', 'linux-64', 'osx-64', 'osx-arm64'] channels = ['conda-forge'] ##################### -# System requirements +# SYSTEM REQUIREMENTS ##################### [system-requirements] @@ -92,8 +92,8 @@ default = { features = ['default', 'py-max'] } unit-tests = 'python -m pytest tests/unit/ --color=yes -v' integration-tests = 'python -m pytest tests/integration/ --color=yes -n auto -v' -notebook-tests = 'python -m pytest --nbmake docs/docs/tutorials/ --nbmake-timeout=600 --color=yes -n auto -v' script-tests = 'python -m pytest tools/test_scripts.py --color=yes -n auto -v' +notebook-tests = 'python -m pytest --nbmake docs/docs/tutorials/ --nbmake-timeout=600 --color=yes -n auto -v' test = { depends-on = ['unit-tests'] } @@ -102,13 +102,13 @@ test = { depends-on = ['unit-tests'] } ########### pyproject-check = 'python -m validate_pyproject pyproject.toml' +param-docstring-check = 'python tools/param_consistency.py src/ --check' docstring-lint-check = 'pydoclint --quiet src/' -docstring-format-check = 'docformatter --check src/' notebook-lint-check = 'nbqa ruff docs/docs/tutorials/' py-lint-check = 'ruff check src/ tests/ docs/docs/tutorials/' -py-format-check = "ruff format --check src/ tests/ docs/docs/tutorials/" -nonpy-format-check = "npx prettier --list-different --config=prettierrc.toml --ignore-unknown ." -nonpy-format-check-modified = "python tools/nonpy_prettier_modified.py" +py-format-check = 'ruff format --check src/ tests/ docs/docs/tutorials/' +nonpy-format-check = 'npx prettier --list-different --config=prettierrc.toml --ignore-unknown .' +nonpy-format-check-modified = 'python tools/nonpy_prettier_modified.py' check = 'pre-commit run --hook-stage manual --all-files' @@ -116,22 +116,23 @@ check = 'pre-commit run --hook-stage manual --all-files' # 🛠️ Fixes ########## -docs-format-fix = 'docformatter --in-place src/ docs/docs/tutorials/' +param-docstring-fix = 'python tools/param_consistency.py src/ --fix' +docstring-format-fix = 'format-docstring src/' notebook-lint-fix = 'nbqa ruff --fix docs/docs/tutorials/' py-lint-fix = 'ruff check --fix src/ tests/ docs/docs/tutorials/' py-lint-fix-unsafe = 'ruff check --fix --unsafe-fixes src/ tests/ docs/docs/tutorials/' py-format-fix = "ruff format src/ tests/ docs/docs/tutorials/" nonpy-format-fix = 'npx prettier --write --list-different --config=prettierrc.toml --ignore-unknown .' -nonpy-format-fix-modified = "python tools/nonpy_prettier_modified.py --write" -success-message-fix = 'echo "✅ All auto-formatting steps completed successfully!"' +nonpy-format-fix-modified = 'python tools/nonpy_prettier_modified.py --write' +success-message = 'echo "✅ All auto-formatting steps completed successfully!"' fix = { depends-on = [ + 'docstring-format-fix', 'py-format-fix', - 'docs-format-fix', 'py-lint-fix', 'nonpy-format-fix', 'notebook-lint-fix', - 'success-message-fix', + 'success-message', ] } #################### @@ -179,11 +180,11 @@ notebook-prepare = { depends-on = [ ######################## docs-vars = "JUPYTER_PLATFORM_DIRS=1 PYTHONWARNINGS='ignore::RuntimeWarning'" -docs-pre = "pixi run docs-vars python -m mkdocs" -docs-serve = "pixi run docs-pre serve -f docs/mkdocs.yml" -docs-serve-dirty = "pixi run docs-serve --dirty" -docs-build = "pixi run docs-pre build -f docs/mkdocs.yml" -docs-build-local = "pixi run docs-build --no-directory-urls" +docs-pre = 'pixi run docs-vars python -m mkdocs' +docs-serve = 'pixi run docs-pre serve -f docs/mkdocs.yml' +docs-serve-dirty = 'pixi run docs-serve --dirty' +docs-build = 'pixi run docs-pre build -f docs/mkdocs.yml' +docs-build-local = 'pixi run docs-build --no-directory-urls' docs-deploy-pre = 'mike deploy -F docs/mkdocs.yml --push --branch gh-pages --update-aliases --alias-type redirect' docs-set-default-pre = 'mike set-default -F docs/mkdocs.yml --push --branch gh-pages' @@ -194,9 +195,9 @@ docs-update-assets = 'python tools/update_docs_assets.py' # 📦 Template Management Tasks ############################## -copier-copy = "copier copy gh:easyscience/templates . --data-file ../dynamics/.copier-answers.yml --data template_type=lib" -copier-recopy = "copier recopy --data-file ../dynamics/.copier-answers.yml --data template_type=lib" -copier-update = "copier update --data-file ../dynamics/.copier-answers.yml --data template_type=lib" +copier-copy = 'copier copy gh:easyscience/templates . --data-file ../dynamics/.copier-answers.yml --data template_type=lib' +copier-recopy = 'copier recopy --data-file ../dynamics/.copier-answers.yml --data template_type=lib' +copier-update = 'copier update --data-file ../dynamics/.copier-answers.yml --data template_type=lib' ##################### # 🪝 Pre-commit Hooks @@ -243,9 +244,9 @@ github-labels = 'python tools/update_github_labels.py' # ⚖️ SPDX License Headers ######################### -license-remove = 'python tools/remove_license_headers.py src/ tests/' -license-add = 'python tools/add_license_headers.py src/ tests/' -license-check = 'python tools/check_license_headers.py src/ tests/' +license-remove = 'python tools/license_headers.py remove src/ tests/ --exclude-from-pyproject-toml tool.ruff.exclude' +license-add = 'python tools/license_headers.py add src/ tests/ --exclude-from-pyproject-toml tool.ruff.exclude' +license-check = 'python tools/license_headers.py check src/ tests/ --exclude-from-pyproject-toml tool.ruff.exclude' #################################### # 🚀 Other Development & Build Tasks diff --git a/pyproject.toml b/pyproject.toml index bcacdf96..dbb31174 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,7 @@ dev = [ 'jupytext', # Jupyter notebook text format support 'jupyterquiz', # Quizzes in Jupyter notebooks 'pydoclint', # Docstring linter - 'docformatter', # Docstring formatter + 'format-docstring', # Docstring formatter 'interrogate', # Docstring coverage checker 'copier', # Template management 'mike', # MkDocs: Versioned documentation support @@ -175,10 +175,12 @@ testpaths = ['tests'] # https://docs.astral.sh/ruff/rules/ [tool.ruff] -exclude = ['tmp'] +exclude = [ + 'tmp', +] indent-width = 4 -line-length = 99 -preview = true # Enable new rules that are not yet stable, like DOC +line-length = 99 # See also `max-line-length` in [tool.ruff.lint.pycodestyle] +preview = true # Enable new rules that are not yet stable, like DOC # Formatting options for Ruff @@ -195,7 +197,8 @@ quote-style = 'single' # But double quotes in docstrings (PEP 8, PEP 25 select = [ # Various rules #'C90', # https://docs.astral.sh/ruff/rules/#mccabe-c90 - 'F', # https://docs.astral.sh/ruff/rules/#pyflakes-f + #'D', # https://docs.astral.sh/ruff/rules/#pydocstyle-d + 'F', # https://docs.astral.sh/ruff/rules/#pyflakes-f #'FLY', # https://docs.astral.sh/ruff/rules/#flynt-fly #'FURB', # https://docs.astral.sh/ruff/rules/#refurb-furb 'I', # https://docs.astral.sh/ruff/rules/#isort-i @@ -254,15 +257,24 @@ select = [ # Ignore specific rules globally ignore = [ 'COM812', # https://docs.astral.sh/ruff/rules/missing-trailing-comma/ - # The following covered by [tool.pydoclint] section below - 'D', # https://docs.astral.sh/ruff/rules/#pydocstyle-d + # The following is replaced by 'D'/[tool.ruff.lint.pydocstyle] and [tool.pydoclint] 'DOC', # https://docs.astral.sh/ruff/rules/#pydoclint-doc + # Disable, as [tool.format_docstring] split one-line docstrings into the canonical multi-line layout + 'D200', # https://docs.astral.sh/ruff/rules/unnecessary-multiline-docstring/ + # Temporary: + 'D100', # https://docs.astral.sh/ruff/rules/undocumented-public-module/#undocumented-publi-module-d100 + 'D104', # https://docs.astral.sh/ruff/rules/undocumented-public-package/#undocumented-public-package-d104 + 'DTZ005', # https://docs.astral.sh/ruff/rules/call-datetime-now-without-tzinfo/#call-datetime-now-without-tzinfo-dtz005 ] # Ignore specific rules in certain files or directories [tool.ruff.lint.per-file-ignores] +'*/__init__.py' = [ + 'F401', # re-exports are intentional in __init__.py +] 'tests/**' = [ 'ANN', # https://docs.astral.sh/ruff/rules/#flake8-annotations-ann + 'D', # https://docs.astral.sh/ruff/rules/#pydocstyle-d 'DOC', # https://docs.astral.sh/ruff/rules/#pydoclint-doc 'INP001', # https://docs.astral.sh/ruff/rules/implicit-namespace-package/ 'S101', # https://docs.astral.sh/ruff/rules/assert/ @@ -290,17 +302,12 @@ max-complexity = 10 # PEP 8 line length guidance: # https://peps.python.org/pep-0008/#maximum-line-length # Use 99 characters as the project-wide maximum for regular code lines. -max-line-length = 99 -# allow longer lines so that parameter declarations such as -# `name (Type | Type | None):` remain on a single line. Splitting these -# lines can prevent tools such as MkDocs and IDEs from correctly -# parsing and rendering parameter documentation. -# The descriptive text itself is wrapped more strictly by -# `docformatter` (see the configuration in [tool.docformatter] below) -# whenever it is treated as normal paragraph text. -# The line length for code snippets in docstrings is also more strict, -# as defined in the [tool.ruff.format] section above. -max-doc-length = 99 +# Use 72 characters for docstrings. +max-line-length = 99 # See also `line-length` in [tool.ruff] +max-doc-length = 72 + +[tool.ruff.lint.pydocstyle] +convention = 'numpy' ############################# # Configuration for pydoclint @@ -317,20 +324,22 @@ max-doc-length = 99 # the parameter declarations in the code (in function's signature). [tool.pydoclint] -style = "google" +exclude = '\.' # Temporarily disable pydoclint until we are ready +style = 'numpy' check-style-mismatch = true check-arg-defaults = true allow-init-docstring = true -################################ -# Configuration for docformatter -################################ +#################################### +# Configuration for format-docstring +#################################### -# 'docformatter' -- Code formatter for docstrings -# https://docformatter.readthedocs.io/en/latest/ +# 'format-docstring' -- Code formatter for docstrings +# https://github.com/jsh9/format-docstring -[tool.docformatter] -recursive = true -wrap-summaries = 72 -wrap-descriptions = 72 -close-quotes-on-newline = true +[tool.format_docstring] +exclude = '\.' # Temporarily disable format-docstring until we are ready +docstring_style = 'numpy' +line_length = 72 +fix_rst_backticks = true +verbose = 'default' diff --git a/tools/add_license_headers.py b/tools/add_license_headers.py deleted file mode 100644 index 28febde7..00000000 --- a/tools/add_license_headers.py +++ /dev/null @@ -1,151 +0,0 @@ -# SPDX-FileCopyrightText: 2026 EasyScience contributors -# SPDX-License-Identifier: BSD-3-Clause -"""Add SPDX headers to Python files. - -- SPDX-FileCopyrightText with the license holder name and organization - URL from ``pyproject.toml`` as well as the file's creation year. -- SPDX-License-Identifier is taken from the project license value in - ``pyproject.toml``. -""" - -from __future__ import annotations - -import argparse -import tomllib -from datetime import datetime -from pathlib import Path -from typing import Optional -from typing import Union - -from git import Repo -from spdx_headers.core import find_repository_root -from spdx_headers.core import get_copyright_info -from spdx_headers.data import load_license_data -from spdx_headers.operations import add_header_to_single_file - -LICENSE_DATABASE = load_license_data() - - -def load_pyproject(repo_path: Union[str, Path]) -> dict: - """Load and return parsed ``pyproject.toml`` data for the - repository. - """ - repo_root = find_repository_root(repo_path) - pyproject_path = repo_root / 'pyproject.toml' - - with open(pyproject_path, 'rb') as file_handle: - return tomllib.load(file_handle) - - -def get_file_creation_year(file_path: Union[str, Path]) -> str: - """Return the year the file was first added to Git history. - - If the year cannot be determined, fall back to the current year. - """ - file_path = Path(file_path) - - repo = Repo(file_path, search_parent_directories=True) - root = Path(repo.working_tree_dir).resolve() - rel_path = file_path.resolve().relative_to(root) - - rel_path_git = rel_path.as_posix() # IMPORTANT for git pathspec - - # Get the year when the file was first added to Git history. - # NOTE: Do not combine `--reverse` with `--max-count=1` here, as it can - # yield an empty result with some Git versions. Instead, get the full - # filtered output and take the first line. - log_output = repo.git.log( - '--follow', - '--diff-filter=A', - '--reverse', - '--format=%ad', - '--date=format:%Y', - '--', - rel_path_git, - ).strip() - - year = log_output.splitlines()[0].strip() if log_output else '' - - return year or str(datetime.now().year) - - -def get_org_url(repo_path: Union[str, Path]) -> str: - """Return the organization URL derived from the repository source - URL. - """ - pyproject_data = load_pyproject(repo_path) - repo_url = pyproject_data['project']['urls']['Source Code'] - return repo_url.rsplit('/', 1)[0] - - -def get_project_license(repo_path: Union[str, Path]) -> str: - """Return the project license value from ``pyproject.toml``.""" - pyproject_data = load_pyproject(repo_path) - return pyproject_data['project']['license'] - - -def get_copyright_holder(repo_path: Union[str, Path]) -> str: - """Return the repository copyright holder name.""" - _, name, _ = get_copyright_info(repo_path) - return name - - -def add_spdx_header( - target_file: Union[str, Path], - *, - license_key: str, - copyright_holder: str, - org_url: str, -) -> None: - """Add SPDX headers.""" - year = get_file_creation_year(target_file) - - add_header_to_single_file( - filepath=target_file, - license_key=license_key, - license_data=LICENSE_DATABASE, - year=year, - name=copyright_holder, - email=org_url, - ) - - -def build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser( - description='Add SPDX headers to Python files under the given paths.', - ) - parser.add_argument( - 'paths', - nargs='+', - help='Relative paths to scan (e.g. src tests)', - ) - return parser - - -def main(argv: Optional[list[str]] = None) -> int: - parser = build_parser() - args = parser.parse_args(argv) - - repo_path = Path('.').resolve() - license_key = get_project_license(repo_path) - copyright_holder = get_copyright_holder(repo_path) - org_url = get_org_url(repo_path) - - for base_dir in args.paths: - base_path = Path(base_dir) - if not base_path.exists(): - parser.error(f'Path does not exist: {base_dir}') - - for py_file in base_path.rglob('*.py'): - add_spdx_header( - py_file, - license_key=license_key, - copyright_holder=copyright_holder, - org_url=org_url, - ) - - return 0 - - -if __name__ == '__main__': - raise SystemExit(main()) diff --git a/tools/check_license_headers.py b/tools/check_license_headers.py deleted file mode 100644 index c8a4df21..00000000 --- a/tools/check_license_headers.py +++ /dev/null @@ -1,45 +0,0 @@ -# SPDX-FileCopyrightText: 2026 EasyScience contributors -# SPDX-License-Identifier: BSD-3-Clause -"""Check SPDX headers in Python files.""" - -from __future__ import annotations - -import argparse -from pathlib import Path -from typing import Optional - -from spdx_headers.operations import check_headers - - -def build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser( - description='Check SPDX headers in Python files under the given paths.', - ) - parser.add_argument( - 'paths', - nargs='+', - help='Relative paths to scan (e.g. src tests)', - ) - return parser - - -def main(argv: Optional[list[str]] = None) -> int: - parser = build_parser() - args = parser.parse_args(argv) - - exit_codes = [] - - for base_dir in args.paths: - base_path = Path(base_dir) - if not base_path.exists(): - parser.error(f'Path does not exist: {base_dir}') - - print('=' * 50) - print(f'Checking SPDX headers in: {base_dir}') - exit_codes.append(check_headers(base_dir)) - - return 0 if all(code == 0 for code in exit_codes) else 1 - - -if __name__ == '__main__': - raise SystemExit(main()) diff --git a/tools/license_headers.py b/tools/license_headers.py new file mode 100644 index 00000000..47d23524 --- /dev/null +++ b/tools/license_headers.py @@ -0,0 +1,315 @@ +# SPDX-FileCopyrightText: 2026 EasyScience contributors +# SPDX-License-Identifier: BSD-3-Clause +"""Add, remove, or check SPDX headers in Python files.""" + +from __future__ import annotations + +import argparse +import fnmatch +import tomllib +from datetime import datetime +from pathlib import Path +from typing import Any +from typing import Optional +from typing import Union + +from git import Repo +from spdx_headers.core import find_repository_root +from spdx_headers.core import get_copyright_info +from spdx_headers.core import has_spdx_header +from spdx_headers.data import load_license_data +from spdx_headers.operations import add_header_to_single_file +from spdx_headers.operations import remove_header_from_single_file + +LICENSE_DATABASE = load_license_data() + + +def load_pyproject(repo_path: Union[str, Path]) -> dict[str, Any]: + """Load and return parsed ``pyproject.toml`` data for the repository.""" + repo_root = find_repository_root(repo_path) + pyproject_path = repo_root / 'pyproject.toml' + + with pyproject_path.open('rb') as file_handle: + return tomllib.load(file_handle) + + +def get_pyproject_value(pyproject_data: dict[str, Any], dotted_key: str) -> Any: + """Return a nested ``pyproject.toml`` value from a dotted key.""" + value: Any = pyproject_data + for part in dotted_key.split('.'): + if not isinstance(value, dict) or part not in value: + raise KeyError(dotted_key) + value = value[part] + return value + + +def normalize_pattern(pattern: str) -> str: + """Normalize an exclude pattern to a POSIX-style relative path.""" + normalized = Path(pattern).as_posix() + if normalized.startswith('./'): + normalized = normalized[2:] + return normalized.rstrip('/') + + +def get_exclude_patterns( + repo_path: Union[str, Path], + exclude_values: list[str], + exclude_from_pyproject_toml: Optional[str], +) -> list[str]: + """Return normalized exclude patterns from CLI and ``pyproject.toml``.""" + pyproject_data = load_pyproject(repo_path) + patterns: list[str] = [] + + if exclude_from_pyproject_toml: + value = get_pyproject_value(pyproject_data, exclude_from_pyproject_toml) + if not isinstance(value, list) or not all(isinstance(item, str) for item in value): + raise ValueError( + f'{exclude_from_pyproject_toml} in pyproject.toml must be a list of strings.', + ) + patterns.extend(value) + + for item in exclude_values: + try: + value = get_pyproject_value(pyproject_data, item) + except KeyError: + patterns.append(item) + continue + + if not isinstance(value, list) or not all(isinstance(entry, str) for entry in value): + raise ValueError(f'{item} in pyproject.toml must be a list of strings.') + patterns.extend(value) + + normalized_patterns: list[str] = [] + seen: set[str] = set() + for pattern in patterns: + normalized = normalize_pattern(pattern) + if normalized and normalized not in seen: + normalized_patterns.append(normalized) + seen.add(normalized) + + return normalized_patterns + + +def get_file_creation_year(file_path: Union[str, Path]) -> str: + """Return the year the file was first added to Git history. + + If the year cannot be determined, fall back to the current year. + """ + file_path = Path(file_path) + + repo = Repo(file_path, search_parent_directories=True) + root = Path(repo.working_tree_dir).resolve() + rel_path = file_path.resolve().relative_to(root) + + rel_path_git = rel_path.as_posix() + + log_output = repo.git.log( + '--follow', + '--diff-filter=A', + '--reverse', + '--format=%ad', + '--date=format:%Y', + '--', + rel_path_git, + ).strip() + + year = log_output.splitlines()[0].strip() if log_output else '' + + return year or str(datetime.now().year) + + +def get_org_url(repo_path: Union[str, Path]) -> str: + """Return the organization URL derived from the repository source URL.""" + pyproject_data = load_pyproject(repo_path) + repo_url = pyproject_data['project']['urls']['Source Code'] + return repo_url.rsplit('/', 1)[0] + + +def get_project_license(repo_path: Union[str, Path]) -> str: + """Return the project license value from ``pyproject.toml``.""" + pyproject_data = load_pyproject(repo_path) + return pyproject_data['project']['license'] + + +def get_copyright_holder(repo_path: Union[str, Path]) -> str: + """Return the repository copyright holder name.""" + _, name, _ = get_copyright_info(repo_path) + return name + + +def add_spdx_header( + target_file: Union[str, Path], + *, + license_key: str, + copyright_holder: str, + org_url: str, +) -> None: + """Add SPDX headers to one file.""" + year = get_file_creation_year(target_file) + + add_header_to_single_file( + filepath=target_file, + license_key=license_key, + license_data=LICENSE_DATABASE, + year=year, + name=copyright_holder, + email=org_url, + ) + + +def is_excluded(relative_path: str, exclude_patterns: list[str]) -> bool: + """Return whether a relative path should be excluded.""" + for pattern in exclude_patterns: + if fnmatch.fnmatch(relative_path, pattern): + return True + if relative_path == pattern: + return True + if relative_path.startswith(f'{pattern}/'): + return True + return False + + +def iter_python_files( + paths: list[str], + *, + repo_root: Path, + exclude_patterns: list[str], + parser: argparse.ArgumentParser, +) -> list[Path]: + """Collect Python files under the given paths after exclusions.""" + files: list[Path] = [] + seen: set[Path] = set() + + for base_dir in paths: + base_path = Path(base_dir) + if not base_path.exists(): + parser.error(f'Path does not exist: {base_dir}') + + if base_path.is_file(): + candidates = [base_path] if base_path.suffix == '.py' else [] + else: + candidates = sorted(base_path.rglob('*.py')) + + for py_file in candidates: + resolved = py_file.resolve() + try: + relative_path = resolved.relative_to(repo_root).as_posix() + except ValueError: + relative_path = py_file.as_posix() + + if is_excluded(relative_path, exclude_patterns): + continue + + if resolved not in seen: + files.append(py_file) + seen.add(resolved) + + return files + + +def run_add( + files: list[Path], + *, + license_key: str, + copyright_holder: str, + org_url: str, +) -> int: + """Add SPDX headers to all selected files.""" + for py_file in files: + add_spdx_header( + py_file, + license_key=license_key, + copyright_holder=copyright_holder, + org_url=org_url, + ) + return 0 + + +def run_remove(files: list[Path]) -> int: + """Remove SPDX headers from all selected files.""" + for py_file in files: + remove_header_from_single_file(py_file) + return 0 + + +def run_check(files: list[Path]) -> int: + """Check SPDX headers in all selected files.""" + missing_files = [py_file for py_file in files if not has_spdx_header(py_file)] + + if not missing_files: + print('✓ All Python files have valid SPDX headers.') + return 0 + + print('✗ The following files are missing SPDX headers:') + for py_file in missing_files: + print(f' - {py_file.as_posix()}') + print(f'\nFound {len(missing_files)} files without SPDX headers.') + return 1 + + +def build_parser() -> argparse.ArgumentParser: + """Build the CLI argument parser.""" + parser = argparse.ArgumentParser( + description='Add, remove, or check SPDX headers in Python files.', + ) + subparsers = parser.add_subparsers(dest='command', required=True) + + for command_name in ('check', 'remove', 'add'): + command_parser = subparsers.add_parser(command_name) + command_parser.add_argument( + 'paths', + nargs='+', + help='Relative paths to scan (e.g. src tests)', + ) + command_parser.add_argument( + '--exclude', + nargs='*', + default=[], + help='Exclude paths, glob patterns, or pyproject dotted keys.', + ) + command_parser.add_argument( + '--exclude-from-pyproject-toml', + help='Read exclude patterns from a dotted key in pyproject.toml.', + ) + + return parser + + +def main(argv: Optional[list[str]] = None) -> int: + """Run the SPDX header CLI.""" + parser = build_parser() + args = parser.parse_args(argv) + + repo_path = Path('.').resolve() + repo_root = find_repository_root(repo_path).resolve() + exclude_patterns = get_exclude_patterns( + repo_path, + args.exclude, + args.exclude_from_pyproject_toml, + ) + files = iter_python_files( + args.paths, + repo_root=repo_root, + exclude_patterns=exclude_patterns, + parser=parser, + ) + + if args.command == 'check': + return run_check(files) + + if args.command == 'remove': + return run_remove(files) + + license_key = get_project_license(repo_path) + copyright_holder = get_copyright_holder(repo_path) + org_url = get_org_url(repo_path) + return run_add( + files, + license_key=license_key, + copyright_holder=copyright_holder, + org_url=org_url, + ) + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/tools/param_consistency.py b/tools/param_consistency.py new file mode 100644 index 00000000..cd63989c --- /dev/null +++ b/tools/param_consistency.py @@ -0,0 +1,677 @@ +"""Check and fix consistency between Parameter/Descriptor +definitions and their public property docstrings and type +annotations. + +Usage:: + + python param_consistency.py --check + python param_consistency.py --fix + python param_consistency.py src/mypackage/ --check + +Template (see architecture.md §9.8 for the full spec) +------------------------------------------------------ +Given ``description='Length of the a axis of the unit +cell.'``, ``units='Å'``, and type ``Parameter``: + +Writable:: + + @property + def length_a(self) -> Parameter: + \"""Length of the a axis of the unit cell (Å). + + Reading this property returns the underlying + ``Parameter`` object. Assigning to it updates + the parameter value. + \""" + return self._length_a + + @length_a.setter + def length_a(self, value: float) -> None: + self._length_a.value = value + +Read-only:: + + @property + def length_a(self) -> Parameter: + \"""Length of the a axis of the unit cell (Å). + + Reading this property returns the underlying + ``Parameter`` object. + \""" + return self._length_a + +Rules: + +- ``{desc}`` = description without trailing period + (single source of truth). +- ``{units}`` = units string; omit ``({units})`` when + absent or empty. +- Getter summary: ``{desc} ({units}).`` or ``{desc}.`` +- Getter body mentions the descriptor class and, for + writable properties, notes that assignment updates + the value. +- Setter has **no** docstring. +- Getter return annotation: the descriptor class name. +- Setter value annotation: ``float`` for numeric, + ``str`` for string. +- Setter return annotation: ``None``. + +Exit code 0 when all checks pass (or fix succeeds), +1 otherwise. +""" + +from __future__ import annotations + +import argparse +import ast +import sys +from dataclasses import dataclass +from dataclasses import field +from pathlib import Path + +# --------------------------------------------------------- +# Constants +# --------------------------------------------------------- + +_SRC_ROOT = ( + Path(__file__).resolve().parents[1] + / 'src' + / 'easydiffraction' +) + +_DESCRIPTOR_TYPES = frozenset( + {'Parameter', 'NumericDescriptor', 'StringDescriptor'} +) + +# Canonical setter value annotation per descriptor family. +_SETTER_ANN: dict[str, str] = { + 'Parameter': 'float', + 'NumericDescriptor': 'float', + 'StringDescriptor': 'str', +} + + +# --------------------------------------------------------- +# Data structures +# --------------------------------------------------------- + + +@dataclass +class DescriptorInfo: + """Descriptor definition from ``__init__``.""" + + attr_name: str # e.g. '_length_a' + prop_name: str # e.g. 'length_a' + type_name: str # 'Parameter' | … + description: str # e.g. 'Length of …' + units: str | None # e.g. 'Å', or None + + +@dataclass +class PropertyInfo: + """Property getter / setter AST nodes.""" + + name: str + getter: ast.FunctionDef + setter: ast.FunctionDef | None = None + + +@dataclass +class Edit: + """A source-level edit. + + Replace ``lines[start:end]`` with *new_text*. + When ``start == end`` the edit is an insertion + before that line. + """ + + start: int # 0-based inclusive + end: int # 0-based exclusive + new_text: str + + +@dataclass +class FileResult: + """Analysis result for one source file.""" + + path: Path + issues: list[str] = field(default_factory=list) + edits: list[Edit] = field(default_factory=list) + + +# --------------------------------------------------------- +# Template helpers +# --------------------------------------------------------- + + +def _strip_dot(s: str) -> str: + """Remove trailing period and whitespace.""" + s = s.rstrip() + if s.endswith('.'): + s = s[:-1].rstrip() + return s + + +def _getter_docstring( + desc: str, + units: str | None, + type_name: str, + has_setter: bool, + indent: str, +) -> str: + """Build the expected getter docstring.""" + d = _strip_dot(desc) + summary = f'{d} ({units}).' if units else f'{d}.' + + if has_setter: + body = ( + f'Reading this property returns the underlying ' + f'``{type_name}`` object. ' + f'Assigning to it updates the parameter value.' + ) + else: + body = ( + f'Reading this property returns the underlying ' + f'``{type_name}`` object.' + ) + + return ( + f'{indent}"""{summary}\n' + f'\n' + f'{indent}{body}\n' + f'{indent}"""\n' + ) + + +def _normalize(text: str) -> str: + """Collapse whitespace for comparison.""" + return ' '.join(text.split()).lower() + + +# --------------------------------------------------------- +# AST helpers +# --------------------------------------------------------- + + +def _call_name(node: ast.Call) -> str | None: + """Return the simple name of a Call's func.""" + if isinstance(node.func, ast.Name): + return node.func.id + if isinstance(node.func, ast.Attribute): + return node.func.attr + return None + + +def _kwarg_str( + call: ast.Call, + name: str, +) -> str | None: + """Extract a string keyword argument.""" + for kw in call.keywords: + if ( + kw.arg == name + and isinstance(kw.value, ast.Constant) + and isinstance(kw.value.value, str) + ): + return kw.value.value + return None + + +def _ann_str(ann: ast.expr | None) -> str | None: + """Return annotation as a source string.""" + if ann is None: + return None + if isinstance(ann, ast.Name): + return ann.id + if isinstance(ann, ast.Constant) and isinstance( + ann.value, str + ): + return ann.value # forward reference + return ast.unparse(ann) + + +def _body_indent( + func: ast.FunctionDef, + lines: list[str], +) -> str: + """Compute the indentation for the body.""" + def_line = lines[func.lineno - 1] + return ' ' * ( + len(def_line) - len(def_line.lstrip()) + 4 + ) + + +def _def_line_range( + func: ast.FunctionDef, + lines: list[str], +) -> tuple[int, int]: + """Return 0-based [start, end) of the def.""" + start = func.lineno - 1 + for i in range(start, min(start + 10, len(lines))): + if lines[i].rstrip().endswith(':'): + return start, i + 1 + if func.body and i + 1 >= func.body[0].lineno: + break + return start, start + 1 + + +def _docstring_range( + func: ast.FunctionDef, +) -> tuple[str | None, int, int]: + """Return (text, start_0, end_exclusive_0).""" + if not func.body: + return None, -1, -1 + first = func.body[0] + if ( + isinstance(first, ast.Expr) + and isinstance(first.value, ast.Constant) + and isinstance(first.value.value, str) + ): + # end_lineno is 1-based inclusive + return ( + first.value.value, + first.lineno - 1, + first.end_lineno, + ) + return None, -1, -1 + + +# --------------------------------------------------------- +# Extraction +# --------------------------------------------------------- + + +def _extract_descriptors( + cls: ast.ClassDef, +) -> dict[str, DescriptorInfo]: + """Find self._xxx = DescriptorType(...) in init.""" + result: dict[str, DescriptorInfo] = {} + + init = next( + ( + n + for n in cls.body + if isinstance(n, ast.FunctionDef) + and n.name == '__init__' + ), + None, + ) + if init is None: + return result + + for stmt in ast.walk(init): + if ( + isinstance(stmt, ast.Assign) + and len(stmt.targets) == 1 + ): + target = stmt.targets[0] + value = stmt.value + elif ( + isinstance(stmt, ast.AnnAssign) + and stmt.value is not None + ): + target = stmt.target + value = stmt.value + else: + continue + + # Target must be self._xxx + if not ( + isinstance(target, ast.Attribute) + and isinstance(target.value, ast.Name) + and target.value.id == 'self' + and target.attr.startswith('_') + ): + continue + + if not isinstance(value, ast.Call): + continue + + name = _call_name(value) + if name not in _DESCRIPTOR_TYPES: + continue + + desc_str = _kwarg_str(value, 'description') + if not desc_str or not _strip_dot(desc_str): + continue + + units = _kwarg_str(value, 'units') or None + prop = target.attr.lstrip('_') + result[prop] = DescriptorInfo( + target.attr, prop, name, desc_str, units + ) + + return result + + +def _extract_properties( + cls: ast.ClassDef, +) -> dict[str, PropertyInfo]: + """Find property getters and setters.""" + result: dict[str, PropertyInfo] = {} + + for item in cls.body: + if not isinstance(item, ast.FunctionDef): + continue + for dec in item.decorator_list: + # @property + if ( + isinstance(dec, ast.Name) + and dec.id == 'property' + ): + result[item.name] = PropertyInfo( + item.name, item + ) + break + # @xxx.setter + if ( + isinstance(dec, ast.Attribute) + and dec.attr == 'setter' + and isinstance(dec.value, ast.Name) + and dec.value.id in result + ): + result[dec.value.id].setter = item + break + + return result + + +# --------------------------------------------------------- +# Analysis (shared by --check and --fix) +# --------------------------------------------------------- + + +def _analyze_file(path: Path) -> FileResult: + """Analyze one file, return issues and edits.""" + result = FileResult(path) + try: + source = path.read_text(encoding='utf-8') + except Exception: # noqa: BLE001 + return result + + lines = source.splitlines(keepends=True) + + try: + tree = ast.parse(source, filename=str(path)) + except SyntaxError: + return result + + for node in tree.body: + if not isinstance(node, ast.ClassDef): + continue + + descriptors = _extract_descriptors(node) + properties = _extract_properties(node) + + for prop_name, prop in properties.items(): + if prop_name not in descriptors: + continue + desc = descriptors[prop_name] + _analyze_property( + node.name, prop, desc, lines, result + ) + + return result + + +def _analyze_property( + cls_name: str, + prop: PropertyInfo, + desc: DescriptorInfo, + lines: list[str], + result: FileResult, +) -> None: + """Check one property against the template.""" + loc = f'{cls_name}.{prop.name}' + indent = _body_indent(prop.getter, lines) + has_setter = prop.setter is not None + + # --- Getter return annotation --- + actual_ret = _ann_str(prop.getter.returns) + expected_ret = desc.type_name + if actual_ret != expected_ret: + result.issues.append( + f'{loc}: getter annotation ' + f'-> {actual_ret} (expected {expected_ret})' + ) + ds, de = _def_line_range(prop.getter, lines) + def_indent = lines[ds][ + : len(lines[ds]) - len(lines[ds].lstrip()) + ] + new_def = ( + f'{def_indent}def {prop.name}' + f'(self) -> {expected_ret}:\n' + ) + result.edits.append(Edit(ds, de, new_def)) + + # --- Getter docstring --- + expected_doc = _getter_docstring( + desc.description, + desc.units, + desc.type_name, + has_setter, + indent, + ) + actual_doc_text, doc_s, doc_e = _docstring_range( + prop.getter + ) + + if actual_doc_text is None: + result.issues.append( + f'{loc}: getter missing docstring' + ) + _, def_end = _def_line_range(prop.getter, lines) + result.edits.append( + Edit(def_end, def_end, expected_doc) + ) + else: + actual_src = ''.join(lines[doc_s:doc_e]) + if _normalize(actual_src) != _normalize( + expected_doc + ): + result.issues.append( + f'{loc}: getter docstring ' + 'does not match template' + ) + result.edits.append( + Edit(doc_s, doc_e, expected_doc) + ) + + # --- Setter --- + if prop.setter is None: + return + + # Setter def-line annotations + setter_args = prop.setter.args.args + setter_param = ( + setter_args[1].arg + if len(setter_args) >= 2 + else 'value' + ) + expected_ann = _SETTER_ANN[desc.type_name] + + actual_val_ann = None + if ( + len(setter_args) >= 2 + and setter_args[1].annotation + ): + actual_val_ann = _ann_str( + setter_args[1].annotation + ) + + actual_ret_ann = _ann_str(prop.setter.returns) + + if ( + actual_val_ann != expected_ann + or actual_ret_ann != 'None' + ): + parts: list[str] = [] + if actual_val_ann != expected_ann: + parts.append( + f'value: {actual_val_ann} ' + f'(expected {expected_ann})' + ) + if actual_ret_ann != 'None': + parts.append( + f'return: {actual_ret_ann} ' + '(expected None)' + ) + result.issues.append( + f'{loc}: setter annotation ' + f'— {", ".join(parts)}' + ) + + ds, de = _def_line_range(prop.setter, lines) + def_indent = lines[ds][ + : len(lines[ds]) - len(lines[ds].lstrip()) + ] + new_def = ( + f'{def_indent}def {prop.name}' + f'(self, {setter_param}: ' + f'{expected_ann}) -> None:\n' + ) + result.edits.append(Edit(ds, de, new_def)) + + # Setter docstring — should not exist + setter_doc_text, sd_s, sd_e = _docstring_range( + prop.setter + ) + if setter_doc_text is not None: + result.issues.append( + f'{loc}: setter has docstring ' + '(should have none)' + ) + result.edits.append(Edit(sd_s, sd_e, '')) + + +# --------------------------------------------------------- +# Apply edits +# --------------------------------------------------------- + + +def _apply_edits( + lines: list[str], + edits: list[Edit], +) -> list[str]: + """Apply edits bottom-up to preserve line numbers.""" + sorted_edits = sorted( + edits, key=lambda e: e.start, reverse=True + ) + result = list(lines) + for edit in sorted_edits: + new_lines = edit.new_text.splitlines(keepends=True) + result[edit.start : edit.end] = new_lines + return result + + +# --------------------------------------------------------- +# Entry point +# --------------------------------------------------------- + + +def _collect_py_files(paths: list[str]) -> list[Path]: + """Resolve paths to a sorted list of .py files. + + Each entry can be a directory (recursively globbed) + or a single .py file. When *paths* is empty, + defaults to ``_SRC_ROOT``. + """ + if not paths: + return sorted(_SRC_ROOT.rglob('*.py')) + + result: list[Path] = [] + for raw in paths: + p = Path(raw).resolve() + if p.is_dir(): + result.extend(p.rglob('*.py')) + elif p.is_file() and p.suffix == '.py': + result.append(p) + return sorted(set(result)) + + +def main() -> int: + """Run param-consistency check or fix.""" + parser = argparse.ArgumentParser( + description=( + 'Parameter / property consistency: ' + 'docstrings and type hints.' + ), + ) + parser.add_argument( + 'paths', + nargs='*', + help=( + 'Directories or .py files to scan ' + '(default: src/easydiffraction/)' + ), + ) + group = parser.add_mutually_exclusive_group() + group.add_argument( + '--check', + action='store_true', + help='Validate consistency (default)', + ) + group.add_argument( + '--fix', + action='store_true', + help='Auto-fix docstrings and type hints', + ) + args = parser.parse_args() + + py_files = _collect_py_files(args.paths) + repo_root = Path(__file__).resolve().parents[1] + total_issues = 0 + total_fixed = 0 + files_touched = 0 + + for path in py_files: + result = _analyze_file(path) + if not result.issues: + continue + + try: + rel = path.relative_to(repo_root) + except ValueError: + rel = path + + if args.fix: + source_lines = path.read_text( + encoding='utf-8' + ).splitlines(keepends=True) + fixed_lines = _apply_edits( + source_lines, result.edits + ) + path.write_text( + ''.join(fixed_lines), encoding='utf-8' + ) + count = len(result.issues) + total_fixed += count + files_touched += 1 + print( + f'📝 {rel}: fixed {count} issue(s)' + ) + else: + for issue in result.issues: + print(f' ❌ {rel}: {issue}') + total_issues += len(result.issues) + + # Summary + print() + if args.fix: + print( + f'✅ Fixed {total_fixed} issue(s) ' + f'in {files_touched} file(s).' + ) + return 0 + if total_issues: + print( + f'❌ {total_issues} consistency ' + 'issue(s) found.' + ) + return 1 + print('✅ All properties match the template.') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/remove_license_headers.py b/tools/remove_license_headers.py deleted file mode 100644 index f5d09da5..00000000 --- a/tools/remove_license_headers.py +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-FileCopyrightText: 2026 EasyScience contributors -# SPDX-License-Identifier: BSD-3-Clause -"""Remove SPDX headers from Python files.""" - -from __future__ import annotations - -import argparse -from pathlib import Path -from typing import Optional - -from spdx_headers.operations import remove_header_from_py_files - - -def build_parser() -> argparse.ArgumentParser: - parser = argparse.ArgumentParser( - description='Remove SPDX headers from Python files under the given paths.', - ) - parser.add_argument( - 'paths', - nargs='+', - help='Relative paths to scan (e.g. src tests)', - ) - return parser - - -def main(argv: Optional[list[str]] = None) -> int: - parser = build_parser() - args = parser.parse_args(argv) - - for base_dir in args.paths: - base_path = Path(base_dir) - if not base_path.exists(): - parser.error(f'Path does not exist: {base_dir}') - - remove_header_from_py_files(base_dir) - - return 0 - - -if __name__ == '__main__': - raise SystemExit(main()) From 7374c926387a450cf4f2ace566fe81c206c0ea00 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 09:45:37 +0200 Subject: [PATCH 02/12] Add docstripy to dev depemdencies --- pixi.lock | 101 +++++++++++++++++++++++++++++-------------------- pyproject.toml | 1 + 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/pixi.lock b/pixi.lock index cdb11917..6fee22c6 100644 --- a/pixi.lock +++ b/pixi.lock @@ -83,8 +83,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -92,6 +92,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -124,6 +125,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -250,7 +252,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -334,8 +335,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -343,6 +344,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -375,6 +377,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -501,7 +504,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -585,8 +587,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -594,6 +596,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -626,6 +629,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -752,7 +756,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -826,8 +829,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -835,6 +838,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -867,6 +871,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -993,7 +998,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -1092,8 +1096,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -1101,6 +1105,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cc/a1/40a5c4d8e28b0851d53a8eeeb46fbd73c325a2a9a165f290a5ed90e6c597/fonttools-4.62.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -1133,6 +1138,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -1260,7 +1266,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -1344,8 +1349,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -1353,6 +1358,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/24/7f/66d3f8a9338a9b67fe6e1739f47e1cd5cee78bd3bc1206ef9b0b982289a5/fonttools-4.62.1-cp311-cp311-macosx_10_9_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -1385,6 +1391,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -1512,7 +1519,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -1596,8 +1602,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -1605,6 +1611,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/88/39/23ff32561ec8d45a4d48578b4d241369d9270dc50926c017570e60893701/fonttools-4.62.1-cp311-cp311-macosx_10_9_universal2.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -1637,6 +1644,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -1764,7 +1772,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -1838,8 +1845,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -1847,6 +1854,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d3/97/bf54c5b3f2be34e1f143e6db838dfdc54f2ffa3e68c738934c82f3b2a08d/fonttools-4.62.1-cp311-cp311-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -1879,6 +1887,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -2006,7 +2015,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -2105,8 +2113,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -2114,6 +2122,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/9b/8a/99c8b3c3888c5c474c08dbfd7c8899786de9604b727fcefb055b42c84bba/fonttools-4.62.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -2146,6 +2155,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -2272,7 +2282,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -2356,8 +2365,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -2365,6 +2374,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/66/9e/a769c8e99b81e5a87ab7e5e7236684de4e96246aae17274e5347d11ebd78/fonttools-4.62.1-cp312-cp312-macosx_10_13_x86_64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -2397,6 +2407,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -2523,7 +2534,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -2607,8 +2617,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -2616,6 +2626,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/47/d4/dbacced3953544b9a93088cc10ef2b596d348c983d5c67a404fa41ec51ba/fonttools-4.62.1-cp312-cp312-macosx_10_13_universal2.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -2648,6 +2659,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -2774,7 +2786,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -2848,8 +2859,8 @@ environments: - pypi: https://files.pythonhosted.org/packages/c7/a0/5ff05d1919ca249508012cad89f08fdc6cfbdaa15b41651c5fe6dffaf1d3/dfo_ls-1.6.5-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1e/77/dc8c558f7593132cf8fefec57c4f60c83b16941c574ac5f619abb3ae7933/dill-0.4.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/64/f2/9d779717fd4ff4136d009a8023704f7eb37f2231fbfbe49eb9b430315bcc/easyscience-2.2.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl @@ -2857,6 +2868,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/28/b1/0c2ab56a16f409c6c8a68816e6af707827ad5d629634691ff60a52879792/fonttools-4.62.1-cp312-cp312-win_amd64.whl + - pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl - pypi: https://files.pythonhosted.org/packages/d5/08/c2409cb01d5368dcfedcbaffa7d044cc8957d57a9d0855244a5eb4709d30/funcy-2.0-py2.py3-none-any.whl @@ -2889,6 +2901,7 @@ environments: - pypi: https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl + - pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl @@ -3015,7 +3028,6 @@ environments: - pypi: https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/8f/5e/f1e1dd319e35e962a4e00b33150a8868b6329cc1d19fd533436ba5488f09/uncertainties-3.2.3-py3-none-any.whl - - pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl - pypi: https://files.pythonhosted.org/packages/b7/ee/e9c95cda829131f71a8dff5ce0406059fd16e591c074414e31ada19ba7c3/validate_pyproject-0.25-py3-none-any.whl @@ -4031,15 +4043,6 @@ packages: name: distlib version: 0.4.0 sha256: 9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16 -- pypi: https://files.pythonhosted.org/packages/dc/b4/a7ec1eaee86761a9dbfd339732b4706db3c6b65e970c12f0f56cfcce3dcf/docformatter-1.7.7-py3-none-any.whl - name: docformatter - version: 1.7.7 - sha256: 7af49f8a46346a77858f6651f431b882c503c2f4442c8b4524b920c863277834 - requires_dist: - - charset-normalizer>=3.0.0,<4.0.0 - - tomli>=2.0.0,<3.0.0 ; python_full_version < '3.11' and extra == 'tomli' - - untokenize>=0.1.1,<0.2.0 - requires_python: '>=3.9,<4.0' - pypi: https://files.pythonhosted.org/packages/bf/50/98b146aea0f1cd7531d25f12bea69fa9ce8d1662124f93fb30dc4511b65e/docstring_parser_fork-0.0.14-py3-none-any.whl name: docstring-parser-fork version: 0.0.14 @@ -4051,6 +4054,13 @@ packages: - pydoctor>=25.4.0 ; extra == 'docs' - pytest ; extra == 'test' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/85/d7/9b6ac05350ab7f7d3a730ff143ff3e2cada54514117c37be37e26dc91242/docstripy-0.7.2-py3-none-any.whl + name: docstripy + version: 0.7.2 + sha256: c4ba35de6c1b1c51f7afad4a46d8953aad55dce1a490d198f7e98c8c63efefda + requires_dist: + - nbformat + requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/87/10/2c7edbf230e5c507d38367af498fa94258ed97205d9b4b6f63a921fe9c49/dunamai-1.26.0-py3-none-any.whl name: dunamai version: 1.26.0 @@ -4061,8 +4071,8 @@ packages: requires_python: '>=3.5' - pypi: ./ name: easydynamics - version: 0.3.0+devdirty13 - sha256: c9fe79448ba34fd24162d77b5501f66b07c86af3dc0e0982ef2ce4d1a597b1d9 + version: 0.4.0+devdirty2 + sha256: f0379543a8255c30ddd29af06e88e5b6617a3e4852a54357113225ea20a814ff requires_dist: - darkdetect - easyscience @@ -4077,7 +4087,8 @@ packages: - sympy - build ; extra == 'dev' - copier ; extra == 'dev' - - docformatter ; extra == 'dev' + - docstripy ; extra == 'dev' + - format-docstring ; extra == 'dev' - gitpython ; extra == 'dev' - interrogate ; extra == 'dev' - jinja2 ; extra == 'dev' @@ -4451,6 +4462,15 @@ packages: - skia-pathops>=0.5.0 ; extra == 'all' - uharfbuzz>=0.45.0 ; extra == 'all' requires_python: '>=3.10' +- pypi: https://files.pythonhosted.org/packages/33/b2/986d1220f6ee931e338d272bc1f3ec02cfe5f9b5fad84e95afdad57f1ebc/format_docstring-0.2.7-py3-none-any.whl + name: format-docstring + version: 0.2.7 + sha256: c9d50eafebe0f260e3270ca662ff3a0ed4050f64d95e352f8c5f88d9aede42d6 + requires_dist: + - click>=8.0 + - jupyter-notebook-parser>=0.1.4 + - tomli>=1.1.0 ; python_full_version < '3.11' + requires_python: '>=3.10' - pypi: https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl name: fqdn version: 1.5.1 @@ -5091,6 +5111,11 @@ packages: - jupyter-server>=1.1.2 - importlib-metadata>=4.8.3 ; python_full_version < '3.10' requires_python: '>=3.8' +- pypi: https://files.pythonhosted.org/packages/f4/a4/61adb19f3c74b0dc0e411de4f06ebef564b1f179928f9dffcbd4b378f2ef/jupyter_notebook_parser-0.1.4-py2.py3-none-any.whl + name: jupyter-notebook-parser + version: 0.1.4 + sha256: 27b3b67cf898684e646d569f017cb27046774ad23866cb0bdf51d5f76a46476b + requires_python: '>=3.7' - pypi: https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl name: jupyter-server version: 2.17.0 @@ -10084,10 +10109,6 @@ packages: - python-docs-theme ; extra == 'doc' - uncertainties[arrays,doc,test] ; extra == 'all' requires_python: '>=3.8' -- pypi: https://files.pythonhosted.org/packages/f7/46/e7cea8159199096e1df52da20a57a6665da80c37fb8aeb848a3e47442c32/untokenize-0.1.1.tar.gz - name: untokenize - version: 0.1.1 - sha256: 3865dbbbb8efb4bb5eaa72f1be7f3e0be00ea8b7f125c69cbd1f5fda926f37a2 - pypi: https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl name: uri-template version: 1.3.0 diff --git a/pyproject.toml b/pyproject.toml index dbb31174..236ac5bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,7 @@ dev = [ 'jupyterquiz', # Quizzes in Jupyter notebooks 'pydoclint', # Docstring linter 'format-docstring', # Docstring formatter + 'docstripy', # Convert docstrings to other formats 'interrogate', # Docstring coverage checker 'copier', # Template management 'mike', # MkDocs: Versioned documentation support From a2ec3235b112e0f2d4ce96f56b5de05d6ac53148 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 09:55:11 +0200 Subject: [PATCH 03/12] Apply latest templates --- .copier-answers.yml | 2 +- pixi.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.copier-answers.yml b/.copier-answers.yml index d9076626..c497a08f 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,6 +1,6 @@ # WARNING: Do not edit this file manually. # Any changes will be overwritten by Copier. -_commit: v0.10.1-34-gd2bd5b6 +_commit: v0.10.1-35-g96726f0 _src_path: gh:easyscience/templates app_docs_url: https://easyscience.github.io/dynamics-app app_doi: 10.5281/zenodo.18877180 diff --git a/pixi.toml b/pixi.toml index b3250ce0..e39b7d48 100644 --- a/pixi.toml +++ b/pixi.toml @@ -118,10 +118,11 @@ check = 'pre-commit run --hook-stage manual --all-files' param-docstring-fix = 'python tools/param_consistency.py src/ --fix' docstring-format-fix = 'format-docstring src/' +docstring-transform = 'pixi run docstripy src/ -s=numpy -w' notebook-lint-fix = 'nbqa ruff --fix docs/docs/tutorials/' py-lint-fix = 'ruff check --fix src/ tests/ docs/docs/tutorials/' py-lint-fix-unsafe = 'ruff check --fix --unsafe-fixes src/ tests/ docs/docs/tutorials/' -py-format-fix = "ruff format src/ tests/ docs/docs/tutorials/" +py-format-fix = 'ruff format src/ tests/ docs/docs/tutorials/' nonpy-format-fix = 'npx prettier --write --list-different --config=prettierrc.toml --ignore-unknown .' nonpy-format-fix-modified = 'python tools/nonpy_prettier_modified.py --write' success-message = 'echo "✅ All auto-formatting steps completed successfully!"' From 36d3af00855fa9d4217f284fa6b5e372c9f0dc4e Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 09:56:17 +0200 Subject: [PATCH 04/12] Transfrom docstrings from google to numpy style --- src/easydynamics/analysis/analysis.py | 376 ++++++++----- src/easydynamics/analysis/analysis1d.py | 520 +++++++++++------- src/easydynamics/analysis/analysis_base.py | 246 +++++---- .../convolution/analytical_convolution.py | 283 ++++++---- src/easydynamics/convolution/convolution.py | 113 ++-- .../convolution/convolution_base.py | 184 ++++--- src/easydynamics/convolution/energy_grid.py | 30 +- .../convolution/numerical_convolution.py | 60 +- .../convolution/numerical_convolution_base.py | 206 ++++--- src/easydynamics/experiment/experiment.py | 335 ++++++----- .../sample_model/background_model.py | 27 +- .../sample_model/component_collection.py | 289 ++++++---- .../components/damped_harmonic_oscillator.py | 113 ++-- .../sample_model/components/delta_function.py | 81 ++- .../sample_model/components/exponential.py | 138 +++-- .../components/expression_component.py | 118 ++-- .../sample_model/components/gaussian.py | 110 ++-- .../sample_model/components/lorentzian.py | 111 ++-- .../sample_model/components/mixins.py | 124 +++-- .../components/model_component.py | 121 ++-- .../sample_model/components/polynomial.py | 133 +++-- .../sample_model/components/voigt.py | 146 +++-- .../brownian_translational_diffusion.py | 192 ++++--- .../diffusion_model/diffusion_model_base.py | 90 +-- .../jump_translational_diffusion.py | 227 +++++--- .../sample_model/instrument_model.py | 343 +++++++----- src/easydynamics/sample_model/model_base.py | 261 +++++---- .../sample_model/resolution_model.py | 40 +- src/easydynamics/sample_model/sample_model.py | 256 +++++---- src/easydynamics/utils/detailed_balance.py | 132 +++-- src/easydynamics/utils/utils.py | 54 +- 31 files changed, 3391 insertions(+), 2068 deletions(-) diff --git a/src/easydynamics/analysis/analysis.py b/src/easydynamics/analysis/analysis.py index 23364709..77776cd1 100644 --- a/src/easydynamics/analysis/analysis.py +++ b/src/easydynamics/analysis/analysis.py @@ -38,22 +38,29 @@ def __init__( ) -> None: """Initialize an Analysis object. - Args: - display_name (str | None, default='MyAnalysis'): Display name of the analysis. - unique_name (str | None, default=None): Unique name of the analysis. If - None, a unique name is automatically generated. - experiment (Experiment | None, default=None): The Experiment associated - with this Analysis. If None, a default Experiment is - created. - sample_model (SampleModel | None, default=None): The SampleModel - associated with this Analysis. If None, a default - SampleModel is created. - instrument_model (InstrumentModel | None, default=None): The - InstrumentModel associated with this Analysis. If None, - a default InstrumentModel is created. - extra_parameters (Parameter | list[Parameter] | None, default=None): Extra - parameters to be included in the analysis for advanced - users. If None, no extra parameters are added. + Parameters + ---------- + display_name : str | None, optional + Display name of the analysis. By default, 'MyAnalysis'. + unique_name : str | None, optional + Unique name of the analysis. If + None, a unique name is automatically generated. By default, None. + experiment : Experiment | None, optional + The Experiment associated + with this Analysis. If None, a default Experiment is + created. By default, None. + sample_model : SampleModel | None, optional + The SampleModel + associated with this Analysis. If None, a default + SampleModel is created. By default, None. + instrument_model : InstrumentModel | None, optional + The + InstrumentModel associated with this Analysis. If None, + a default InstrumentModel is created. By default, None. + extra_parameters : Parameter | list[Parameter] | None, optional + Extra + parameters to be included in the analysis for advanced + users. If None, no extra parameters are added. By default, None. """ # Avoid triggering updates before the object is fully @@ -92,26 +99,32 @@ def __init__( def analysis_list(self) -> list[Analysis1d]: """Get the Analysis1d objects associated with this Analysis. - Returns: - list[Analysis1d]: A list of Analysis1d objects, one for - each Q index. + Returns + ------- + list[Analysis1d] + A list of Analysis1d objects, one for + each Q index. """ return self._analysis_list @analysis_list.setter def analysis_list(self, _value: list[Analysis1d]) -> None: - """analysis_list is read-only. + """Analysis_list is read-only. To change the analysis list, modify the experiment, sample model, or instrument model. - Args: - _value (list[Analysis1d]): The new list of Analysis1d objects. This - argument is ignored, as analysis_list is read-only. - - Raises: - AttributeError: Always raised, since analysis_list is - read-only. + Parameters + ---------- + _value : list[Analysis1d] + The new list of Analysis1d objects. This + argument is ignored, as analysis_list is read-only. + + Raises + ------ + AttributeError : + Always raised, since analysis_list is + read-only. """ raise AttributeError( @@ -128,21 +141,28 @@ def calculate( Q_index: int | None = None, energy: sc.Variable | None = None, ) -> list[np.ndarray] | np.ndarray: - """Calculate model data for a specific Q index. If Q_index is - None, calculate for all Q indices and return a list of arrays. - - Args: - Q_index (int | None, default=None): Index of the Q value to calculate - for. If None, calculate for all Q values. - energy (sc.Variable | None, default=None): The energy values to use for - calculating the model. If None, uses the energy from the - experiment. - - Returns: - list[np.ndarray] | np.ndarray: If Q_index is None, returns - a list of numpy arrays, one for each Q index. - If Q_index is an integer, returns a single numpy array - for that Q index. + """Calculate model data for a specific Q index. + + If Q_index is +None, calculate for all Q indices and return a list of arrays. + + Parameters + ---------- + Q_index : int | None, optional + Index of the Q value to calculate + for. If None, calculate for all Q values. By default, None. + energy : sc.Variable | None, optional + The energy values to use for + calculating the model. If None, uses the energy from the + experiment. By default, None. + + Returns + ------- + list[np.ndarray] | np.ndarray + If Q_index is None, returns + a list of numpy arrays, one for each Q index. + If Q_index is an integer, returns a single numpy array + for that Q index. """ if energy is None: energy = self.energy @@ -160,23 +180,29 @@ def fit( ) -> FitResults | list[FitResults]: """Fit the model to the experimental data. - Args: - fit_method (str, default="independent"): Method to use for fitting. Options are - "independent" (fit each Q index independently, one after - the other) or "simultaneous" (fit all Q indices - simultaneously). Default is "independent". - Q_index (int | None, default=None): If fit_method is "independent", - specify which Q index to fit. If None, fit all Q indices - independently. Ignored if fit_method is "simultaneous". - Default is None. - - Returns: - FitResults | list[FitResults]: a list of FitResults if fitting independently, - or a single FitResults object if fitting simultaneously. - - Raises: - ValueError: If fit_method is not "independent" or - "simultaneous" or if there are no Q values available for fitting. + Parameters + ---------- + fit_method : str, optional + Method to use for fitting. Options are + "independent" (fit each Q index independently, one after + the other) or "simultaneous" (fit all Q indices + simultaneously). By default, 'independent'. + Q_index : int | None, optional + If fit_method is "independent", + specify which Q index to fit. If None, fit all Q indices + independently. Ignored if fit_method is "simultaneous". By default, None. + + Raises + ------ + ValueError : + If fit_method is not "independent" or + "simultaneous" or if there are no Q values available for fitting. + + Returns + ------- + FitResults | list[FitResults] + A list of FitResults if fitting independently, + or a single FitResults object if fitting simultaneously. """ if self.Q is None: @@ -203,35 +229,48 @@ def plot_data_and_model( **kwargs: dict[str, Any], ) -> InteractiveFigure: """Plot the experimental data and the model prediction. + Optionally also plot the individual components of the model. Uses Plopp for plotting: https://scipp.github.io/plopp/ - Args: - Q_index (int | None, default=None): Index of the Q value to plot. If - None, plot all Q values. Default is None. - plot_components (bool, default=True): Whether to plot the individual - components. Default is True. - add_background (bool, default=True): Whether to add background components - to the sample model components when plotting. Default is - True. - energy (sc.Variable | None, default=None): The energy values to use for - calculating the model. If None, uses the energy from the - experiment. - **kwargs (dict[str, Any]): Additional keyword arguments passed to plopp - for customizing the plot. - - Raises: - ValueError: If Q_index is out of bounds, or if there is no - data to plot, or if there are no Q values available for - plotting. - RuntimeError: If not in a Jupyter notebook environment. - TypeError: If plot_components or add_background is not True - or False. - - Returns: - InteractiveFigure: A Plopp InteractiveFigure containing the - plot of the data and model. + Parameters + ---------- + Q_index : int | None, optional + Index of the Q value to plot. If + None, plot all Q values. By default, None. + plot_components : bool, optional + Whether to plot the individual + components. By default, True. + add_background : bool, optional + Whether to add background components + to the sample model components when plotting. Default is + True. By default, True. + energy : sc.Variable | None, optional + The energy values to use for + calculating the model. If None, uses the energy from the + experiment. By default, None. + **kwargs : dict[str, Any] + Additional keyword arguments passed to plopp + for customizing the plot. + + Raises + ------ + ValueError : + If Q_index is out of bounds, or if there is no + data to plot, or if there are no Q values available for + plotting. + RuntimeError : + If not in a Jupyter notebook environment. + TypeError : + If plot_components or add_background is not True + or False. + + Returns + ------- + InteractiveFigure + A Plopp InteractiveFigure containing the + plot of the data and model. """ if Q_index is not None: @@ -305,14 +344,18 @@ def parameters_to_dataset(self) -> sc.Dataset: Ensures unit consistency across Q. - Returns: - sc.Dataset: A dataset where each entry is a parameter, with - dimensions "Q" and values corresponding to the parameter - values. - - Raises: - UnitError: If there are inconsistent units for the same - parameter across different Q values. + Raises + ------ + UnitError : + If there are inconsistent units for the same + parameter across different Q values. + + Returns + ------- + sc.Dataset + A dataset where each entry is a parameter, with + dimensions "Q" and values corresponding to the parameter + values. """ ds = sc.Dataset(coords={'Q': self.Q}) @@ -372,20 +415,28 @@ def plot_parameters( ) -> InteractiveFigure: """Plot fitted parameters as a function of Q. - Args: - names (str | list[str] | None, default=None): Name(s) of the parameter(s) - to plot. If None, plots all parameters. - **kwargs (dict[str, Any]): Additional keyword arguments passed to - plopp.slicer for customizing the plot (e.g., title, - linestyle, marker, color). - - Returns: - InteractiveFigure: A Plopp InteractiveFigure containing the - plot of the parameters. - - Raises: - TypeError: If names is not a string, list of strings, or None. - ValueError: If any of the specified parameter names are not found in the dataset. + Parameters + ---------- + names : str | list[str] | None, optional + Name(s) of the parameter(s) + to plot. If None, plots all parameters. By default, None. + **kwargs : dict[str, Any] + Additional keyword arguments passed to + plopp.slicer for customizing the plot (e.g., title, + linestyle, marker, color). + + Raises + ------ + TypeError : + If names is not a string, list of strings, or None. + ValueError : + If any of the specified parameter names are not found in the dataset. + + Returns + ------- + InteractiveFigure + A Plopp InteractiveFigure containing the + plot of the parameters. """ ds = self.parameters_to_dataset() @@ -423,10 +474,12 @@ def fix_energy_offset(self, Q_index: int | None = None) -> None: """Fix the energy offset parameter(s) for a specific Q index, or for all Q indices if Q_index is None. - Args: - Q_index (int | None, default=None): Index of the Q value to - fix the energy offset for. If None, fixes the energy - offset for all Q values. Default is None. + Parameters + ---------- + Q_index : int | None, optional + Index of the Q value to + fix the energy offset for. If None, fixes the energy + offset for all Q values. By default, None. """ if Q_index is not None: Q_index = self._verify_Q_index(Q_index) @@ -439,10 +492,12 @@ def free_energy_offset(self, Q_index: int | None = None) -> None: """Free the energy offset parameter(s) for a specific Q index, or for all Q indices if Q_index is None. - Args: - Q_index (int | None, default=None): Index of the Q value to - free the energy offset for. If None, frees the energy - offset for all Q values. Default is None. + Parameters + ---------- + Q_index : int | None, optional + Index of the Q value to + free the energy offset for. If None, frees the energy + offset for all Q values. By default, None. """ if Q_index is not None: Q_index = self._verify_Q_index(Q_index) @@ -497,12 +552,16 @@ def _on_instrument_model_changed(self) -> None: def _fit_single_Q(self, Q_index: int) -> FitResults: """Fit data for a single Q index. - Args: - Q_index (int): Index of the Q value to fit. + Parameters + ---------- + Q_index : int + Index of the Q value to fit. - Returns: - FitResults: The results of the fit for the specified - Q index. + Returns + ------- + FitResults + The results of the fit for the specified + Q index. """ Q_index = self._verify_Q_index(Q_index) @@ -512,18 +571,22 @@ def _fit_single_Q(self, Q_index: int) -> FitResults: def _fit_all_Q_independently(self) -> list[FitResults]: """Fit data for all Q indices independently. - Returns: - list[FitResults]: A list of FitResults, one for each Q - index. + Returns + ------- + list[FitResults] + A list of FitResults, one for each Q + index. """ return [analysis.fit() for analysis in self.analysis_list] def _fit_all_Q_simultaneously(self) -> FitResults: """Fit data for all Q indices simultaneously. - Returns: - FitResults: The results of the simultaneous fit across all - Q indices. + Returns + ------- + FitResults + The results of the simultaneous fit across all + Q indices. """ xs = [] @@ -554,23 +617,29 @@ def get_fit_functions(self) -> list[callable]: """Get fit functions for all Q indices, which can be used for simultaneous fitting. - Returns: - list[callable]: A list of fit functions, one for each - Q index. + Returns + ------- + list[callable] + A list of fit functions, one for each + Q index. """ return [analysis.as_fit_function() for analysis in self.analysis_list] def _create_model_array(self, energy: sc.Variable | None = None) -> sc.DataArray: """Create a scipp array for the model. - Args: - energy (sc.Variable | None, default=None): The energy values to use for - calculating the model. If None, uses the energy from the - experiment. - - Returns: - sc.DataArray: A DataArray containing the model values, with - dimensions "Q" and "energy". + Parameters + ---------- + energy : sc.Variable | None, optional + The energy values to use for + calculating the model. If None, uses the energy from the + experiment. By default, None. + + Returns + ------- + sc.DataArray + A DataArray containing the model values, with + dimensions "Q" and "energy". """ if energy is None: energy = self.energy @@ -588,20 +657,27 @@ def _create_components_dataset( """Create a scipp dataset containing the individual components of the model for plotting. - Args: - add_background (bool, default=True): Whether to add background components - to the sample model components when creating the - dataset. - energy (sc.Variable | None, default=None): The energy values to use for - calculating the components. If None, uses the energy from - the experiment. - - Raises: - TypeError: If add_background is not True or False. - - Returns: - sc.Dataset: A scipp Dataset where each entry is a component - of the model, with dimensions "Q". + Parameters + ---------- + add_background : bool, optional + Whether to add background components + to the sample model components when creating the + dataset. By default, True. + energy : sc.Variable | None, optional + The energy values to use for + calculating the components. If None, uses the energy from + the experiment. By default, None. + + Raises + ------ + TypeError : + If add_background is not True or False. + + Returns + ------- + sc.Dataset + A scipp Dataset where each entry is a component + of the model, with dimensions "Q". """ if not isinstance(add_background, bool): raise TypeError('add_background must be True or False.') diff --git a/src/easydynamics/analysis/analysis1d.py b/src/easydynamics/analysis/analysis1d.py index 81f98f55..bbfbc753 100644 --- a/src/easydynamics/analysis/analysis1d.py +++ b/src/easydynamics/analysis/analysis1d.py @@ -40,25 +40,33 @@ def __init__( ) -> None: """Initialize a Analysis1d. - Args: - display_name (str | None, default='MyAnalysis'): Display name of the analysis. - unique_name (str | None, default=None): Unique name of the analysis. If - None, a unique name is automatically generated. - experiment (Experiment | None, default=None): The Experiment associated - with this Analysis. If None, a default Experiment is - created. - sample_model (SampleModel | None, default=None): The SampleModel - associated with this Analysis. If None, a default - SampleModel is created. - instrument_model (InstrumentModel | None, default=None): The - InstrumentModel associated with this Analysis. If None, - a default InstrumentModel is created. - Q_index (int | None, default=None): The Q index to analyze. If None, the - analysis will not be able to calculate or fit until a - Q index is set. - extra_parameters (Parameter | list[Parameter] | None, default=None): Extra - parameters to be included in the analysis for advanced - users. If None, no extra parameters are added. + Parameters + ---------- + display_name : str | None, optional + Display name of the analysis. By default, 'MyAnalysis'. + unique_name : str | None, optional + Unique name of the analysis. If + None, a unique name is automatically generated. By default, None. + experiment : Experiment | None, optional + The Experiment associated + with this Analysis. If None, a default Experiment is + created. By default, None. + sample_model : SampleModel | None, optional + The SampleModel + associated with this Analysis. If None, a default + SampleModel is created. By default, None. + instrument_model : InstrumentModel | None, optional + The + InstrumentModel associated with this Analysis. If None, + a default InstrumentModel is created. By default, None. + Q_index : int | None, optional + The Q index to analyze. If None, the + analysis will not be able to calculate or fit until a + Q index is set. By default, None. + extra_parameters : Parameter | list[Parameter] | None, optional + Extra + parameters to be included in the analysis for advanced + users. If None, no extra parameters are added. By default, None. """ super().__init__( display_name=display_name, @@ -91,8 +99,10 @@ def __init__( def Q_index(self) -> int | None: """Get the Q index associated with this Analysis. - Returns: - int | None: The Q index associated with this Analysis. + Returns + ------- + int | None + The Q index associated with this Analysis. """ return self._Q_index @@ -101,8 +111,10 @@ def Q_index(self) -> int | None: def Q_index(self, value: int | None) -> None: """Set the Q index for single Q analysis. - Args: - value (int | None): The Q index. + Parameters + ---------- + value : int | None + The Q index. """ self._Q_index = self._verify_Q_index(value) @@ -113,16 +125,22 @@ def Q_index(self, value: int | None) -> None: ############# def calculate(self, energy: sc.Variable | None = None) -> np.ndarray: - """Calculate the model prediction for the chosen Q index. Makes - sure the convolver is up to date before calculating. - - Args: - energy (sc.Variable | None, default=None): Optional energy grid to use for - calculation. If None, the energy grid from the experiment - is used. - - Returns: - np.ndarray: The calculated model prediction. + """Calculate the model prediction for the chosen Q index. + + Makes +sure the convolver is up to date before calculating. + + Parameters + ---------- + energy : sc.Variable | None, optional + Optional energy grid to use for + calculation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + np.ndarray + The calculated model prediction. """ energy = self._verify_energy(energy) self._convolver = self._create_convolver(energy=energy) @@ -130,16 +148,22 @@ def calculate(self, energy: sc.Variable | None = None) -> np.ndarray: return self._calculate(energy=energy) def _calculate(self, energy: sc.Variable | None = None) -> np.ndarray: - """Calculate the model prediction for the chosen Q index. Does - not check if the convolver is up to date. - - Args: - energy (sc.Variable | None, default=None): Optional energy grid to use for - calculation. If None, the energy grid from the experiment - is used. - - Returns: - np.ndarray: The calculated model prediction. + """Calculate the model prediction for the chosen Q index. + + Does +not check if the convolver is up to date. + + Parameters + ---------- + energy : sc.Variable | None, optional + Optional energy grid to use for + calculation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + np.ndarray + The calculated model prediction. """ sample_intensity = self._evaluate_sample(energy=energy) @@ -156,12 +180,16 @@ def fit(self) -> FitResults: Convolution objects are created once and reused during parameter optimization for performance reasons. - Returns: - FitResults: The result of the fit. + Raises + ------ + ValueError : + If no experiment is associated with this + Analysis. - Raises: - ValueError: If no experiment is associated with this - Analysis. + Returns + ------- + FitResults + The result of the fit. """ if self._experiment is None: raise ValueError('No experiment is associated with this Analysis.') @@ -195,21 +223,27 @@ def as_fit_function( experiment. So we ignore the x input and just return the calculated model. - Args: - _x (np.ndarray | sc.Variable | None, default=None): Ignored. - The energy grid is taken from the experiment. - **kwargs (dict[str, Any]): Ignored. Included for compatibility with the - EasyScience fitter. - - Returns: - callable: A function that can be used as a fit function in the - EasyScience fitter, which returns the calculated model. + Parameters + ---------- + _x : np.ndarray | sc.Variable | None, optional + Ignored. + The energy grid is taken from the experiment. By default, None. + **kwargs : dict[str, Any] + Ignored. Included for compatibility with the + EasyScience fitter. + + Returns + ------- + callable + A function that can be used as a fit function in the + EasyScience fitter, which returns the calculated model. """ def fit_function( _x: np.ndarray | sc.Variable | None = None, **kwargs: dict[str, Any], # noqa: ARG001 ) -> np.ndarray: + """Fit function.""" return self._calculate() return fit_function @@ -217,8 +251,10 @@ def fit_function( def get_all_variables(self) -> list[DescriptorNumber]: """Get all variables used in the analysis. - Returns: - list[DescriptorNumber]: A list of all variables. + Returns + ------- + list[DescriptorNumber] + A list of all variables. """ variables = self.sample_model.get_all_variables(Q_index=self.Q_index) @@ -242,22 +278,31 @@ def plot_data_and_model( Uses Plopp for plotting: https://scipp.github.io/plopp/ - Args: - plot_components (bool, default=True): Whether to plot the individual - components of the model. - add_background (bool, default=True): Whether to add the background to the - model prediction when plotting individual components. - energy (sc.Variable | None, default=None): Optional energy grid to use for - plotting. If None, the energy grid from the experiment - is used. - **kwargs (dict[str, Any]): Keyword arguments to pass to the plotting - function. - - Returns: - InteractiveFigure: A plot of the data and model. - - Raises: - ValueError: If no data is available to plot. + Parameters + ---------- + plot_components : bool, optional + Whether to plot the individual + components of the model. By default, True. + add_background : bool, optional + Whether to add the background to the + model prediction when plotting individual components. By default, True. + energy : sc.Variable | None, optional + Optional energy grid to use for + plotting. If None, the energy grid from the experiment + is used. By default, None. + **kwargs : dict[str, Any] + Keyword arguments to pass to the plotting + function. + + Raises + ------ + ValueError : + If no data is available to plot. + + Returns + ------- + InteractiveFigure + A plot of the data and model. """ import plopp as pp @@ -317,14 +362,20 @@ def free_energy_offset(self) -> None: ############# def _require_Q_index(self) -> int: - """Get the Q index, ensuring it is set. Raises a ValueError if - the Q index is not set. + """Get the Q index, ensuring it is set. - Returns: - int: The Q index. + Raises a ValueError if +the Q index is not set. - Raises: - ValueError: If the Q index is not set. + Raises + ------ + ValueError : + If the Q index is not set. + + Returns + ------- + int + The Q index. """ if self._Q_index is None: raise ValueError('Q_index must be set.') @@ -344,15 +395,21 @@ def _on_Q_index_changed(self) -> None: def _verify_energy(self, energy: sc.Variable | None) -> sc.Variable | None: """Verify that the provided energy is the correct type. - Args: - energy (sc.Variable | None): The energy to verify. - - Returns: - sc.Variable | None: The verified energy, or None if no - energy is provided. - - Raises: - TypeError: If energy is not a sc.Variable or None. + Parameters + ---------- + energy : sc.Variable | None + The energy to verify. + + Raises + ------ + TypeError : + If energy is not a sc.Variable or None. + + Returns + ------- + sc.Variable | None + The verified energy, or None if no + energy is provided. """ if energy is not None and not isinstance(energy, sc.Variable): @@ -366,16 +423,23 @@ def _calculate_energy_with_offset( ) -> sc.Variable: """Calculate the energy grid with the energy offset applied. - Args: - energy (sc.Variable): The energy grid to apply the offset to. - energy_offset (Parameter): The energy offset to apply. - - Returns: - sc.Variable: The energy grid with the offset applied. - - Raises: - sc.UnitError: If the energy and energy offset have - incompatible units. + Parameters + ---------- + energy : sc.Variable + The energy grid to apply the offset to. + energy_offset : Parameter + The energy offset to apply. + + Raises + ------ + sc.UnitError : + If the energy and energy offset have + incompatible units. + + Returns + ------- + sc.Variable + The energy grid with the offset applied. """ if energy.unit != energy_offset.unit: @@ -415,20 +479,27 @@ def _evaluate_components( If convolve is False, evaluate the components directly without convolution (for background). - Args: - components (ComponentCollection | ModelComponent): The - components to evaluate. - convolver (Convolution | None, default=None): An optional Convolution - object to use for convolution. If None, a new - Convolution object will be created if convolve is True. - convolve (bool, default=True): Whether to perform convolution with the - resolution. Default is True. - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - np.ndarray: The evaluated contribution of the components. + Parameters + ---------- + components : ComponentCollection | ModelComponent + The + components to evaluate. + convolver : Convolution | None, optional + An optional Convolution + object to use for convolution. If None, a new + Convolution object will be created if convolve is True. By default, None. + convolve : bool, optional + Whether to perform convolution with the + resolution. By default, True. + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + np.ndarray + The evaluated contribution of the components. """ Q_index = self._require_Q_index() @@ -481,13 +552,17 @@ def _evaluate_sample( Assumes that self._convolver is up to date. - Args: - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - np.ndarray: The evaluated sample contribution. + Parameters + ---------- + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + np.ndarray + The evaluated sample contribution. """ Q_index = self._require_Q_index() components = self.sample_model.get_component_collection(Q_index=Q_index) @@ -505,15 +580,20 @@ def _evaluate_sample_component( ) -> np.ndarray: """Evaluate a single sample component for the chosen Q index. - Args: - component (ModelComponent): The sample component to - evaluate. - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - np.ndarray: The evaluated sample component contribution. + Parameters + ---------- + component : ModelComponent + The sample component to + evaluate. + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + np.ndarray + The evaluated sample component contribution. """ return self._evaluate_components( components=component, @@ -525,13 +605,17 @@ def _evaluate_sample_component( def _evaluate_background(self, energy: sc.Variable | None = None) -> np.ndarray: """Evaluate the background contribution for the chosen Q index. - Args: - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - np.ndarray: The evaluated background contribution. + Parameters + ---------- + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + np.ndarray + The evaluated background contribution. """ Q_index = self._require_Q_index() background_components = self.instrument_model.background_model.get_component_collection( @@ -552,15 +636,20 @@ def _evaluate_background_component( """Evaluate a single background component for the chosen Q index. - Args: - component (ModelComponent): The background component to - evaluate. - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - np.ndarray: The evaluated background component contribution. + Parameters + ---------- + component : ModelComponent + The background component to + evaluate. + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + np.ndarray + The evaluated background component contribution. """ return self._evaluate_components( @@ -578,14 +667,18 @@ def _create_convolver( index. If the necessary components for convolution are not available, return None. - Args: - energy (sc.Variable | None, default=None): Optional energy grid to use for - convolution. If None, the energy grid from the experiment - is used. - - Returns: - Convolution | None: The initialized Convolution object or - None if not available. + Parameters + ---------- + energy : sc.Variable | None, optional + Optional energy grid to use for + convolution. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + Convolution | None + The initialized Convolution object or + None if not available. """ Q_index = self._require_Q_index() @@ -621,19 +714,27 @@ def _create_component_scipp_array( background: np.ndarray | None = None, energy: sc.Variable | None = None, ) -> sc.DataArray: - """Create a scipp DataArray for a single component. Adds the - background if it is not None. - - Args: - component (ModelComponent): The component to evaluate. - background (np.ndarray | None, default=None): Optional background to add - to the component. - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - sc.DataArray: The model calculation of the component. + """Create a scipp DataArray for a single component. + + Adds the +background if it is not None. + + Parameters + ---------- + component : ModelComponent + The component to evaluate. + background : np.ndarray | None, optional + Optional background to add + to the component. By default, None. + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + sc.DataArray + The model calculation of the component. """ values = self._evaluate_sample_component(component=component, energy=energy) @@ -648,14 +749,19 @@ def _create_background_component_scipp_array( ) -> sc.DataArray: """Create a scipp DataArray for a single background component. - Args: - component (ModelComponent): The component to evaluate. - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - sc.DataArray: The model calculation of the component. + Parameters + ---------- + component : ModelComponent + The component to evaluate. + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + sc.DataArray + The model calculation of the component. """ values = self._evaluate_background_component( @@ -668,14 +774,18 @@ def _create_sample_scipp_array(self, energy: sc.Variable | None = None) -> sc.Da """Create a scipp DataArray for the full sample model including background. - Args: - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - sc.DataArray: The model calculation of the full sample - model. + Parameters + ---------- + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + sc.DataArray + The model calculation of the full sample + model. """ values = self.calculate(energy=energy) return self._to_scipp_array(values=values, energy=energy) @@ -688,15 +798,20 @@ def _create_components_dataset_single_Q( """Create sc.DataArrays for all sample and background components. - Args: - add_background (bool, default=True): Whether to add background components. - energy (sc.Variable | None, default=None): Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. - - Returns: - dict[str, sc.DataArray]: A dictionary of component names to - their corresponding sc.DataArrays. + Parameters + ---------- + add_background : bool, optional + Whether to add background components. By default, True. + energy : sc.Variable | None, optional + Optional energy grid to use for + evaluation. If None, the energy grid from the experiment + is used. By default, None. + + Returns + ------- + dict[str, sc.DataArray] + A dictionary of component names to + their corresponding sc.DataArrays. """ scipp_arrays = {} sample_components = self.sample_model.get_component_collection( @@ -730,14 +845,19 @@ def _to_scipp_array( """Convert a numpy array of values to a sc.DataArray with the correct coordinates for energy and Q. - Args: - values (np.ndarray): The values to convert. - energy (sc.Variable | None, default=None): Optional energy grid to use for the - energy coordinate. If None, the energy grid from the - experiment is used. - - Returns: - sc.DataArray: The converted sc.DataArray. + Parameters + ---------- + values : np.ndarray + The values to convert. + energy : sc.Variable | None, optional + Optional energy grid to use for the + energy coordinate. If None, the energy grid from the + experiment is used. By default, None. + + Returns + ------- + sc.DataArray + The converted sc.DataArray. """ if energy is None: diff --git a/src/easydynamics/analysis/analysis_base.py b/src/easydynamics/analysis/analysis_base.py index 61247e0e..7915c69d 100644 --- a/src/easydynamics/analysis/analysis_base.py +++ b/src/easydynamics/analysis/analysis_base.py @@ -12,8 +12,10 @@ class AnalysisBase(EasyScienceModelBase): - """Base class for analysis in EasyDynamics. This class is not meant - to be used directly. + """Base class for analysis in EasyDynamics. + + This class is not meant +to be used directly. An Analysis consists of an Experiment, a SampleModel, and an InstrumentModel. The Experiment contains the data to be fitted, the @@ -33,29 +35,38 @@ def __init__( ) -> None: """Initialize the AnalysisBase. - Args: - display_name (str | None, default='MyAnalysis'): Display name of the analysis. - unique_name (str | None, default=None): Unique name of the analysis. If - None, a unique name is automatically generated. - experiment (Experiment | None, default=None): The Experiment associated - with this Analysis. If None, a default Experiment is - created. - sample_model (SampleModel | None, default=None): The SampleModel - associated with this Analysis. If None, a default - SampleModel is created. - instrument_model (InstrumentModel | None, default=None): The - InstrumentModel associated with this Analysis. If None, - a default InstrumentModel is created. - extra_parameters (Parameter | list[Parameter] | None, default=None): Extra - parameters to be included in the analysis for advanced - users. If None, no extra parameters are added. - - Raises: - TypeError: If experiment is not an Experiment or None or - if sample_model is not a SampleModel or None or if - instrument_model is not an InstrumentModel or None or if - extra_parameters is not a Parameter, a list of Parameters, - or None. + Parameters + ---------- + display_name : str | None, optional + Display name of the analysis. By default, 'MyAnalysis'. + unique_name : str | None, optional + Unique name of the analysis. If + None, a unique name is automatically generated. By default, None. + experiment : Experiment | None, optional + The Experiment associated + with this Analysis. If None, a default Experiment is + created. By default, None. + sample_model : SampleModel | None, optional + The SampleModel + associated with this Analysis. If None, a default + SampleModel is created. By default, None. + instrument_model : InstrumentModel | None, optional + The + InstrumentModel associated with this Analysis. If None, + a default InstrumentModel is created. By default, None. + extra_parameters : Parameter | list[Parameter] | None, optional + Extra + parameters to be included in the analysis for advanced + users. If None, no extra parameters are added. By default, None. + + Raises + ------ + TypeError : + If experiment is not an Experiment or None or + if sample_model is not a SampleModel or None or if + instrument_model is not an InstrumentModel or None or if + extra_parameters is not a Parameter, a list of Parameters, + or None. """ super().__init__(display_name=display_name, unique_name=unique_name) @@ -103,8 +114,10 @@ def __init__( def experiment(self) -> Experiment: """Get the Experiment associated with this Analysis. - Returns: - Experiment: The Experiment associated with this Analysis. + Returns + ------- + Experiment + The Experiment associated with this Analysis. """ return self._experiment @@ -113,11 +126,15 @@ def experiment(self) -> Experiment: def experiment(self, value: Experiment) -> None: """Set the Experiment for this Analysis. - Args: - value (Experiment): The Experiment to set for this Analysis. + Parameters + ---------- + value : Experiment + The Experiment to set for this Analysis. - Raises: - TypeError: if value is not an Experiment. + Raises + ------ + TypeError : + If value is not an Experiment. """ if not isinstance(value, Experiment): @@ -129,8 +146,10 @@ def experiment(self, value: Experiment) -> None: def sample_model(self) -> SampleModel: """Get the SampleModel associated with this Analysis. - Returns: - SampleModel: The SampleModel associated with this Analysis. + Returns + ------- + SampleModel + The SampleModel associated with this Analysis. """ return self._sample_model @@ -139,11 +158,15 @@ def sample_model(self) -> SampleModel: def sample_model(self, value: SampleModel) -> None: """Set the SampleModel for this Analysis. - Args: - value (SampleModel): The SampleModel to set for this Analysis. + Parameters + ---------- + value : SampleModel + The SampleModel to set for this Analysis. - Raises: - TypeError: if value is not a SampleModel. + Raises + ------ + TypeError : + If value is not a SampleModel. """ if not isinstance(value, SampleModel): raise TypeError('sample_model must be an instance of SampleModel') @@ -154,9 +177,11 @@ def sample_model(self, value: SampleModel) -> None: def instrument_model(self) -> InstrumentModel: """Get the InstrumentModel associated with this Analysis. - Returns: - InstrumentModel: The InstrumentModel associated with this - Analysis. + Returns + ------- + InstrumentModel + The InstrumentModel associated with this + Analysis. """ return self._instrument_model @@ -164,12 +189,16 @@ def instrument_model(self) -> InstrumentModel: def instrument_model(self, value: InstrumentModel) -> None: """Set the InstrumentModel for this Analysis. - Args: - value (InstrumentModel): The InstrumentModel to set for this - Analysis. + Parameters + ---------- + value : InstrumentModel + The InstrumentModel to set for this + Analysis. - Raises: - TypeError: if value is not an InstrumentModel. + Raises + ------ + TypeError : + If value is not an InstrumentModel. """ if not isinstance(value, InstrumentModel): raise TypeError('instrument_model must be an instance of InstrumentModel') @@ -181,9 +210,11 @@ def Q(self) -> sc.Variable | None: """Get the Q values from the associated Experiment, if available. - Returns: - sc.Variable | None: The Q values from the associated Experiment, - if available, and None if not. + Returns + ------- + sc.Variable | None + The Q values from the associated Experiment, + if available, and None if not. """ return self.experiment.Q @@ -192,12 +223,16 @@ def Q(self, _value: sc.Variable) -> None: """Q cannot be set, as it is a read-only property derived from the Experiment. - Args: - _value (sc.Variable): The Q values to set. This argument is - ignored, as Q is a read-only property. + Parameters + ---------- + _value : sc.Variable + The Q values to set. This argument is + ignored, as Q is a read-only property. - Raises: - AttributeError: If trying to set Q. + Raises + ------ + AttributeError : + If trying to set Q. """ raise AttributeError('Q is a read-only property derived from the Experiment.') @@ -206,9 +241,11 @@ def energy(self) -> sc.Variable | None: """Get the energy values from the associated Experiment, if available. - Returns: - sc.Variable | None: The energy values from the associated - Experiment, if available, and None if not. + Returns + ------- + sc.Variable | None + The energy values from the associated. + Experiment, if available, and None if not. """ return self.experiment.energy @@ -218,12 +255,16 @@ def energy(self, _value: sc.Variable) -> None: """Energy cannot be set, as it is a read-only property derived from the Experiment. - Args: - _value (sc.Variable): The energy values to set. This argument is - ignored, as energy is a read-only property. + Parameters + ---------- + _value : sc.Variable + The energy values to set. This argument is + ignored, as energy is a read-only property. - Raises: - AttributeError: If trying to set energy. + Raises + ------ + AttributeError : + If trying to set energy. """ raise AttributeError('energy is a read-only property derived from the Experiment.') @@ -233,9 +274,11 @@ def temperature(self) -> Parameter | None: """Get the temperature from the associated SampleModel, if available. - Returns: - Parameter | None: The temperature from the associated SampleModel, - if available, and None if not. + Returns + ------- + Parameter | None + The temperature from the associated SampleModel, + if available, and None if not. """ return self.sample_model.temperature @@ -245,13 +288,17 @@ def temperature(self, _value: np.ndarray | Parameter) -> None: """Temperature cannot be set, as it is a read-only property derived from the SampleModel. - Args: - _value (np.ndarray | Parameter): The temperature to set. - This argument is ignored, as temperature is a read-only - property. - - Raises: - AttributeError: If trying to set temperature. + Parameters + ---------- + _value : np.ndarray | Parameter + The temperature to set. + This argument is ignored, as temperature is a read-only + property. + + Raises + ------ + AttributeError : + If trying to set temperature. """ raise AttributeError('temperature is a read-only property derived from the SampleModel.') @@ -260,9 +307,11 @@ def temperature(self, _value: np.ndarray | Parameter) -> None: def extra_parameters(self) -> list[Parameter]: """Get the extra parameters included in this Analysis. - Returns: - list[Parameter]: The extra parameters included in this - Analysis. + Returns + ------- + list[Parameter] + The extra parameters included in this + Analysis. """ return self._extra_parameters @@ -270,13 +319,17 @@ def extra_parameters(self) -> list[Parameter]: def extra_parameters(self, value: Parameter | list[Parameter]) -> None: """Set the extra parameters for this Analysis. - Args: - value (Parameter | list[Parameter]): The extra parameters to - include in this Analysis. - - Raises: - TypeError: If value is not a Parameter, a list of - Parameters, or None. + Parameters + ---------- + value : Parameter | list[Parameter] + The extra parameters to + include in this Analysis. + + Raises + ------ + TypeError : + If value is not a Parameter, a list of + Parameters, or None. """ if isinstance(value, Parameter): self._extra_parameters = [value] @@ -326,15 +379,22 @@ def _on_instrument_model_changed(self) -> None: def _verify_Q_index(self, Q_index: int | None) -> int | None: """Verify that the Q index is valid. - Args: - Q_index (int | None): The Q index to verify. - - Returns: - int | None: The verified Q index. - - Raises: - TypeError: If Q_index is not an integer or None. - IndexError: If the Q index is not valid. + Parameters + ---------- + Q_index : int | None + The Q index to verify. + + Raises + ------ + TypeError : + If Q_index is not an integer or None. + IndexError : + If the Q index is not valid. + + Returns + ------- + int | None + The verified Q index. """ if Q_index is None: return None @@ -353,8 +413,10 @@ def _verify_Q_index(self, Q_index: int | None) -> int | None: def __repr__(self) -> str: """Return a string representation of the Analysis. - Returns: - str: A string representation of the Analysis. + Returns + ------- + str + A string representation of the Analysis. """ return f' {self.__class__.__name__} (display_name={self.display_name}, \ unique_name={self.unique_name})' diff --git a/src/easydynamics/convolution/analytical_convolution.py b/src/easydynamics/convolution/analytical_convolution.py index 70ecc318..43a29fe1 100644 --- a/src/easydynamics/convolution/analytical_convolution.py +++ b/src/easydynamics/convolution/analytical_convolution.py @@ -45,17 +45,21 @@ def __init__( ) -> None: """Initialize an AnalyticalConvolution. - Args: - energy (np.ndarray | sc.Variable): 1D array of energy values - where the convolution is evaluated. - energy_unit (str | sc.Unit, default='meV'): The unit of the - energy. - sample_components (ComponentCollection | ModelComponent | None, default=None): - The sample model to be convolved. - resolution_components (ComponentCollection | ModelComponent | None, default=None): - The resolution model to convolve with. - energy_offset (Numeric | Parameter, default=0.0): An offset to - shift the energy values by. + Parameters + ---------- + energy : np.ndarray | sc.Variable + 1D array of energy values + where the convolution is evaluated. + energy_unit : str | sc.Unit, optional + The unit of the + energy. By default, 'meV'. + sample_components : ComponentCollection | ModelComponent | None, optional + The sample model to be convolved. By default, None. + resolution_components : ComponentCollection | ModelComponent | None, optional + The resolution model to convolve with. By default, None. + energy_offset : Numeric | Parameter, optional + An offset to + shift the energy values by. By default, 0.0. """ super().__init__( energy=energy, @@ -69,13 +73,16 @@ def convolution( self, ) -> np.ndarray: """Convolve sample with resolution analytically if possible. + Accepts ComponentCollection or single ModelComponent for each. Possible analytical convolutions are any combination of delta functions, Gaussians, Lorentzians and Voigt profiles. - Returns: - np.ndarray: The convolution of the sample_components and - resolution_components values evaluated at self.energy. + Returns + ------- + np.ndarray + The convolution of the sample_components and + resolution_components values evaluated at self.energy. """ sample_components = self.sample_components.components @@ -130,18 +137,25 @@ def _convolute_analytic_pair( All areas are multiplied in the convolution. - Args: - sample_component (ModelComponent): The sample component to - be convolved. - resolution_component (ModelComponent): The resolution - component to convolve with. - - Returns: - np.ndarray: The convolution result - - Raises: - ValueError: If the component pair cannot be handled - analytically. + Parameters + ---------- + sample_component : ModelComponent + The sample component to + be convolved. + resolution_component : ModelComponent + The resolution + component to convolve with. + + Raises + ------ + ValueError : + If the component pair cannot be handled + analytically. + + Returns + ------- + np.ndarray + The convolution result. """ if isinstance(resolution_component, DeltaFunction): @@ -192,14 +206,18 @@ def _convolute_delta_any( ComponentCollection shifted by the delta center. The areas are multiplied. - Args: - sample_component (DeltaFunction): The sample component to - be convolved. - resolution_components (ComponentCollection | ModelComponent) - : The resolution model to convolve with. - - Returns: - np.ndarray: The evaluated convolution values at self.energy. + Parameters + ---------- + sample_component : DeltaFunction + The sample component to + be convolved. + resolution_components : ComponentCollection | ModelComponent + : The resolution model to convolve with. + + Returns + ------- + np.ndarray + The evaluated convolution values at self.energy. """ return sample_component.area.value * resolution_components.evaluate( self.energy_with_offset.values - sample_component.center.value @@ -214,14 +232,19 @@ def _convolute_gaussian_gaussian( Gaussian component with width $\sqrt{w_1^2 + w_2^2}$. The areas are multiplied. - Args: - sample_component (Gaussian): The sample Gaussian component - to be convolved. - resolution_component (Gaussian): The resolution Gaussian - component to convolve with. - - Returns: - np.ndarray: The evaluated convolution values at self.energy. + Parameters + ---------- + sample_component : Gaussian + The sample Gaussian component + to be convolved. + resolution_component : Gaussian + The resolution Gaussian + component to convolve with. + + Returns + ------- + np.ndarray + The evaluated convolution values at self.energy. """ width = np.sqrt(sample_component.width.value**2 + resolution_component.width.value**2) @@ -240,14 +263,19 @@ def _convolute_gaussian_lorentzian( """Convolution of a Gaussian and a Lorentzian results in a Voigt profile. The areas are multiplied. - Args: - sample_component (Gaussian): The sample Gaussian component - to be convolved. - resolution_component (Lorentzian): The resolution Lorentzian - component to convolve with. - - Returns: - np.ndarray: The evaluated convolution values at self.energy. + Parameters + ---------- + sample_component : Gaussian + The sample Gaussian component + to be convolved. + resolution_component : Lorentzian + The resolution Lorentzian + component to convolve with. + + Returns + ------- + np.ndarray + The evaluated convolution values at self.energy. """ center = sample_component.center.value + resolution_component.center.value area = sample_component.area.value * resolution_component.area.value @@ -269,14 +297,19 @@ def _convolute_gaussian_voigt( while the Gaussian widths are summed in quadrature. The areas are multiplied. - Args: - sample_component (Gaussian): The sample Gaussian component - to be convolved. - resolution_component (Voigt): The resolution Voigt component - to convolve with. - - Returns: - np.ndarray: The evaluated convolution values at self.energy. + Parameters + ---------- + sample_component : Gaussian + The sample Gaussian component + to be convolved. + resolution_component : Voigt + The resolution Voigt component + to convolve with. + + Returns + ------- + np.ndarray + The evaluated convolution values at self.energy. """ area = sample_component.area.value * resolution_component.area.value @@ -304,14 +337,19 @@ def _convolute_lorentzian_lorentzian( Lorentzian component with width $w_1 + w_2$. The areas are multiplied. - Args: - sample_component (Lorentzian): The sample Lorentzian - component to be convolved. - resolution_component (Lorentzian): The resolution Lorentzian - component to convolve with. - - Returns: - np.ndarray: The evaluated convolution values at self.energy. + Parameters + ---------- + sample_component : Lorentzian + The sample Lorentzian + component to be convolved. + resolution_component : Lorentzian + The resolution Lorentzian + component to convolve with. + + Returns + ------- + np.ndarray + The evaluated convolution values at self.energy. """ area = sample_component.area.value * resolution_component.area.value @@ -334,13 +372,19 @@ def _convolute_lorentzian_voigt( The areas are multiplied. - Args: - sample_component (Lorentzian): The sample Lorentzian - component to be convolved. - resolution_component (Voigt): The resolution Voigt component - to convolve with. - Returns: - np.ndarray: The evaluated convolution values at self.energy. + Parameters + ---------- + sample_component : Lorentzian + The sample Lorentzian + component to be convolved. + resolution_component : Voigt + The resolution Voigt component + to convolve with. + + Returns + ------- + np.ndarray + The evaluated convolution values at self.energy. """ area = sample_component.area.value * resolution_component.area.value @@ -371,14 +415,19 @@ def _convolute_voigt_voigt( while the Lorentzian widths are summed. The areas are multiplied. - Args: - sample_component (Voigt): The sample Voigt component to be - convolved. - resolution_component (Voigt): The resolution Voigt component - to convolve with. - - Returns: - np.ndarray: The evaluated convolution values at self.energy. + Parameters + ---------- + sample_component : Voigt + The sample Voigt component to be + convolved. + resolution_component : Voigt + The resolution Voigt component + to convolve with. + + Returns + ------- + np.ndarray + The evaluated convolution values at self.energy. """ area = sample_component.area.value * resolution_component.area.value @@ -419,13 +468,19 @@ def _gaussian_eval( All checks are handled in the calling function. - Args: - area (float): The area under the Gaussian curve. - center (float): The center of the Gaussian. - width (float): The width (sigma) of the Gaussian. - - Returns: - np.ndarray: The evaluated Gaussian values at self.energy. + Parameters + ---------- + area : float + The area under the Gaussian curve. + center : float + The center of the Gaussian. + width : float + The width (sigma) of the Gaussian. + + Returns + ------- + np.ndarray + The evaluated Gaussian values at self.energy. """ normalization = 1 / (np.sqrt(2 * np.pi) * width) @@ -434,8 +489,7 @@ def _gaussian_eval( return area * normalization * np.exp(exponent) def _lorentzian_eval(self, area: float, center: float, width: float) -> np.ndarray: - r""" - Evaluate a Lorentzian function. + r"""Evaluate a Lorentzian function. $$ I(x) = \frac{A}{\\pi} \frac{\Gamma}{(x - x_0)^2 + \Gamma^2}, @@ -446,13 +500,19 @@ def _lorentzian_eval(self, area: float, center: float, width: float) -> np.ndarr All checks are handled in the calling function. - Args: - area (float): The area under the Lorentzian. - center (float): The center of the Lorentzian. - width (float): The width (HWHM) of the Lorentzian. - - Returns: - np.ndarray: The evaluated Lorentzian values at self.energy. + Parameters + ---------- + area : float + The area under the Lorentzian. + center : float + The center of the Lorentzian. + width : float + The width (HWHM) of the Lorentzian. + + Returns + ------- + np.ndarray + The evaluated Lorentzian values at self.energy. """ normalization = width / np.pi @@ -470,17 +530,24 @@ def _voigt_eval( """Evaluate a Voigt profile function using scipy's voigt_profile. - Args: - area (float): The area under the Voigt profile. - center (float): The center of the Voigt profile. - gaussian_width (float): The Gaussian width (sigma) of the - Voigt profile. - lorentzian_width (float): The Lorentzian width (HWHM) of the - Voigt profile. - - Returns: - np.ndarray: The evaluated Voigt profile values at - self.energy. + Parameters + ---------- + area : float + The area under the Voigt profile. + center : float + The center of the Voigt profile. + gaussian_width : float + The Gaussian width (sigma) of the + Voigt profile. + lorentzian_width : float + The Lorentzian width (HWHM) of the + Voigt profile. + + Returns + ------- + np.ndarray + The evaluated Voigt profile values at + self.energy. """ return area * voigt_profile( diff --git a/src/easydynamics/convolution/convolution.py b/src/easydynamics/convolution/convolution.py index 3f3f1ef3..a859bb3d 100644 --- a/src/easydynamics/convolution/convolution.py +++ b/src/easydynamics/convolution/convolution.py @@ -63,31 +63,38 @@ def __init__( ) -> None: """Initialize the Convolution class. - Args: - energy (np.ndarray | sc.Variable): 1D array of energy - values where the convolution is evaluated. - sample_components (ComponentCollection | ModelComponent): - The sample components to be convolved. - resolution_components (ComponentCollection | ModelComponent): - The resolution components to convolve with. - energy_offset (Numeric | Parameter, default=0.0): An energy - offset to apply to the energy values before convolution. - upsample_factor (Numeric | None, default=5): The factor by which to - upsample the input data before convolution. Default is - 5. - extension_factor (Numeric | None, default=0.2): The factor by which to - extend the input data range before convolution. Default - is 0.2. - temperature (Parameter | Numeric | None, default=None): The - temperature to use for detailed balance correction. - Default is None. - temperature_unit (str | sc.Unit, default='K'): The unit of the - temperature parameter. Default is 'K'. - energy_unit (str | sc.Unit, default='meV'): The unit of the energy. - Default is 'meV'. - normalize_detailed_balance (bool, default=True): Whether to - normalize the detailed balance correction. Default is - True. + Parameters + ---------- + energy : np.ndarray | sc.Variable + 1D array of energy + values where the convolution is evaluated. + sample_components : ComponentCollection | ModelComponent + The sample components to be convolved. + resolution_components : ComponentCollection | ModelComponent + The resolution components to convolve with. + energy_offset : Numeric | Parameter, optional + An energy + offset to apply to the energy values before convolution. By default, 0.0. + upsample_factor : Numeric | None, optional + The factor by which to + upsample the input data before convolution. Default is + 5. By default, 5. + extension_factor : Numeric | None, optional + The factor by which to + extend the input data range before convolution. Default + is 0.2. By default, 0.2. + temperature : Parameter | Numeric | None, optional + The + temperature to use for detailed balance correction. By default, None. + temperature_unit : str | sc.Unit, optional + The unit of the + temperature parameter. By default, 'K'. + energy_unit : str | sc.Unit, optional + The unit of the energy. By default, 'meV'. + normalize_detailed_balance : bool, optional + Whether to + normalize the detailed balance correction. Default is + True. By default, True. """ self._convolution_plan_is_valid = False @@ -119,8 +126,10 @@ def convolution( possible, and numerical convolutions for the remaining components. - Returns: - np.ndarray: The convolved values evaluated at energy. + Returns + ------- + np.ndarray + The convolved values evaluated at energy. """ if not self._convolution_plan_is_valid: self._build_convolution_plan() @@ -145,9 +154,11 @@ def _convolve_delta_functions(self) -> np.ndarray: the resolution components. No detailed balance correction is applied to delta functions. - Returns: - np.ndarray: The convolved values of the delta function c - components evaluated at energy. + Returns + ------- + np.ndarray + The convolved values of the delta function c + components evaluated at energy. """ return sum( delta.area.value @@ -165,19 +176,26 @@ def _check_if_pair_is_analytic( """Check if the convolution of the given component pair can be handled analytically. - Args: - sample_component (ModelComponent): The sample component to - be convolved. - resolution_component (ModelComponent): The resolution - component to convolve with. - - Returns: - bool: True if the component pair can be handled - analytically, False otherwise. - - Raises: - TypeError: If either component is not a ModelComponent, or if - the resolution component is a DeltaFunction. + Parameters + ---------- + sample_component : ModelComponent + The sample component to + be convolved. + resolution_component : ModelComponent + The resolution + component to convolve with. + + Raises + ------ + TypeError : + If either component is not a ModelComponent, or if + the resolution component is a DeltaFunction. + + Returns + ------- + bool + True if the component pair can be handled + analytically, False otherwise. """ if not isinstance(sample_component, ModelComponent): @@ -290,9 +308,12 @@ def __setattr__(self, name: str, value: any) -> None: The new plan is only built after initialization (when _reactions_enabled is True) to avoid issues during __init__. - Args: - name (str): The name of the attribute to set. - value (any): The value to set the attribute to. + Parameters + ---------- + name : str + The name of the attribute to set. + value : any + The value to set the attribute to. """ super().__setattr__(name, value) diff --git a/src/easydynamics/convolution/convolution_base.py b/src/easydynamics/convolution/convolution_base.py index 3037c649..04423f3f 100644 --- a/src/easydynamics/convolution/convolution_base.py +++ b/src/easydynamics/convolution/convolution_base.py @@ -26,24 +26,30 @@ def __init__( ) -> None: """Initialize the ConvolutionBase. - Args: - energy (np.ndarray | sc.Variable): 1D array of energy - values where the convolution is evaluated. - sample_components (ComponentCollection | ModelComponent | None, default=None): - The sample model to be convolved. - resolution_components (ComponentCollection | ModelComponent | None, default=None): - The resolution model to convolve with. - energy_unit (str | sc.Unit, default='meV'): The unit of the - energy. - energy_offset (Numeric | Parameter, default=0.0): The energy - offset applied to the convolution. Default is 0.0. - - Raises: - TypeError: If energy is not a numpy ndarray or a scipp - Variable or if energy_unit is not a string or scipp unit, or if - energy_offset is not a number or a Parameter, or if - sample_components is not a ComponentCollection or ModelComponent, or if - resolution_components is not a ComponentCollection or ModelComponent. + Parameters + ---------- + energy : np.ndarray | sc.Variable + 1D array of energy + values where the convolution is evaluated. + sample_components : ComponentCollection | ModelComponent | None, optional + The sample model to be convolved. By default, None. + resolution_components : ComponentCollection | ModelComponent | None, optional + The resolution model to convolve with. By default, None. + energy_unit : str | sc.Unit, optional + The unit of the + energy. By default, 'meV'. + energy_offset : Numeric | Parameter, optional + The energy + offset applied to the convolution. By default, 0.0. + + Raises + ------ + TypeError : + If energy is not a numpy ndarray or a scipp + Variable or if energy_unit is not a string or scipp unit, or if + energy_offset is not a number or a Parameter, or if + sample_components is not a ComponentCollection or ModelComponent, or if + resolution_components is not a ComponentCollection or ModelComponent. """ if isinstance(energy, Numeric): energy = np.array([float(energy)]) @@ -93,8 +99,10 @@ def __init__( def energy_offset(self) -> Parameter: """Get the energy offset. - Returns: - Parameter: The energy offset applied to the convolution. + Returns + ------- + Parameter + The energy offset applied to the convolution. """ return self._energy_offset @@ -102,12 +110,16 @@ def energy_offset(self) -> Parameter: def energy_offset(self, energy_offset: Numeric | Parameter) -> None: """Set the energy offset. - Args: - energy_offset (Numeric | Parameter): The energy offset to - apply to the convolution. + Parameters + ---------- + energy_offset : Numeric | Parameter + The energy offset to + apply to the convolution. - Raises: - TypeError: If energy_offset is not a number or a Parameter. + Raises + ------ + TypeError : + If energy_offset is not a number or a Parameter. """ if not isinstance(energy_offset, Parameter | Numeric): raise TypeError('Energy_offset must be a number or a Parameter.') @@ -122,8 +134,10 @@ def energy_offset(self, energy_offset: Numeric | Parameter) -> None: def energy_with_offset(self) -> sc.Variable: """Get the energy with the offset applied. - Returns: - sc.Variable: The energy values with the offset applied. + Returns + ------- + sc.Variable + The energy values with the offset applied. """ energy_with_offset = self.energy.copy() energy_with_offset.values = self.energy.values - self.energy_offset.value @@ -134,12 +148,16 @@ def energy_with_offset(self, _value: sc.Variable) -> None: """Energy with offset is a read-only property derived from energy and energy_offset. - Args: - _value (sc.Variable): The value to set (ignored). + Parameters + ---------- + _value : sc.Variable + The value to set (ignored). - Raises: - AttributeError: Always raised since energy_with_offset is - read-only. + Raises + ------ + AttributeError : + Always raised since energy_with_offset is + read-only. """ raise AttributeError( 'Energy with offset is a read-only property derived from energy and energy_offset.' @@ -149,9 +167,11 @@ def energy_with_offset(self, _value: sc.Variable) -> None: def energy(self) -> sc.Variable: """Get the energy. - Returns: - sc.Variable: The energy values where the convolution is - evaluated. + Returns + ------- + sc.Variable + The energy values where the convolution is + evaluated. """ return self._energy @@ -160,13 +180,17 @@ def energy(self) -> sc.Variable: def energy(self, energy: np.ndarray | sc.Variable) -> None: """Set the energy. - Args: - energy (np.ndarray | sc.Variable): 1D array of energy - values where the convolution is evaluated. - - Raises: - TypeError: If energy is not a numpy ndarray or a - scipp Variable. + Parameters + ---------- + energy : np.ndarray | sc.Variable + 1D array of energy + values where the convolution is evaluated. + + Raises + ------ + TypeError : + If energy is not a numpy ndarray or a + scipp Variable. """ if isinstance(energy, Numeric): @@ -186,13 +210,16 @@ def energy(self, energy: np.ndarray | sc.Variable) -> None: def energy_unit(self) -> str: """Get the energy unit. - Returns: - str: The unit of the energy. + Returns + ------- + str + The unit of the energy. """ return self._energy_unit @energy_unit.setter def energy_unit(self, _unit_str: str) -> None: + """Energy unit.""" raise AttributeError( f'Unit is read-only. Use convert_unit to change the unit between allowed types ' f'or create a new {self.__class__.__name__} with the desired unit.' @@ -201,13 +228,18 @@ def energy_unit(self, _unit_str: str) -> None: def convert_energy_unit(self, energy_unit: str | sc.Unit) -> None: """Convert the energy and energy_offset to the specified unit. - Args: - energy_unit (str | sc.Unit): The unit of the energy. - - Raises: - TypeError: If energy_unit is not a string or scipp unit. - Exception: If energy cannot be converted to the specified - unit. + Parameters + ---------- + energy_unit : str | sc.Unit + The unit of the energy. + + Raises + ------ + TypeError : + If energy_unit is not a string or scipp unit. + Exception : + If energy cannot be converted to the specified + unit. """ if not isinstance(energy_unit, (str, sc.Unit)): raise TypeError('Energy unit must be a string or scipp unit.') @@ -232,9 +264,11 @@ def convert_energy_unit(self, energy_unit: str | sc.Unit) -> None: def sample_components(self) -> ComponentCollection | ModelComponent: """Get the sample model. - Returns: - ComponentCollection | ModelComponent: The sample model to - be convolved. + Returns + ------- + ComponentCollection | ModelComponent + The sample model to + be convolved. """ return self._sample_components @@ -242,13 +276,16 @@ def sample_components(self) -> ComponentCollection | ModelComponent: def sample_components(self, sample_components: ComponentCollection | ModelComponent) -> None: """Set the sample model. - Args: - sample_components (ComponentCollection | ModelComponent): - The sample model to be convolved. + Parameters + ---------- + sample_components : ComponentCollection | ModelComponent + The sample model to be convolved. - Raises: - TypeError: If sample_components is not a ComponentCollection - or ModelComponent. + Raises + ------ + TypeError : + If sample_components is not a ComponentCollection + or ModelComponent. """ if not isinstance(sample_components, (ComponentCollection, ModelComponent)): raise TypeError( @@ -263,9 +300,11 @@ def sample_components(self, sample_components: ComponentCollection | ModelCompon def resolution_components(self) -> ComponentCollection | ModelComponent: """Get the resolution model. - Returns: - ComponentCollection | ModelComponent: The resolution model - to be convolved. + Returns + ------- + ComponentCollection | ModelComponent + The resolution model + to be convolved. """ return self._resolution_components @@ -275,14 +314,17 @@ def resolution_components( ) -> None: """Set the resolution model. - Args: - resolution_components (ComponentCollection | ModelComponent): - The resolution model to be convolved. Can be a - ComponentCollection or a single ModelComponent - - Raises: - TypeError: If resolution_components is not a - ComponentCollection or ModelComponent. + Parameters + ---------- + resolution_components : ComponentCollection | ModelComponent + The resolution model to be convolved. Can be a + ComponentCollection or a single ModelComponent. + + Raises + ------ + TypeError : + If resolution_components is not a + ComponentCollection or ModelComponent. """ if not isinstance(resolution_components, (ComponentCollection, ModelComponent)): raise TypeError( diff --git a/src/easydynamics/convolution/energy_grid.py b/src/easydynamics/convolution/energy_grid.py index 645a605b..2e78bcc3 100644 --- a/src/easydynamics/convolution/energy_grid.py +++ b/src/easydynamics/convolution/energy_grid.py @@ -10,18 +10,24 @@ class EnergyGrid: """Container for the dense energy grid and related metadata. - Attributes: - energy_dense (np.ndarray): The upsampled and extended energy - array. - energy_dense_centered (np.ndarray): The centered version of - energy_dense (used for resolution evaluation). - energy_dense_step (float): The spacing of energy_dense - (used for width checks and normalization). - energy_span_dense (float): The total span of energy_dense. - (used for width checks). - energy_even_length_offset (float): The offset to apply if - energy_dense has even length (used for convolution - alignment). + Attributes + ---------- + energy_dense : np.ndarray + The upsampled and extended energy + array. + energy_dense_centered : np.ndarray + The centered version of + energy_dense (used for resolution evaluation). + energy_dense_step : float + The spacing of energy_dense + (used for width checks and normalization). + energy_span_dense : float + The total span of energy_dense. + (used for width checks). + energy_even_length_offset : float + The offset to apply if + energy_dense has even length (used for convolution + alignment). """ energy_dense: np.ndarray diff --git a/src/easydynamics/convolution/numerical_convolution.py b/src/easydynamics/convolution/numerical_convolution.py index 10a55c81..2b70280b 100644 --- a/src/easydynamics/convolution/numerical_convolution.py +++ b/src/easydynamics/convolution/numerical_convolution.py @@ -38,29 +38,37 @@ def __init__( ) -> None: """Initialize the NumericalConvolution object. - Args: - energy (np.ndarray | sc.Variable): 1D array of energy values - where the convolution is evaluated. - sample_components (ComponentCollection | ModelComponent): - The sample model to be convolved. - resolution_components (ComponentCollection | ModelComponent): - The resolution model to convolve with. - energy_offset (Numeric | Parameter, default=0.0): An energy - offset to apply to the energy values before convolution. - upsample_factor (Numeric | None, default=5): The factor by which to - upsample the input data before convolution. - extension_factor (Numeric | None, default=0.2): The factor by which to - extend the input data range before convolution. - temperature (Parameter | Numeric | None, default=None): The - temperature to use for detailed balance correction. - Default is None. - temperature_unit (str | sc.Unit, default='K'): The unit of the - temperature parameter. - energy_unit (str | sc.Unit, default='meV'): The unit of the - energy. Default is 'meV'. - normalize_detailed_balance (bool, default=True): Whether to - normalize the detailed balance correction. Default is - True. + Parameters + ---------- + energy : np.ndarray | sc.Variable + 1D array of energy values + where the convolution is evaluated. + sample_components : ComponentCollection | ModelComponent + The sample model to be convolved. + resolution_components : ComponentCollection | ModelComponent + The resolution model to convolve with. + energy_offset : Numeric | Parameter, optional + An energy + offset to apply to the energy values before convolution. By default, 0.0. + upsample_factor : Numeric | None, optional + The factor by which to + upsample the input data before convolution. By default, 5. + extension_factor : Numeric | None, optional + The factor by which to + extend the input data range before convolution. By default, 0.2. + temperature : Parameter | Numeric | None, optional + The + temperature to use for detailed balance correction. By default, None. + temperature_unit : str | sc.Unit, optional + The unit of the + temperature parameter. By default, 'K'. + energy_unit : str | sc.Unit, optional + The unit of the + energy. By default, 'meV'. + normalize_detailed_balance : bool, optional + Whether to + normalize the detailed balance correction. Default is + True. By default, True. """ super().__init__( energy=energy, @@ -82,8 +90,10 @@ def convolution( at the values given in energy. Includes detailed balance correction if temperature is provided. - Returns: - np.ndarray: The convolved values evaluated at energy. + Returns + ------- + np.ndarray + The convolved values evaluated at energy. """ # Give warnings if peaks are very wide or very narrow diff --git a/src/easydynamics/convolution/numerical_convolution_base.py b/src/easydynamics/convolution/numerical_convolution_base.py index ccbdea57..d93dc95c 100644 --- a/src/easydynamics/convolution/numerical_convolution_base.py +++ b/src/easydynamics/convolution/numerical_convolution_base.py @@ -48,32 +48,43 @@ def __init__( ) -> None: """Initialize the NumericalConvolutionBase. - Args: - energy (np.ndarray | sc.Variable): 1D array of energy values - where the convolution is evaluated. - sample_components (ComponentCollection | ModelComponent): - The components to be convolved. - resolution_components (ComponentCollection | ModelComponent): - The resolution components to convolve with. - energy_offset (Numeric | Parameter, default=0.0): An energy - offset to apply to the energy values before convolution. - upsample_factor (Numeric | None, default=5): The factor by which to - upsample the input data before convolution. - extension_factor (Numeric | None, default=0.2): The factor by which to - extend the input data range before convolution. - temperature (Parameter | Numeric | None, default=None): The temperature to - use for detailed balance correction. - temperature_unit (str | sc.Unit, default='K'): The unit of the - temperature parameter. - energy_unit (str | sc.Unit, default='meV'): The unit of the energy. - normalize_detailed_balance (bool, default=True): Whether to normalize the - detailed balance correction. - - Raises: - TypeError: If temperature is not None, a number, or a - Parameter, or if temperature_unit is not a string or sc.Unit, or if - upsample_factor is not a number or None, or if extension_factor - is not a number, or if normalize_detailed_balance is not a bool. + Parameters + ---------- + energy : np.ndarray | sc.Variable + 1D array of energy values + where the convolution is evaluated. + sample_components : ComponentCollection | ModelComponent + The components to be convolved. + resolution_components : ComponentCollection | ModelComponent + The resolution components to convolve with. + energy_offset : Numeric | Parameter, optional + An energy + offset to apply to the energy values before convolution. By default, 0.0. + upsample_factor : Numeric | None, optional + The factor by which to + upsample the input data before convolution. By default, 5. + extension_factor : Numeric | None, optional + The factor by which to + extend the input data range before convolution. By default, 0.2. + temperature : Parameter | Numeric | None, optional + The temperature to + use for detailed balance correction. By default, None. + temperature_unit : str | sc.Unit, optional + The unit of the + temperature parameter. By default, 'K'. + energy_unit : str | sc.Unit, optional + The unit of the energy. By default, 'meV'. + normalize_detailed_balance : bool, optional + Whether to normalize the + detailed balance correction. By default, True. + + Raises + ------ + TypeError : + If temperature is not None, a number, or a + Parameter, or if temperature_unit is not a string or sc.Unit, or if + upsample_factor is not a number or None, or if extension_factor + is not a number, or if normalize_detailed_balance is not a bool. """ super().__init__( energy=energy, @@ -106,8 +117,10 @@ def __init__( def energy(self, energy: np.ndarray) -> None: """Set the energy array and recreate the dense grid. - Args: - energy (np.ndarray): The new energy array. + Parameters + ---------- + energy : np.ndarray + The new energy array. """ ConvolutionBase.energy.fset(self, energy) # Recreate dense grid when energy is updated @@ -117,8 +130,10 @@ def energy(self, energy: np.ndarray) -> None: def upsample_factor(self) -> Numeric | None: """Get the upsample factor. - Returns: - Numeric | None: The upsample factor. + Returns + ------- + Numeric | None + The upsample factor. """ return self._upsample_factor @@ -127,12 +142,17 @@ def upsample_factor(self) -> Numeric | None: def upsample_factor(self, factor: Numeric | None) -> None: """Set the upsample factor and recreate the dense grid. - Args: - factor (Numeric | None): The new upsample factor. - - Raises: - TypeError: If factor is not a number or None. - ValueError: If factor is not greater than 1. + Parameters + ---------- + factor : Numeric | None + The new upsample factor. + + Raises + ------ + TypeError : + If factor is not a number or None. + ValueError : + If factor is not greater than 1. """ if factor is None: self._upsample_factor = factor @@ -159,27 +179,34 @@ def extension_factor(self) -> float: 0.2 means extending by 20% of the original energy span on each side - Returns: - float: The extension factor. + Returns + ------- + float + The extension factor. """ return self._extension_factor @extension_factor.setter def extension_factor(self, factor: Numeric) -> None: - """ - Set the extension factor and recreate the dense grid. + """Set the extension factor and recreate the dense grid. + The extension factor determines how much the energy range is extended on both sides before convolution. 0.2 means extending by 20% of the original energy span on each side. - Args: - factor (Numeric): The new extension factor. - - Raises: - TypeError: If factor is not a number. - ValueError: If factor is negative. + Parameters + ---------- + factor : Numeric + The new extension factor. + + Raises + ------ + TypeError : + If factor is not a number. + ValueError : + If factor is negative. """ if not isinstance(factor, Numeric): @@ -195,9 +222,11 @@ def extension_factor(self, factor: Numeric) -> None: def temperature(self) -> Parameter | None: """Get the temperature. - Returns: - Parameter | None: The temperature parameter, or None if - detailed balance correction is disabled. + Returns + ------- + Parameter | None + The temperature parameter, or None if + detailed balance correction is disabled. """ return self._temperature @@ -209,13 +238,17 @@ def temperature(self, temp: Parameter | Numeric | None) -> None: If None, disables detailed balance correction and removes the temperature parameter. - Args: - temp (Parameter | Numeric | None): The temperature to set. - The unit will be the same as the existing temperature - parameter if it exists, otherwise 'K'. - - Raises: - TypeError: If temp is not a Numeric, Parameter, or None. + Parameters + ---------- + temp : Parameter | Numeric | None + The temperature to set. + The unit will be the same as the existing temperature + parameter if it exists, otherwise 'K'. + + Raises + ------ + TypeError : + If temp is not a Numeric, Parameter, or None. """ if temp is None: @@ -241,8 +274,10 @@ def normalize_detailed_balance(self) -> bool: If True, the detailed balance factor is divided by temperature. - Returns: - bool: Whether to normalize the detailed balance factor. + Returns + ------- + bool + Whether to normalize the detailed balance factor. """ return self._normalize_detailed_balance @@ -253,12 +288,16 @@ def normalize_detailed_balance(self, normalize: bool) -> None: If True, the detailed balance factor is divided by temperature. - Args: - normalize (bool): Whether to normalize the detailed balance - factor. + Parameters + ---------- + normalize : bool + Whether to normalize the detailed balance + factor. - Raises: - TypeError: If normalize is not a bool. + Raises + ------ + TypeError : + If normalize is not a bool. """ if not isinstance(normalize, bool): @@ -276,13 +315,17 @@ def _create_energy_grid( performed. This dense grid is used for convolution to improve accuracy. - Returns: - EnergyGrid: The dense grid created by upsampling and - extending energy. - - Raises: - ValueError: If energy array is not uniformly spaced when - upsample_factor is None, or if energy array has less than 2 points. + Raises + ------ + ValueError : + If energy array is not uniformly spaced when + upsample_factor is None, or if energy array has less than 2 points. + + Returns + ------- + EnergyGrid + The dense grid created by upsampling and + extending energy. """ if self.upsample_factor is None: # Check if the array is uniformly spaced. @@ -351,12 +394,15 @@ def _check_width_thresholds( In both cases, the convolution accuracy may be compromised. - Args: - model (ComponentCollection | ModelComponent): The model to - check - model_name (str): A string indicating whether the model is a - 'sample model' or 'resolution model' for warning - messages. + Parameters + ---------- + model : ComponentCollection | ModelComponent + The model to + check. + model_name : str + A string indicating whether the model is a + 'sample model' or 'resolution model' for warning + messages. """ # Handle ComponentCollection or ModelComponent @@ -389,9 +435,11 @@ def __repr__(self) -> str: """Return a string representation of the NumericalConvolutionBase. - Returns: - str: A string representation of the - NumericalConvolutionBase. + Returns + ------- + str + A string representation of the + NumericalConvolutionBase. """ return ( f'{self.__class__.__name__}(' diff --git a/src/easydynamics/experiment/experiment.py b/src/easydynamics/experiment/experiment.py index ad829e37..dc8cb9c4 100644 --- a/src/easydynamics/experiment/experiment.py +++ b/src/easydynamics/experiment/experiment.py @@ -30,16 +30,22 @@ def __init__( ) -> None: """Initialize the Experiment object. - Args: - display_name (str | None, default="MyExperiment"): Display name of the experiment. - unique_name (str | None, default=None): Unique name of the experiment. If - None, a unique name will be generated. - data (sc.DataArray | str | None, default=None): Dataset associated with - the experiment. Can be a sc.DataArray or a filename - string to load from. If None, no data is loaded. - - Raises: - TypeError: If data is not a sc.DataArray, a string, or None. + Parameters + ---------- + display_name : str | None, optional + Display name of the experiment. By default, 'MyExperiment'. + unique_name : str | None, optional + Unique name of the experiment. If + None, a unique name will be generated. By default, None. + data : sc.DataArray | str | None, optional + Dataset associated with + the experiment. Can be a sc.DataArray or a filename + string to load from. If None, no data is loaded. By default, None. + + Raises + ------ + TypeError : + If data is not a sc.DataArray, a string, or None. """ super().__init__( display_name=display_name, @@ -70,9 +76,11 @@ def __init__( def data(self) -> sc.DataArray | None: """Get the dataset associated with this experiment. - Returns: - sc.DataArray | None: The dataset associated with this - experiment, or None if no data is loaded. + Returns + ------- + sc.DataArray | None + The dataset associated with this + experiment, or None if no data is loaded. """ return self._data @@ -80,12 +88,16 @@ def data(self) -> sc.DataArray | None: def data(self, value: sc.DataArray) -> None: """Set the dataset associated with this experiment. - Args: - value (sc.DataArray): The new dataset to associate with this - experiment. + Parameters + ---------- + value : sc.DataArray + The new dataset to associate with this + experiment. - Raises: - TypeError: If the value is not a sc.DataArray. + Raises + ------ + TypeError : + If the value is not a sc.DataArray. """ if not isinstance(value, sc.DataArray): raise TypeError(f'Data must be a sc.DataArray, not {type(value).__name__}') @@ -99,23 +111,31 @@ def data(self, value: sc.DataArray) -> None: def binned_data(self) -> sc.DataArray | None: """Get the binned dataset associated with this experiment. - Returns: - sc.DataArray | None: The binned dataset associated with this - experiment, or None if no data is loaded. + Returns + ------- + sc.DataArray | None + The binned dataset associated with this + experiment, or None if no data is loaded. """ return self._binned_data @binned_data.setter def binned_data(self, _value: sc.DataArray) -> None: - """Set the binned dataset associated with this experiment. Read- - only property. Use rebin() to rebin the data instead. + """Set the binned dataset associated with this experiment. - Args: - _value (sc.DataArray): The new binned dataset to associate - with this experiment (ignored) + Read- +only property. Use rebin() to rebin the data instead. - Raises: - AttributeError: Always, since binned_data is read-only. + Parameters + ---------- + _value : sc.DataArray + The new binned dataset to associate + with this experiment (ignored). + + Raises + ------ + AttributeError : + Always, since binned_data is read-only. """ raise AttributeError('binned_data is a read-only property. Use rebin() to rebin the data') @@ -123,9 +143,11 @@ def binned_data(self, _value: sc.DataArray) -> None: def Q(self) -> sc.Variable | None: """Get the Q values from the dataset. - Returns: - sc.Variable | None: The Q values from the dataset, or None - if no data is loaded. + Returns + ------- + sc.Variable | None + The Q values from the dataset, or None + if no data is loaded. """ if self._binned_data is None: return None @@ -133,14 +155,20 @@ def Q(self) -> sc.Variable | None: @Q.setter def Q(self, _value: sc.Variable) -> None: - """Set the Q values for the dataset. Q is a read-only property - derived from the data, so this setter raises an error. + """Set the Q values for the dataset. + + Q is a read-only property +derived from the data, so this setter raises an error. - Args: - _value (sc.Variable): The new Q values to set (ignored) + Parameters + ---------- + _value : sc.Variable + The new Q values to set (ignored). - Raises: - AttributeError: Always, since Q is read-only. + Raises + ------ + AttributeError : + Always, since Q is read-only. """ raise AttributeError('Q is a read-only property derived from the data.') @@ -148,9 +176,11 @@ def Q(self, _value: sc.Variable) -> None: def energy(self) -> sc.Variable | None: """Get the energy values from the dataset. - Returns: - sc.Variable | None: The energy values from the dataset, or - None if no data is loaded. + Returns + ------- + sc.Variable | None + The energy values from the dataset, or + None if no data is loaded. """ if self._binned_data is None: return None @@ -158,14 +188,20 @@ def energy(self) -> sc.Variable | None: @energy.setter def energy(self, _value: sc.Variable) -> None: - """Set the energy values for the dataset. Energy is a read-only - property derived from the data, so this setter raises an error. + """Set the energy values for the dataset. - Args: - _value (sc.Variable): The new energy values to set (ignored) + Energy is a read-only +property derived from the data, so this setter raises an error. - Raises: - AttributeError: Always, since energy is read-only. + Parameters + ---------- + _value : sc.Variable + The new energy values to set (ignored). + + Raises + ------ + AttributeError : + Always, since energy is read-only. """ raise AttributeError('energy is a read-only property derived from the data.') @@ -173,16 +209,22 @@ def get_masked_energy(self, Q_index: int) -> sc.Variable | None: """Get the energy values from the dataset, removing points where the y values or variances are NaN or Inf for the given Q index. - Args: - Q_index (int): The Q index to get the masked energy values - for. - - Returns: - sc.Variable | None: The masked energy values from the - dataset, or None if no data is loaded. - - Raises: - IndexError: If Q_index is not a valid index for the Q values. + Parameters + ---------- + Q_index : int + The Q index to get the masked energy values + for. + + Raises + ------ + IndexError : + If Q_index is not a valid index for the Q values. + + Returns + ------- + sc.Variable | None + The masked energy values from the + dataset, or None if no data is loaded. """ if self._binned_data is None: return None @@ -207,14 +249,19 @@ def get_masked_energy(self, Q_index: int) -> sc.Variable | None: def load_hdf5(self, filename: str, display_name: str | None = None) -> None: """Load data from an HDF5 file. - Args: - filename (str ): Path to the HDF5 file. - display_name (str | None, default=None): Optional display name for the - experiment. - - Raises: - TypeError: If filename is not a string or if display_name is - not a string or None or if the loaded data is not a sc.DataArray. + Parameters + ---------- + filename : str + Path to the HDF5 file. + display_name : str | None, optional + Optional display name for the + experiment. By default, None. + + Raises + ------ + TypeError : + If filename is not a string or if display_name is + not a string or None or if the loaded data is not a sc.DataArray. """ if not isinstance(filename, str): raise TypeError(f'Filename must be a string, not {type(filename).__name__}') @@ -237,14 +284,19 @@ def load_hdf5(self, filename: str, display_name: str | None = None) -> None: def save_hdf5(self, filename: str | None = None) -> None: """Save the dataset to HDF5. - Args: - filename (str | None, default=None): Path to the output HDF5 file. - If None, the file will be named after the unique_name of - the experiment with a .h5 extension. - - Raises: - TypeError: If filename is not a string or None. - ValueError: If there is no data to save. + Parameters + ---------- + filename : str | None, optional + Path to the output HDF5 file. + If None, the file will be named after the unique_name of + the experiment with a .h5 extension. By default, None. + + Raises + ------ + TypeError : + If filename is not a string or None. + ValueError : + If there is no data to save. """ if filename is None: @@ -268,16 +320,22 @@ def remove_data(self) -> None: def rebin(self, dimensions: dict[str, int | sc.Variable]) -> None: """Rebin the dataset along specified dimensions. - Args: - dimensions (dict[str, int | sc.Variable]): A dictionary - mapping dimension names to number of bins (int) or bin - edges (sc.Variable). - - Raises: - TypeError: If dimensions is not a dictionary or if - keys/values are of incorrect types. - ValueError: If there is no data to rebin. - KeyError: If a specified dimension is not in the dataset. + Parameters + ---------- + dimensions : dict[str, int | sc.Variable] + A dictionary + mapping dimension names to number of bins (int) or bin + edges (sc.Variable). + + Raises + ------ + TypeError : + If dimensions is not a dictionary or if + keys/values are of incorrect types. + ValueError : + If there is no data to rebin. + KeyError : + If a specified dimension is not in the dataset. """ if not isinstance(dimensions, dict): @@ -320,15 +378,21 @@ def rebin(self, dimensions: dict[str, int | sc.Variable]) -> None: ########### def plot_data(self, slicer: bool = False, **kwargs: dict) -> None: - """Plot the dataset using plopp: https://scipp.github.io/plopp/ - - Args: - slicer (bool, default=False): If True, use plopp's slicer instead of plot. - **kwargs (dict): Additional keyword arguments to pass to plopp. - - Raises: - ValueError: If there is no data to plot. - RuntimeError: If not in a Jupyter notebook environment. + """Plot the dataset using plopp: https://scipp.github.io/plopp/. + + Parameters + ---------- + slicer : bool, optional + If True, use plopp's slicer instead of plot. By default, False. + **kwargs : dict + Additional keyword arguments to pass to plopp. + + Raises + ------ + ValueError : + If there is no data to plot. + RuntimeError : + If not in a Jupyter notebook environment. """ if self._binned_data is None: @@ -369,12 +433,17 @@ def plot_data(self, slicer: bool = False, **kwargs: dict) -> None: def _validate_coordinates(data: sc.DataArray) -> None: """Validate that required coordinates are present in the data. - Args: - data (sc.DataArray): The data to validate. - - Raises: - TypeError: If data is not a sc.DataArray. - ValueError: If required coordinates are missing. + Parameters + ---------- + data : sc.DataArray + The data to validate. + + Raises + ------ + TypeError : + If data is not a sc.DataArray. + ValueError : + If required coordinates are missing. """ if not isinstance(data, sc.DataArray): raise TypeError('Data must be a sc.DataArray.') @@ -387,11 +456,15 @@ def _validate_coordinates(data: sc.DataArray) -> None: def _convert_to_bin_centers(self, data: sc.DataArray) -> sc.DataArray: """Convert the coordinates of the data to bin centers. - Args: - data (sc.DataArray): The data to convert. + Parameters + ---------- + data : sc.DataArray + The data to convert. - Returns: - sc.DataArray: The data with coordinates at bin centers. + Returns + ------- + sc.DataArray + The data with coordinates at bin centers. """ for dim in data.dims: coord = data.coords[dim] @@ -404,13 +477,17 @@ def _extract_x_y_var(self, Q_index: int) -> tuple[np.ndarray, np.ndarray, np.nda """Extract the x, y, and weights arrays from the experiment for the given Q index. - Args: - Q_index (int): The Q index to extract the data for. - - Returns: - tuple[np.ndarray, np.ndarray, np.ndarray]: The x, y, and - variances arrays extracted from the experiment for the - given Q index. + Parameters + ---------- + Q_index : int + The Q index to extract the data for. + + Returns + ------- + tuple[np.ndarray, np.ndarray, np.ndarray] + The x, y, and + variances arrays extracted from the experiment for the + given Q index. """ data = self.binned_data['Q', Q_index] x = data.coords['energy'].values @@ -424,18 +501,24 @@ def _extract_x_y_weights_only_finite( """Extract the x, y, and weights arrays from the experiment for the given Q index, removing any NaN and Inf values. - Args: - Q_index (int): The Q index to extract the data for. - - Returns: - tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: The - x, y, weights, and mask arrays extracted from the - experiment for the given Q index, with NaNs and Infs - removed. - - Raises: - ValueError: If any variances are zero after removing NaNs - and Infs, since this would lead to infinite weights. + Parameters + ---------- + Q_index : int + The Q index to extract the data for. + + Raises + ------ + ValueError : + If any variances are zero after removing NaNs + and Infs, since this would lead to infinite weights. + + Returns + ------- + tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray] + The + x, y, weights, and mask arrays extracted from the + experiment for the given Q index, with NaNs and Infs + removed. """ x, y, var = self._extract_x_y_var(Q_index) @@ -465,8 +548,10 @@ def _extract_x_y_weights_only_finite( def __repr__(self) -> str: """Return a string representation of the Experiment object. - Returns: - str: A string representation of the Experiment object. + Returns + ------- + str + A string representation of the Experiment object. """ return f'Experiment `{self.unique_name}` with data: {self._data}' @@ -474,8 +559,10 @@ def __repr__(self) -> str: def __copy__(self) -> 'Experiment': """Return a copy of the object. - Returns: - Experiment: A copy of the Experiment object. + Returns + ------- + Experiment + A copy of the Experiment object. """ temp = self.to_dict(skip=['unique_name']) new_obj = self.__class__.from_dict(temp) diff --git a/src/easydynamics/sample_model/background_model.py b/src/easydynamics/sample_model/background_model.py index 2f4645f5..860b5218 100644 --- a/src/easydynamics/sample_model/background_model.py +++ b/src/easydynamics/sample_model/background_model.py @@ -25,17 +25,22 @@ def __init__( ) -> None: """Initialize the BackgroundModel. - Args: - display_name (str | None, default='MyBackgroundModel'): Display name of the model. - unique_name (str | None, default=None): Unique name of the model. If None, - a unique name will be generated. - unit (str | sc.Unit, default='meV'): Unit of the model. - components (ModelComponent | ComponentCollection | None, default=None): - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. - Q (Q_type | None, default=None): Q values for the model. If None, Q is not - set. + Parameters + ---------- + display_name : str | None, optional + Display name of the model. By default, 'MyBackgroundModel'. + unique_name : str | None, optional + Unique name of the model. If None, + a unique name will be generated. By default, None. + unit : str | sc.Unit, optional + Unit of the model. By default, 'meV'. + components : ModelComponent | ComponentCollection | None, optional + Template components of the model. If None, no components + are added. These components are copied into + ComponentCollections for each Q value. By default, None. + Q : Q_type | None, optional + Q values for the model. If None, Q is not + set. By default, None. """ super().__init__( display_name=display_name, diff --git a/src/easydynamics/sample_model/component_collection.py b/src/easydynamics/sample_model/component_collection.py index 5f483091..39997eba 100644 --- a/src/easydynamics/sample_model/component_collection.py +++ b/src/easydynamics/sample_model/component_collection.py @@ -30,18 +30,24 @@ def __init__( ) -> None: """Initialize a new ComponentCollection. - Args: - unit (str | sc.Unit, default='meV'): Unit of the collection. - display_name (str | None, default="MyComponentCollection"): Display - name of the collection - unique_name (str | None, default=None): Unique name of the collection - Defaults to None. - components (list[ModelComponent] | None, default=None): Initial model - components to add to the ComponentCollection. - - Raises: - TypeError: If unit is not a string or sc.Unit, - or if components is not a list of ModelComponent. + Parameters + ---------- + unit : str | sc.Unit, optional + Unit of the collection. By default, 'meV'. + display_name : str | None, optional + Display + name of the collection. By default, 'MyComponentCollection'. + unique_name : str | None, optional + Unique name of the collection. By default, None. + components : list[ModelComponent] | None, optional + Initial model + components to add to the ComponentCollection. By default, None. + + Raises + ------ + TypeError : + If unit is not a string or sc.Unit, + or if components is not a list of ModelComponent. """ super().__init__(display_name=display_name, unique_name=unique_name) @@ -68,8 +74,10 @@ def __init__( def components(self) -> list[ModelComponent]: """Get the list of components in the collection. - Returns: - list[ModelComponent]: The components in the collection. + Returns + ------- + list[ModelComponent] + The components in the collection. """ return list(self._components) @@ -78,12 +86,16 @@ def components(self) -> list[ModelComponent]: def components(self, components: list[ModelComponent]) -> None: """Set the list of components in the collection. - Args: - components (list[ModelComponent]): The new list of - components. + Parameters + ---------- + components : list[ModelComponent] + The new list of + components. - Raises: - TypeError: If components is not a list of ModelComponent. + Raises + ------ + TypeError : + If components is not a list of ModelComponent. """ if not isinstance(components, list): @@ -101,22 +113,28 @@ def components(self, components: list[ModelComponent]) -> None: def is_empty(self) -> bool: """Check if the ComponentCollection has no components. - Returns: - bool: True if the collection has no components, - False otherwise. + Returns + ------- + bool + True if the collection has no components, + False otherwise. """ return not self._components @is_empty.setter def is_empty(self, _value: bool) -> None: - """is_empty is a read-only property that indicates whether the + """Is_empty is a read-only property that indicates whether the collection has components. - Args: - _value (bool): The value to set (ignored). + Parameters + ---------- + _value : bool + The value to set (ignored). - Raises: - AttributeError: Always raised since is_empty is read-only. + Raises + ------ + AttributeError : + Always raised since is_empty is read-only. """ raise AttributeError( 'is_empty is a read-only property that indicates ' @@ -127,9 +145,11 @@ def is_empty(self, _value: bool) -> None: def unit(self) -> str | sc.Unit | None: """Get the unit of the ComponentCollection. - Returns: - str | sc.Unit | None: The unit of the ComponentCollection, - which is the same as the unit of its components. + Returns + ------- + str | sc.Unit | None + The unit of the ComponentCollection, + which is the same as the unit of its components. """ return self._unit @@ -137,11 +157,15 @@ def unit(self) -> str | sc.Unit | None: def unit(self, _unit_str: str) -> None: """Unit is read-only and cannot be set directly. - Args: - _unit_str (str): The unit to set (ignored). + Parameters + ---------- + _unit_str : str + The unit to set (ignored). - Raises: - AttributeError: Always raised since unit is read-only. + Raises + ------ + AttributeError : + Always raised since unit is read-only. """ raise AttributeError( @@ -153,13 +177,18 @@ def convert_unit(self, unit: str | sc.Unit) -> None: """Convert the unit of the ComponentCollection and all its components. - Args: - unit (str | sc.Unit): The target unit to convert to. - - Raises: - TypeError: If unit is not a string or sc.Unit. - Exception: If any component cannot be converted to the - specified unit. + Parameters + ---------- + unit : str | sc.Unit + The target unit to convert to. + + Raises + ------ + TypeError : + If unit is not a string or sc.Unit. + Exception : + If any component cannot be converted to the + specified unit. """ if not isinstance(unit, (str, sc.Unit)): @@ -188,16 +217,21 @@ def append_component(self, component: ModelComponent | ComponentCollection) -> N """Append a model component or the components from another ComponentCollection to this ComponentCollection. - Args: - component (ModelComponent | "ComponentCollection"): The component - to append. If a ComponentCollection is provided, all of its - components will be appended. - - Raises: - TypeError: If component is not a ModelComponent or - ComponentCollection. - ValueError: If a component with the same unique name already - exists in the collection. + Parameters + ---------- + component : ModelComponent | ComponentCollection + The component + to append. If a ComponentCollection is provided, all of its + components will be appended. + + Raises + ------ + TypeError : + If component is not a ModelComponent or + ComponentCollection. + ValueError : + If a component with the same unique name already + exists in the collection. """ if not isinstance(component, (ModelComponent, ComponentCollection)): raise TypeError( @@ -221,13 +255,18 @@ def append_component(self, component: ModelComponent | ComponentCollection) -> N def remove_component(self, unique_name: str) -> None: """Remove a component from the collection by its unique name. - Args: - unique_name (str): Unique name of the component to remove. - - Raises: - TypeError: If unique_name is not a string. - KeyError: If no component with the given unique name exists - in the collection. + Parameters + ---------- + unique_name : str + Unique name of the component to remove. + + Raises + ------ + TypeError : + If unique_name is not a string. + KeyError : + If no component with the given unique name exists + in the collection. """ if not isinstance(unique_name, str): @@ -248,8 +287,10 @@ def remove_component(self, unique_name: str) -> None: def components(self) -> list[ModelComponent]: """Get the list of components in the collection. - Returns: - list[ModelComponent]: The components in the collection. + Returns + ------- + list[ModelComponent] + The components in the collection. """ return list(self._components) @@ -257,11 +298,15 @@ def components(self) -> list[ModelComponent]: def components(self, components: list[ModelComponent]) -> None: """Set the components in the collection. - Args: - components (list[ModelComponent]): The new components in the collection + Parameters + ---------- + components : list[ModelComponent] + The new components in the collection. - Raises: - TypeError: If components is not a list of ModelComponent + Raises + ------ + TypeError : + If components is not a list of ModelComponent. """ if not isinstance(components, list): raise TypeError('components must be a list of ModelComponent instances.') @@ -279,20 +324,26 @@ def is_empty(self) -> bool: """Returns True if the collection has no components, otherwise False. - Returns: - bool: True if the collection has no components, otherwise False + Returns + ------- + bool + True if the collection has no components, otherwise False. """ return not self._components @is_empty.setter def is_empty(self, _value: bool) -> None: - """is_empty is read-only. + """Is_empty is read-only. - Args: - _value (bool): ignored. + Parameters + ---------- + _value : bool + Ignored. - Raises: - AttributeError: Always raised since is_empty is read-only + Raises + ------ + AttributeError : + Always raised since is_empty is read-only. """ raise AttributeError( 'is_empty is a read-only property that indicates ' @@ -302,9 +353,11 @@ def is_empty(self, _value: bool) -> None: def list_component_names(self) -> list[str]: """List the names of all components in the model. - Returns: - list[str]: List of unique names of the components in the - collection. + Returns + ------- + list[str] + List of unique names of the components in the + collection. """ return [component.unique_name for component in self._components] @@ -314,13 +367,17 @@ def clear_components(self) -> None: self._components.clear() def normalize_area(self) -> None: - """Normalize the areas of all components so they sum to 1. This - is useful for convolutions. + """Normalize the areas of all components so they sum to 1. + + This +is useful for convolutions. - Raises: - ValueError: If there are no components in the model or - if the total area is zero or not finite, which - would prevent normalization. + Raises + ------ + ValueError : + If there are no components in the model or + if the total area is zero or not finite, which + would prevent normalization. """ if not self.components: raise ValueError('No components in the model to normalize.') @@ -356,8 +413,10 @@ def normalize_area(self) -> None: def get_all_variables(self) -> list[DescriptorBase]: """Get all parameters from the model component. - Returns: - list[DescriptorBase]: List of parameters in the component. + Returns + ------- + list[DescriptorBase] + List of parameters in the component. """ return [var for component in self.components for var in component.get_all_variables()] @@ -365,12 +424,15 @@ def get_all_variables(self) -> list[DescriptorBase]: def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: """Evaluate the sum of all components. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - Energy axis. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + Energy axis. - Returns: - np.ndarray: Evaluated model values. + Returns + ------- + np.ndarray + Evaluated model values. """ if not self.components: @@ -384,18 +446,27 @@ def evaluate_component( ) -> np.ndarray: """Evaluate a single component by name. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - Energy axis. - unique_name (str): Component unique name. - - Returns: - np.ndarray: Evaluated values for the specified component. - Raises: - ValueError: If there are no components in the model. - TypeError: If unique_name is not a string. - KeyError: If no component with the given unique name exists - in the collection. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + Energy axis. + unique_name : str + Component unique name. + + Raises + ------ + ValueError : + If there are no components in the model. + TypeError : + If unique_name is not a string. + KeyError : + If no component with the given unique name exists + in the collection. + + Returns + ------- + np.ndarray + Evaluated values for the specified component. """ if not self.components: raise ValueError('No components in the model to evaluate.') @@ -431,12 +502,16 @@ def __contains__(self, item: str | ModelComponent) -> bool: """Check if a component with the given name or instance exists in the ComponentCollection. - Args: - item (str | ModelComponent): The component name or instance - to check for. + Parameters + ---------- + item : str | ModelComponent + The component name or instance + to check for. - Returns: - bool: True if the component exists, False otherwise. + Returns + ------- + bool + True if the component exists, False otherwise. """ if isinstance(item, str): @@ -450,8 +525,10 @@ def __contains__(self, item: str | ModelComponent) -> bool: def __repr__(self) -> str: """Return a string representation of the ComponentCollection. - Returns: - str: String representation of the ComponentCollection. + Returns + ------- + str + String representation of the ComponentCollection. """ comp_names = ', '.join(c.unique_name for c in self.components) or 'No components' diff --git a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py index 81a766f7..64ade714 100644 --- a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py +++ b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py @@ -36,17 +36,23 @@ def __init__( ) -> None: """Initialize the Damped Harmonic Oscillator. - Args: - area (Numeric | Parameter, default=1.0): Area under the curve. - center (Numeric | Parameter, default=1.0): Resonance frequency, approximately the - peak position. - width (Numeric | Parameter, default=1.0): Damping constant, approximately the - half width at half max (HWHM) of the peaks. - unit (str | sc.Unit, default='meV'): Unit of the parameters. - display_name (str | None, default='DampedHarmonicOscillator'): - Display name of the component. - unique_name (str | None, default=None): Unique name of the component. - If None, a unique_name is automatically generated. + Parameters + ---------- + area : Numeric | Parameter, optional + Area under the curve. By default, 1.0. + center : Numeric | Parameter, optional + Resonance frequency, approximately the + peak position. By default, 1.0. + width : Numeric | Parameter, optional + Damping constant, approximately the + half width at half max (HWHM) of the peaks. By default, 1.0. + unit : str | sc.Unit, optional + Unit of the parameters. By default, 'meV'. + display_name : str | None, optional + Display name of the component. By default, 'DampedHarmonicOscillator'. + unique_name : str | None, optional + Unique name of the component. + If None, a unique_name is automatically generated. By default, None. """ super().__init__( @@ -75,8 +81,10 @@ def __init__( def area(self) -> Parameter: """Get the area parameter. - Returns: - Parameter: The area parameter. + Returns + ------- + Parameter + The area parameter. """ return self._area @@ -84,11 +92,15 @@ def area(self) -> Parameter: def area(self, value: Numeric) -> None: """Set the value of the area parameter. - Args: - value (Numeric): The new value for the area parameter. + Parameters + ---------- + value : Numeric + The new value for the area parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if not isinstance(value, Numeric): raise TypeError('area must be a number') @@ -98,8 +110,10 @@ def area(self, value: Numeric) -> None: def center(self) -> Parameter: """Get the center parameter. - Returns: - Parameter: The center parameter. + Returns + ------- + Parameter + The center parameter. """ return self._center @@ -107,12 +121,17 @@ def center(self) -> Parameter: def center(self, value: Numeric) -> None: """Set the value of the center parameter. - Args: - value (Numeric): The new value for the center parameter. - - Raises: - TypeError: If the value is not a number. - ValueError: If the value is not positive. + Parameters + ---------- + value : Numeric + The new value for the center parameter. + + Raises + ------ + TypeError : + If the value is not a number. + ValueError : + If the value is not positive. """ if not isinstance(value, Numeric): raise TypeError('center must be a number') @@ -125,8 +144,10 @@ def center(self, value: Numeric) -> None: def width(self) -> Parameter: """Get the width parameter. - Returns: - Parameter: The width parameter. + Returns + ------- + Parameter + The width parameter. """ return self._width @@ -134,12 +155,17 @@ def width(self) -> Parameter: def width(self, value: Numeric) -> None: """Set the value of the width parameter. - Args: - value (Numeric): The new value for the width parameter. - - Raises: - TypeError: If the value is not a number. - ValueError: If the value is not positive. + Parameters + ---------- + value : Numeric + The new value for the width parameter. + + Raises + ------ + TypeError : + If the value is not a number. + ValueError : + If the value is not positive. """ if not isinstance(value, Numeric): raise TypeError('width must be a number') @@ -162,12 +188,15 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) where $A$ is the area, $x_0$ is the center, and $\gamma$ is the width. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the DHO. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the DHO. - Returns: - np.ndarray: The intensity of the DHO at the given x values. + Returns + ------- + np.ndarray + The intensity of the DHO at the given x values. """ x = self._prepare_x_for_evaluate(x) @@ -182,9 +211,11 @@ def __repr__(self) -> str: """Return a string representation of the Damped Harmonic Oscillator. - Returns: - str: A string representation of the Damped Harmonic - Oscillator. + Returns + ------- + str + A string representation of the Damped Harmonic + Oscillator. """ return ( f'DampedHarmonicOscillator(display_name = {self.display_name}, unit = {self._unit},\n \ diff --git a/src/easydynamics/sample_model/components/delta_function.py b/src/easydynamics/sample_model/components/delta_function.py index 820a039b..dcbd4f6c 100644 --- a/src/easydynamics/sample_model/components/delta_function.py +++ b/src/easydynamics/sample_model/components/delta_function.py @@ -34,14 +34,20 @@ def __init__( ) -> None: """Initialize the Delta function. - Args: - center (Numeric | Parameter | None, default=None): Center of the delta function. - If None, defaults to 0 and is fixed. - area (Numeric | Parameter, default=1.0): Total area under the curve. - unit (str | sc.Unit, default='meV'): Unit of the parameters. - display_name (str | None, default='DeltaFunction'): Name of the component. - unique_name (str | None, default=None): Unique name of the component. - If None, a unique_name is automatically generated. + Parameters + ---------- + center : Numeric | Parameter | None, optional + Center of the delta function. + If None. By default, None. + area : Numeric | Parameter, optional + Total area under the curve. By default, 1.0. + unit : str | sc.Unit, optional + Unit of the parameters. By default, 'meV'. + display_name : str | None, optional + Name of the component. By default, 'DeltaFunction'. + unique_name : str | None, optional + Unique name of the component. + If None, a unique_name is automatically generated. By default, None. """ # Validate inputs and create Parameters if not given super().__init__( @@ -63,8 +69,10 @@ def __init__( def area(self) -> Parameter: """Get the area parameter. - Returns: - Parameter: The area parameter. + Returns + ------- + Parameter + The area parameter. """ return self._area @@ -73,11 +81,15 @@ def area(self) -> Parameter: def area(self, value: Numeric) -> None: """Set the value of the area parameter. - Args: - value (Numeric): The new value for the area parameter. + Parameters + ---------- + value : Numeric + The new value for the area parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if not isinstance(value, Numeric): @@ -88,8 +100,10 @@ def area(self, value: Numeric) -> None: def center(self) -> Parameter: """Get the center parameter. - Returns: - Parameter: The center parameter. + Returns + ------- + Parameter + The center parameter. """ return self._center @@ -98,12 +112,16 @@ def center(self) -> Parameter: def center(self, value: Numeric | None) -> None: """Set the center parameter value. - Args: - value (Numeric | None): The new value for the center - parameter. If None, defaults to 0 and is fixed. + Parameters + ---------- + value : Numeric | None, optional + The new value for the center + parameter. If None. By default, 0 and is fixed. - Raises: - TypeError: If the value is not a number or None. + Raises + ------ + TypeError : + If the value is not a number or None. """ if value is None: @@ -120,13 +138,16 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) center. Its numerical integral is equal to the area. It acts as an identity in convolutions. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the Delta function. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the Delta function. - Returns: - np.ndarray: The evaluated Delta function at the given x - values. + Returns + ------- + np.ndarray + The evaluated Delta function at the given x + values. """ # x assumed sorted, 1D numpy array @@ -161,8 +182,10 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) def __repr__(self) -> str: """Return a string representation of the Delta function. - Returns: - str: A string representation of the Delta function. + Returns + ------- + str + A string representation of the Delta function. """ return f'DeltaFunction(unique_name = {self.unique_name}, unit = {self._unit},\n \ diff --git a/src/easydynamics/sample_model/components/exponential.py b/src/easydynamics/sample_model/components/exponential.py index 56a72912..9889aea5 100644 --- a/src/easydynamics/sample_model/components/exponential.py +++ b/src/easydynamics/sample_model/components/exponential.py @@ -35,22 +35,32 @@ def __init__( ) -> None: """Initialize the Exponential component. - Args: - amplitude (Numeric | Parameter, default=1.0): Amplitude of the - Exponential. - center (Numeric | Parameter | None, default=None): Center of the Exponential. - If None, the center is fixed at 0. - rate (Numeric | Parameter, default=1.0): Decay or growth - constant of the Exponential. - unit (str | sc.Unit, default='meV'): Unit of the parameters. - display_name (str | None, default='Exponential'): Name of the component. - unique_name (str | None, default=None): Unique name of the component. if - None, a unique_name is automatically generated. - - Raises: - TypeError: If amplitude, center, or rate are not numbers or - Parameters. - ValueError: If amplitude, center or rate are not finite numbers + Parameters + ---------- + amplitude : Numeric | Parameter, optional + Amplitude of the + Exponential. By default, 1.0. + center : Numeric | Parameter | None, optional + Center of the Exponential. + If None, the center is fixed at 0. By default, None. + rate : Numeric | Parameter, optional + Decay or growth + constant of the Exponential. By default, 1.0. + unit : str | sc.Unit, optional + Unit of the parameters. By default, 'meV'. + display_name : str | None, optional + Name of the component. By default, 'Exponential'. + unique_name : str | None, optional + Unique name of the component. if + None, a unique_name is automatically generated. By default, None. + + Raises + ------ + TypeError : + If amplitude, center, or rate are not numbers or + Parameters. + ValueError : + If amplitude, center or rate are not finite numbers. """ # Validate inputs and create Parameters if not given super().__init__( @@ -91,8 +101,10 @@ def __init__( def amplitude(self) -> Parameter: """Get the amplitude parameter. - Returns: - Parameter: The amplitude parameter. + Returns + ------- + Parameter + The amplitude parameter. """ return self._amplitude @@ -101,11 +113,15 @@ def amplitude(self) -> Parameter: def amplitude(self, value: Numeric) -> None: """Set the value of the amplitude parameter. - Args: - value (Numeric): The new value for the amplitude parameter. + Parameters + ---------- + value : Numeric + The new value for the amplitude parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if not isinstance(value, Numeric): @@ -116,8 +132,10 @@ def amplitude(self, value: Numeric) -> None: def center(self) -> Parameter: """Get the center parameter. - Returns: - Parameter: The center parameter. + Returns + ------- + Parameter + The center parameter. """ return self._center @@ -126,12 +144,16 @@ def center(self) -> Parameter: def center(self, value: Numeric | None) -> None: """Set the center parameter value. - Args: - value (Numeric | None): The new value for the center - parameter. + Parameters + ---------- + value : Numeric | None + The new value for the center + parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if value is None: @@ -146,8 +168,10 @@ def center(self, value: Numeric | None) -> None: def rate(self) -> Parameter: """Get the rate parameter. - Returns: - Parameter: The rate parameter. + Returns + ------- + Parameter + The rate parameter. """ return self._rate @@ -155,12 +179,16 @@ def rate(self) -> Parameter: def rate(self, value: Numeric) -> None: """Set the rate parameter value. - Args: - value (Numeric): The new value for the rate - parameter. + Parameters + ---------- + value : Numeric + The new value for the rate + parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if not isinstance(value, Numeric): raise TypeError('rate must be a number') @@ -183,13 +211,16 @@ def evaluate( where $A$ is the amplitude, $x_0$ is the center, and $r$ is the rate. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the Exponential. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the Exponential. - Returns: - np.ndarray: The intensity of the Exponential at the given x - values. + Returns + ------- + np.ndarray + The intensity of the Exponential at the given x + values. """ x = self._prepare_x_for_evaluate(x) @@ -200,12 +231,17 @@ def evaluate( def convert_unit(self, unit: str | sc.Unit) -> None: """Convert the unit of the Parameters in the component. - Args: - unit (str | sc.Unit): The new unit to convert to. - - Raises: - TypeError: If unit is not a string or sc.Unit. - Exception: If conversion fails for any parameter. + Parameters + ---------- + unit : str | sc.Unit + The new unit to convert to. + + Raises + ------ + TypeError : + If unit is not a string or sc.Unit. + Exception : + If conversion fails for any parameter. """ if not isinstance(unit, (str, sc.Unit)): @@ -231,8 +267,10 @@ def convert_unit(self, unit: str | sc.Unit) -> None: def __repr__(self) -> str: """Return a string representation of the Exponential. - Returns: - str: A string representation of the Exponential. + Returns + ------- + str + A string representation of the Exponential. """ return f'Exponential(unique_name = {self.unique_name}, unit = {self._unit},\n \ diff --git a/src/easydynamics/sample_model/components/expression_component.py b/src/easydynamics/sample_model/components/expression_component.py index dcc9e445..6adb4f8d 100644 --- a/src/easydynamics/sample_model/components/expression_component.py +++ b/src/easydynamics/sample_model/components/expression_component.py @@ -79,19 +79,26 @@ def __init__( ) -> None: """Initialize the ExpressionComponent. - Args: - expression (str): The symbolic expression as a string. - Must contain 'x' as the independent variable. - parameters (dict[str, Numeric] | None, default=None): - Dictionary of parameter names and their initial values. - Defaults to None (no parameters). - unit (str | sc.Unit, default="meV"): Unit of the output. - display_name (str | None, default="Expression"): Display name for the component. - unique_name (str | None, default=None): Unique name for the component. - - Raises: - ValueError: If the expression is invalid or does not contain 'x'. - TypeError: If any parameter value is not numeric. + Parameters + ---------- + expression : str + The symbolic expression as a string. + Must contain 'x' as the independent variable. + parameters : dict[str, Numeric] | None, optional + Dictionary of parameter names and their initial values. By default, None. + unit : str | sc.Unit, optional + Unit of the output. By default, 'meV'. + display_name : str | None, optional + Display name for the component. By default, 'Expression'. + unique_name : str | None, optional + Unique name for the component. By default, None. + + Raises + ------ + ValueError : + If the expression is invalid or does not contain 'x'. + TypeError : + If any parameter value is not numeric. """ super().__init__(unit=unit, display_name=display_name, unique_name=unique_name) @@ -189,11 +196,15 @@ def expression(self) -> str: def expression(self, _new_expr: str) -> None: """Prevent changing the expression after initialization. - Args: - _new_expr (str): New expression string (ignored). + Parameters + ---------- + _new_expr : str + New expression string (ignored). - Raises: - AttributeError: Always raised to prevent changing the expression. + Raises + ------ + AttributeError : + Always raised to prevent changing the expression. """ raise AttributeError('Expression cannot be changed after initialization') @@ -203,12 +214,15 @@ def evaluate( ) -> np.ndarray: """Evaluate the expression for given x values. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - Input values for the independent variable. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + Input values for the independent variable. - Returns: - np.ndarray: Evaluated results. + Returns + ------- + np.ndarray + Evaluated results. """ x = self._prepare_x_for_evaluate(x) @@ -224,8 +238,10 @@ def evaluate( def get_all_variables(self) -> list[Parameter]: """Return all parameters. - Returns: - list[Parameter]: List of all parameters in the expression. + Returns + ------- + list[Parameter] + List of all parameters in the expression. """ return list(self._parameters.values()) @@ -234,11 +250,15 @@ def convert_unit(self, _new_unit: str | sc.Unit) -> None: Unit conversion is not implemented for ExpressionComponent. - Args: - _new_unit (str | sc.Unit): The new unit to convert to (ignored). + Parameters + ---------- + _new_unit : str | sc.Unit + The new unit to convert to (ignored). - Raises: - NotImplementedError: Always raised to indicate unit conversion is not supported. + Raises + ------ + NotImplementedError : + Always raised to indicate unit conversion is not supported. """ raise NotImplementedError('Unit conversion is not implemented for ExpressionComponent') @@ -250,14 +270,20 @@ def convert_unit(self, _new_unit: str | sc.Unit) -> None: def __getattr__(self, name: str) -> Parameter: """Allow access to parameters as attributes. - Args: - name (str): Name of the parameter to access. + Parameters + ---------- + name : str + Name of the parameter to access. - Returns: - Parameter: The parameter with the given name. + Raises + ------ + AttributeError : + If the parameter does not exist. - Raises: - AttributeError: If the parameter does not exist. + Returns + ------- + Parameter + The parameter with the given name. """ if '_parameters' in self.__dict__ and name in self._parameters: return self._parameters[name] @@ -266,12 +292,17 @@ def __getattr__(self, name: str) -> Parameter: def __setattr__(self, name: str, value: Numeric) -> None: """Allow setting parameter values as attributes. - Args: - name (str): Name of the parameter to set. - value (Numeric): New value for the parameter. - - Raises: - TypeError: If the value is not numeric. + Parameters + ---------- + name : str + Name of the parameter to set. + value : Numeric + New value for the parameter. + + Raises + ------ + TypeError : + If the value is not numeric. """ if '_parameters' in self.__dict__ and name in self._parameters: param = self._parameters[name] @@ -288,12 +319,15 @@ def __dir__(self) -> list[str]: """Include parameter names in dir() output for better IDE support. - Returns: - list[str]: List of attribute names, including parameters. + Returns + ------- + list[str] + List of attribute names, including parameters. """ return super().__dir__() + list(self._parameters.keys()) def __repr__(self) -> str: + """Repr function.""" param_str = ', '.join(f'{k}={v.value}' for k, v in self._parameters.items()) return ( f'{self.__class__.__name__}(\n' diff --git a/src/easydynamics/sample_model/components/gaussian.py b/src/easydynamics/sample_model/components/gaussian.py index 892577e1..02097788 100644 --- a/src/easydynamics/sample_model/components/gaussian.py +++ b/src/easydynamics/sample_model/components/gaussian.py @@ -44,15 +44,22 @@ def __init__( ) -> None: """Initialize the Gaussian component. - Args: - area (Numeric | Parameter, default=1.0): Area of the Gaussian. - center (Numeric | Parameter | None, default=None): Center of the - Gaussian. If None, defaults to 0 and is fixed. - width (Numeric | Parameter, default=1.0): Standard deviation. - unit (str | sc.Unit, default='meV'): Unit of the parameters. - display_name (str | None, default='Gaussian'): Name of the component. - unique_name (str | None, default=None): Unique name of the component. - if None, a unique_name is automatically generated. + Parameters + ---------- + area : Numeric | Parameter, optional + Area of the Gaussian. By default, 1.0. + center : Numeric | Parameter | None, optional + Center of the + Gaussian. If None. By default, None. + width : Numeric | Parameter, optional + Standard deviation. By default, 1.0. + unit : str | sc.Unit, optional + Unit of the parameters. By default, 'meV'. + display_name : str | None, optional + Name of the component. By default, 'Gaussian'. + unique_name : str | None, optional + Unique name of the component. + if None, a unique_name is automatically generated. By default, None. """ # Validate inputs and create Parameters if not given super().__init__( @@ -76,8 +83,10 @@ def __init__( def area(self) -> Parameter: """Get the area parameter. - Returns: - Parameter: The area parameter. + Returns + ------- + Parameter + The area parameter. """ return self._area @@ -86,11 +95,15 @@ def area(self) -> Parameter: def area(self, value: Numeric) -> None: """Set the value of the area parameter. - Args: - value (Numeric): The new value for the area parameter. + Parameters + ---------- + value : Numeric + The new value for the area parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if not isinstance(value, Numeric): @@ -101,8 +114,10 @@ def area(self, value: Numeric) -> None: def center(self) -> Parameter: """Get the center parameter. - Returns: - Parameter: The center parameter. + Returns + ------- + Parameter + The center parameter. """ return self._center @@ -111,12 +126,16 @@ def center(self) -> Parameter: def center(self, value: Numeric | None) -> None: """Set the center parameter value. - Args: - value (Numeric | None): The new value for the center - parameter. If None, defaults to 0 and is fixed. + Parameters + ---------- + value : Numeric | None, optional + The new value for the center + parameter. If None. By default, 0 and is fixed. - Raises: - TypeError: If the value is not a number or None. + Raises + ------ + TypeError : + If the value is not a number or None. """ if value is None: @@ -130,8 +149,10 @@ def center(self, value: Numeric | None) -> None: def width(self) -> Parameter: """Get the width parameter (standard deviation). - Returns: - Parameter: The width parameter. + Returns + ------- + Parameter + The width parameter. """ return self._width @@ -139,13 +160,18 @@ def width(self) -> Parameter: def width(self, value: Numeric) -> None: """Set the width parameter value. - Args: - value (Numeric): The new value for the width - parameter. - - Raises: - TypeError: If the value is not a number or None. - ValueError: If the value is not positive. + Parameters + ---------- + value : Numeric + The new value for the width + parameter. + + Raises + ------ + TypeError : + If the value is not a number or None. + ValueError : + If the value is not positive. """ if not isinstance(value, Numeric): raise TypeError('width must be a number') @@ -175,14 +201,16 @@ def evaluate( where $A$ is the area, $x_0$ is the center, and $\sigma$ is the width. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the Gaussian. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the Gaussian. - - Returns: - np.ndarray: The intensity of the Gaussian at the given x - values. + Returns + ------- + np.ndarray + The intensity of the Gaussian at the given x + values. """ x = self._prepare_x_for_evaluate(x) @@ -195,8 +223,10 @@ def evaluate( def __repr__(self) -> str: """Return a string representation of the Gaussian. - Returns: - str: A string representation of the Gaussian. + Returns + ------- + str + A string representation of the Gaussian. """ return f'Gaussian(unique_name = {self.unique_name}, unit = {self._unit},\n \ diff --git a/src/easydynamics/sample_model/components/lorentzian.py b/src/easydynamics/sample_model/components/lorentzian.py index 8f5697bd..bffeada1 100644 --- a/src/easydynamics/sample_model/components/lorentzian.py +++ b/src/easydynamics/sample_model/components/lorentzian.py @@ -38,16 +38,23 @@ def __init__( ) -> None: """Initialize the Lorentzian component. - Args: - area (Numeric | Parameter, default=1.0): Area of the Lorentzian. - center (Numeric | Parameter | None, default=None): Center of the - Lorentzian. If None, defaults to 0 and is fixed. - width (Numeric | Parameter, default=1.0): Half width at half maximum - (HWHM). - unit (str | sc.Unit, default='meV'): Unit of the parameters. - display_name (str | None, default='Lorentzian'): Name of the component. - unique_name (str | None, default=None): Unique name of the component. If - None, a unique_name is automatically generated. + Parameters + ---------- + area : Numeric | Parameter, optional + Area of the Lorentzian. By default, 1.0. + center : Numeric | Parameter | None, optional + Center of the + Lorentzian. If None. By default, None. + width : Numeric | Parameter, optional + Half width at half maximum + (HWHM). By default, 1.0. + unit : str | sc.Unit, optional + Unit of the parameters. By default, 'meV'. + display_name : str | None, optional + Name of the component. By default, 'Lorentzian'. + unique_name : str | None, optional + Unique name of the component. If + None, a unique_name is automatically generated. By default, None. """ super().__init__( @@ -71,8 +78,10 @@ def __init__( def area(self) -> Parameter: """Get the area parameter. - Returns: - Parameter: The area parameter. + Returns + ------- + Parameter + The area parameter. """ return self._area @@ -80,11 +89,15 @@ def area(self) -> Parameter: def area(self, value: Numeric) -> None: """Set the value of the area parameter. - Args: - value (Numeric): The new value for the area parameter. + Parameters + ---------- + value : Numeric + The new value for the area parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if not isinstance(value, Numeric): raise TypeError('area must be a number') @@ -94,8 +107,10 @@ def area(self, value: Numeric) -> None: def center(self) -> Parameter: """Get the center parameter. - Returns: - Parameter: The center parameter. + Returns + ------- + Parameter + The center parameter. """ return self._center @@ -103,12 +118,16 @@ def center(self) -> Parameter: def center(self, value: Numeric | None) -> None: """Set the value of the center parameter. - Args: - value (Numeric | None): The new value for the center - parameter. If None, defaults to 0 and is fixed. + Parameters + ---------- + value : Numeric | None, optional + The new value for the center + parameter. If None. By default, 0 and is fixed. - Raises: - TypeError: If the value is not a number or None. + Raises + ------ + TypeError : + If the value is not a number or None. """ if value is None: @@ -122,8 +141,10 @@ def center(self, value: Numeric | None) -> None: def width(self) -> Parameter: """Get the width parameter (HWHM). - Returns: - Parameter: The width parameter. + Returns + ------- + Parameter + The width parameter. """ return self._width @@ -131,13 +152,18 @@ def width(self) -> Parameter: def width(self, value: Numeric) -> None: """Set the width parameter value (HWHM). - Args: - value (Numeric): The new value for the width - parameter. - - Raises: - TypeError: If the value is not a number. - ValueError: If the value is not positive. + Parameters + ---------- + value : Numeric + The new value for the width + parameter. + + Raises + ------ + TypeError : + If the value is not a number. + ValueError : + If the value is not positive. """ if not isinstance(value, Numeric): raise TypeError('width must be a number') @@ -160,13 +186,16 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) where $A$ is the area, $x_0$ is the center, and $\Gamma$ is the half width at half maximum (HWHM). - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the Lorentzian. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the Lorentzian. - Returns: - np.ndarray: The intensity of the Lorentzian at the given x - values. + Returns + ------- + np.ndarray + The intensity of the Lorentzian at the given x + values. """ x = self._prepare_x_for_evaluate(x) @@ -179,8 +208,10 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) def __repr__(self) -> str: """Return a string representation of the Lorentzian. - Returns: - str: A string representation of the Lorentzian. + Returns + ------- + str + A string representation of the Lorentzian. """ return f'Lorentzian(unique_name = {self.unique_name}, unit = {self._unit},\n \ area = {self.area},\n center = {self.center},\n width = {self.width})' diff --git a/src/easydynamics/sample_model/components/mixins.py b/src/easydynamics/sample_model/components/mixins.py index b5125767..3bd07e67 100644 --- a/src/easydynamics/sample_model/components/mixins.py +++ b/src/easydynamics/sample_model/components/mixins.py @@ -37,19 +37,29 @@ def _create_area_parameter( If the area is non-negative, its minimum is set to 0 to avoid it accidentally becoming negative during fitting. - Args: - area (Numeric | Parameter): The area value or Parameter. - name (str): The name of the model component. - unit (str | sc.Unit, default='meV'): The unit of the area Parameter. - minimum_area (float, default=MINIMUM_AREA): The minimum allowed area. - - Returns: - Parameter: The validated area Parameter. - - Raises: - TypeError: If area is not a number or a Parameter. - ValueError: If area is not a finite number or if the area - Parameter has a non-finite value. + Parameters + ---------- + area : Numeric | Parameter + The area value or Parameter. + name : str + The name of the model component. + unit : str | sc.Unit, optional + The unit of the area Parameter. By default, 'meV'. + minimum_area : float, optional + The minimum allowed area. By default, MINIMUM_AREA. + + Raises + ------ + TypeError : + If area is not a number or a Parameter. + ValueError : + If area is not a finite number or if the area + Parameter has a non-finite value. + + Returns + ------- + Parameter + The validated area Parameter. """ if not isinstance(area, (Parameter, Numeric)): raise TypeError('area must be a number or a Parameter.') @@ -82,25 +92,36 @@ def _create_center_parameter( """Validate and convert a number to a Parameter describing the center of a function. - Args: - center (Numeric | Parameter | None): The center value or - Parameter. - name (str): The name of the model component. - fix_if_none (bool): Whether to fix the center Parameter - if center is None. - unit (str | sc.Unit, default='meV'): The unit of the center - Parameter. - enforce_minimum_center (bool, default=False): Whether to - enforce a minimum center value to avoid zero center in - DHO. - - Returns: - Parameter: The validated center Parameter. - - Raises: - TypeError: If center is not None, a number, or a Parameter. - ValueError: If center is a number but not finite, or if - center is a Parameter but has a non-finite value. + Parameters + ---------- + center : Numeric | Parameter | None + The center value or + Parameter. + name : str + The name of the model component. + fix_if_none : bool + Whether to fix the center Parameter + if center is None. + unit : str | sc.Unit, optional + The unit of the center + Parameter. By default, 'meV'. + enforce_minimum_center : bool, optional + Whether to + enforce a minimum center value to avoid zero center in + DHO. By default, False. + + Raises + ------ + TypeError : + If center is not None, a number, or a Parameter. + ValueError : + If center is a number but not finite, or if + center is a Parameter but has a non-finite value. + + Returns + ------- + Parameter + The validated center Parameter. """ if center is not None and not isinstance(center, (Numeric, Parameter)): raise TypeError('center must be None, a number, or a Parameter.') @@ -132,20 +153,31 @@ def _create_width_parameter( """Validate and convert a number to a Parameter describing the width of a function. - Args: - width (Numeric | Parameter): The width value or Parameter. - name (str): The name of the model component. - param_name (str, default='width'): The name of the width parameter. - unit (str | sc.Unit, default='meV'): The unit of the width Parameter. - minimum_width (float, default=MINIMUM_WIDTH): The minimum - allowed width. - - Returns: - Parameter: The validated width Parameter. - - Raises: - TypeError: If width is not a number or a Parameter. - ValueError: If width is non-positive. + Parameters + ---------- + width : Numeric | Parameter + The width value or Parameter. + name : str + The name of the model component. + param_name : str, optional + The name of the width parameter. By default, 'width'. + unit : str | sc.Unit, optional + The unit of the width Parameter. By default, 'meV'. + minimum_width : float, optional + The minimum + allowed width. By default, MINIMUM_WIDTH. + + Raises + ------ + TypeError : + If width is not a number or a Parameter. + ValueError : + If width is non-positive. + + Returns + ------- + Parameter + The validated width Parameter. """ if not isinstance(width, (Numeric, Parameter)): raise TypeError(f'{param_name} must be a number or a Parameter.') diff --git a/src/easydynamics/sample_model/components/model_component.py b/src/easydynamics/sample_model/components/model_component.py index bfbd7384..4778bea6 100644 --- a/src/easydynamics/sample_model/components/model_component.py +++ b/src/easydynamics/sample_model/components/model_component.py @@ -25,12 +25,16 @@ def __init__( ) -> None: """Initialize the ModelComponent. - Args: - unit (str | sc.Unit, default="meV"): The unit of the model component. - display_name (str | None, default=None): A human-readable name for the - component. - unique_name (str | None, default=None): A unique identifier for the - component. + Parameters + ---------- + unit : str | sc.Unit, optional + The unit of the model component. By default, 'meV'. + display_name : str | None, optional + A human-readable name for the + component. By default, None. + unique_name : str | None, optional + A unique identifier for the + component. By default, None. """ self.validate_unit(unit) super().__init__(display_name=display_name, unique_name=unique_name) @@ -40,22 +44,30 @@ def __init__( def unit(self) -> str: """Get the unit. - Returns: - str: The unit of the model component. + Returns + ------- + str + The unit of the model component. """ return str(self._unit) @unit.setter def unit(self, _unit_str: str) -> None: - """Unit is read-only. Use convert_unit to change the unit - between allowed types or create a new ModelComponent with the + """Unit is read-only. + + Use convert_unit to change the unit +between allowed types or create a new ModelComponent with the desired unit. - Args: - _unit_str (str): The new unit to set. + Parameters + ---------- + _unit_str : str + The new unit to set. - Raises: - AttributeError: Always raised since unit is read-only. + Raises + ------ + AttributeError : + Always raised since unit is read-only. """ raise AttributeError( f'Unit is read-only. Use convert_unit to change the unit between allowed types ' @@ -80,18 +92,24 @@ def _prepare_x_for_evaluate( """Prepare the input x for evaluation by handling units and converting to a numpy array. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The input data to prepare. - - Returns: - np.ndarray: The prepared input data as a numpy array. - - Raises: - ValueError: If x contains NaN or infinite values, or if a - sc.DataArray has more than one coordinate. - UnitError: If x has incompatible units that cannot be - converted to the component's unit. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The input data to prepare. + + Raises + ------ + ValueError : + If x contains NaN or infinite values, or if a + sc.DataArray has more than one coordinate. + UnitError : + If x has incompatible units that cannot be + converted to the component's unit. + + Returns + ------- + np.ndarray + The prepared input data as a numpy array. """ # Handle units @@ -150,11 +168,15 @@ def _prepare_x_for_evaluate( def validate_unit(unit: str | sc.Unit | None) -> None: """Validate that the unit is either a string or a scipp Unit. - Args: - unit (str | sc.Unit | None): The unit to validate. + Parameters + ---------- + unit : str | sc.Unit | None + The unit to validate. - Raises: - TypeError: If unit is not a string or scipp Unit. + Raises + ------ + TypeError : + If unit is not a string or scipp Unit. """ if unit is not None and not isinstance(unit, (str, sc.Unit)): raise TypeError( @@ -164,13 +186,18 @@ def validate_unit(unit: str | sc.Unit | None) -> None: def convert_unit(self, unit: str | sc.Unit) -> None: """Convert the unit of the Parameters in the component. - Args: - unit (str | sc.Unit): The new unit to convert to. - - Raises: - TypeError: If the provided unit is not a str or sc.Unit - Exception: If the provided unit is invalid or incompatible - with the component's parameters. + Parameters + ---------- + unit : str | sc.Unit + The new unit to convert to. + + Raises + ------ + TypeError : + If the provided unit is not a str or sc.Unit. + Exception : + If the provided unit is invalid or incompatible + with the component's parameters. """ if not isinstance(unit, (str, sc.Unit)): raise TypeError(f'Unit must be a string or sc.Unit, got {type(unit).__name__}') @@ -194,22 +221,28 @@ def convert_unit(self, unit: str | sc.Unit) -> None: @abstractmethod def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: """Abstract method to evaluate the model component at input x. + Must be implemented by subclasses. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the component. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the component. - Returns: - np.ndarray: Evaluated function values. + Returns + ------- + np.ndarray + Evaluated function values. """ pass def __repr__(self) -> str: """Return a string representation of the ModelComponent. - Returns: - str: A string representation of the ModelComponent. + Returns + ------- + str + A string representation of the ModelComponent. """ return f'{self.__class__.__name__}(unique_name={self.unique_name}, unit={self._unit})' diff --git a/src/easydynamics/sample_model/components/polynomial.py b/src/easydynamics/sample_model/components/polynomial.py index 340ca537..7d4033d6 100644 --- a/src/easydynamics/sample_model/components/polynomial.py +++ b/src/easydynamics/sample_model/components/polynomial.py @@ -36,22 +36,29 @@ def __init__( ) -> None: """Initialize the Polynomial component. - Args: - coefficients (Sequence[Numeric | Parameter], default=(0.0,)): - Coefficients c0, c1, ..., cN - unit (str | sc.Unit, default='meV'): Unit of the Polynomial - component. - display_name (str | None, default='Polynomial'): Display - name of the Polynomial component. - unique_name (str | None, default=None): Unique name of the - component. If None, a unique_name is automatically - generated. - - Raises: - TypeError: If coefficients is not a sequence of numbers or - Parameters or if any item in coefficients is not a - number or Parameter. - ValueError: If coefficients is an empty sequence. + Parameters + ---------- + coefficients : Sequence[Numeric | Parameter], optional + Coefficients c0, c1, ..., cN. By default, (0.0,). + unit : str | sc.Unit, optional + Unit of the Polynomial + component. By default, 'meV'. + display_name : str | None, optional + Display + name of the Polynomial component. By default, 'Polynomial'. + unique_name : str | None, optional + Unique name of the + component. If None, a unique_name is automatically + generated. By default, None. + + Raises + ------ + TypeError : + If coefficients is not a sequence of numbers or + Parameters or if any item in coefficients is not a + number or Parameter. + ValueError : + If coefficients is an empty sequence. """ super().__init__(display_name=display_name, unit=unit, unique_name=unique_name) @@ -87,8 +94,10 @@ def coefficients(self) -> list[Parameter]: """Get the coefficients of the polynomial as a list of Parameters. - Returns: - list[Parameter]: The coefficients of the polynomial. + Returns + ------- + list[Parameter] + The coefficients of the polynomial. """ return list(self._coefficients) @@ -98,15 +107,20 @@ def coefficients(self, coeffs: Sequence[Numeric | Parameter]) -> None: Length must match current number of coefficients. - Args: - coeffs (Sequence[Numeric | Parameter]): New coefficients as - a sequence of numbers or Parameters. - - Raises: - TypeError: If coeffs is not a sequence of numbers or - Parameters or if any item in coeffs is not a number or Parameter. - ValueError: If the length of coeffs does not match the - existing number of coefficients. + Parameters + ---------- + coeffs : Sequence[Numeric | Parameter] + New coefficients as + a sequence of numbers or Parameters. + + Raises + ------ + TypeError : + If coeffs is not a sequence of numbers or + Parameters or if any item in coeffs is not a number or Parameter. + ValueError : + If the length of coeffs does not match the + existing number of coefficients. """ if not isinstance(coeffs, (list, tuple, np.ndarray)): raise TypeError( @@ -128,8 +142,10 @@ def coefficients(self, coeffs: Sequence[Numeric | Parameter]) -> None: def coefficient_values(self) -> list[float]: """Get the coefficients of the polynomial as a list. - Returns: - list[float]: The coefficient values of the polynomial. + Returns + ------- + list[float] + The coefficient values of the polynomial. """ return [param.value for param in self._coefficients] @@ -142,13 +158,16 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) $$ where $C_i$ are the coefficients. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the Polynomial. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the Polynomial. - Returns: - np.ndarray: The evaluated Polynomial at the given x - values. + Returns + ------- + np.ndarray + The evaluated Polynomial at the given x + values. """ x = self._prepare_x_for_evaluate(x) @@ -170,8 +189,10 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) def degree(self) -> int: """Get the degree of the polynomial. - Returns: - int: The degree of the polynomial. + Returns + ------- + int + The degree of the polynomial. """ return len(self._coefficients) - 1 @@ -180,12 +201,16 @@ def degree(self, _value: int) -> None: """The degree is determined by the number of coefficients and cannot be set directly. - Args: - _value (int): The new degree of the polynomial. + Parameters + ---------- + _value : int + The new degree of the polynomial. - Raises: - AttributeError: Always raised since degree cannot be set - directly. + Raises + ------ + AttributeError : + Always raised since degree cannot be set + directly. """ raise AttributeError( 'The degree of the polynomial is determined by the number of coefficients ' @@ -195,19 +220,25 @@ def degree(self, _value: int) -> None: def get_all_variables(self) -> list[DescriptorBase]: """Get all variables from the model component. - Returns: - list[DescriptorBase]: List of variables in the component. + Returns + ------- + list[DescriptorBase] + List of variables in the component. """ return list(self._coefficients) def convert_unit(self, unit: str | sc.Unit) -> None: """Convert the unit of the polynomial. - Args: - unit (str | sc.Unit): The target unit to convert to. + Parameters + ---------- + unit : str | sc.Unit + The target unit to convert to. - Raises: - UnitError: If the provided unit is not a string or sc.Unit. + Raises + ------ + UnitError : + If the provided unit is not a string or sc.Unit. """ if not isinstance(unit, (str, sc.Unit)): @@ -228,8 +259,10 @@ def convert_unit(self, unit: str | sc.Unit) -> None: def __repr__(self) -> str: """Return a string representation of the Polynomial. - Returns: - str: A string representation of the Polynomial. + Returns + ------- + str + A string representation of the Polynomial. """ coeffs_str = ', '.join(f'{param.name}={param.value}' for param in self._coefficients) diff --git a/src/easydynamics/sample_model/components/voigt.py b/src/easydynamics/sample_model/components/voigt.py index d57c91bc..61ab2aa9 100644 --- a/src/easydynamics/sample_model/components/voigt.py +++ b/src/easydynamics/sample_model/components/voigt.py @@ -15,8 +15,10 @@ class Voigt(CreateParametersMixin, ModelComponent): - r"""Voigt profile, a convolution of Gaussian and Lorentzian. If the - center is not provided, it will be centered at 0 and fixed, which is + r"""Voigt profile, a convolution of Gaussian and Lorentzian. + + If the +center is not provided, it will be centered at 0 and fixed, which is typically what you want in QENS. Use scipy.special.voigt_profile to evaluate the Voigt profile. @@ -34,17 +36,25 @@ def __init__( ) -> None: """Initialize a Voigt component. - Args: - area (Numeric | Parameter, default=1.0): Total area under the curve. - center (Numeric | Parameter | None, default=None): Center of the Voigt profile. - gaussian_width (Numeric | Parameter, default=1.0): Standard deviation of the - Gaussian part. - lorentzian_width (Numeric | Parameter, default=1.0): Half width at half max - (HWHM) of the Lorentzian part. - unit (str | sc.Unit, default='meV'): Unit of the parameters. - display_name (str | None, default='Voigt'): Display name of the component. - unique_name (str | None, default=None): Unique name of the component. - If None, a unique_name is automatically generated. + Parameters + ---------- + area : Numeric | Parameter, optional + Total area under the curve. By default, 1.0. + center : Numeric | Parameter | None, optional + Center of the Voigt profile. By default, None. + gaussian_width : Numeric | Parameter, optional + Standard deviation of the + Gaussian part. By default, 1.0. + lorentzian_width : Numeric | Parameter, optional + Half width at half max + (HWHM) of the Lorentzian part. By default, 1.0. + unit : str | sc.Unit, optional + Unit of the parameters. By default, 'meV'. + display_name : str | None, optional + Display name of the component. By default, 'Voigt'. + unique_name : str | None, optional + Unique name of the component. + If None, a unique_name is automatically generated. By default, None. """ super().__init__( @@ -80,8 +90,10 @@ def __init__( def area(self) -> Parameter: """Get the area parameter. - Returns: - Parameter: The area parameter. + Returns + ------- + Parameter + The area parameter. """ return self._area @@ -89,11 +101,15 @@ def area(self) -> Parameter: def area(self, value: Numeric) -> None: """Set the value of the area parameter. - Args: - value (Numeric): The new value for the area parameter. + Parameters + ---------- + value : Numeric + The new value for the area parameter. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if not isinstance(value, Numeric): raise TypeError('area must be a number') @@ -103,8 +119,10 @@ def area(self, value: Numeric) -> None: def center(self) -> Parameter: """Get the center parameter. - Returns: - Parameter: The center parameter. + Returns + ------- + Parameter + The center parameter. """ return self._center @@ -112,12 +130,16 @@ def center(self) -> Parameter: def center(self, value: Numeric | None) -> None: """Set the value of the center parameter. - Args: - value (Numeric | None): The new value for the center - parameter. If None, defaults to 0 and is fixed. + Parameters + ---------- + value : Numeric | None, optional + The new value for the center + parameter. If None. By default, 0 and is fixed. - Raises: - TypeError: If the value is not a number. + Raises + ------ + TypeError : + If the value is not a number. """ if value is None: value = 0.0 @@ -130,8 +152,10 @@ def center(self, value: Numeric | None) -> None: def gaussian_width(self) -> Parameter: """Get the Gaussian width parameter. - Returns: - Parameter: The Gaussian width parameter. + Returns + ------- + Parameter + The Gaussian width parameter. """ return self._gaussian_width @@ -139,13 +163,18 @@ def gaussian_width(self) -> Parameter: def gaussian_width(self, value: Numeric) -> None: """Set the width parameter value. - Args: - value (Numeric): The new value for the width - parameter. - - Raises: - TypeError: If the value is not a number. - ValueError: If the value is not positive. + Parameters + ---------- + value : Numeric + The new value for the width + parameter. + + Raises + ------ + TypeError : + If the value is not a number. + ValueError : + If the value is not positive. """ if not isinstance(value, Numeric): raise TypeError('gaussian_width must be a number') @@ -157,8 +186,10 @@ def gaussian_width(self, value: Numeric) -> None: def lorentzian_width(self) -> Parameter: """Get the Lorentzian width parameter (HWHM). - Returns: - Parameter: The Lorentzian width parameter. + Returns + ------- + Parameter + The Lorentzian width parameter. """ return self._lorentzian_width @@ -166,13 +197,18 @@ def lorentzian_width(self) -> Parameter: def lorentzian_width(self, value: Numeric) -> None: """Set the value of the Lorentzian width parameter. - Args: - value (Numeric): The new value for the Lorentzian width - parameter. - - Raises: - TypeError: If the value is not a number. - ValueError: If the value is not positive. + Parameters + ---------- + value : Numeric + The new value for the Lorentzian width + parameter. + + Raises + ------ + TypeError : + If the value is not a number. + ValueError : + If the value is not positive. """ if not isinstance(value, Numeric): raise TypeError('lorentzian_width must be a number') @@ -189,14 +225,16 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) width at half max lorentzian_width, centered at center, with area equal to area. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values at which to evaluate the Voigt. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values at which to evaluate the Voigt. - - Returns: - np.ndarray: The intensity of the Voigt at the given x - values. + Returns + ------- + np.ndarray + The intensity of the Voigt at the given x + values. """ x = self._prepare_x_for_evaluate(x) @@ -210,8 +248,10 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) def __repr__(self) -> str: """Return a string representation of the Voigt. - Returns: - str: A string representation of the Voigt. + Returns + ------- + str + A string representation of the Voigt. """ return f'Voigt(unique_name = {self.unique_name}, unit = {self._unit},\n \ diff --git a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py index f9aa17d3..547baab5 100644 --- a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py @@ -48,21 +48,28 @@ def __init__( ) -> None: """Initialize a new BrownianTranslationalDiffusion model. - Args: - display_name (str | None, default='BrownianTranslationalDiffusion'): - Display name of the diffusion model. - unique_name (str | None, default=None): Unique name of the diffusion - model. If None, a unique name will be generated. - unit (str | sc.Unit, default='meV'): Unit of the diffusion model. Must be - convertible to meV. - scale (Numeric, default=1.0): Scale factor for the diffusion model. Must - be a non-negative number. - diffusion_coefficient (Numeric, default=1.0): Diffusion coefficient D in - m^2/s. - - Raises: - TypeError: If scale or diffusion_coefficient is not a - number. + Parameters + ---------- + display_name : str | None, optional + Display name of the diffusion model. By default, 'BrownianTranslationalDiffusion'. + unique_name : str | None, optional + Unique name of the diffusion + model. If None, a unique name will be generated. By default, None. + unit : str | sc.Unit, optional + Unit of the diffusion model. Must be + convertible to meV. By default, 'meV'. + scale : Numeric, optional + Scale factor for the diffusion model. Must + be a non-negative number. By default, 1.0. + diffusion_coefficient : Numeric, optional + Diffusion coefficient D in + m^2/s. By default, 1.0. + + Raises + ------ + TypeError : + If scale or diffusion_coefficient is not a + number. """ if not isinstance(scale, Numeric): raise TypeError('scale must be a number.') @@ -95,8 +102,10 @@ def __init__( def diffusion_coefficient(self) -> Parameter: """Get the diffusion coefficient parameter D. - Returns: - Parameter: Diffusion coefficient D in m^2/s. + Returns + ------- + Parameter + Diffusion coefficient D in m^2/s. """ return self._diffusion_coefficient @@ -104,13 +113,18 @@ def diffusion_coefficient(self) -> Parameter: def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: """Set the diffusion coefficient parameter D. - Args: - diffusion_coefficient (Numeric): The new value for the - diffusion coefficient D in m^2/s. - - Raises: - TypeError: If diffusion_coefficient is not a number. - ValueError: If diffusion_coefficient is negative. + Parameters + ---------- + diffusion_coefficient : Numeric + The new value for the + diffusion coefficient D in m^2/s. + + Raises + ------ + TypeError : + If diffusion_coefficient is not a number. + ValueError : + If diffusion_coefficient is negative. """ if not isinstance(diffusion_coefficient, Numeric): raise TypeError('diffusion_coefficient must be a number.') @@ -127,12 +141,16 @@ def calculate_width(self, Q: Q_type) -> np.ndarray: """Calculate the half-width at half-maximum (HWHM) for the diffusion model. - Args: - Q (Q_type): Scattering vector in 1/angstrom + Parameters + ---------- + Q : Q_type + Scattering vector in 1/angstrom. - Returns: - np.ndarray: HWHM values in the unit of the model - (e.g., meV). + Returns + ------- + np.ndarray + HWHM values in the unit of the model + (e.g., meV). """ Q = _validate_and_convert_Q(Q) @@ -145,12 +163,16 @@ def calculate_EISF(self, Q: Q_type) -> np.ndarray: """Calculate the Elastic Incoherent Structure Factor (EISF) for the Brownian translational diffusion model. - Args: - Q (Q_type): Scattering - vector in 1/angstrom + Parameters + ---------- + Q : Q_type + Scattering + vector in 1/angstrom. - Returns: - np.ndarray: EISF values (dimensionless). + Returns + ------- + np.ndarray + EISF values (dimensionless). """ Q = _validate_and_convert_Q(Q) return np.zeros_like(Q) @@ -159,11 +181,15 @@ def calculate_QISF(self, Q: Q_type) -> np.ndarray: """Calculate the Quasi-Elastic Incoherent Structure Factor (QISF). - Args: - Q (Q_type): Scattering vector in 1/angstrom + Parameters + ---------- + Q : Q_type + Scattering vector in 1/angstrom. - Returns: - np.ndarray: QISF values (dimensionless). + Returns + ------- + np.ndarray + QISF values (dimensionless). """ Q = _validate_and_convert_Q(Q) @@ -177,20 +203,26 @@ def create_component_collections( r"""Create ComponentCollection components for the Brownian translational diffusion model at given Q values. - Args: - Q (Q_type): Scattering vector values. - component_display_name (str, default="Brownian diffusion"): - Name of the Lorentzian component. - - Returns: - list[ComponentCollection]: List of ComponentCollections with - Lorentzian components for each Q value. Each Lorentzian - has a width given by $D*Q^2$ and an area given by the - scale parameter multiplied by the QISF (which is 1 for - this model). - - Raises: - TypeError: If component_display_name is not a string. + Parameters + ---------- + Q : Q_type + Scattering vector values. + component_display_name : str, optional + Name of the Lorentzian component. By default, 'Brownian diffusion'. + + Raises + ------ + TypeError : + If component_display_name is not a string. + + Returns + ------- + list[ComponentCollection] + List of ComponentCollections with + Lorentzian components for each Q value. Each Lorentzian + has a width given by $D*Q^2$ and an area given by the + scale parameter multiplied by the QISF (which is 1 for + this model). """ Q = _validate_and_convert_Q(Q) @@ -244,14 +276,20 @@ def _write_width_dependency_expression(self, Q: float) -> str: """Write the dependency expression for the width as a function of Q to make dependent Parameters. - Args: - Q (float): Scattering vector in 1/angstrom. + Parameters + ---------- + Q : float + Scattering vector in 1/angstrom. - Returns: - str: Dependency expression for the width. + Raises + ------ + TypeError : + If Q is not a float. - Raises: - TypeError: If Q is not a float. + Returns + ------- + str + Dependency expression for the width. """ if not isinstance(Q, (float)): raise TypeError('Q must be a float.') @@ -263,8 +301,10 @@ def _write_width_dependency_map_expression(self) -> dict[str, DescriptorNumber]: """Write the dependency map expression to make dependent Parameters. - Returns: - dict[str, DescriptorNumber]: Dependency map for the width. + Returns + ------- + dict[str, DescriptorNumber] + Dependency map for the width. """ return { 'D': self.diffusion_coefficient, @@ -276,14 +316,20 @@ def _write_area_dependency_expression(self, QISF: float) -> str: """Write the dependency expression for the area to make dependent Parameters. - Args: - QISF (float): Quasielastic Incoherent Scattering Function. + Parameters + ---------- + QISF : float + Quasielastic Incoherent Scattering Function. - Returns: - str: Dependency expression for the area. + Raises + ------ + TypeError : + If QISF is not a float. - Raises: - TypeError: If QISF is not a float. + Returns + ------- + str + Dependency expression for the area. """ if not isinstance(QISF, (float)): raise TypeError('QISF must be a float.') @@ -294,8 +340,10 @@ def _write_area_dependency_map_expression(self) -> dict[str, DescriptorNumber]: """Write the dependency map expression to make dependent Parameters. - Returns: - dict[str, DescriptorNumber]: Dependency map for the area. + Returns + ------- + dict[str, DescriptorNumber] + Dependency map for the area. """ return { 'scale': self.scale, @@ -309,9 +357,11 @@ def __repr__(self) -> str: """String representation of the BrownianTranslationalDiffusion model. - Returns: - str: String representation of the - BrownianTranslationalDiffusion model. + Returns + ------- + str + String representation of the + BrownianTranslationalDiffusion model. """ return ( f'BrownianTranslationalDiffusion(display_name={self.display_name},' diff --git a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py index 6360ca52..32843579 100644 --- a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py +++ b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py @@ -22,20 +22,27 @@ def __init__( ) -> None: """Initialize a new DiffusionModel. - Args: - display_name (str | None, default='MyDiffusionModel'): - Display name of the diffusion model. - unique_name (str | None, default=None): Unique name of the diffusion - model. If None, a unique name will be generated. - scale (Numeric, default=1.0): Scale factor for the diffusion model. Must - be a non-negative number. - unit (str | sc.Unit, default='meV'): Unit of the diffusion model. Must be - convertible to meV. - - Raises: - TypeError: If scale is not a number. - UnitError: If unit is not a string or scipp Unit, or if it - cannot be converted to meV. + Parameters + ---------- + display_name : str | None, optional + Display name of the diffusion model. By default, 'MyDiffusionModel'. + unique_name : str | None, optional + Unique name of the diffusion + model. If None, a unique name will be generated. By default, None. + scale : Numeric, optional + Scale factor for the diffusion model. Must + be a non-negative number. By default, 1.0. + unit : str | sc.Unit, optional + Unit of the diffusion model. Must be + convertible to meV. By default, 'meV'. + + Raises + ------ + TypeError : + If scale is not a number. + UnitError : + If unit is not a string or scipp Unit, or if it + cannot be converted to meV. """ try: @@ -63,22 +70,30 @@ def __init__( def unit(self) -> str | sc.Unit | None: """Get the unit of the energy axis of the DiffusionModel. - Returns: - str | sc.Unit | None: Unit of the DiffusionModel. + Returns + ------- + str | sc.Unit | None + Unit of the DiffusionModel. """ return str(self._unit) @unit.setter def unit(self, _unit_str: str) -> None: - """The unit of the energy axis is read-only. To change the unit, - use convert_unit or create a new DiffusionModel with the desired + """The unit of the energy axis is read-only. + + To change the unit, +use convert_unit or create a new DiffusionModel with the desired unit. - Args: - _unit_str (str): The new unit to set (ignored) + Parameters + ---------- + _unit_str : str + The new unit to set (ignored). - Raises: - AttributeError: Always, since the unit is read-only. + Raises + ------ + AttributeError : + Always, since the unit is read-only. """ raise AttributeError( f'Unit is read-only. Use convert_unit to change the unit between allowed types ' @@ -89,8 +104,10 @@ def unit(self, _unit_str: str) -> None: def scale(self) -> Parameter: """Get the scale parameter of the diffusion model. - Returns: - Parameter: scale parameter of the diffusion model + Returns + ------- + Parameter + Scale parameter of the diffusion model. """ return self._scale @@ -98,13 +115,18 @@ def scale(self) -> Parameter: def scale(self, scale: Numeric) -> None: """Set the scale parameter of the diffusion model. - Args: - scale (Numeric): The new value for the scale parameter. Must - be a non-negative number. - - Raises: - TypeError: If scale is not a number. - ValueError: If scale is negative. + Parameters + ---------- + scale : Numeric + The new value for the scale parameter. Must + be a non-negative number. + + Raises + ------ + TypeError : + If scale is not a number. + ValueError : + If scale is negative. """ if not isinstance(scale, Numeric): raise TypeError('scale must be a number.') @@ -120,7 +142,9 @@ def scale(self, scale: Numeric) -> None: def __repr__(self) -> str: """String representation of the Diffusion model. - Returns: - str: String representation of the DiffusionModel. + Returns + ------- + str + String representation of the DiffusionModel. """ return f'{self.__class__.__name__}(display_name={self.display_name}, unit={self.unit})' diff --git a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py index 888a0ad5..6493b19a 100644 --- a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py @@ -18,8 +18,10 @@ class JumpTranslationalDiffusion(DiffusionModelBase): - r"""Model of Jump translational diffusion. The model consists of a - Lorentzian function for each Q-value, where the width is given by + r"""Model of Jump translational diffusion. + + The model consists of a +Lorentzian function for each Q-value, where the width is given by $$ \Gamma(Q) = \frac{Q^2}{1+D t Q^2}. @@ -54,22 +56,30 @@ def __init__( ) -> None: """Initialize a new JumpTranslationalDiffusion model. - Args: - display_name (str | None, default="JumpTranslationalDiffusion"): - Display name of the diffusion model. - unique_name (str | None, default=None): Unique name of the diffusion - model. If None, a unique name will be generated. - unit (str | sc.Unit, default="meV"): Unit of the diffusion model. Must be - convertible to meV. - scale (Numeric, default=1.0): Scale factor for the diffusion model. Must - be a non-negative number. - diffusion_coefficient (Numeric, default=1.0): Diffusion coefficient D in - m^2/s. - relaxation_time (Numeric, default=1.0): Relaxation time t in ps. - - Raises: - TypeError: If scale, diffusion_coefficient, or - relaxation_time are not numbers. + Parameters + ---------- + display_name : str | None, optional + Display name of the diffusion model. By default, 'JumpTranslationalDiffusion'. + unique_name : str | None, optional + Unique name of the diffusion + model. If None, a unique name will be generated. By default, None. + unit : str | sc.Unit, optional + Unit of the diffusion model. Must be + convertible to meV. By default, 'meV'. + scale : Numeric, optional + Scale factor for the diffusion model. Must + be a non-negative number. By default, 1.0. + diffusion_coefficient : Numeric, optional + Diffusion coefficient D in + m^2/s. By default, 1.0. + relaxation_time : Numeric, optional + Relaxation time t in ps. By default, 1.0. + + Raises + ------ + TypeError : + If scale, diffusion_coefficient, or + relaxation_time are not numbers. """ super().__init__( display_name=display_name, @@ -111,8 +121,10 @@ def __init__( def diffusion_coefficient(self) -> Parameter: """Get the diffusion coefficient parameter D. - Returns: - Parameter: Diffusion coefficient D. + Returns + ------- + Parameter + Diffusion coefficient D. """ return self._diffusion_coefficient @@ -120,13 +132,18 @@ def diffusion_coefficient(self) -> Parameter: def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: """Set the diffusion coefficient parameter D. - Args: - diffusion_coefficient (Numeric): Diffusion coefficient D in - m^2/s. - - Raises: - TypeError: If diffusion_coefficient is not a number. - ValueError: If diffusion_coefficient is negative. + Parameters + ---------- + diffusion_coefficient : Numeric + Diffusion coefficient D in + m^2/s. + + Raises + ------ + TypeError : + If diffusion_coefficient is not a number. + ValueError : + If diffusion_coefficient is negative. """ if not isinstance(diffusion_coefficient, Numeric): raise TypeError('diffusion_coefficient must be a number.') @@ -138,8 +155,10 @@ def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: def relaxation_time(self) -> Parameter: """Get the relaxation time parameter t. - Returns: - Parameter: Relaxation time t in ps. + Returns + ------- + Parameter + Relaxation time t in ps. """ return self._relaxation_time @@ -147,12 +166,17 @@ def relaxation_time(self) -> Parameter: def relaxation_time(self, relaxation_time: Numeric) -> None: """Set the relaxation time parameter t. - Args: - relaxation_time (Numeric): Relaxation time t in ps. - - Raises: - TypeError: If relaxation_time is not a number. - ValueError: If relaxation_time is negative. + Parameters + ---------- + relaxation_time : Numeric + Relaxation time t in ps. + + Raises + ------ + TypeError : + If relaxation_time is not a number. + ValueError : + If relaxation_time is negative. """ if not isinstance(relaxation_time, Numeric): raise TypeError('relaxation_time must be a number.') @@ -170,13 +194,17 @@ def calculate_width(self, Q: Q_type) -> np.ndarray: diffusion model. $\Gamma(Q) = Q^2/(1+D t Q^2)$, where $D$ is the diffusion coefficient and $t$ is the relaxation time. - Args: - Q (Q_type): Scattering vector in 1/angstrom. Can be a single - value or an array of values. - - Returns: - np.ndarray: HWHM values in the unit of the model (e.g., - meV). + Parameters + ---------- + Q : Q_type + Scattering vector in 1/angstrom. Can be a single + value or an array of values. + + Returns + ------- + np.ndarray + HWHM values in the unit of the model (e.g., + meV). """ Q = _validate_and_convert_Q(Q) @@ -200,12 +228,16 @@ def calculate_width(self, Q: Q_type) -> np.ndarray: def calculate_EISF(self, Q: Q_type) -> np.ndarray: """Calculate the Elastic Incoherent Structure Factor (EISF). - Args: - Q (Q_type): Scattering vector in 1/angstrom. Can be a single - value or an array of values. + Parameters + ---------- + Q : Q_type + Scattering vector in 1/angstrom. Can be a single + value or an array of values. - Returns: - np.ndarray: EISF values (dimensionless). + Returns + ------- + np.ndarray + EISF values (dimensionless). """ Q = _validate_and_convert_Q(Q) return np.zeros_like(Q) @@ -214,11 +246,16 @@ def calculate_QISF(self, Q: Q_type) -> np.ndarray: """Calculate the Quasi-Elastic Incoherent Structure Factor (QISF). - Args: - Q (Q_type): Scattering vector in 1/angstrom. Can be a single - value or an array of values. - Returns: - np.ndarray: QISF values (dimensionless). + Parameters + ---------- + Q : Q_type + Scattering vector in 1/angstrom. Can be a single + value or an array of values. + + Returns + ------- + np.ndarray + QISF values (dimensionless). """ Q = _validate_and_convert_Q(Q) return np.ones_like(Q) @@ -231,18 +268,24 @@ def create_component_collections( """Create ComponentCollection components for the diffusion model at given Q values. - Args: - Q (Q_type): Scattering vector in 1/angstrom. Can be a single - value or an array of values. - component_display_name (str, default="Jump translational diffusion"): - Name of the Jump Diffusion Lorentzian component. - - Returns: - list[ComponentCollection]: List of ComponentCollections with - Jump Diffusion Lorentzian components. - - Raises: - TypeError: If component_display_name is not a string. + Parameters + ---------- + Q : Q_type + Scattering vector in 1/angstrom. Can be a single + value or an array of values. + component_display_name : str, optional + Name of the Jump Diffusion Lorentzian component. By default, 'Jump translational diffusion'. + + Raises + ------ + TypeError : + If component_display_name is not a string. + + Returns + ------- + list[ComponentCollection] + List of ComponentCollections with + Jump Diffusion Lorentzian components. """ Q = _validate_and_convert_Q(Q) @@ -296,14 +339,20 @@ def _write_width_dependency_expression(self, Q: float) -> str: """Write the dependency expression for the width as a function of Q to make dependent Parameters. - Args: - Q (float): Scattering vector in 1/angstrom + Parameters + ---------- + Q : float + Scattering vector in 1/angstrom. - Returns: - str: Dependency expression for the width. + Raises + ------ + TypeError : + If Q is not a float. - Raises: - TypeError: If Q is not a float. + Returns + ------- + str + Dependency expression for the width. """ if not isinstance(Q, (float)): raise TypeError('Q must be a float.') @@ -315,8 +364,10 @@ def _write_width_dependency_map_expression(self) -> dict[str, DescriptorNumber]: """Write the dependency map expression to make dependent Parameters. - Returns: - dict[str, DescriptorNumber]: Dependency map for the width. + Returns + ------- + dict[str, DescriptorNumber] + Dependency map for the width. """ return { 'D': self._diffusion_coefficient, @@ -329,14 +380,20 @@ def _write_area_dependency_expression(self, QISF: float) -> str: """Write the dependency expression for the area to make dependent Parameters. - Args: - QISF (float): Q-dependent intermediate scattering function. + Parameters + ---------- + QISF : float + Q-dependent intermediate scattering function. - Returns: - str: Dependency expression for the area. + Raises + ------ + TypeError : + If QISF is not a float. - Raises: - TypeError: If QISF is not a float. + Returns + ------- + str + Dependency expression for the area. """ if not isinstance(QISF, (float)): @@ -348,8 +405,10 @@ def _write_area_dependency_map_expression(self) -> dict[str, DescriptorNumber]: """Write the dependency map expression to make dependent Parameters. - Returns: - dict[str, DescriptorNumber]: Dependency map for the area. + Returns + ------- + dict[str, DescriptorNumber] + Dependency map for the area. """ return { 'scale': self._scale, @@ -363,9 +422,11 @@ def __repr__(self) -> str: """String representation of the JumpTranslationalDiffusion model. - Returns: - str: String representation of the JumpTranslationalDiffusion - model. + Returns + ------- + str + String representation of the JumpTranslationalDiffusion + model. """ return ( f'JumpTranslationalDiffusion(display_name={self.display_name}, ' diff --git a/src/easydynamics/sample_model/instrument_model.py b/src/easydynamics/sample_model/instrument_model.py index 78815553..a677fda6 100644 --- a/src/easydynamics/sample_model/instrument_model.py +++ b/src/easydynamics/sample_model/instrument_model.py @@ -36,28 +36,38 @@ def __init__( ) -> None: """Initialize an InstrumentModel. - Args: - display_name (str, default="MyInstrumentModel"): The display name of the - InstrumentModel. Default is "MyInstrumentModel". - unique_name (str | None, default=None): The unique name of the - InstrumentModel. - Q (Q_type | None, default=None): The Q values where the instrument is modelled. - resolution_model (ResolutionModel | None, default=None): The resolution - model of the instrument. If None, an empty resolution - model is created and no resolution convolution is - carried out. - background_model (BackgroundModel | None, default=None): The background - model of the instrument. If None, an empty background - model is created, and the background evaluates to 0. - energy_offset (Numeric | None, default=None): Template energy offset - of the instrument. Will be copied to each Q value. If - None, the energy offset will be 0. - unit (str | sc.Unit, default="meV"): The unit of the energy axis. - - Raises: - TypeError: If resolution_model is not a ResolutionModel or - None, or if background_model is not a BackgroundModel or None, or - if energy_offset is not a number or None. + Parameters + ---------- + display_name : str, optional + The display name of the + InstrumentModel. By default, 'MyInstrumentModel'. + unique_name : str | None, optional + The unique name of the + InstrumentModel. By default, None. + Q : Q_type | None, optional + The Q values where the instrument is modelled. By default, None. + resolution_model : ResolutionModel | None, optional + The resolution + model of the instrument. If None, an empty resolution + model is created and no resolution convolution is + carried out. By default, None. + background_model : BackgroundModel | None, optional + The background + model of the instrument. If None, an empty background + model is created, and the background evaluates to 0. By default, None. + energy_offset : Numeric | None, optional + Template energy offset + of the instrument. Will be copied to each Q value. If + None, the energy offset will be 0. By default, None. + unit : str | sc.Unit, optional + The unit of the energy axis. By default, 'meV'. + + Raises + ------ + TypeError : + If resolution_model is not a ResolutionModel or + None, or if background_model is not a BackgroundModel or None, or + if energy_offset is not a number or None. """ super().__init__( display_name=display_name, @@ -109,8 +119,10 @@ def __init__( def resolution_model(self) -> ResolutionModel: """Get the resolution model of the instrument. - Returns: - ResolutionModel: The resolution model of the instrument. + Returns + ------- + ResolutionModel + The resolution model of the instrument. """ return self._resolution_model @@ -118,12 +130,16 @@ def resolution_model(self) -> ResolutionModel: def resolution_model(self, value: ResolutionModel) -> None: """Set the resolution model of the instrument. - Args: - value (ResolutionModel): The new resolution model of the - instrument. + Parameters + ---------- + value : ResolutionModel + The new resolution model of the + instrument. - Raises: - TypeError: If value is not a ResolutionModel. + Raises + ------ + TypeError : + If value is not a ResolutionModel. """ if not isinstance(value, ResolutionModel): raise TypeError( @@ -136,8 +152,10 @@ def resolution_model(self, value: ResolutionModel) -> None: def background_model(self) -> BackgroundModel: """Get the background model of the instrument. - Returns: - BackgroundModel: The background model of the instrument. + Returns + ------- + BackgroundModel + The background model of the instrument. """ return self._background_model @@ -146,12 +164,16 @@ def background_model(self) -> BackgroundModel: def background_model(self, value: BackgroundModel) -> None: """Set the background model of the instrument. - Args: - value (BackgroundModel): The new background model of the - instrument. + Parameters + ---------- + value : BackgroundModel + The new background model of the + instrument. - Raises: - TypeError: If value is not a BackgroundModel. + Raises + ------ + TypeError : + If value is not a BackgroundModel. """ if not isinstance(value, BackgroundModel): @@ -165,26 +187,34 @@ def background_model(self, value: BackgroundModel) -> None: def Q(self) -> np.ndarray | None: """Get the Q values of the InstrumentModel. - Returns: - np.ndarray | None: The Q values of the InstrumentModel, or - None if not set + Returns + ------- + np.ndarray | None + The Q values of the InstrumentModel, or + None if not set. """ return self._Q @Q.setter def Q(self, value: Q_type | None) -> None: - """Set the Q values of the InstrumentModel. If Q is already set, - it raises an error if the new Q values are not similar to the + """Set the Q values of the InstrumentModel. + + If Q is already set, +it raises an error if the new Q values are not similar to the old ones to prevent accidental changes to the background and resolution models. To change Q values, first run clear_Q(). - Args: - value (Q_type | None): The new Q values to set. - If None, Q values are not changed. - - Raises: - ValueError: If the new Q values are not similar to the old - ones when Q is not None + Parameters + ---------- + value : Q_type | None + The new Q values to set. + If None, Q values are not changed. + + Raises + ------ + ValueError : + If the new Q values are not similar to the old + ones when Q is not None. """ if value is None: return @@ -206,24 +236,32 @@ def Q(self, value: Q_type | None) -> None: def unit(self) -> str | sc.Unit: """Get the unit of the InstrumentModel. - Returns: - str | sc.Unit: The unit of the InstrumentModel. + Returns + ------- + str | sc.Unit + The unit of the InstrumentModel. """ return self._unit @unit.setter def unit(self, _unit_str: str) -> None: - """Set the unit of the InstrumentModel. The unit is read-only - and cannot be set directly. Use convert_unit to change the unit + """Set the unit of the InstrumentModel. + + The unit is read-only +and cannot be set directly. Use convert_unit to change the unit between allowed types or create a new InstrumentModel with the desired unit. - Args: - _unit_str (str): The new unit for the InstrumentModel - (ignored) + Parameters + ---------- + _unit_str : str + The new unit for the InstrumentModel + (ignored). - Raises: - AttributeError: Always, as the unit is read-only. + Raises + ------ + AttributeError : + Always, as the unit is read-only. """ raise AttributeError( f'Unit is read-only. Use convert_unit to change the unit between allowed types ' @@ -235,9 +273,11 @@ def energy_offset(self) -> Parameter: """Get the energy offset template parameter of the instrument model. - Returns: - Parameter: The energy offset template parameter of the - instrument model. + Returns + ------- + Parameter + The energy offset template parameter of the + instrument model. """ return self._energy_offset @@ -245,12 +285,16 @@ def energy_offset(self) -> Parameter: def energy_offset(self, value: Numeric) -> None: """Set the offset parameter of the instrument model. - Args: - value (Numeric): The new value for the energy offset - parameter. Will be copied to all Q values. + Parameters + ---------- + value : Numeric + The new value for the energy offset + parameter. Will be copied to all Q values. - Raises: - TypeError: If value is not a number. + Raises + ------ + TypeError : + If value is not a number. """ if not isinstance(value, Numeric): raise TypeError(f'energy_offset must be a number, got {type(value).__name__}') @@ -267,12 +311,16 @@ def clear_Q(self, confirm: bool = False) -> None: ResolutionModel and BackgroundModel, removing all component collections and their associated Parameters. - Args: - confirm (bool, default=False): Confirmation to clear Q - values. + Parameters + ---------- + confirm : bool, optional + Confirmation to clear Q + values. By default, False. - Raises: - ValueError: If confirm is not True. + Raises + ------ + ValueError : + If confirm is not True. """ if not confirm: raise ValueError( @@ -286,12 +334,16 @@ def clear_Q(self, confirm: bool = False) -> None: def convert_unit(self, unit_str: str | sc.Unit) -> None: """Convert the unit of the InstrumentModel. - Args: - unit_str (str | sc.Unit): The unit to convert to. + Parameters + ---------- + unit_str : str | sc.Unit + The unit to convert to. - Raises: - ValueError: If unit_str is not a valid unit string or - scipp Unit. + Raises + ------ + ValueError : + If unit_str is not a valid unit string or + scipp Unit. """ unit = _validate_unit(unit_str) if unit is None: @@ -308,21 +360,28 @@ def convert_unit(self, unit_str: str | sc.Unit) -> None: def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: """Get all variables in the InstrumentModel. - Args: - Q_index (int | None, default=None): The index of the Q value to get - variables for. If None, get variables for all Q values. - - Returns: - list[Parameter]: A list of all variables in the - InstrumentModel. If Q_index is specified, only variables - from the ComponentCollection at the given Q index are - included. Otherwise, all variables in the - InstrumentModel are included. - - Raises: - TypeError: If Q_index is not an int or None. - IndexError: If Q_index is out of bounds for the Q values in - the InstrumentModel. + Parameters + ---------- + Q_index : int | None, optional + The index of the Q value to get + variables for. If None, get variables for all Q values. By default, None. + + Raises + ------ + TypeError : + If Q_index is not an int or None. + IndexError : + If Q_index is out of bounds for the Q values in + the InstrumentModel. + + Returns + ------- + list[Parameter] + A list of all variables in the + InstrumentModel. If Q_index is specified, only variables + from the ComponentCollection at the given Q index are + included. Otherwise, all variables in the + InstrumentModel are included. """ if self._Q is None: return [] @@ -361,18 +420,26 @@ def get_energy_offset( ) -> Parameter | list[Parameter]: """Get the energy offset Parameter at a specific Q index. - Args: - Q_index (int | None, default=None): The index of the Q value to get the energy - offset for. If None, get the energy offset for all Q values. - - Returns: - Parameter | list[Parameter]: The energy offset Parameter at the specified Q - index, or a list of Parameters if Q_index is None. - - Raises: - ValueError: If no Q values are set in the InstrumentModel. - IndexError: If Q_index is out of bounds. - TypeError: If Q_index is not an int or None. + Parameters + ---------- + Q_index : int | None, optional + The index of the Q value to get the energy + offset for. If None, get the energy offset for all Q values. By default, None. + + Raises + ------ + ValueError : + If no Q values are set in the InstrumentModel. + IndexError : + If Q_index is out of bounds. + TypeError : + If Q_index is not an int or None. + + Returns + ------- + Parameter | list[Parameter] + The energy offset Parameter at the specified Q + index, or a list of Parameters if Q_index is None. """ if self._Q is None: raise ValueError('No Q values are set in the InstrumentModel.') @@ -389,26 +456,34 @@ def get_energy_offset( return self._energy_offsets[Q_index] def fix_energy_offset(self, Q_index: int | None = None) -> None: - """Fix energy offset parameters. If Q_index is specified, only - fix the energy offset for that Q value. If Q_index is None, fix + """Fix energy offset parameters. + + If Q_index is specified, only +fix the energy offset for that Q value. If Q_index is None, fix energy offsets for all Q values. - Args: - Q_index (int | None, default=None): The index of the Q value - to fix the energy offset for. If None, fix energy - offsets for all Q values. + Parameters + ---------- + Q_index : int | None, optional + The index of the Q value + to fix the energy offset for. If None, fix energy + offsets for all Q values. By default, None. """ self._fix_or_free_energy_offset(Q_index, fixed=True) def free_energy_offset(self, Q_index: int | None = None) -> None: - """Free energy offset parameters. If Q_index is specified, only - free the energy offset for that Q value. If Q_index is None, + """Free energy offset parameters. + + If Q_index is specified, only +free the energy offset for that Q value. If Q_index is None, free energy offsets for all Q values. - Args: - Q_index (int | None, default=None): The index of the Q value - to free the energy offset for. If None, free energy - offsets for all Q values. + Parameters + ---------- + Q_index : int | None, optional + The index of the Q value + to free the energy offset for. If None, free energy + offsets for all Q values. By default, None. """ self._fix_or_free_energy_offset(Q_index, fixed=False) @@ -416,21 +491,29 @@ def free_energy_offset(self, Q_index: int | None = None) -> None: # Private methods # -------------------------------------------------------------- def _fix_or_free_energy_offset(self, Q_index: int | None = None, fixed: bool = True) -> None: - """Fix or free energy offset parameters. If Q_index is - specified, only fix or free the energy offset for that Q value. + """Fix or free energy offset parameters. + + If Q_index is +specified, only fix or free the energy offset for that Q value. If Q_index is None, fix or free energy offsets for all Q values. - Args: - Q_index (int | None, default=None): The index of the Q value - to fix or free the energy offset for. If None, fix or - free energy offsets for all Q values. - fixed (bool, default=True): Whether to fix (True) or free - (False) the energy offset. - - Raises: - TypeError: If Q_index is not an int or None. - IndexError: If Q_index is out of bounds for the Q values in - the InstrumentModel. + Parameters + ---------- + Q_index : int | None, optional + The index of the Q value + to fix or free the energy offset for. If None, fix or + free energy offsets for all Q values. By default, None. + fixed : bool, optional + Whether to fix (True) or free + (False) the energy offset. By default, True. + + Raises + ------ + TypeError : + If Q_index is not an int or None. + IndexError : + If Q_index is out of bounds for the Q values in + the InstrumentModel. """ if Q_index is None: @@ -480,8 +563,10 @@ def _on_background_model_change(self) -> None: def __repr__(self) -> str: """Return a string representation of the InstrumentModel. - Returns: - str: A string representation of the InstrumentModel. + Returns + ------- + str + A string representation of the InstrumentModel. """ return ( diff --git a/src/easydynamics/sample_model/model_base.py b/src/easydynamics/sample_model/model_base.py index 0bb95860..35b33515 100644 --- a/src/easydynamics/sample_model/model_base.py +++ b/src/easydynamics/sample_model/model_base.py @@ -33,20 +33,27 @@ def __init__( ) -> None: """Initialize the ModelBase. - Args: - display_name (str, default="MyModelBase"): Display name of the model. - unique_name (str | None, default=None): Unique name of the model. If None, - a unique name will be generated. - unit (str | sc.Unit | None, default="meV"): Unit of the model. - components (ModelComponent | ComponentCollection | None, default=None): - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. - Q (Q_type | None, default=None): Q values for the model. - If None, Q is not set. - - Raises: - TypeError: If components is not a ModelComponent or ComponentCollection. + Parameters + ---------- + display_name : str, optional + Display name of the model. By default, 'MyModelBase'. + unique_name : str | None, optional + Unique name of the model. If None, + a unique name will be generated. By default, None. + unit : str | sc.Unit | None, optional + Unit of the model. By default, 'meV'. + components : ModelComponent | ComponentCollection | None, optional + Template components of the model. If None, no components + are added. These components are copied into + ComponentCollections for each Q value. By default, None. + Q : Q_type | None, optional + Q values for the model. + If None, Q is not set. By default, None. + + Raises + ------ + TypeError : + If components is not a ModelComponent or ComponentCollection. """ super().__init__( display_name=display_name, @@ -74,21 +81,26 @@ def evaluate( ) -> list[np.ndarray]: """Evaluate the sample model at all Q for the given x values. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - Energy axis values to evaluate the model at. If a scipp - Variable or DataArray is provided, the unit of the model - will be converted to match the unit of x for evaluation, and - the result will be returned in the same unit as x. - - Returns: - list[np.ndarray]: A list of numpy arrays containing the - evaluated model values for each Q. The length of the - list will match the number of Q values in the model. - - Raises: - ValueError: If there are no components in the model to - evaluate. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + Energy axis values to evaluate the model at. If a scipp + Variable or DataArray is provided, the unit of the model + will be converted to match the unit of x for evaluation, and + the result will be returned in the same unit as x. + + Raises + ------ + ValueError : + If there are no components in the model to + evaluate. + + Returns + ------- + list[np.ndarray] + A list of numpy arrays containing the + evaluated model values for each Q. The length of the + list will match the number of Q values in the model. """ if not self._component_collections: @@ -105,9 +117,11 @@ def append_component(self, component: ModelComponent | ComponentCollection) -> N """Append a ModelComponent or ComponentCollection to the SampleModel. - Args: - component (ModelComponent | ComponentCollection): The - ModelComponent or ComponentCollection to append. + Parameters + ---------- + component : ModelComponent | ComponentCollection + The + ModelComponent or ComponentCollection to append. """ self._components.append_component(component) self._on_components_change() @@ -116,9 +130,11 @@ def remove_component(self, unique_name: str) -> None: """Remove a ModelComponent from the SampleModel by its unique name. - Args: - unique_name (str): The unique name of the ModelComponent - to remove. + Parameters + ---------- + unique_name : str + The unique name of the ModelComponent + to remove. """ self._components.remove_component(unique_name) self._on_components_change() @@ -136,8 +152,10 @@ def clear_components(self) -> None: def unit(self) -> str | sc.Unit | None: """Get the unit of the ComponentCollection. - Returns: - str | sc.Unit | None: The unit of the ComponentCollection. + Returns + ------- + str | sc.Unit | None + The unit of the ComponentCollection. """ return self._unit @@ -146,12 +164,16 @@ def unit(self) -> str | sc.Unit | None: def unit(self, _unit_str: str) -> None: """Unit is read-only and cannot be set directly. - Args: - _unit_str (str): The new unit to set (ignored). + Parameters + ---------- + _unit_str : str + The new unit to set (ignored). - Raises: - AttributeError: Always raised to indicate that the unit is - read-only. + Raises + ------ + AttributeError : + Always raised to indicate that the unit is + read-only. """ raise AttributeError( f'Unit is read-only. Use convert_unit to change the unit between allowed types ' @@ -162,13 +184,18 @@ def convert_unit(self, unit: str | sc.Unit) -> None: """Convert the unit of the ComponentCollection and all its components. - Args: - unit (str | sc.Unit): The new unit to convert to. - - Raises: - TypeError: If the provided unit is not a string or sc.Unit. - Exception: If the provided unit is not compatible with the - current unit. + Parameters + ---------- + unit : str | sc.Unit + The new unit to convert to. + + Raises + ------ + TypeError : + If the provided unit is not a string or sc.Unit. + Exception : + If the provided unit is not compatible with the + current unit. """ old_unit = self._unit @@ -193,8 +220,10 @@ def convert_unit(self, unit: str | sc.Unit) -> None: def components(self) -> list[ModelComponent]: """Get the components of the SampleModel. - Returns: - list[ModelComponent]: The components of the SampleModel. + Returns + ------- + list[ModelComponent] + The components of the SampleModel. """ return self._components.components @@ -202,13 +231,17 @@ def components(self) -> list[ModelComponent]: def components(self, value: ModelComponent | ComponentCollection | None) -> None: """Set the components of the SampleModel. - Args: - value (ModelComponent | ComponentCollection | None): The new - components to set. If None, all components will be cleared. - - Raises: - TypeError: If value is not a ModelComponent, - ComponentCollection, or None. + Parameters + ---------- + value : ModelComponent | ComponentCollection | None + The new + components to set. If None, all components will be cleared. + + Raises + ------ + TypeError : + If value is not a ModelComponent, + ComponentCollection, or None. """ if not isinstance(value, (ModelComponent, ComponentCollection, type(None))): raise TypeError('Components must be a ModelComponent or a ComponentCollection') @@ -221,25 +254,33 @@ def components(self, value: ModelComponent | ComponentCollection | None) -> None def Q(self) -> np.ndarray | None: """Get the Q values of the SampleModel. - Returns: - np.ndarray | None: The Q values of the SampleModel, or None - if not set. + Returns + ------- + np.ndarray | None + The Q values of the SampleModel, or None + if not set. """ return self._Q @Q.setter def Q(self, value: Q_type | None) -> None: - """Set the Q values of the SampleModel. If Q is already set, it - throws an error if the new Q values are not similar to the old - ones. To change Q values, first run clear_Q(). + """Set the Q values of the SampleModel. - Args: - value (Q_type | None): The new Q values to set. - If None, Q values are not changed. + If Q is already set, it +throws an error if the new Q values are not similar to the old + ones. To change Q values, first run clear_Q(). - Raises: - ValueError: If the new Q values are not similar to the old - ones when Q is already set. + Parameters + ---------- + value : Q_type | None + The new Q values to set. + If None, Q values are not changed. + + Raises + ------ + ValueError : + If the new Q values are not similar to the old + ones when Q is already set. """ if value is None: return @@ -261,11 +302,15 @@ def clear_Q(self, confirm: bool = False) -> None: """Clear the Q values of the SampleModel, removing all component collections and their associated Parameters. - Args: - confirm (bool, default=False): Confirmation to clear Q values. + Parameters + ---------- + confirm : bool, optional + Confirmation to clear Q values. By default, False. - Raises: - ValueError: If confirm is not True. + Raises + ------ + ValueError : + If confirm is not True. """ if not confirm: raise ValueError( @@ -293,19 +338,26 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: Parameters and Descriptors in self._components as these are just templates. - Args: - Q_index (int | None, default=None): If None, get variables for all - ComponentCollections. If int, get variables for the - ComponentCollection at this index. Defaults to None. - - Returns: - list[Parameter]: A list of all Parameters and Descriptors - from the ComponentCollections in the ModelBase. - - Raises: - TypeError: If Q_index is not an int or None. - IndexError: If Q_index is out of bounds for the number of - ComponentCollections. + Parameters + ---------- + Q_index : int | None, optional + If None, get variables for all + ComponentCollections. If int, get variables for the + ComponentCollection at this index. By default, None. + + Raises + ------ + TypeError : + If Q_index is not an int or None. + IndexError : + If Q_index is out of bounds for the number of + ComponentCollections. + + Returns + ------- + list[Parameter] + A list of all Parameters and Descriptors + from the ComponentCollections in the ModelBase. """ if Q_index is None: @@ -328,17 +380,24 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: def get_component_collection(self, Q_index: int) -> ComponentCollection: """Get the ComponentCollection at the given Q index. - Args: - Q_index (int): The index of the desired ComponentCollection. - - Returns: - ComponentCollection: The ComponentCollection at the - specified Q index. - - Raises: - TypeError: If Q_index is not an int. - IndexError: If Q_index is out of bounds for the number of - ComponentCollections. + Parameters + ---------- + Q_index : int + The index of the desired ComponentCollection. + + Raises + ------ + TypeError : + If Q_index is not an int. + IndexError : + If Q_index is out of bounds for the number of + ComponentCollections. + + Returns + ------- + ComponentCollection + The ComponentCollection at the. + specified Q index. """ if not isinstance(Q_index, int): raise TypeError(f'Q_index must be an int, got {type(Q_index).__name__}') @@ -384,8 +443,10 @@ def _on_components_change(self) -> None: def __repr__(self) -> str: """Return a string representation of the ModelBase. - Returns: - str: A string representation of the ModelBase. + Returns + ------- + str + A string representation of the ModelBase. """ return ( f'{self.__class__.__name__}(unique_name={self.unique_name}, ' diff --git a/src/easydynamics/sample_model/resolution_model.py b/src/easydynamics/sample_model/resolution_model.py index 639bf8f8..154ce397 100644 --- a/src/easydynamics/sample_model/resolution_model.py +++ b/src/easydynamics/sample_model/resolution_model.py @@ -27,17 +27,22 @@ def __init__( ) -> None: """Initialize a ResolutionModel. - Args: - display_name (str, default="MyResolutionModel"): Display name of the model. - unique_name (str | None, default=None): Unique name of the model. If None, - a unique name will be generated. - unit (str | sc.Unit, default="meV"): Unit of the model. - components (ModelComponent | ComponentCollection | None, default=None): - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. - Q (Q_type | None, default=None): Q values for the model. If None, Q is not - set. + Parameters + ---------- + display_name : str, optional + Display name of the model. By default, 'MyResolutionModel'. + unique_name : str | None, optional + Unique name of the model. If None, + a unique name will be generated. By default, None. + unit : str | sc.Unit, optional + Unit of the model. By default, 'meV'. + components : ModelComponent | ComponentCollection | None, optional + Template components of the model. If None, no components + are added. These components are copied into + ComponentCollections for each Q value. By default, None. + Q : Q_type | None, optional + Q values for the model. If None, Q is not + set. By default, None. """ super().__init__( @@ -54,12 +59,15 @@ def append_component(self, component: ModelComponent | ComponentCollection) -> N Does not allow DeltaFunction or Polynomial components, as these are not physical resolution components. - Args: - component (ModelComponent | ComponentCollection): - Component(s) to append. + Parameters + ---------- + component : ModelComponent | ComponentCollection + Component(s) to append. - Raises: - TypeError: If the component is a DeltaFunction or Polynomial + Raises + ------ + TypeError : + If the component is a DeltaFunction or Polynomial. """ if isinstance(component, ComponentCollection): components = component.components diff --git a/src/easydynamics/sample_model/sample_model.py b/src/easydynamics/sample_model/sample_model.py index d6c63492..b9cc587b 100644 --- a/src/easydynamics/sample_model/sample_model.py +++ b/src/easydynamics/sample_model/sample_model.py @@ -40,34 +40,42 @@ def __init__( ) -> None: """Initialize the SampleModel. - Args: - display_name (str, default="MySampleModel"): Display name of the model. - unique_name (str | None, default=None): Unique name of the model. If None, - a unique name will be generated. - unit (str | sc.Unit, default="meV"): Unit of the model. If None, - defaults to "meV". - components (ModelComponent | ComponentCollection | None, default=None): - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. - Q (Q_type | None, default=None): - Q values for the model. If None, Q is not set. - diffusion_models (DiffusionModelBase | list[DiffusionModelBase] | None, default=None): - Diffusion models to include in the SampleModel. If None, - no diffusion models are added. - temperature (float | None, default=None): Temperature for detailed - balancing. If None, no detailed balancing is applied. - temperature_unit (str | sc.Unit, default="K"): Unit of the temperature. - Defaults to "K". - divide_by_temperature (bool, default=True): Whether to divide the detailed - balance factor by temperature. Defaults to True. - - Raises: - TypeError: If diffusion_models is not a DiffusionModelBase, - a list of DiffusionModelBase, or None, or if temperature - is not a number or None, or if divide_by_temperature is - not a bool. - ValueError: If temperature is negative. + Parameters + ---------- + display_name : str, optional + Display name of the model. By default, 'MySampleModel'. + unique_name : str | None, optional + Unique name of the model. If None, + a unique name will be generated. By default, None. + unit : str | sc.Unit, optional + Unit of the model. If None,. By default, 'meV'. + components : ModelComponent | ComponentCollection | None, optional + Template components of the model. If None, no components + are added. These components are copied into + ComponentCollections for each Q value. By default, None. + Q : Q_type | None, optional + Q values for the model. If None, Q is not set. By default, None. + diffusion_models : DiffusionModelBase | list[DiffusionModelBase] | None, optional + Diffusion models to include in the SampleModel. If None, + no diffusion models are added. By default, None. + temperature : float | None, optional + Temperature for detailed + balancing. If None, no detailed balancing is applied. By default, None. + temperature_unit : str | sc.Unit, optional + Unit of the temperature. By default, 'K'. + divide_by_temperature : bool, optional + Whether to divide the detailed + balance factor by temperature. By default, True. + + Raises + ------ + TypeError : + If diffusion_models is not a DiffusionModelBase, + a list of DiffusionModelBase, or None, or if temperature + is not a number or None, or if divide_by_temperature is + not a bool. + ValueError : + If temperature is negative. """ if diffusion_models is None: self._diffusion_models = [] @@ -119,13 +127,17 @@ def __init__( def append_diffusion_model(self, diffusion_model: DiffusionModelBase) -> None: """Append a DiffusionModel to the SampleModel. - Args: - diffusion_model (DiffusionModelBase): The DiffusionModel - to append. - - Raises: - TypeError: If the diffusion_model is not a - DiffusionModelBase + Parameters + ---------- + diffusion_model : DiffusionModelBase + The DiffusionModel + to append. + + Raises + ------ + TypeError : + If the diffusion_model is not a + DiffusionModelBase. """ if not isinstance(diffusion_model, DiffusionModelBase): @@ -139,12 +151,16 @@ def append_diffusion_model(self, diffusion_model: DiffusionModelBase) -> None: def remove_diffusion_model(self, name: 'str') -> None: """Remove a DiffusionModel from the SampleModel by unique name. - Args: - name (str): The unique name of the DiffusionModel to remove. + Parameters + ---------- + name : 'str' + The unique name of the DiffusionModel to remove. - Raises: - ValueError: If no DiffusionModel with the given unique name - is found. + Raises + ------ + ValueError : + If no DiffusionModel with the given unique name + is found. """ for i, dm in enumerate(self._diffusion_models): if dm.unique_name == name: @@ -169,9 +185,11 @@ def clear_diffusion_models(self) -> None: def diffusion_models(self) -> list[DiffusionModelBase]: """Get the diffusion models of the SampleModel. - Returns: - list[DiffusionModelBase]: The diffusion models of the - SampleModel. + Returns + ------- + list[DiffusionModelBase] + The diffusion models of the + SampleModel. """ return self._diffusion_models @@ -181,15 +199,18 @@ def diffusion_models( ) -> None: """Set the diffusion models of the SampleModel. - Args: - value (DiffusionModelBase | list[DiffusionModelBase] | None): - The diffusion model(s) to set. Can be a single - DiffusionModelBase, a list of DiffusionModelBase, or - None to clear all diffusion models. - - Raises: - TypeError: If value is not a DiffusionModelBase, a list of - DiffusionModelBase, or None. + Parameters + ---------- + value : DiffusionModelBase | list[DiffusionModelBase] | None + The diffusion model(s) to set. Can be a single + DiffusionModelBase, a list of DiffusionModelBase, or + None to clear all diffusion models. + + Raises + ------ + TypeError : + If value is not a DiffusionModelBase, a list of + DiffusionModelBase, or None. """ if value is None: @@ -212,9 +233,11 @@ def diffusion_models( def temperature(self) -> Parameter | None: """Get the temperature of the SampleModel. - Returns: - Parameter | None: The temperature Parameter of the - SampleModel, or None if not set. + Returns + ------- + Parameter | None + The temperature Parameter of the + SampleModel, or None if not set. """ return self._temperature @@ -222,13 +245,18 @@ def temperature(self) -> Parameter | None: def temperature(self, value: Numeric | None) -> None: """Set the temperature of the SampleModel. - Args: - value (Numeric | None): The temperature value to set. Can be - a number or None to unset the temperature. - - Raises: - TypeError: If value is not a number or None. - ValueError: If value is negative. + Parameters + ---------- + value : Numeric | None + The temperature value to set. Can be + a number or None to unset the temperature. + + Raises + ------ + TypeError : + If value is not a number or None. + ValueError : + If value is negative. """ if value is None: self._temperature = None @@ -255,8 +283,10 @@ def temperature(self, value: Numeric | None) -> None: def temperature_unit(self) -> str | sc.Unit: """Get the temperature unit of the SampleModel. - Returns: - str | sc.Unit: The unit of the temperature Parameter. + Returns + ------- + str | sc.Unit + The unit of the temperature Parameter. """ return self._temperature_unit @@ -264,12 +294,16 @@ def temperature_unit(self) -> str | sc.Unit: def temperature_unit(self, _value: str | sc.Unit) -> None: """The temperature unit of the SampleModel is read-only. - Args: - _value (str | sc.Unit): The unit to set for the temperature - Parameter. + Parameters + ---------- + _value : str | sc.Unit + The unit to set for the temperature + Parameter. - Raises: - AttributeError: Always, as temperature_unit is read-only. + Raises + ------ + AttributeError : + Always, as temperature_unit is read-only. """ raise AttributeError( @@ -280,13 +314,18 @@ def temperature_unit(self, _value: str | sc.Unit) -> None: def convert_temperature_unit(self, unit: str | sc.Unit) -> None: """Convert the unit of the temperature Parameter. - Args: - unit (str | sc.Unit): The unit to convert the temperature - Parameter to. - - Raises: - ValueError: If temperature is not set or conversion fails. - Exception: If the provided unit is invalid or cannot be converted. + Parameters + ---------- + unit : str | sc.Unit + The unit to convert the temperature + Parameter to. + + Raises + ------ + ValueError : + If temperature is not set or conversion fails. + Exception : + If the provided unit is invalid or cannot be converted. """ if self._temperature is None: @@ -308,9 +347,11 @@ def divide_by_temperature(self) -> bool: """Get whether to divide the detailed balance factor by temperature. - Returns: - bool: True if the detailed balance factor is divided by - temperature, False otherwise. + Returns + ------- + bool + True if the detailed balance factor is divided by + temperature, False otherwise. """ return self._divide_by_temperature @@ -319,12 +360,16 @@ def divide_by_temperature(self, value: bool) -> None: """Set whether to divide the detailed balance factor by temperature. - Args: - value (bool): True to divide the detailed balance factor by - temperature, False otherwise. + Parameters + ---------- + value : bool + True to divide the detailed balance factor by + temperature, False otherwise. - Raises: - TypeError: If value is not a bool. + Raises + ------ + TypeError : + If value is not a bool. """ if not isinstance(value, bool): raise TypeError('divide_by_temperature must be True or False') @@ -339,13 +384,16 @@ def evaluate( ) -> list[np.ndarray]: """Evaluate the sample model at all Q for the given x values. - Args: - x (Numeric | list | np.ndarray | sc.Variable | sc.DataArray): - The x values to evaluate the model at. Can be a number, - list, numpy array, scipp Variable, or scipp DataArray. + Parameters + ---------- + x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray + The x values to evaluate the model at. Can be a number, + list, numpy array, scipp Variable, or scipp DataArray. - Returns: - list[np.ndarray]: List of evaluated model values for each Q. + Returns + ------- + list[np.ndarray] + List of evaluated model values for each Q. """ y = super().evaluate(x) @@ -369,15 +417,19 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: diffusion models. Ignores the Parameters and Descriptors in self._components as these are just templates. - Args: - Q_index (int | None, default=None): If specified, only get variables from - the ComponentCollection at the given Q index. If None, - get variables from all ComponentCollections. - - Returns: - list[Parameter]: List of all Parameters and Descriptors, - including temperature if set and all variables from - diffusion models. + Parameters + ---------- + Q_index : int | None, optional + If specified, only get variables from + the ComponentCollection at the given Q index. If None, + get variables from all ComponentCollections. By default, None. + + Returns + ------- + list[Parameter] + List of all Parameters and Descriptors, + including temperature if set and all variables from + diffusion models. """ all_vars = super().get_all_variables(Q_index=Q_index) @@ -424,8 +476,10 @@ def _on_diffusion_models_change(self) -> None: def __repr__(self) -> str: """Return a string representation of the SampleModel. - Returns: - str: A string representation of the SampleModel. + Returns + ------- + str + A string representation of the SampleModel. """ return ( diff --git a/src/easydynamics/utils/detailed_balance.py b/src/easydynamics/utils/detailed_balance.py index cd8ff347..00f36949 100644 --- a/src/easydynamics/utils/detailed_balance.py +++ b/src/easydynamics/utils/detailed_balance.py @@ -29,8 +29,7 @@ def detailed_balance_factor( temperature_unit: str | sc.Unit = 'K', divide_by_temperature: bool = True, ) -> np.ndarray: - r""" - Compute the detailed balance factor (DBF): + r"""Compute the detailed balance factor (DBF): $$ DBF(E, T) = E(n(E)+1)=\frac{E}{(1 - e^{-E / (k_B*T)})}}, $$ @@ -40,41 +39,54 @@ def detailed_balance_factor( If divide_by_temperature is True, the result is normalized by $k_B*T$ to have value 1 at $E=0$. - Args: - energy (int | float | list | np.ndarray | sc.Variable): The energy - transfer. If number, assumed to be in meV unless energy_unit - is set. - temperature (int | float | sc.Variable | Parameter): The - temperature. If number, assumed to be in K unless - temperature_unit is set. - energy_unit (str | sc.Unit, default='meV'): Unit for energy if energy is - given as a number or list. Default is 'meV' - temperature_unit (str | sc.Unit, default='K'): Unit for temperature if - temperature is given as a number. Default is 'K' - divide_by_temperature (bool, default=True): If True, divide the result - by $k_B*T$ to make it dimensionless and have value 1 at E=0. - Default is True. - - Returns: - np.ndarray: Detailed balance factor evaluated at the - given energy and temperature. - - Raises: - TypeError: If energy or temperature is not a number, list, - numpy array, or scipp Variable, or if energy_unit or - temperature_unit is not a string or scipp Unit, - or if divide_by_temperature is not a boolean. - ValueError: If temperature is negative, or if energy is a numpy - array with more than 1 dimension, or if temperature is a - scipp Variable that does not have a single dimension named - 'temperature', or if energy is a scipp Variable that does - not have a single dimension named 'energy'. - UnitError: If the provided energy_unit or temperature_unit is - invalid, or if the units of energy or temperature cannot be - converted to the expected units. - ZeroDivisionError: If divide_by_temperature is True and temperature is zero. - - Examples: + Parameters + ---------- + energy : int | float | list | np.ndarray | sc.Variable + The energy + transfer. If number, assumed to be in meV unless energy_unit + is set. + temperature : int | float | sc.Variable | Parameter + The + temperature. If number, assumed to be in K unless + temperature_unit is set. + energy_unit : str | sc.Unit, optional + Unit for energy if energy is + given as a number or list. By default, 'meV'. + temperature_unit : str | sc.Unit, optional + Unit for temperature if + temperature is given as a number. By default, 'K'. + divide_by_temperature : bool, optional + If True, divide the result + by $k_B*T$ to make it dimensionless and have value 1 at E=0. By default, True. + + Raises + ------ + TypeError : + If energy or temperature is not a number, list, + numpy array, or scipp Variable, or if energy_unit or + temperature_unit is not a string or scipp Unit, + or if divide_by_temperature is not a boolean. + ValueError : + If temperature is negative, or if energy is a numpy + array with more than 1 dimension, or if temperature is a + scipp Variable that does not have a single dimension named + 'temperature', or if energy is a scipp Variable that does + not have a single dimension named 'energy'. + UnitError : + If the provided energy_unit or temperature_unit is + invalid, or if the units of energy or temperature cannot be + converted to the expected units. + ZeroDivisionError : + If divide_by_temperature is True and temperature is zero. + + Returns + ------- + np.ndarray + Detailed balance factor evaluated at the + given energy and temperature. + + Examples + -------- >>> detailed_balance_factor(1.0, 300) # 1 meV at 300 K >>> detailed_balance_factor( ... energy=[1.0, 2.0], @@ -189,25 +201,33 @@ def _convert_to_scipp_variable( """Convert various input types to a scipp Variable with proper units. - Args: - value (int | float | list | np.ndarray | Parameter | sc.Variable): - The value to convert. Can be a number, list, numpy array, - Parameter, or scipp Variable. If a number or list, the unit - must be specified in the unit argument. - name (str): The name of the variable, used for error messages. - unit (str | None, default=None): The unit to use if value is a number or list. - Must be specified if value is a number or list. Ignored if - value is a Parameter or sc.Variable, which have their own - units. - - Raises: - TypeError: If value is not one of the accepted types, or if unit - is not a string when needed. - UnitError: If the provided unit is invalid. - - Returns: - sc.Variable: The input value converted to a scipp Variable with - appropriate units. + Parameters + ---------- + value : int | float | list | np.ndarray | Parameter | sc.Variable + The value to convert. Can be a number, list, numpy array, + Parameter, or scipp Variable. If a number or list, the unit + must be specified in the unit argument. + name : str + The name of the variable, used for error messages. + unit : str | None, optional + The unit to use if value is a number or list. + Must be specified if value is a number or list. Ignored if + value is a Parameter or sc.Variable, which have their own + units. By default, None. + + Raises + ------ + TypeError : + If value is not one of the accepted types, or if unit + is not a string when needed. + UnitError : + If the provided unit is invalid. + + Returns + ------- + sc.Variable + The input value converted to a scipp Variable with + appropriate units. """ if isinstance(value, sc.Variable): return value diff --git a/src/easydynamics/utils/utils.py b/src/easydynamics/utils/utils.py index 7b9134bc..6cb8bd5b 100644 --- a/src/easydynamics/utils/utils.py +++ b/src/easydynamics/utils/utils.py @@ -21,18 +21,24 @@ def _validate_and_convert_Q( ) -> np.ndarray | None: """Validate and convert Q to a numpy array. - Args: - Q (np.ndarray | Numeric | list | ArrayLike | sc.Variable | None): - Scattering vector values in 1/angstrom. - - Returns: - np.ndarray | None: Q as a np.ndarray or None if Q is None. - - Raises: - TypeError: If Q is not a number, list, numpy array, or scipp - Variable. - ValueError: If Q is a numpy array with more than 1 dimension, or - if Q is a scipp Variable that does not have a single dimension named 'Q'. + Parameters + ---------- + Q : np.ndarray | Numeric | list | ArrayLike | sc.Variable | None + Scattering vector values in 1/angstrom. + + Raises + ------ + TypeError : + If Q is not a number, list, numpy array, or scipp + Variable. + ValueError : + If Q is a numpy array with more than 1 dimension, or + if Q is a scipp Variable that does not have a single dimension named 'Q'. + + Returns + ------- + np.ndarray | None + Q as a np.ndarray or None if Q is None. """ if Q is None: return None @@ -59,14 +65,20 @@ def _validate_and_convert_Q( def _validate_unit(unit: str | sc.Unit | None) -> sc.Unit | None: """Validate that the unit is a string or scipp Unit. - Args: - unit (str | sc.Unit | None): Unit to validate. + Parameters + ---------- + unit : str | sc.Unit | None + Unit to validate. - Returns: - sc.Unit | None: Validated unit or None. + Raises + ------ + TypeError : + If unit is not None, a string, or a scipp Unit. - Raises: - TypeError: If unit is not None, a string, or a scipp Unit. + Returns + ------- + sc.Unit | None + Validated unit or None. """ if unit is not None and not isinstance(unit, (str, sc.Unit)): @@ -79,8 +91,10 @@ def _validate_unit(unit: str | sc.Unit | None) -> sc.Unit | None: def _in_notebook() -> bool: """Check if the code is running in a Jupyter notebook. - Returns: - bool: True if in a Jupyter notebook, False otherwise. + Returns + ------- + bool + True if in a Jupyter notebook, False otherwise. """ try: from IPython import get_ipython From 70a26f21ffaad519ade9fe67e36b8b76985ae883 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 10:04:05 +0200 Subject: [PATCH 05/12] Reformat docstrings --- pixi.lock | 4 +- pyproject.toml | 12 +- src/easydynamics/analysis/analysis.py | 275 +++++++------- src/easydynamics/analysis/analysis1d.py | 344 ++++++++---------- src/easydynamics/analysis/analysis_base.py | 164 ++++----- .../convolution/analytical_convolution.py | 210 +++++------ src/easydynamics/convolution/convolution.py | 119 +++--- .../convolution/convolution_base.py | 99 +++-- src/easydynamics/convolution/energy_grid.py | 19 +- .../convolution/numerical_convolution.py | 60 ++- .../convolution/numerical_convolution_base.py | 144 ++++---- src/easydynamics/experiment/experiment.py | 160 ++++---- .../sample_model/background_model.py | 28 +- .../sample_model/component_collection.py | 133 +++---- .../components/damped_harmonic_oscillator.py | 82 ++--- .../sample_model/components/delta_function.py | 61 ++-- .../sample_model/components/exponential.py | 85 +++-- .../components/expression_component.py | 49 +-- .../sample_model/components/gaussian.py | 96 +++-- .../sample_model/components/lorentzian.py | 89 +++-- .../sample_model/components/mixins.py | 64 ++-- .../components/model_component.py | 52 +-- .../sample_model/components/polynomial.py | 89 +++-- .../sample_model/components/voigt.py | 87 ++--- .../brownian_translational_diffusion.py | 122 +++---- .../diffusion_model/diffusion_model_base.py | 46 +-- .../jump_translational_diffusion.py | 151 ++++---- .../sample_model/instrument_model.py | 225 ++++++------ src/easydynamics/sample_model/model_base.py | 144 ++++---- .../sample_model/resolution_model.py | 35 +- src/easydynamics/sample_model/sample_model.py | 161 ++++---- src/easydynamics/utils/detailed_balance.py | 85 ++--- src/easydynamics/utils/utils.py | 16 +- 33 files changed, 1645 insertions(+), 1865 deletions(-) diff --git a/pixi.lock b/pixi.lock index 6fee22c6..f2a8e7c2 100644 --- a/pixi.lock +++ b/pixi.lock @@ -4071,8 +4071,8 @@ packages: requires_python: '>=3.5' - pypi: ./ name: easydynamics - version: 0.4.0+devdirty2 - sha256: f0379543a8255c30ddd29af06e88e5b6617a3e4852a54357113225ea20a814ff + version: 0.4.0+devdirty6 + sha256: 5b1107b6daf15e96707835633212fc434e3dbfbbd839c89739505f1abcf44453 requires_dist: - darkdetect - easyscience diff --git a/pyproject.toml b/pyproject.toml index 236ac5bf..7cc49a0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -187,7 +187,7 @@ preview = true # Enable new rules that are not yet stable, like DOC [tool.ruff.format] docstring-code-format = true # Whether to format code snippets in docstrings -docstring-code-line-length = 72 # Line length for code snippets in docstrings +docstring-code-line-length = 99 # Line length for code snippets in docstrings indent-style = 'space' # PEP 8 recommends using spaces over tabs line-ending = 'lf' # Line endings will be converted to \n quote-style = 'single' # But double quotes in docstrings (PEP 8, PEP 257) @@ -303,9 +303,9 @@ max-complexity = 10 # PEP 8 line length guidance: # https://peps.python.org/pep-0008/#maximum-line-length # Use 99 characters as the project-wide maximum for regular code lines. -# Use 72 characters for docstrings. +# Use 99 characters for docstrings. max-line-length = 99 # See also `line-length` in [tool.ruff] -max-doc-length = 72 +max-doc-length = 99 [tool.ruff.lint.pydocstyle] convention = 'numpy' @@ -325,7 +325,7 @@ convention = 'numpy' # the parameter declarations in the code (in function's signature). [tool.pydoclint] -exclude = '\.' # Temporarily disable pydoclint until we are ready +#exclude = '\.' # Temporarily disable pydoclint until we are ready style = 'numpy' check-style-mismatch = true check-arg-defaults = true @@ -339,8 +339,8 @@ allow-init-docstring = true # https://github.com/jsh9/format-docstring [tool.format_docstring] -exclude = '\.' # Temporarily disable format-docstring until we are ready +#exclude = '\.' # Temporarily disable format-docstring until we are ready docstring_style = 'numpy' -line_length = 72 +line_length = 99 fix_rst_backticks = true verbose = 'default' diff --git a/src/easydynamics/analysis/analysis.py b/src/easydynamics/analysis/analysis.py index 77776cd1..eb7496ea 100644 --- a/src/easydynamics/analysis/analysis.py +++ b/src/easydynamics/analysis/analysis.py @@ -20,11 +20,10 @@ class Analysis(AnalysisBase): - """For analysing two-dimensional data, i.e. intensity as function of - energy and Q. + """ + For analysing two-dimensional data, i.e. intensity as function of energy and Q. - Supports independent fits of each Q value and simultaneous fits of - all Q. + Supports independent fits of each Q value and simultaneous fits of all Q. """ def __init__( @@ -36,31 +35,28 @@ def __init__( instrument_model: InstrumentModel | None = None, extra_parameters: Parameter | list[Parameter] | None = None, ) -> None: - """Initialize an Analysis object. + """ + Initialize an Analysis object. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='MyAnalysis' Display name of the analysis. By default, 'MyAnalysis'. - unique_name : str | None, optional - Unique name of the analysis. If - None, a unique name is automatically generated. By default, None. - experiment : Experiment | None, optional - The Experiment associated - with this Analysis. If None, a default Experiment is + unique_name : str | None, default=None + Unique name of the analysis. If None, a unique name is automatically generated. By + default, None. + experiment : Experiment | None, default=None + The Experiment associated with this Analysis. If None, a default Experiment is created. + By default, None. + sample_model : SampleModel | None, default=None + The SampleModel associated with this Analysis. If None, a default SampleModel is created. By default, None. - sample_model : SampleModel | None, optional - The SampleModel - associated with this Analysis. If None, a default - SampleModel is created. By default, None. - instrument_model : InstrumentModel | None, optional - The - InstrumentModel associated with this Analysis. If None, - a default InstrumentModel is created. By default, None. - extra_parameters : Parameter | list[Parameter] | None, optional - Extra - parameters to be included in the analysis for advanced - users. If None, no extra parameters are added. By default, None. + instrument_model : InstrumentModel | None, default=None + The InstrumentModel associated with this Analysis. If None, a default InstrumentModel + is created. By default, None. + extra_parameters : Parameter | list[Parameter] | None, default=None + Extra parameters to be included in the analysis for advanced users. If None, no extra + parameters are added. By default, None. """ # Avoid triggering updates before the object is fully @@ -97,34 +93,33 @@ def __init__( @property def analysis_list(self) -> list[Analysis1d]: - """Get the Analysis1d objects associated with this Analysis. + """ + Get the Analysis1d objects associated with this Analysis. Returns ------- list[Analysis1d] - A list of Analysis1d objects, one for - each Q index. + A list of Analysis1d objects, one for each Q index. """ return self._analysis_list @analysis_list.setter def analysis_list(self, _value: list[Analysis1d]) -> None: - """Analysis_list is read-only. + """ + Analysis_list is read-only. - To change the analysis list, modify the experiment, sample - model, or instrument model. + To change the analysis list, modify the experiment, sample model, or instrument model. Parameters ---------- _value : list[Analysis1d] - The new list of Analysis1d objects. This - argument is ignored, as analysis_list is read-only. + The new list of Analysis1d objects. This argument is ignored, as analysis_list is + read-only. Raises ------ AttributeError : - Always raised, since analysis_list is - read-only. + Always raised, since analysis_list is read-only. """ raise AttributeError( @@ -141,28 +136,25 @@ def calculate( Q_index: int | None = None, energy: sc.Variable | None = None, ) -> list[np.ndarray] | np.ndarray: - """Calculate model data for a specific Q index. + """ + Calculate model data for a specific Q index. - If Q_index is -None, calculate for all Q indices and return a list of arrays. + If Q_index is None, calculate for all Q indices and return a list of arrays. Parameters ---------- - Q_index : int | None, optional - Index of the Q value to calculate - for. If None, calculate for all Q values. By default, None. - energy : sc.Variable | None, optional - The energy values to use for - calculating the model. If None, uses the energy from the + Q_index : int | None, default=None + Index of the Q value to calculate for. If None, calculate for all Q values. By default, + None. + energy : sc.Variable | None, default=None + The energy values to use for calculating the model. If None, uses the energy from the experiment. By default, None. Returns ------- list[np.ndarray] | np.ndarray - If Q_index is None, returns - a list of numpy arrays, one for each Q index. - If Q_index is an integer, returns a single numpy array - for that Q index. + If Q_index is None, returns a list of numpy arrays, one for each Q index. If Q_index is + an integer, returns a single numpy array for that Q index. """ if energy is None: energy = self.energy @@ -178,31 +170,30 @@ def fit( fit_method: str = 'independent', Q_index: int | None = None, ) -> FitResults | list[FitResults]: - """Fit the model to the experimental data. + """ + Fit the model to the experimental data. Parameters ---------- - fit_method : str, optional - Method to use for fitting. Options are - "independent" (fit each Q index independently, one after - the other) or "simultaneous" (fit all Q indices - simultaneously). By default, 'independent'. - Q_index : int | None, optional - If fit_method is "independent", - specify which Q index to fit. If None, fit all Q indices - independently. Ignored if fit_method is "simultaneous". By default, None. + fit_method : str, default='independent' + Method to use for fitting. Options are "independent" (fit each Q index independently, + one after the other) or "simultaneous" (fit all Q indices simultaneously). By default, + 'independent'. + Q_index : int | None, default=None + If fit_method is "independent", specify which Q index to fit. If None, fit all Q + indices independently. Ignored if fit_method is "simultaneous". By default, None. Raises ------ ValueError : - If fit_method is not "independent" or - "simultaneous" or if there are no Q values available for fitting. + If fit_method is not "independent" or "simultaneous" or if there are no Q values + available for fitting. Returns ------- FitResults | list[FitResults] - A list of FitResults if fitting independently, - or a single FitResults object if fitting simultaneously. + A list of FitResults if fitting independently, or a single FitResults object if fitting + simultaneously. """ if self.Q is None: @@ -228,7 +219,8 @@ def plot_data_and_model( energy: sc.Variable | None = None, **kwargs: dict[str, Any], ) -> InteractiveFigure: - """Plot the experimental data and the model prediction. + """ + Plot the experimental data and the model prediction. Optionally also plot the individual components of the model. @@ -236,41 +228,33 @@ def plot_data_and_model( Parameters ---------- - Q_index : int | None, optional - Index of the Q value to plot. If - None, plot all Q values. By default, None. - plot_components : bool, optional - Whether to plot the individual - components. By default, True. - add_background : bool, optional - Whether to add background components - to the sample model components when plotting. Default is - True. By default, True. - energy : sc.Variable | None, optional - The energy values to use for - calculating the model. If None, uses the energy from the + Q_index : int | None, default=None + Index of the Q value to plot. If None, plot all Q values. By default, None. + plot_components : bool, default=True + Whether to plot the individual components. By default, True. + add_background : bool, default=True + Whether to add background components to the sample model components when plotting. + Default is True. By default, True. + energy : sc.Variable | None, default=None + The energy values to use for calculating the model. If None, uses the energy from the experiment. By default, None. **kwargs : dict[str, Any] - Additional keyword arguments passed to plopp - for customizing the plot. + Additional keyword arguments passed to plopp for customizing the plot. Raises ------ ValueError : - If Q_index is out of bounds, or if there is no - data to plot, or if there are no Q values available for - plotting. + If Q_index is out of bounds, or if there is no data to plot, or if there are no Q + values available for plotting. RuntimeError : If not in a Jupyter notebook environment. TypeError : - If plot_components or add_background is not True - or False. + If plot_components or add_background is not True or False. Returns ------- InteractiveFigure - A Plopp InteractiveFigure containing the - plot of the data and model. + A Plopp InteractiveFigure containing the plot of the data and model. """ if Q_index is not None: @@ -339,23 +323,21 @@ def plot_data_and_model( return fig def parameters_to_dataset(self) -> sc.Dataset: - """Creates a scipp dataset with copies of the Parameters in the - model. + """ + Creates a scipp dataset with copies of the Parameters in the model. Ensures unit consistency across Q. Raises ------ UnitError : - If there are inconsistent units for the same - parameter across different Q values. + If there are inconsistent units for the same parameter across different Q values. Returns ------- sc.Dataset - A dataset where each entry is a parameter, with - dimensions "Q" and values corresponding to the parameter - values. + A dataset where each entry is a parameter, with dimensions "Q" and values corresponding + to the parameter values. """ ds = sc.Dataset(coords={'Q': self.Q}) @@ -413,17 +395,16 @@ def plot_parameters( names: str | list[str] | None = None, **kwargs: dict[str, Any], ) -> InteractiveFigure: - """Plot fitted parameters as a function of Q. + """ + Plot fitted parameters as a function of Q. Parameters ---------- - names : str | list[str] | None, optional - Name(s) of the parameter(s) - to plot. If None, plots all parameters. By default, None. + names : str | list[str] | None, default=None + Name(s) of the parameter(s) to plot. If None, plots all parameters. By default, None. **kwargs : dict[str, Any] - Additional keyword arguments passed to - plopp.slicer for customizing the plot (e.g., title, - linestyle, marker, color). + Additional keyword arguments passed to plopp.slicer for customizing the plot (e.g., + title, linestyle, marker, color). Raises ------ @@ -435,8 +416,7 @@ def plot_parameters( Returns ------- InteractiveFigure - A Plopp InteractiveFigure containing the - plot of the parameters. + A Plopp InteractiveFigure containing the plot of the parameters. """ ds = self.parameters_to_dataset() @@ -471,15 +451,15 @@ def plot_parameters( ) def fix_energy_offset(self, Q_index: int | None = None) -> None: - """Fix the energy offset parameter(s) for a specific Q index, or - for all Q indices if Q_index is None. + """ + Fix the energy offset parameter(s) for a specific Q index, or for all Q indices if Q_index + is None. Parameters ---------- - Q_index : int | None, optional - Index of the Q value to - fix the energy offset for. If None, fixes the energy - offset for all Q values. By default, None. + Q_index : int | None, default=None + Index of the Q value to fix the energy offset for. If None, fixes the energy offset for + all Q values. By default, None. """ if Q_index is not None: Q_index = self._verify_Q_index(Q_index) @@ -489,15 +469,15 @@ def fix_energy_offset(self, Q_index: int | None = None) -> None: analysis.fix_energy_offset() def free_energy_offset(self, Q_index: int | None = None) -> None: - """Free the energy offset parameter(s) for a specific Q index, - or for all Q indices if Q_index is None. + """ + Free the energy offset parameter(s) for a specific Q index, or for all Q indices if Q_index + is None. Parameters ---------- - Q_index : int | None, optional - Index of the Q value to - free the energy offset for. If None, frees the energy - offset for all Q values. By default, None. + Q_index : int | None, default=None + Index of the Q value to free the energy offset for. If None, frees the energy offset + for all Q values. By default, None. """ if Q_index is not None: Q_index = self._verify_Q_index(Q_index) @@ -511,8 +491,8 @@ def free_energy_offset(self, Q_index: int | None = None) -> None: ############# def _on_experiment_changed(self) -> None: - """Update the Q values in the sample and instrument models when - the experiment changes. + """ + Update the Q values in the sample and instrument models when the experiment changes. Also update all the Analysis1d objects with the new experiment. """ @@ -522,11 +502,10 @@ def _on_experiment_changed(self) -> None: analysis.experiment = self.experiment def _on_sample_model_changed(self) -> None: - """Update the Q values in the sample model when the sample model - changes. + """ + Update the Q values in the sample model when the sample model changes. - Also update all the Analysis1d objects with the new sample - model. + Also update all the Analysis1d objects with the new sample model. """ if self._call_updaters: super()._on_sample_model_changed() @@ -534,11 +513,10 @@ def _on_sample_model_changed(self) -> None: analysis.sample_model = self.sample_model def _on_instrument_model_changed(self) -> None: - """Update the Q values in the instrument model when the - instrument model changes. + """ + Update the Q values in the instrument model when the instrument model changes. - Also update all the Analysis1d objects with the new instrument - model. + Also update all the Analysis1d objects with the new instrument model. """ if self._call_updaters: super()._on_instrument_model_changed() @@ -550,7 +528,8 @@ def _on_instrument_model_changed(self) -> None: ############# def _fit_single_Q(self, Q_index: int) -> FitResults: - """Fit data for a single Q index. + """ + Fit data for a single Q index. Parameters ---------- @@ -560,8 +539,7 @@ def _fit_single_Q(self, Q_index: int) -> FitResults: Returns ------- FitResults - The results of the fit for the specified - Q index. + The results of the fit for the specified Q index. """ Q_index = self._verify_Q_index(Q_index) @@ -569,24 +547,24 @@ def _fit_single_Q(self, Q_index: int) -> FitResults: return self.analysis_list[Q_index].fit() def _fit_all_Q_independently(self) -> list[FitResults]: - """Fit data for all Q indices independently. + """ + Fit data for all Q indices independently. Returns ------- list[FitResults] - A list of FitResults, one for each Q - index. + A list of FitResults, one for each Q index. """ return [analysis.fit() for analysis in self.analysis_list] def _fit_all_Q_simultaneously(self) -> FitResults: - """Fit data for all Q indices simultaneously. + """ + Fit data for all Q indices simultaneously. Returns ------- FitResults - The results of the simultaneous fit across all - Q indices. + The results of the simultaneous fit across all Q indices. """ xs = [] @@ -614,32 +592,30 @@ def _fit_all_Q_simultaneously(self) -> FitResults: ) def get_fit_functions(self) -> list[callable]: - """Get fit functions for all Q indices, which can be used for - simultaneous fitting. + """ + Get fit functions for all Q indices, which can be used for simultaneous fitting. Returns ------- list[callable] - A list of fit functions, one for each - Q index. + A list of fit functions, one for each Q index. """ return [analysis.as_fit_function() for analysis in self.analysis_list] def _create_model_array(self, energy: sc.Variable | None = None) -> sc.DataArray: - """Create a scipp array for the model. + """ + Create a scipp array for the model. Parameters ---------- - energy : sc.Variable | None, optional - The energy values to use for - calculating the model. If None, uses the energy from the + energy : sc.Variable | None, default=None + The energy values to use for calculating the model. If None, uses the energy from the experiment. By default, None. Returns ------- sc.DataArray - A DataArray containing the model values, with - dimensions "Q" and "energy". + A DataArray containing the model values, with dimensions "Q" and "energy". """ if energy is None: energy = self.energy @@ -654,18 +630,16 @@ def _create_components_dataset( add_background: bool = True, energy: sc.Variable | None = None, ) -> sc.Dataset: - """Create a scipp dataset containing the individual components - of the model for plotting. + """ + Create a scipp dataset containing the individual components of the model for plotting. Parameters ---------- - add_background : bool, optional - Whether to add background components - to the sample model components when creating the + add_background : bool, default=True + Whether to add background components to the sample model components when creating the dataset. By default, True. - energy : sc.Variable | None, optional - The energy values to use for - calculating the components. If None, uses the energy from + energy : sc.Variable | None, default=None + The energy values to use for calculating the components. If None, uses the energy from the experiment. By default, None. Raises @@ -676,8 +650,7 @@ def _create_components_dataset( Returns ------- sc.Dataset - A scipp Dataset where each entry is a component - of the model, with dimensions "Q". + A scipp Dataset where each entry is a component of the model, with dimensions "Q". """ if not isinstance(add_background, bool): raise TypeError('add_background must be True or False.') diff --git a/src/easydynamics/analysis/analysis1d.py b/src/easydynamics/analysis/analysis1d.py index bbfbc753..866b10f9 100644 --- a/src/easydynamics/analysis/analysis1d.py +++ b/src/easydynamics/analysis/analysis1d.py @@ -21,11 +21,10 @@ class Analysis1d(AnalysisBase): - """For analysing one-dimensional data, i.e. intensity as function of - energy for a single Q index. + """ + For analysing one-dimensional data, i.e. intensity as function of energy for a single Q index. - Is used primarily in the Analysis class, but can also be used on its - own for simpler analyses. + Is used primarily in the Analysis class, but can also be used on its own for simpler analyses. """ def __init__( @@ -38,35 +37,31 @@ def __init__( Q_index: int | None = None, extra_parameters: Parameter | list[Parameter] | None = None, ) -> None: - """Initialize a Analysis1d. + """ + Initialize a Analysis1d. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='MyAnalysis' Display name of the analysis. By default, 'MyAnalysis'. - unique_name : str | None, optional - Unique name of the analysis. If - None, a unique name is automatically generated. By default, None. - experiment : Experiment | None, optional - The Experiment associated - with this Analysis. If None, a default Experiment is + unique_name : str | None, default=None + Unique name of the analysis. If None, a unique name is automatically generated. By + default, None. + experiment : Experiment | None, default=None + The Experiment associated with this Analysis. If None, a default Experiment is created. + By default, None. + sample_model : SampleModel | None, default=None + The SampleModel associated with this Analysis. If None, a default SampleModel is created. By default, None. - sample_model : SampleModel | None, optional - The SampleModel - associated with this Analysis. If None, a default - SampleModel is created. By default, None. - instrument_model : InstrumentModel | None, optional - The - InstrumentModel associated with this Analysis. If None, - a default InstrumentModel is created. By default, None. - Q_index : int | None, optional - The Q index to analyze. If None, the - analysis will not be able to calculate or fit until a - Q index is set. By default, None. - extra_parameters : Parameter | list[Parameter] | None, optional - Extra - parameters to be included in the analysis for advanced - users. If None, no extra parameters are added. By default, None. + instrument_model : InstrumentModel | None, default=None + The InstrumentModel associated with this Analysis. If None, a default InstrumentModel + is created. By default, None. + Q_index : int | None, default=None + The Q index to analyze. If None, the analysis will not be able to calculate or fit + until a Q index is set. By default, None. + extra_parameters : Parameter | list[Parameter] | None, default=None + Extra parameters to be included in the analysis for advanced users. If None, no extra + parameters are added. By default, None. """ super().__init__( display_name=display_name, @@ -97,7 +92,8 @@ def __init__( @property def Q_index(self) -> int | None: - """Get the Q index associated with this Analysis. + """ + Get the Q index associated with this Analysis. Returns ------- @@ -109,7 +105,8 @@ def Q_index(self) -> int | None: @Q_index.setter def Q_index(self, value: int | None) -> None: - """Set the Q index for single Q analysis. + """ + Set the Q index for single Q analysis. Parameters ---------- @@ -125,17 +122,16 @@ def Q_index(self, value: int | None) -> None: ############# def calculate(self, energy: sc.Variable | None = None) -> np.ndarray: - """Calculate the model prediction for the chosen Q index. + """ + Calculate the model prediction for the chosen Q index. - Makes -sure the convolver is up to date before calculating. + Makes sure the convolver is up to date before calculating. Parameters ---------- - energy : sc.Variable | None, optional - Optional energy grid to use for - calculation. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for calculation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -148,17 +144,16 @@ def calculate(self, energy: sc.Variable | None = None) -> np.ndarray: return self._calculate(energy=energy) def _calculate(self, energy: sc.Variable | None = None) -> np.ndarray: - """Calculate the model prediction for the chosen Q index. + """ + Calculate the model prediction for the chosen Q index. - Does -not check if the convolver is up to date. + Does not check if the convolver is up to date. Parameters ---------- - energy : sc.Variable | None, optional - Optional energy grid to use for - calculation. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for calculation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -173,18 +168,16 @@ def _calculate(self, energy: sc.Variable | None = None) -> np.ndarray: return sample_intensity + background_intensity def fit(self) -> FitResults: - """Fit the model to the experimental data for the chosen Q - index. + """ + Fit the model to the experimental data for the chosen Q index. - The energy grid is fixed for the duration of the fit. - Convolution objects are created once and reused during - parameter optimization for performance reasons. + The energy grid is fixed for the duration of the fit. Convolution objects are created once + and reused during parameter optimization for performance reasons. Raises ------ ValueError : - If no experiment is associated with this - Analysis. + If no experiment is associated with this Analysis. Returns ------- @@ -216,27 +209,24 @@ def as_fit_function( _x: np.ndarray | sc.Variable | None = None, **kwargs: dict[str, Any], # noqa: ARG002 ) -> callable: - """Return self._calculate as a fit function. + """ + Return self._calculate as a fit function. - The EasyScience fitter requires x as input, but - self._calculate() already uses the correct energy from the - experiment. So we ignore the x input and just return the - calculated model. + The EasyScience fitter requires x as input, but self._calculate() already uses the correct + energy from the experiment. So we ignore the x input and just return the calculated model. Parameters ---------- - _x : np.ndarray | sc.Variable | None, optional - Ignored. - The energy grid is taken from the experiment. By default, None. + _x : np.ndarray | sc.Variable | None, default=None + Ignored. The energy grid is taken from the experiment. By default, None. **kwargs : dict[str, Any] - Ignored. Included for compatibility with the - EasyScience fitter. + Ignored. Included for compatibility with the EasyScience fitter. Returns ------- callable - A function that can be used as a fit function in the - EasyScience fitter, which returns the calculated model. + A function that can be used as a fit function in the EasyScience fitter, which returns + the calculated model. """ def fit_function( @@ -249,7 +239,8 @@ def fit_function( return fit_function def get_all_variables(self) -> list[DescriptorNumber]: - """Get all variables used in the analysis. + """ + Get all variables used in the analysis. Returns ------- @@ -272,27 +263,24 @@ def plot_data_and_model( energy: sc.Variable | None = None, **kwargs: dict[str, Any], ) -> InteractiveFigure: - """Plot the experimental data and the model prediction for the - chosen Q index. Optionally also plot the individual components - of the model. + """ + Plot the experimental data and the model prediction for the chosen Q index. Optionally also + plot the individual components of the model. Uses Plopp for plotting: https://scipp.github.io/plopp/ Parameters ---------- - plot_components : bool, optional - Whether to plot the individual - components of the model. By default, True. - add_background : bool, optional - Whether to add the background to the - model prediction when plotting individual components. By default, True. - energy : sc.Variable | None, optional - Optional energy grid to use for - plotting. If None, the energy grid from the experiment + plot_components : bool, default=True + Whether to plot the individual components of the model. By default, True. + add_background : bool, default=True + Whether to add the background to the model prediction when plotting individual + components. By default, True. + energy : sc.Variable | None, default=None + Optional energy grid to use for plotting. If None, the energy grid from the experiment is used. By default, None. **kwargs : dict[str, Any] - Keyword arguments to pass to the plotting - function. + Keyword arguments to pass to the plotting function. Raises ------ @@ -362,10 +350,10 @@ def free_energy_offset(self) -> None: ############# def _require_Q_index(self) -> int: - """Get the Q index, ensuring it is set. + """ + Get the Q index, ensuring it is set. - Raises a ValueError if -the Q index is not set. + Raises a ValueError if the Q index is not set. Raises ------ @@ -382,18 +370,19 @@ def _require_Q_index(self) -> int: return self._Q_index def _on_Q_index_changed(self) -> None: - """Handle changes to the Q index. + """ + Handle changes to the Q index. - This method is called whenever the Q index is changed. It - updates the Convolution object for the new Q index and the - masked energy from the experiment for the new Q index. + This method is called whenever the Q index is changed. It updates the Convolution object + for the new Q index and the masked energy from the experiment for the new Q index. """ masked_energy = self.experiment.get_masked_energy(Q_index=self._Q_index) self._masked_energy = masked_energy self._convolver = self._create_convolver() def _verify_energy(self, energy: sc.Variable | None) -> sc.Variable | None: - """Verify that the provided energy is the correct type. + """ + Verify that the provided energy is the correct type. Parameters ---------- @@ -408,8 +397,7 @@ def _verify_energy(self, energy: sc.Variable | None) -> sc.Variable | None: Returns ------- sc.Variable | None - The verified energy, or None if no - energy is provided. + The verified energy, or None if no energy is provided. """ if energy is not None and not isinstance(energy, sc.Variable): @@ -421,7 +409,8 @@ def _calculate_energy_with_offset( energy: sc.Variable, energy_offset: Parameter, ) -> sc.Variable: - """Calculate the energy grid with the energy offset applied. + """ + Calculate the energy grid with the energy offset applied. Parameters ---------- @@ -433,8 +422,7 @@ def _calculate_energy_with_offset( Raises ------ sc.UnitError : - If the energy and energy offset have - incompatible units. + If the energy and energy offset have incompatible units. Returns ------- @@ -466,35 +454,28 @@ def _evaluate_components( convolve: bool = True, energy: sc.Variable | None = None, ) -> np.ndarray: - """Calculate the contribution of a set of components, optionally - convolving with the resolution. - - If convolve is True and a - Convolution object is provided (for full model evaluation), we - use it to perform the convolution of the components with the + """ + Calculate the contribution of a set of components, optionally convolving with the resolution. - If convolve is True but no Convolution object is - provided, create a new Convolution object for the given - components (for individual components). - If convolve is False, evaluate the components directly without - convolution (for background). + + If convolve is True and a Convolution object is provided (for full model evaluation), we + use it to perform the convolution of the components with the resolution. If convolve is + True but no Convolution object is provided, create a new Convolution object for the given + components (for individual components). If convolve is False, evaluate the components + directly without convolution (for background). Parameters ---------- components : ComponentCollection | ModelComponent - The - components to evaluate. - convolver : Convolution | None, optional - An optional Convolution - object to use for convolution. If None, a new - Convolution object will be created if convolve is True. By default, None. - convolve : bool, optional - Whether to perform convolution with the - resolution. By default, True. - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + The components to evaluate. + convolver : Convolution | None, default=None + An optional Convolution object to use for convolution. If None, a new Convolution + object will be created if convolve is True. By default, None. + convolve : bool, default=True + Whether to perform convolution with the resolution. By default, True. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -548,16 +529,16 @@ def _evaluate_sample( self, energy: sc.Variable | None = None, ) -> np.ndarray: - """Evaluate the sample contribution for a given Q index. + """ + Evaluate the sample contribution for a given Q index. Assumes that self._convolver is up to date. Parameters ---------- - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -578,17 +559,16 @@ def _evaluate_sample_component( component: ModelComponent, energy: sc.Variable | None = None, ) -> np.ndarray: - """Evaluate a single sample component for the chosen Q index. + """ + Evaluate a single sample component for the chosen Q index. Parameters ---------- component : ModelComponent - The sample component to - evaluate. - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + The sample component to evaluate. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -603,14 +583,14 @@ def _evaluate_sample_component( ) def _evaluate_background(self, energy: sc.Variable | None = None) -> np.ndarray: - """Evaluate the background contribution for the chosen Q index. + """ + Evaluate the background contribution for the chosen Q index. Parameters ---------- - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -633,18 +613,16 @@ def _evaluate_background_component( component: ModelComponent, energy: sc.Variable | None = None, ) -> np.ndarray: - """Evaluate a single background component for the chosen Q - index. + """ + Evaluate a single background component for the chosen Q index. Parameters ---------- component : ModelComponent - The background component to - evaluate. - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + The background component to evaluate. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -663,22 +641,20 @@ def _create_convolver( self, energy: sc.Variable | None = None, ) -> Convolution | None: - """Initialize and return a Convolution object for the chosen Q - index. If the necessary components for convolution are not - available, return None. + """ + Initialize and return a Convolution object for the chosen Q index. If the necessary + components for convolution are not available, return None. Parameters ---------- - energy : sc.Variable | None, optional - Optional energy grid to use for - convolution. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for convolution. If None, the energy grid from the + experiment is used. By default, None. Returns ------- Convolution | None - The initialized Convolution object or - None if not available. + The initialized Convolution object or None if not available. """ Q_index = self._require_Q_index() @@ -714,22 +690,20 @@ def _create_component_scipp_array( background: np.ndarray | None = None, energy: sc.Variable | None = None, ) -> sc.DataArray: - """Create a scipp DataArray for a single component. + """ + Create a scipp DataArray for a single component. - Adds the -background if it is not None. + Adds the background if it is not None. Parameters ---------- component : ModelComponent The component to evaluate. - background : np.ndarray | None, optional - Optional background to add - to the component. By default, None. - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + background : np.ndarray | None, default=None + Optional background to add to the component. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -747,16 +721,16 @@ def _create_background_component_scipp_array( component: ModelComponent, energy: sc.Variable | None = None, ) -> sc.DataArray: - """Create a scipp DataArray for a single background component. + """ + Create a scipp DataArray for a single background component. Parameters ---------- component : ModelComponent The component to evaluate. - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- @@ -771,21 +745,19 @@ def _create_background_component_scipp_array( return self._to_scipp_array(values=values, energy=energy) def _create_sample_scipp_array(self, energy: sc.Variable | None = None) -> sc.DataArray: - """Create a scipp DataArray for the full sample model including - background. + """ + Create a scipp DataArray for the full sample model including background. Parameters ---------- - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- sc.DataArray - The model calculation of the full sample - model. + The model calculation of the full sample model. """ values = self.calculate(energy=energy) return self._to_scipp_array(values=values, energy=energy) @@ -795,23 +767,21 @@ def _create_components_dataset_single_Q( add_background: bool = True, energy: sc.Variable | None = None, ) -> dict[str, sc.DataArray]: - """Create sc.DataArrays for all sample and background - components. + """ + Create sc.DataArrays for all sample and background components. Parameters ---------- - add_background : bool, optional + add_background : bool, default=True Whether to add background components. By default, True. - energy : sc.Variable | None, optional - Optional energy grid to use for - evaluation. If None, the energy grid from the experiment - is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for evaluation. If None, the energy grid from the + experiment is used. By default, None. Returns ------- dict[str, sc.DataArray] - A dictionary of component names to - their corresponding sc.DataArrays. + A dictionary of component names to their corresponding sc.DataArrays. """ scipp_arrays = {} sample_components = self.sample_model.get_component_collection( @@ -842,17 +812,17 @@ def _to_scipp_array( values: np.ndarray, energy: sc.Variable | None = None, ) -> sc.DataArray: - """Convert a numpy array of values to a sc.DataArray with the - correct coordinates for energy and Q. + """ + Convert a numpy array of values to a sc.DataArray with the correct coordinates for energy + and Q. Parameters ---------- values : np.ndarray The values to convert. - energy : sc.Variable | None, optional - Optional energy grid to use for the - energy coordinate. If None, the energy grid from the - experiment is used. By default, None. + energy : sc.Variable | None, default=None + Optional energy grid to use for the energy coordinate. If None, the energy grid from + the experiment is used. By default, None. Returns ------- diff --git a/src/easydynamics/analysis/analysis_base.py b/src/easydynamics/analysis/analysis_base.py index 7915c69d..2dbd9681 100644 --- a/src/easydynamics/analysis/analysis_base.py +++ b/src/easydynamics/analysis/analysis_base.py @@ -12,16 +12,14 @@ class AnalysisBase(EasyScienceModelBase): - """Base class for analysis in EasyDynamics. + """ + Base class for analysis in EasyDynamics. - This class is not meant -to be used directly. + This class is not meant to be used directly. - An Analysis consists of an Experiment, a SampleModel, and an - InstrumentModel. The Experiment contains the data to be fitted, the - SampleModel contains the model for the sample, and the - InstrumentModel contains the model for the instrument, including - background and resolution + An Analysis consists of an Experiment, a SampleModel, and an InstrumentModel. The Experiment + contains the data to be fitted, the SampleModel contains the model for the sample, and the + InstrumentModel contains the model for the instrument, including background and resolution """ def __init__( @@ -33,40 +31,35 @@ def __init__( instrument_model: InstrumentModel | None = None, extra_parameters: Parameter | list[Parameter] | None = None, ) -> None: - """Initialize the AnalysisBase. + """ + Initialize the AnalysisBase. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='MyAnalysis' Display name of the analysis. By default, 'MyAnalysis'. - unique_name : str | None, optional - Unique name of the analysis. If - None, a unique name is automatically generated. By default, None. - experiment : Experiment | None, optional - The Experiment associated - with this Analysis. If None, a default Experiment is + unique_name : str | None, default=None + Unique name of the analysis. If None, a unique name is automatically generated. By + default, None. + experiment : Experiment | None, default=None + The Experiment associated with this Analysis. If None, a default Experiment is created. + By default, None. + sample_model : SampleModel | None, default=None + The SampleModel associated with this Analysis. If None, a default SampleModel is created. By default, None. - sample_model : SampleModel | None, optional - The SampleModel - associated with this Analysis. If None, a default - SampleModel is created. By default, None. - instrument_model : InstrumentModel | None, optional - The - InstrumentModel associated with this Analysis. If None, - a default InstrumentModel is created. By default, None. - extra_parameters : Parameter | list[Parameter] | None, optional - Extra - parameters to be included in the analysis for advanced - users. If None, no extra parameters are added. By default, None. + instrument_model : InstrumentModel | None, default=None + The InstrumentModel associated with this Analysis. If None, a default InstrumentModel + is created. By default, None. + extra_parameters : Parameter | list[Parameter] | None, default=None + Extra parameters to be included in the analysis for advanced users. If None, no extra + parameters are added. By default, None. Raises ------ TypeError : - If experiment is not an Experiment or None or - if sample_model is not a SampleModel or None or if - instrument_model is not an InstrumentModel or None or if - extra_parameters is not a Parameter, a list of Parameters, - or None. + If experiment is not an Experiment or None or if sample_model is not a SampleModel or + None or if instrument_model is not an InstrumentModel or None or if extra_parameters is + not a Parameter, a list of Parameters, or None. """ super().__init__(display_name=display_name, unique_name=unique_name) @@ -112,7 +105,8 @@ def __init__( @property def experiment(self) -> Experiment: - """Get the Experiment associated with this Analysis. + """ + Get the Experiment associated with this Analysis. Returns ------- @@ -124,7 +118,8 @@ def experiment(self) -> Experiment: @experiment.setter def experiment(self, value: Experiment) -> None: - """Set the Experiment for this Analysis. + """ + Set the Experiment for this Analysis. Parameters ---------- @@ -144,7 +139,8 @@ def experiment(self, value: Experiment) -> None: @property def sample_model(self) -> SampleModel: - """Get the SampleModel associated with this Analysis. + """ + Get the SampleModel associated with this Analysis. Returns ------- @@ -156,7 +152,8 @@ def sample_model(self) -> SampleModel: @sample_model.setter def sample_model(self, value: SampleModel) -> None: - """Set the SampleModel for this Analysis. + """ + Set the SampleModel for this Analysis. Parameters ---------- @@ -175,25 +172,25 @@ def sample_model(self, value: SampleModel) -> None: @property def instrument_model(self) -> InstrumentModel: - """Get the InstrumentModel associated with this Analysis. + """ + Get the InstrumentModel associated with this Analysis. Returns ------- InstrumentModel - The InstrumentModel associated with this - Analysis. + The InstrumentModel associated with this Analysis. """ return self._instrument_model @instrument_model.setter def instrument_model(self, value: InstrumentModel) -> None: - """Set the InstrumentModel for this Analysis. + """ + Set the InstrumentModel for this Analysis. Parameters ---------- value : InstrumentModel - The InstrumentModel to set for this - Analysis. + The InstrumentModel to set for this Analysis. Raises ------ @@ -207,27 +204,25 @@ def instrument_model(self, value: InstrumentModel) -> None: @property def Q(self) -> sc.Variable | None: - """Get the Q values from the associated Experiment, if - available. + """ + Get the Q values from the associated Experiment, if available. Returns ------- sc.Variable | None - The Q values from the associated Experiment, - if available, and None if not. + The Q values from the associated Experiment, if available, and None if not. """ return self.experiment.Q @Q.setter def Q(self, _value: sc.Variable) -> None: - """Q cannot be set, as it is a read-only property derived from - the Experiment. + """ + Q cannot be set, as it is a read-only property derived from the Experiment. Parameters ---------- _value : sc.Variable - The Q values to set. This argument is - ignored, as Q is a read-only property. + The Q values to set. This argument is ignored, as Q is a read-only property. Raises ------ @@ -238,28 +233,27 @@ def Q(self, _value: sc.Variable) -> None: @property def energy(self) -> sc.Variable | None: - """Get the energy values from the associated Experiment, if - available. + """ + Get the energy values from the associated Experiment, if available. Returns ------- sc.Variable | None The energy values from the associated. - Experiment, if available, and None if not. + sc.Variable | None """ return self.experiment.energy @energy.setter def energy(self, _value: sc.Variable) -> None: - """Energy cannot be set, as it is a read-only property derived - from the Experiment. + """ + Energy cannot be set, as it is a read-only property derived from the Experiment. Parameters ---------- _value : sc.Variable - The energy values to set. This argument is - ignored, as energy is a read-only property. + The energy values to set. This argument is ignored, as energy is a read-only property. Raises ------ @@ -271,28 +265,26 @@ def energy(self, _value: sc.Variable) -> None: @property def temperature(self) -> Parameter | None: - """Get the temperature from the associated SampleModel, if - available. + """ + Get the temperature from the associated SampleModel, if available. Returns ------- Parameter | None - The temperature from the associated SampleModel, - if available, and None if not. + The temperature from the associated SampleModel, if available, and None if not. """ return self.sample_model.temperature @temperature.setter def temperature(self, _value: np.ndarray | Parameter) -> None: - """Temperature cannot be set, as it is a read-only property - derived from the SampleModel. + """ + Temperature cannot be set, as it is a read-only property derived from the SampleModel. Parameters ---------- _value : np.ndarray | Parameter - The temperature to set. - This argument is ignored, as temperature is a read-only + The temperature to set. This argument is ignored, as temperature is a read-only property. Raises @@ -305,31 +297,30 @@ def temperature(self, _value: np.ndarray | Parameter) -> None: @property def extra_parameters(self) -> list[Parameter]: - """Get the extra parameters included in this Analysis. + """ + Get the extra parameters included in this Analysis. Returns ------- list[Parameter] - The extra parameters included in this - Analysis. + The extra parameters included in this Analysis. """ return self._extra_parameters @extra_parameters.setter def extra_parameters(self, value: Parameter | list[Parameter]) -> None: - """Set the extra parameters for this Analysis. + """ + Set the extra parameters for this Analysis. Parameters ---------- value : Parameter | list[Parameter] - The extra parameters to - include in this Analysis. + The extra parameters to include in this Analysis. Raises ------ TypeError : - If value is not a Parameter, a list of - Parameters, or None. + If value is not a Parameter, a list of Parameters, or None. """ if isinstance(value, Parameter): self._extra_parameters = [value] @@ -345,11 +336,10 @@ def extra_parameters(self, value: Parameter | list[Parameter]) -> None: ############# def normalize_resolution(self) -> None: - """Normalize the resolution in the InstrumentModel to ensure - that it integrates to 1. + """ + Normalize the resolution in the InstrumentModel to ensure that it integrates to 1. - This is important for accurate fitting and interpretation of the - results. + This is important for accurate fitting and interpretation of the results. """ self.instrument_model.normalize_resolution() @@ -358,26 +348,27 @@ def normalize_resolution(self) -> None: ############# def _on_experiment_changed(self) -> None: - """Update the Q values in the sample and instrument models when - the experiment changes. + """ + Update the Q values in the sample and instrument models when the experiment changes. """ self.sample_model.Q = self.Q self.instrument_model.Q = self.Q def _on_sample_model_changed(self) -> None: - """Update the Q values in the sample model when the sample model - changes. + """ + Update the Q values in the sample model when the sample model changes. """ self.sample_model.Q = self.Q def _on_instrument_model_changed(self) -> None: - """Update the Q values in the instrument model when the - instrument model changes. + """ + Update the Q values in the instrument model when the instrument model changes. """ self.instrument_model.Q = self.Q def _verify_Q_index(self, Q_index: int | None) -> int | None: - """Verify that the Q index is valid. + """ + Verify that the Q index is valid. Parameters ---------- @@ -411,7 +402,8 @@ def _verify_Q_index(self, Q_index: int | None) -> int | None: ############# def __repr__(self) -> str: - """Return a string representation of the Analysis. + """ + Return a string representation of the Analysis. Returns ------- diff --git a/src/easydynamics/convolution/analytical_convolution.py b/src/easydynamics/convolution/analytical_convolution.py index 43a29fe1..2940dc81 100644 --- a/src/easydynamics/convolution/analytical_convolution.py +++ b/src/easydynamics/convolution/analytical_convolution.py @@ -17,11 +17,11 @@ class AnalyticalConvolution(ConvolutionBase): - """Analytical convolution of a ModelComponent or ComponentCollection - with a ResolutionModel. + """ + Analytical convolution of a ModelComponent or ComponentCollection with a ResolutionModel. - Possible analytical convolutions are any combination of delta - functions, Gaussians, Lorentzians and Voigt profiles. + Possible analytical convolutions are any combination of delta functions, Gaussians, Lorentzians + and Voigt profiles. """ # Mapping of supported component type pairs to convolution methods. @@ -43,23 +43,21 @@ def __init__( resolution_components: ComponentCollection | ModelComponent | None = None, energy_offset: Numeric | Parameter = 0.0, ) -> None: - """Initialize an AnalyticalConvolution. + """ + Initialize an AnalyticalConvolution. Parameters ---------- energy : np.ndarray | sc.Variable - 1D array of energy values - where the convolution is evaluated. - energy_unit : str | sc.Unit, optional - The unit of the - energy. By default, 'meV'. - sample_components : ComponentCollection | ModelComponent | None, optional + 1D array of energy values where the convolution is evaluated. + energy_unit : str | sc.Unit, default='meV' + The unit of the energy. By default, 'meV'. + sample_components : ComponentCollection | ModelComponent | None, default=None The sample model to be convolved. By default, None. - resolution_components : ComponentCollection | ModelComponent | None, optional + resolution_components : ComponentCollection | ModelComponent | None, default=None The resolution model to convolve with. By default, None. - energy_offset : Numeric | Parameter, optional - An offset to - shift the energy values by. By default, 0.0. + energy_offset : Numeric | Parameter, default=0.0 + An offset to shift the energy values by. By default, 0.0. """ super().__init__( energy=energy, @@ -72,17 +70,18 @@ def __init__( def convolution( self, ) -> np.ndarray: - """Convolve sample with resolution analytically if possible. + """ + Convolve sample with resolution analytically if possible. - Accepts ComponentCollection or single ModelComponent for each. - Possible analytical convolutions are any combination of delta - functions, Gaussians, Lorentzians and Voigt profiles. + Accepts ComponentCollection or single ModelComponent for each. Possible analytical + convolutions are any combination of delta functions, Gaussians, Lorentzians and Voigt + profiles. Returns ------- np.ndarray - The convolution of the sample_components and - resolution_components values evaluated at self.energy. + The convolution of the sample_components and resolution_components values evaluated at + self.energy. """ sample_components = self.sample_components.components @@ -107,50 +106,42 @@ def _convolute_analytic_pair( sample_component: ModelComponent, resolution_component: ModelComponent, ) -> np.ndarray: - r"""Analytic convolution for component pair (sample_component, - resolution_component). + r""" + Analytic convolution for component pair (sample_component, resolution_component). - The convolution of two Gaussian components results in another - Gaussian component with width $\sqrt{w_1^2 + w_2^2}$. + The convolution of two Gaussian components results in another Gaussian component with width + $\sqrt{w_1^2 + w_2^2}$. - The convolution of two Lorentzian components results in another - Lorentzian component with width $w_1 + w_2$. + The convolution of two Lorentzian components results in another Lorentzian component with + width $w_1 + w_2$. - The convolution of a Gaussian and a Lorentzian results in a - Voigt profile. + The convolution of a Gaussian and a Lorentzian results in a Voigt profile. - The convolution of a Gaussian and a Voigt profile results in - another Voigt profile, with the Lorentzian width unchanged and - the Gaussian widths summed in quadrature. + The convolution of a Gaussian and a Voigt profile results in another Voigt profile, with + the Lorentzian width unchanged and the Gaussian widths summed in quadrature. - The convolution of a Lorentzian and a Voigt profile results in - another Voigt profile, with the Gaussian width unchanged and the - Lorentzian widths summed. + The convolution of a Lorentzian and a Voigt profile results in another Voigt profile, with + the Gaussian width unchanged and the Lorentzian widths summed. - The convolution of two Voigt profiles results in another Voigt - profile, with the Gaussian widths summed in quadrature and the - Lorentzian widths summed. + The convolution of two Voigt profiles results in another Voigt profile, with the Gaussian + widths summed in quadrature and the Lorentzian widths summed. - The convolution of a delta function with any component or - ComponentCollection results in the same component or - ComponentCollection shifted by the delta center. + The convolution of a delta function with any component or ComponentCollection results in + the same component or ComponentCollection shifted by the delta center. All areas are multiplied in the convolution. Parameters ---------- sample_component : ModelComponent - The sample component to - be convolved. + The sample component to be convolved. resolution_component : ModelComponent - The resolution - component to convolve with. + The resolution component to convolve with. Raises ------ ValueError : - If the component pair cannot be handled - analytically. + If the component pair cannot be handled analytically. Returns ------- @@ -201,16 +192,15 @@ def _convolute_delta_any( sample_component: DeltaFunction, resolution_components: ComponentCollection | ModelComponent, ) -> np.ndarray: - """Convolution of delta function with any ModelComponent or - ComponentCollection results in the same component or - ComponentCollection shifted by the delta center. The areas are + """ + Convolution of delta function with any ModelComponent or ComponentCollection results in the + same component or ComponentCollection shifted by the delta center. The areas are multiplied. Parameters ---------- sample_component : DeltaFunction - The sample component to - be convolved. + The sample component to be convolved. resolution_components : ComponentCollection | ModelComponent : The resolution model to convolve with. @@ -228,18 +218,16 @@ def _convolute_gaussian_gaussian( sample_component: Gaussian, resolution_component: Gaussian, ) -> np.ndarray: - r"""Convolution of two Gaussian components results in another - Gaussian component with width $\sqrt{w_1^2 + w_2^2}$. The areas - are multiplied. + r""" + Convolution of two Gaussian components results in another Gaussian component with width + $\sqrt{w_1^2 + w_2^2}$. The areas are multiplied. Parameters ---------- sample_component : Gaussian - The sample Gaussian component - to be convolved. + The sample Gaussian component to be convolved. resolution_component : Gaussian - The resolution Gaussian - component to convolve with. + The resolution Gaussian component to convolve with. Returns ------- @@ -260,17 +248,16 @@ def _convolute_gaussian_lorentzian( sample_component: Gaussian, resolution_component: Lorentzian, ) -> np.ndarray: - """Convolution of a Gaussian and a Lorentzian results in a Voigt - profile. The areas are multiplied. + """ + Convolution of a Gaussian and a Lorentzian results in a Voigt profile. The areas are + multiplied. Parameters ---------- sample_component : Gaussian - The sample Gaussian component - to be convolved. + The sample Gaussian component to be convolved. resolution_component : Lorentzian - The resolution Lorentzian - component to convolve with. + The resolution Lorentzian component to convolve with. Returns ------- @@ -292,19 +279,17 @@ def _convolute_gaussian_voigt( sample_component: Gaussian, resolution_component: Voigt, ) -> np.ndarray: - """Convolution of a Gaussian and a Voigt profile results in - another Voigt profile. The Lorentzian width remains unchanged, - while the Gaussian widths are summed in quadrature. The areas - are multiplied. + """ + Convolution of a Gaussian and a Voigt profile results in another Voigt profile. The + Lorentzian width remains unchanged, while the Gaussian widths are summed in quadrature. The + areas are multiplied. Parameters ---------- sample_component : Gaussian - The sample Gaussian component - to be convolved. + The sample Gaussian component to be convolved. resolution_component : Voigt - The resolution Voigt component - to convolve with. + The resolution Voigt component to convolve with. Returns ------- @@ -333,18 +318,16 @@ def _convolute_lorentzian_lorentzian( sample_component: Lorentzian, resolution_component: Lorentzian, ) -> np.ndarray: - r"""Convolution of two Lorentzian components results in another - Lorentzian component with width $w_1 + w_2$. The areas are - multiplied. + r""" + Convolution of two Lorentzian components results in another Lorentzian component with width + $w_1 + w_2$. The areas are multiplied. Parameters ---------- sample_component : Lorentzian - The sample Lorentzian - component to be convolved. + The sample Lorentzian component to be convolved. resolution_component : Lorentzian - The resolution Lorentzian - component to convolve with. + The resolution Lorentzian component to convolve with. Returns ------- @@ -364,22 +347,19 @@ def _convolute_lorentzian_voigt( sample_component: Lorentzian, resolution_component: Voigt, ) -> np.ndarray: - """Convolution of a Lorentzian and a Voigt profile results in - another Voigt profile. + """ + Convolution of a Lorentzian and a Voigt profile results in another Voigt profile. - The Gaussian width remains unchanged, while the Lorentzian - widths are summed. + The Gaussian width remains unchanged, while the Lorentzian widths are summed. The areas are multiplied. Parameters ---------- sample_component : Lorentzian - The sample Lorentzian - component to be convolved. + The sample Lorentzian component to be convolved. resolution_component : Voigt - The resolution Voigt component - to convolve with. + The resolution Voigt component to convolve with. Returns ------- @@ -408,21 +388,18 @@ def _convolute_voigt_voigt( sample_component: Voigt, resolution_component: Voigt, ) -> np.ndarray: - """Convolution of two Voigt profiles results in another Voigt - profile. + """ + Convolution of two Voigt profiles results in another Voigt profile. - The Gaussian widths are summed in quadrature, - while the Lorentzian widths are summed. - The areas are multiplied. + The Gaussian widths are summed in quadrature, while the Lorentzian widths are summed. The + areas are multiplied. Parameters ---------- sample_component : Voigt - The sample Voigt component to be - convolved. + The sample Voigt component to be convolved. resolution_component : Voigt - The resolution Voigt component - to convolve with. + The resolution Voigt component to convolve with. Returns ------- @@ -453,18 +430,13 @@ def _gaussian_eval( center: float, width: float, ) -> np.ndarray: - r"""Evaluate a Gaussian function. + r""" + Evaluate a Gaussian function. - $$ - I(x) = \frac{A}{\sigma \sqrt{2\pi}} - \exp\left( - -\frac{1}{2} - \left(\frac{x - x_0}{\sigma}\right)^2 - \right) - $$ + $$ I(x) = \frac{A}{\sigma \sqrt{2\pi}} \exp\left( -\frac{1}{2} \left(\frac{x - + x_0}{\sigma}\right)^2 \right) $$ - where $A$ is the area, $x_0$ is the center, and $\sigma$ is the - width. + where $A$ is the area, $x_0$ is the center, and $\sigma$ is the width. All checks are handled in the calling function. @@ -489,14 +461,13 @@ def _gaussian_eval( return area * normalization * np.exp(exponent) def _lorentzian_eval(self, area: float, center: float, width: float) -> np.ndarray: - r"""Evaluate a Lorentzian function. + r""" + Evaluate a Lorentzian function. - $$ - I(x) = \frac{A}{\\pi} \frac{\Gamma}{(x - x_0)^2 + \Gamma^2}, - $$ + $$ I(x) = \frac{A}{\\pi} \frac{\Gamma}{(x - x_0)^2 + \Gamma^2}, $$ - where $A$ is the area, $x_0$ is the center, and $\\Gamma$ is - the half width at half maximum (HWHM). + where $A$ is the area, $x_0$ is the center, and $\\Gamma$ is the half width at half maximum + (HWHM). All checks are handled in the calling function. @@ -527,8 +498,8 @@ def _voigt_eval( gaussian_width: float, lorentzian_width: float, ) -> np.ndarray: - """Evaluate a Voigt profile function using scipy's - voigt_profile. + """ + Evaluate a Voigt profile function using scipy's voigt_profile. Parameters ---------- @@ -537,17 +508,14 @@ def _voigt_eval( center : float The center of the Voigt profile. gaussian_width : float - The Gaussian width (sigma) of the - Voigt profile. + The Gaussian width (sigma) of the Voigt profile. lorentzian_width : float - The Lorentzian width (HWHM) of the - Voigt profile. + The Lorentzian width (HWHM) of the Voigt profile. Returns ------- np.ndarray - The evaluated Voigt profile values at - self.energy. + The evaluated Voigt profile values at self.energy. """ return area * voigt_profile( diff --git a/src/easydynamics/convolution/convolution.py b/src/easydynamics/convolution/convolution.py index a859bb3d..6694e057 100644 --- a/src/easydynamics/convolution/convolution.py +++ b/src/easydynamics/convolution/convolution.py @@ -18,19 +18,17 @@ class Convolution(NumericalConvolutionBase): - """Convolution class that combines analytical and numerical - convolution methods to efficiently perform convolutions of - ComponentCollections with ResolutionComponents. - - Supports analytical convolution for pairs of analytical model - components (DeltaFunction, Gaussian, Lorentzian, Voigt), while using - numerical convolution for other components. If temperature is - provided, detailed balance correction is applied to the sample - model. In this case, all convolutions are handled numerically. - Includes a setting to normalize the detailed balance correction. - Includes optional upsampling and extended range to improve accuracy - of the numerical convolutions. Also warns about numerical - instabilities if peaks are very wide or very narrow. + """ + Convolution class that combines analytical and numerical convolution methods to efficiently + perform convolutions of ComponentCollections with ResolutionComponents. + + Supports analytical convolution for pairs of analytical model components (DeltaFunction, + Gaussian, Lorentzian, Voigt), while using numerical convolution for other components. If + temperature is provided, detailed balance correction is applied to the sample model. In this + case, all convolutions are handled numerically. Includes a setting to normalize the detailed + balance correction. Includes optional upsampling and extended range to improve accuracy of the + numerical convolutions. Also warns about numerical instabilities if peaks are very wide or very + narrow. """ # When these attributes are changed, the convolution plan @@ -61,40 +59,34 @@ def __init__( energy_unit: str | sc.Unit = 'meV', normalize_detailed_balance: bool = True, ) -> None: - """Initialize the Convolution class. + """ + Initialize the Convolution class. Parameters ---------- energy : np.ndarray | sc.Variable - 1D array of energy - values where the convolution is evaluated. + 1D array of energy values where the convolution is evaluated. sample_components : ComponentCollection | ModelComponent The sample components to be convolved. resolution_components : ComponentCollection | ModelComponent The resolution components to convolve with. - energy_offset : Numeric | Parameter, optional - An energy - offset to apply to the energy values before convolution. By default, 0.0. - upsample_factor : Numeric | None, optional - The factor by which to - upsample the input data before convolution. Default is + energy_offset : Numeric | Parameter, default=0.0 + An energy offset to apply to the energy values before convolution. By default, 0.0. + upsample_factor : Numeric | None, default=5 + The factor by which to upsample the input data before convolution. Default is 5. By default, 5. - extension_factor : Numeric | None, optional - The factor by which to - extend the input data range before convolution. Default - is 0.2. By default, 0.2. - temperature : Parameter | Numeric | None, optional - The - temperature to use for detailed balance correction. By default, None. - temperature_unit : str | sc.Unit, optional - The unit of the - temperature parameter. By default, 'K'. - energy_unit : str | sc.Unit, optional + extension_factor : Numeric | None, default=0.2 + The factor by which to extend the input data range before convolution. Default is 0.2. + By default, 0.2. + temperature : Parameter | Numeric | None, default=None + The temperature to use for detailed balance correction. By default, None. + temperature_unit : str | sc.Unit, default='K' + The unit of the temperature parameter. By default, 'K'. + energy_unit : str | sc.Unit, default='meV' The unit of the energy. By default, 'meV'. - normalize_detailed_balance : bool, optional - Whether to - normalize the detailed balance correction. Default is - True. By default, True. + normalize_detailed_balance : bool, default=True + Whether to normalize the detailed balance correction. Default is True. By default, + True. """ self._convolution_plan_is_valid = False @@ -122,9 +114,9 @@ def __init__( def convolution( self, ) -> np.ndarray: - """Perform convolution using analytical convolutions where - possible, and numerical convolutions for the remaining - components. + """ + Perform convolution using analytical convolutions where possible, and numerical + convolutions for the remaining components. Returns ------- @@ -150,15 +142,14 @@ def convolution( return total def _convolve_delta_functions(self) -> np.ndarray: - """Convolve delta function components of the sample model with - the resolution components. No detailed balance correction is - applied to delta functions. + """ + Convolve delta function components of the sample model with the resolution components. No + detailed balance correction is applied to delta functions. Returns ------- np.ndarray - The convolved values of the delta function c - components evaluated at energy. + The convolved values of the delta function c components evaluated at energy. """ return sum( delta.area.value @@ -173,29 +164,26 @@ def _check_if_pair_is_analytic( sample_component: ModelComponent, resolution_component: ModelComponent, ) -> bool: - """Check if the convolution of the given component pair can be - handled analytically. + """ + Check if the convolution of the given component pair can be handled analytically. Parameters ---------- sample_component : ModelComponent - The sample component to - be convolved. + The sample component to be convolved. resolution_component : ModelComponent - The resolution - component to convolve with. + The resolution component to convolve with. Raises ------ TypeError : - If either component is not a ModelComponent, or if - the resolution component is a DeltaFunction. + If either component is not a ModelComponent, or if the resolution component is a + DeltaFunction. Returns ------- bool - True if the component pair can be handled - analytically, False otherwise. + True if the component pair can be handled analytically, False otherwise. """ if not isinstance(sample_component, ModelComponent): @@ -222,8 +210,8 @@ def _check_if_pair_is_analytic( ) def _build_convolution_plan(self) -> None: - """Separate sample model components into analytical pairs, delta - functions, and the rest. + """ + Separate sample model components into analytical pairs, delta functions, and the rest. """ analytical_sample_components = ComponentCollection() @@ -268,11 +256,11 @@ def _build_convolution_plan(self) -> None: self._set_convolvers() def _set_convolvers(self) -> None: - """Initialize analytical and numerical convolvers based on - sample model components. + """ + Initialize analytical and numerical convolvers based on sample model components. - There is no delta function convolver, as delta functions are - handled directly in the convolution method. + There is no delta function convolver, as delta functions are handled directly in the + convolution method. """ if self._analytical_sample_components.components: @@ -302,11 +290,12 @@ def _set_convolvers(self) -> None: # Update some setters so the internal sample models are updated def __setattr__(self, name: str, value: any) -> None: - """Custom setattr to invalidate convolution plan on relevant - attribute changes, and build a new plan. + """ + Custom setattr to invalidate convolution plan on relevant attribute changes, and build a + new plan. - The new plan is only built after initialization (when - _reactions_enabled is True) to avoid issues during __init__. + The new plan is only built after initialization (when _reactions_enabled is True) to avoid + issues during __init__. Parameters ---------- diff --git a/src/easydynamics/convolution/convolution_base.py b/src/easydynamics/convolution/convolution_base.py index 04423f3f..1f94d2fc 100644 --- a/src/easydynamics/convolution/convolution_base.py +++ b/src/easydynamics/convolution/convolution_base.py @@ -11,7 +11,8 @@ class ConvolutionBase: - """Base class for convolutions of sample and resolution models. + """ + Base class for convolutions of sample and resolution models. This base class has no convolution functionality. """ @@ -24,30 +25,27 @@ def __init__( energy_unit: str | sc.Unit = 'meV', energy_offset: Numeric | Parameter = 0.0, ) -> None: - """Initialize the ConvolutionBase. + """ + Initialize the ConvolutionBase. Parameters ---------- energy : np.ndarray | sc.Variable - 1D array of energy - values where the convolution is evaluated. - sample_components : ComponentCollection | ModelComponent | None, optional + 1D array of energy values where the convolution is evaluated. + sample_components : ComponentCollection | ModelComponent | None, default=None The sample model to be convolved. By default, None. - resolution_components : ComponentCollection | ModelComponent | None, optional + resolution_components : ComponentCollection | ModelComponent | None, default=None The resolution model to convolve with. By default, None. - energy_unit : str | sc.Unit, optional - The unit of the - energy. By default, 'meV'. - energy_offset : Numeric | Parameter, optional - The energy - offset applied to the convolution. By default, 0.0. + energy_unit : str | sc.Unit, default='meV' + The unit of the energy. By default, 'meV'. + energy_offset : Numeric | Parameter, default=0.0 + The energy offset applied to the convolution. By default, 0.0. Raises ------ TypeError : - If energy is not a numpy ndarray or a scipp - Variable or if energy_unit is not a string or scipp unit, or if - energy_offset is not a number or a Parameter, or if + If energy is not a numpy ndarray or a scipp Variable or if energy_unit is not a string + or scipp unit, or if energy_offset is not a number or a Parameter, or if sample_components is not a ComponentCollection or ModelComponent, or if resolution_components is not a ComponentCollection or ModelComponent. """ @@ -97,7 +95,8 @@ def __init__( @property def energy_offset(self) -> Parameter: - """Get the energy offset. + """ + Get the energy offset. Returns ------- @@ -108,13 +107,13 @@ def energy_offset(self) -> Parameter: @energy_offset.setter def energy_offset(self, energy_offset: Numeric | Parameter) -> None: - """Set the energy offset. + """ + Set the energy offset. Parameters ---------- energy_offset : Numeric | Parameter - The energy offset to - apply to the convolution. + The energy offset to apply to the convolution. Raises ------ @@ -132,7 +131,8 @@ def energy_offset(self, energy_offset: Numeric | Parameter) -> None: @property def energy_with_offset(self) -> sc.Variable: - """Get the energy with the offset applied. + """ + Get the energy with the offset applied. Returns ------- @@ -145,8 +145,8 @@ def energy_with_offset(self) -> sc.Variable: @energy_with_offset.setter def energy_with_offset(self, _value: sc.Variable) -> None: - """Energy with offset is a read-only property derived from - energy and energy_offset. + """ + Energy with offset is a read-only property derived from energy and energy_offset. Parameters ---------- @@ -156,8 +156,7 @@ def energy_with_offset(self, _value: sc.Variable) -> None: Raises ------ AttributeError : - Always raised since energy_with_offset is - read-only. + Always raised since energy_with_offset is read-only. """ raise AttributeError( 'Energy with offset is a read-only property derived from energy and energy_offset.' @@ -165,32 +164,31 @@ def energy_with_offset(self, _value: sc.Variable) -> None: @property def energy(self) -> sc.Variable: - """Get the energy. + """ + Get the energy. Returns ------- sc.Variable - The energy values where the convolution is - evaluated. + The energy values where the convolution is evaluated. """ return self._energy @energy.setter def energy(self, energy: np.ndarray | sc.Variable) -> None: - """Set the energy. + """ + Set the energy. Parameters ---------- energy : np.ndarray | sc.Variable - 1D array of energy - values where the convolution is evaluated. + 1D array of energy values where the convolution is evaluated. Raises ------ TypeError : - If energy is not a numpy ndarray or a - scipp Variable. + If energy is not a numpy ndarray or a scipp Variable. """ if isinstance(energy, Numeric): @@ -208,7 +206,8 @@ def energy(self, energy: np.ndarray | sc.Variable) -> None: @property def energy_unit(self) -> str: - """Get the energy unit. + """ + Get the energy unit. Returns ------- @@ -226,7 +225,8 @@ def energy_unit(self, _unit_str: str) -> None: ) # noqa: E501 def convert_energy_unit(self, energy_unit: str | sc.Unit) -> None: - """Convert the energy and energy_offset to the specified unit. + """ + Convert the energy and energy_offset to the specified unit. Parameters ---------- @@ -238,8 +238,7 @@ def convert_energy_unit(self, energy_unit: str | sc.Unit) -> None: TypeError : If energy_unit is not a string or scipp unit. Exception : - If energy cannot be converted to the specified - unit. + If energy cannot be converted to the specified unit. """ if not isinstance(energy_unit, (str, sc.Unit)): raise TypeError('Energy unit must be a string or scipp unit.') @@ -262,19 +261,20 @@ def convert_energy_unit(self, energy_unit: str | sc.Unit) -> None: @property def sample_components(self) -> ComponentCollection | ModelComponent: - """Get the sample model. + """ + Get the sample model. Returns ------- ComponentCollection | ModelComponent - The sample model to - be convolved. + The sample model to be convolved. """ return self._sample_components @sample_components.setter def sample_components(self, sample_components: ComponentCollection | ModelComponent) -> None: - """Set the sample model. + """ + Set the sample model. Parameters ---------- @@ -284,8 +284,7 @@ def sample_components(self, sample_components: ComponentCollection | ModelCompon Raises ------ TypeError : - If sample_components is not a ComponentCollection - or ModelComponent. + If sample_components is not a ComponentCollection or ModelComponent. """ if not isinstance(sample_components, (ComponentCollection, ModelComponent)): raise TypeError( @@ -298,13 +297,13 @@ def sample_components(self, sample_components: ComponentCollection | ModelCompon @property def resolution_components(self) -> ComponentCollection | ModelComponent: - """Get the resolution model. + """ + Get the resolution model. Returns ------- ComponentCollection | ModelComponent - The resolution model - to be convolved. + The resolution model to be convolved. """ return self._resolution_components @@ -312,19 +311,19 @@ def resolution_components(self) -> ComponentCollection | ModelComponent: def resolution_components( self, resolution_components: ComponentCollection | ModelComponent ) -> None: - """Set the resolution model. + """ + Set the resolution model. Parameters ---------- resolution_components : ComponentCollection | ModelComponent - The resolution model to be convolved. Can be a - ComponentCollection or a single ModelComponent. + The resolution model to be convolved. Can be a ComponentCollection or a single + ModelComponent. Raises ------ TypeError : - If resolution_components is not a - ComponentCollection or ModelComponent. + If resolution_components is not a ComponentCollection or ModelComponent. """ if not isinstance(resolution_components, (ComponentCollection, ModelComponent)): raise TypeError( diff --git a/src/easydynamics/convolution/energy_grid.py b/src/easydynamics/convolution/energy_grid.py index 2e78bcc3..0722aa59 100644 --- a/src/easydynamics/convolution/energy_grid.py +++ b/src/easydynamics/convolution/energy_grid.py @@ -8,26 +8,21 @@ @dataclass(frozen=True) class EnergyGrid: - """Container for the dense energy grid and related metadata. + """ + Container for the dense energy grid and related metadata. Attributes ---------- energy_dense : np.ndarray - The upsampled and extended energy - array. + The upsampled and extended energy array. energy_dense_centered : np.ndarray - The centered version of - energy_dense (used for resolution evaluation). + The centered version of energy_dense (used for resolution evaluation). energy_dense_step : float - The spacing of energy_dense - (used for width checks and normalization). + The spacing of energy_dense (used for width checks and normalization). energy_span_dense : float - The total span of energy_dense. - (used for width checks). + The total span of energy_dense. (used for width checks). energy_even_length_offset : float - The offset to apply if - energy_dense has even length (used for convolution - alignment). + The offset to apply if energy_dense has even length (used for convolution alignment). """ energy_dense: np.ndarray diff --git a/src/easydynamics/convolution/numerical_convolution.py b/src/easydynamics/convolution/numerical_convolution.py index 2b70280b..00c26640 100644 --- a/src/easydynamics/convolution/numerical_convolution.py +++ b/src/easydynamics/convolution/numerical_convolution.py @@ -14,13 +14,12 @@ class NumericalConvolution(NumericalConvolutionBase): - """Numerical convolution of a ComponentCollection with a - ComponentCollection using FFT. + """ + Numerical convolution of a ComponentCollection with a ComponentCollection using FFT. - Includes optional upsampling and extended range to improve accuracy. - Warns about very wide or very narrow peaks in the models. If - temperature is provided, detailed balance correction is applied to - the sample model. + Includes optional upsampling and extended range to improve accuracy. Warns about very wide or + very narrow peaks in the models. If temperature is provided, detailed balance correction is + applied to the sample model. """ def __init__( @@ -36,39 +35,32 @@ def __init__( energy_unit: str | sc.Unit = 'meV', normalize_detailed_balance: bool = True, ) -> None: - """Initialize the NumericalConvolution object. + """ + Initialize the NumericalConvolution object. Parameters ---------- energy : np.ndarray | sc.Variable - 1D array of energy values - where the convolution is evaluated. + 1D array of energy values where the convolution is evaluated. sample_components : ComponentCollection | ModelComponent The sample model to be convolved. resolution_components : ComponentCollection | ModelComponent The resolution model to convolve with. - energy_offset : Numeric | Parameter, optional - An energy - offset to apply to the energy values before convolution. By default, 0.0. - upsample_factor : Numeric | None, optional - The factor by which to - upsample the input data before convolution. By default, 5. - extension_factor : Numeric | None, optional - The factor by which to - extend the input data range before convolution. By default, 0.2. - temperature : Parameter | Numeric | None, optional - The - temperature to use for detailed balance correction. By default, None. - temperature_unit : str | sc.Unit, optional - The unit of the - temperature parameter. By default, 'K'. - energy_unit : str | sc.Unit, optional - The unit of the - energy. By default, 'meV'. - normalize_detailed_balance : bool, optional - Whether to - normalize the detailed balance correction. Default is - True. By default, True. + energy_offset : Numeric | Parameter, default=0.0 + An energy offset to apply to the energy values before convolution. By default, 0.0. + upsample_factor : Numeric | None, default=5 + The factor by which to upsample the input data before convolution. By default, 5. + extension_factor : Numeric | None, default=0.2 + The factor by which to extend the input data range before convolution. By default, 0.2. + temperature : Parameter | Numeric | None, default=None + The temperature to use for detailed balance correction. By default, None. + temperature_unit : str | sc.Unit, default='K' + The unit of the temperature parameter. By default, 'K'. + energy_unit : str | sc.Unit, default='meV' + The unit of the energy. By default, 'meV'. + normalize_detailed_balance : bool, default=True + Whether to normalize the detailed balance correction. Default is True. By default, + True. """ super().__init__( energy=energy, @@ -86,9 +78,9 @@ def __init__( def convolution( self, ) -> np.ndarray: - """Calculate the convolution of the sample and resolution models - at the values given in energy. Includes detailed balance - correction if temperature is provided. + """ + Calculate the convolution of the sample and resolution models at the values given in + energy. Includes detailed balance correction if temperature is provided. Returns ------- diff --git a/src/easydynamics/convolution/numerical_convolution_base.py b/src/easydynamics/convolution/numerical_convolution_base.py index d93dc95c..f93a7447 100644 --- a/src/easydynamics/convolution/numerical_convolution_base.py +++ b/src/easydynamics/convolution/numerical_convolution_base.py @@ -25,12 +25,11 @@ class NumericalConvolutionBase(ConvolutionBase): - """Base class for numerical convolutions of sample and resolution - models. + """ + Base class for numerical convolutions of sample and resolution models. - Provides methods to handle upsampling, extension, and detailed - balance correction. This base class has no convolution - functionality. + Provides methods to handle upsampling, extension, and detailed balance correction. This base + class has no convolution functionality. """ def __init__( @@ -46,45 +45,38 @@ def __init__( energy_unit: str | sc.Unit = 'meV', normalize_detailed_balance: bool = True, ) -> None: - """Initialize the NumericalConvolutionBase. + """ + Initialize the NumericalConvolutionBase. Parameters ---------- energy : np.ndarray | sc.Variable - 1D array of energy values - where the convolution is evaluated. + 1D array of energy values where the convolution is evaluated. sample_components : ComponentCollection | ModelComponent The components to be convolved. resolution_components : ComponentCollection | ModelComponent The resolution components to convolve with. - energy_offset : Numeric | Parameter, optional - An energy - offset to apply to the energy values before convolution. By default, 0.0. - upsample_factor : Numeric | None, optional - The factor by which to - upsample the input data before convolution. By default, 5. - extension_factor : Numeric | None, optional - The factor by which to - extend the input data range before convolution. By default, 0.2. - temperature : Parameter | Numeric | None, optional - The temperature to - use for detailed balance correction. By default, None. - temperature_unit : str | sc.Unit, optional - The unit of the - temperature parameter. By default, 'K'. - energy_unit : str | sc.Unit, optional + energy_offset : Numeric | Parameter, default=0.0 + An energy offset to apply to the energy values before convolution. By default, 0.0. + upsample_factor : Numeric | None, default=5 + The factor by which to upsample the input data before convolution. By default, 5. + extension_factor : Numeric | None, default=0.2 + The factor by which to extend the input data range before convolution. By default, 0.2. + temperature : Parameter | Numeric | None, default=None + The temperature to use for detailed balance correction. By default, None. + temperature_unit : str | sc.Unit, default='K' + The unit of the temperature parameter. By default, 'K'. + energy_unit : str | sc.Unit, default='meV' The unit of the energy. By default, 'meV'. - normalize_detailed_balance : bool, optional - Whether to normalize the - detailed balance correction. By default, True. + normalize_detailed_balance : bool, default=True + Whether to normalize the detailed balance correction. By default, True. Raises ------ TypeError : - If temperature is not None, a number, or a - Parameter, or if temperature_unit is not a string or sc.Unit, or if - upsample_factor is not a number or None, or if extension_factor - is not a number, or if normalize_detailed_balance is not a bool. + If temperature is not None, a number, or a Parameter, or if temperature_unit is not a + string or sc.Unit, or if upsample_factor is not a number or None, or if + extension_factor is not a number, or if normalize_detailed_balance is not a bool. """ super().__init__( energy=energy, @@ -115,7 +107,8 @@ def __init__( @ConvolutionBase.energy.setter def energy(self, energy: np.ndarray) -> None: - """Set the energy array and recreate the dense grid. + """ + Set the energy array and recreate the dense grid. Parameters ---------- @@ -128,7 +121,8 @@ def energy(self, energy: np.ndarray) -> None: @property def upsample_factor(self) -> Numeric | None: - """Get the upsample factor. + """ + Get the upsample factor. Returns ------- @@ -140,7 +134,8 @@ def upsample_factor(self) -> Numeric | None: @upsample_factor.setter def upsample_factor(self, factor: Numeric | None) -> None: - """Set the upsample factor and recreate the dense grid. + """ + Set the upsample factor and recreate the dense grid. Parameters ---------- @@ -172,12 +167,11 @@ def upsample_factor(self, factor: Numeric | None) -> None: @property def extension_factor(self) -> float: - """Get the extension factor. + """ + Get the extension factor. - The extension factor determines how much the energy range is - extended on both sides before convolution. - 0.2 means extending by 20% of the original energy span - on each side + The extension factor determines how much the energy range is extended on both sides before + convolution. 0.2 means extending by 20% of the original energy span on each side Returns ------- @@ -189,12 +183,11 @@ def extension_factor(self) -> float: @extension_factor.setter def extension_factor(self, factor: Numeric) -> None: - """Set the extension factor and recreate the dense grid. + """ + Set the extension factor and recreate the dense grid. - The extension factor determines how much the energy range is - extended on both sides before convolution. - 0.2 means extending by 20% of the original energy span - on each side. + The extension factor determines how much the energy range is extended on both sides before + convolution. 0.2 means extending by 20% of the original energy span on each side. Parameters ---------- @@ -220,30 +213,29 @@ def extension_factor(self, factor: Numeric) -> None: @property def temperature(self) -> Parameter | None: - """Get the temperature. + """ + Get the temperature. Returns ------- Parameter | None - The temperature parameter, or None if - detailed balance correction is disabled. + The temperature parameter, or None if detailed balance correction is disabled. """ return self._temperature @temperature.setter def temperature(self, temp: Parameter | Numeric | None) -> None: - """Set the temperature. + """ + Set the temperature. - If None, disables detailed balance - correction and removes the temperature parameter. + If None, disables detailed balance correction and removes the temperature parameter. Parameters ---------- temp : Parameter | Numeric | None - The temperature to set. - The unit will be the same as the existing temperature - parameter if it exists, otherwise 'K'. + The temperature to set. The unit will be the same as the existing temperature parameter + if it exists, otherwise 'K'. Raises ------ @@ -270,7 +262,8 @@ def temperature(self, temp: Parameter | Numeric | None) -> None: @property def normalize_detailed_balance(self) -> bool: - """Get whether to normalize the detailed balance factor. + """ + Get whether to normalize the detailed balance factor. If True, the detailed balance factor is divided by temperature. @@ -284,15 +277,15 @@ def normalize_detailed_balance(self) -> bool: @normalize_detailed_balance.setter def normalize_detailed_balance(self, normalize: bool) -> None: - """Set whether to normalize the detailed balance factor. + """ + Set whether to normalize the detailed balance factor. If True, the detailed balance factor is divided by temperature. Parameters ---------- normalize : bool - Whether to normalize the detailed balance - factor. + Whether to normalize the detailed balance factor. Raises ------ @@ -308,24 +301,22 @@ def normalize_detailed_balance(self, normalize: bool) -> None: def _create_energy_grid( self, ) -> EnergyGrid: - """Create a dense grid by upsampling and extending the energy - array. + """ + Create a dense grid by upsampling and extending the energy array. - If upsample_factor is None, no upsampling or extension is - performed. - This dense grid is used for convolution to improve accuracy. + If upsample_factor is None, no upsampling or extension is performed. This dense grid is + used for convolution to improve accuracy. Raises ------ ValueError : - If energy array is not uniformly spaced when - upsample_factor is None, or if energy array has less than 2 points. + If energy array is not uniformly spaced when upsample_factor is None, or if energy + array has less than 2 points. Returns ------- EnergyGrid - The dense grid created by upsampling and - extending energy. + The dense grid created by upsampling and extending energy. """ if self.upsample_factor is None: # Check if the array is uniformly spaced. @@ -388,21 +379,19 @@ def _check_width_thresholds( model: ComponentCollection | ModelComponent, model_name: str, ) -> None: - """Helper function to check and warn if components are wide - compared to the span of the data, or narrow compared to the - spacing. + """ + Helper function to check and warn if components are wide compared to the span of the data, + or narrow compared to the spacing. In both cases, the convolution accuracy may be compromised. Parameters ---------- model : ComponentCollection | ModelComponent - The model to - check. + The model to check. model_name : str - A string indicating whether the model is a - 'sample model' or 'resolution model' for warning - messages. + A string indicating whether the model is a 'sample model' or 'resolution model' for + warning messages. """ # Handle ComponentCollection or ModelComponent @@ -432,14 +421,13 @@ def _check_width_thresholds( ) def __repr__(self) -> str: - """Return a string representation of the - NumericalConvolutionBase. + """ + Return a string representation of the NumericalConvolutionBase. Returns ------- str - A string representation of the - NumericalConvolutionBase. + A string representation of the NumericalConvolutionBase. """ return ( f'{self.__class__.__name__}(' diff --git a/src/easydynamics/experiment/experiment.py b/src/easydynamics/experiment/experiment.py index dc8cb9c4..2d5a53ab 100644 --- a/src/easydynamics/experiment/experiment.py +++ b/src/easydynamics/experiment/experiment.py @@ -15,11 +15,10 @@ class Experiment(NewBase): - """Holds data from an experiment as a sc.DataArray along with - metadata. + """ + Holds data from an experiment as a sc.DataArray along with metadata. - This is a minimal implementation that will be extended in the - future. + This is a minimal implementation that will be extended in the future. """ def __init__( @@ -28,19 +27,19 @@ def __init__( unique_name: str | None = None, data: sc.DataArray | str | None = None, ) -> None: - """Initialize the Experiment object. + """ + Initialize the Experiment object. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='MyExperiment' Display name of the experiment. By default, 'MyExperiment'. - unique_name : str | None, optional - Unique name of the experiment. If - None, a unique name will be generated. By default, None. - data : sc.DataArray | str | None, optional - Dataset associated with - the experiment. Can be a sc.DataArray or a filename - string to load from. If None, no data is loaded. By default, None. + unique_name : str | None, default=None + Unique name of the experiment. If None, a unique name will be generated. By default, + None. + data : sc.DataArray | str | None, default=None + Dataset associated with the experiment. Can be a sc.DataArray or a filename string to + load from. If None, no data is loaded. By default, None. Raises ------ @@ -74,25 +73,25 @@ def __init__( @property def data(self) -> sc.DataArray | None: - """Get the dataset associated with this experiment. + """ + Get the dataset associated with this experiment. Returns ------- sc.DataArray | None - The dataset associated with this - experiment, or None if no data is loaded. + The dataset associated with this experiment, or None if no data is loaded. """ return self._data @data.setter def data(self, value: sc.DataArray) -> None: - """Set the dataset associated with this experiment. + """ + Set the dataset associated with this experiment. Parameters ---------- value : sc.DataArray - The new dataset to associate with this - experiment. + The new dataset to associate with this experiment. Raises ------ @@ -109,28 +108,27 @@ def data(self, value: sc.DataArray) -> None: @property def binned_data(self) -> sc.DataArray | None: - """Get the binned dataset associated with this experiment. + """ + Get the binned dataset associated with this experiment. Returns ------- sc.DataArray | None - The binned dataset associated with this - experiment, or None if no data is loaded. + The binned dataset associated with this experiment, or None if no data is loaded. """ return self._binned_data @binned_data.setter def binned_data(self, _value: sc.DataArray) -> None: - """Set the binned dataset associated with this experiment. + """ + Set the binned dataset associated with this experiment. - Read- -only property. Use rebin() to rebin the data instead. + Read- only property. Use rebin() to rebin the data instead. Parameters ---------- _value : sc.DataArray - The new binned dataset to associate - with this experiment (ignored). + The new binned dataset to associate with this experiment (ignored). Raises ------ @@ -141,13 +139,13 @@ def binned_data(self, _value: sc.DataArray) -> None: @property def Q(self) -> sc.Variable | None: - """Get the Q values from the dataset. + """ + Get the Q values from the dataset. Returns ------- sc.Variable | None - The Q values from the dataset, or None - if no data is loaded. + The Q values from the dataset, or None if no data is loaded. """ if self._binned_data is None: return None @@ -155,10 +153,10 @@ def Q(self) -> sc.Variable | None: @Q.setter def Q(self, _value: sc.Variable) -> None: - """Set the Q values for the dataset. + """ + Set the Q values for the dataset. - Q is a read-only property -derived from the data, so this setter raises an error. + Q is a read-only property derived from the data, so this setter raises an error. Parameters ---------- @@ -174,13 +172,13 @@ def Q(self, _value: sc.Variable) -> None: @property def energy(self) -> sc.Variable | None: - """Get the energy values from the dataset. + """ + Get the energy values from the dataset. Returns ------- sc.Variable | None - The energy values from the dataset, or - None if no data is loaded. + The energy values from the dataset, or None if no data is loaded. """ if self._binned_data is None: return None @@ -188,10 +186,10 @@ def energy(self) -> sc.Variable | None: @energy.setter def energy(self, _value: sc.Variable) -> None: - """Set the energy values for the dataset. + """ + Set the energy values for the dataset. - Energy is a read-only -property derived from the data, so this setter raises an error. + Energy is a read-only property derived from the data, so this setter raises an error. Parameters ---------- @@ -206,14 +204,14 @@ def energy(self, _value: sc.Variable) -> None: raise AttributeError('energy is a read-only property derived from the data.') def get_masked_energy(self, Q_index: int) -> sc.Variable | None: - """Get the energy values from the dataset, removing points where - the y values or variances are NaN or Inf for the given Q index. + """ + Get the energy values from the dataset, removing points where the y values or variances are + NaN or Inf for the given Q index. Parameters ---------- Q_index : int - The Q index to get the masked energy values - for. + The Q index to get the masked energy values for. Raises ------ @@ -223,8 +221,7 @@ def get_masked_energy(self, Q_index: int) -> sc.Variable | None: Returns ------- sc.Variable | None - The masked energy values from the - dataset, or None if no data is loaded. + The masked energy values from the dataset, or None if no data is loaded. """ if self._binned_data is None: return None @@ -247,21 +244,21 @@ def get_masked_energy(self, Q_index: int) -> sc.Variable | None: ########### def load_hdf5(self, filename: str, display_name: str | None = None) -> None: - """Load data from an HDF5 file. + """ + Load data from an HDF5 file. Parameters ---------- filename : str Path to the HDF5 file. - display_name : str | None, optional - Optional display name for the - experiment. By default, None. + display_name : str | None, default=None + Optional display name for the experiment. By default, None. Raises ------ TypeError : - If filename is not a string or if display_name is - not a string or None or if the loaded data is not a sc.DataArray. + If filename is not a string or if display_name is not a string or None or if the loaded + data is not a sc.DataArray. """ if not isinstance(filename, str): raise TypeError(f'Filename must be a string, not {type(filename).__name__}') @@ -282,13 +279,13 @@ def load_hdf5(self, filename: str, display_name: str | None = None) -> None: self.data = loaded_data def save_hdf5(self, filename: str | None = None) -> None: - """Save the dataset to HDF5. + """ + Save the dataset to HDF5. Parameters ---------- - filename : str | None, optional - Path to the output HDF5 file. - If None, the file will be named after the unique_name of + filename : str | None, default=None + Path to the output HDF5 file. If None, the file will be named after the unique_name of the experiment with a .h5 extension. By default, None. Raises @@ -318,20 +315,19 @@ def remove_data(self) -> None: self._binned_data = None def rebin(self, dimensions: dict[str, int | sc.Variable]) -> None: - """Rebin the dataset along specified dimensions. + """ + Rebin the dataset along specified dimensions. Parameters ---------- dimensions : dict[str, int | sc.Variable] - A dictionary - mapping dimension names to number of bins (int) or bin - edges (sc.Variable). + A dictionary mapping dimension names to number of bins (int) or bin edges + (sc.Variable). Raises ------ TypeError : - If dimensions is not a dictionary or if - keys/values are of incorrect types. + If dimensions is not a dictionary or if keys/values are of incorrect types. ValueError : If there is no data to rebin. KeyError : @@ -378,11 +374,12 @@ def rebin(self, dimensions: dict[str, int | sc.Variable]) -> None: ########### def plot_data(self, slicer: bool = False, **kwargs: dict) -> None: - """Plot the dataset using plopp: https://scipp.github.io/plopp/. + """ + Plot the dataset using plopp: https://scipp.github.io/plopp/. Parameters ---------- - slicer : bool, optional + slicer : bool, default=False If True, use plopp's slicer instead of plot. By default, False. **kwargs : dict Additional keyword arguments to pass to plopp. @@ -431,7 +428,8 @@ def plot_data(self, slicer: bool = False, **kwargs: dict) -> None: @staticmethod def _validate_coordinates(data: sc.DataArray) -> None: - """Validate that required coordinates are present in the data. + """ + Validate that required coordinates are present in the data. Parameters ---------- @@ -454,7 +452,8 @@ def _validate_coordinates(data: sc.DataArray) -> None: raise ValueError(f"Data is missing required coordinate: '{coord}'") def _convert_to_bin_centers(self, data: sc.DataArray) -> sc.DataArray: - """Convert the coordinates of the data to bin centers. + """ + Convert the coordinates of the data to bin centers. Parameters ---------- @@ -474,8 +473,8 @@ def _convert_to_bin_centers(self, data: sc.DataArray) -> sc.DataArray: return data def _extract_x_y_var(self, Q_index: int) -> tuple[np.ndarray, np.ndarray, np.ndarray]: - """Extract the x, y, and weights arrays from the experiment for - the given Q index. + """ + Extract the x, y, and weights arrays from the experiment for the given Q index. Parameters ---------- @@ -485,9 +484,7 @@ def _extract_x_y_var(self, Q_index: int) -> tuple[np.ndarray, np.ndarray, np.nda Returns ------- tuple[np.ndarray, np.ndarray, np.ndarray] - The x, y, and - variances arrays extracted from the experiment for the - given Q index. + The x, y, and variances arrays extracted from the experiment for the given Q index. """ data = self.binned_data['Q', Q_index] x = data.coords['energy'].values @@ -498,8 +495,9 @@ def _extract_x_y_var(self, Q_index: int) -> tuple[np.ndarray, np.ndarray, np.nda def _extract_x_y_weights_only_finite( self, Q_index: int ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: - """Extract the x, y, and weights arrays from the experiment for - the given Q index, removing any NaN and Inf values. + """ + Extract the x, y, and weights arrays from the experiment for the given Q index, removing + any NaN and Inf values. Parameters ---------- @@ -509,16 +507,14 @@ def _extract_x_y_weights_only_finite( Raises ------ ValueError : - If any variances are zero after removing NaNs - and Infs, since this would lead to infinite weights. + If any variances are zero after removing NaNs and Infs, since this would lead to + infinite weights. Returns ------- tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray] - The - x, y, weights, and mask arrays extracted from the - experiment for the given Q index, with NaNs and Infs - removed. + The x, y, weights, and mask arrays extracted from the experiment for the given Q index, + with NaNs and Infs removed. """ x, y, var = self._extract_x_y_var(Q_index) @@ -546,7 +542,8 @@ def _extract_x_y_weights_only_finite( ########### def __repr__(self) -> str: - """Return a string representation of the Experiment object. + """ + Return a string representation of the Experiment object. Returns ------- @@ -557,11 +554,12 @@ def __repr__(self) -> str: return f'Experiment `{self.unique_name}` with data: {self._data}' def __copy__(self) -> 'Experiment': - """Return a copy of the object. + """ + Return a copy of the object. Returns ------- - Experiment + 'Experiment' A copy of the Experiment object. """ temp = self.to_dict(skip=['unique_name']) diff --git a/src/easydynamics/sample_model/background_model.py b/src/easydynamics/sample_model/background_model.py index 860b5218..bd538a6b 100644 --- a/src/easydynamics/sample_model/background_model.py +++ b/src/easydynamics/sample_model/background_model.py @@ -11,8 +11,8 @@ class BackgroundModel(ModelBase): - """BackgroundModel represents a model of the background in an - experiment at various Q. + """ + BackgroundModel represents a model of the background in an experiment at various Q. """ def __init__( @@ -23,24 +23,22 @@ def __init__( components: ModelComponent | ComponentCollection | None = None, Q: Q_type | None = None, ) -> None: - """Initialize the BackgroundModel. + """ + Initialize the BackgroundModel. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='MyBackgroundModel' Display name of the model. By default, 'MyBackgroundModel'. - unique_name : str | None, optional - Unique name of the model. If None, - a unique name will be generated. By default, None. - unit : str | sc.Unit, optional + unique_name : str | None, default=None + Unique name of the model. If None, a unique name will be generated. By default, None. + unit : str | sc.Unit, default='meV' Unit of the model. By default, 'meV'. - components : ModelComponent | ComponentCollection | None, optional - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. By default, None. - Q : Q_type | None, optional - Q values for the model. If None, Q is not - set. By default, None. + components : ModelComponent | ComponentCollection | None, default=None + Template components of the model. If None, no components are added. These components + are copied into ComponentCollections for each Q value. By default, None. + Q : Q_type | None, default=None + Q values for the model. If None, Q is not set. By default, None. """ super().__init__( display_name=display_name, diff --git a/src/easydynamics/sample_model/component_collection.py b/src/easydynamics/sample_model/component_collection.py index 39997eba..966d9916 100644 --- a/src/easydynamics/sample_model/component_collection.py +++ b/src/easydynamics/sample_model/component_collection.py @@ -17,8 +17,8 @@ class ComponentCollection(ModelBase): - """Collection of model components representing a sample, background - or resolution model. + """ + Collection of model components representing a sample, background or resolution model. """ def __init__( @@ -28,26 +28,24 @@ def __init__( unique_name: str | None = None, components: list[ModelComponent] | None = None, ) -> None: - """Initialize a new ComponentCollection. + """ + Initialize a new ComponentCollection. Parameters ---------- - unit : str | sc.Unit, optional + unit : str | sc.Unit, default='meV' Unit of the collection. By default, 'meV'. - display_name : str | None, optional - Display - name of the collection. By default, 'MyComponentCollection'. - unique_name : str | None, optional + display_name : str | None, default='MyComponentCollection' + Display name of the collection. By default, 'MyComponentCollection'. + unique_name : str | None, default=None Unique name of the collection. By default, None. - components : list[ModelComponent] | None, optional - Initial model - components to add to the ComponentCollection. By default, None. + components : list[ModelComponent] | None, default=None + Initial model components to add to the ComponentCollection. By default, None. Raises ------ TypeError : - If unit is not a string or sc.Unit, - or if components is not a list of ModelComponent. + If unit is not a string or sc.Unit, or if components is not a list of ModelComponent. """ super().__init__(display_name=display_name, unique_name=unique_name) @@ -72,7 +70,8 @@ def __init__( @property def components(self) -> list[ModelComponent]: - """Get the list of components in the collection. + """ + Get the list of components in the collection. Returns ------- @@ -84,13 +83,13 @@ def components(self) -> list[ModelComponent]: @components.setter def components(self, components: list[ModelComponent]) -> None: - """Set the list of components in the collection. + """ + Set the list of components in the collection. Parameters ---------- components : list[ModelComponent] - The new list of - components. + The new list of components. Raises ------ @@ -111,20 +110,20 @@ def components(self, components: list[ModelComponent]) -> None: @property def is_empty(self) -> bool: - """Check if the ComponentCollection has no components. + """ + Check if the ComponentCollection has no components. Returns ------- bool - True if the collection has no components, - False otherwise. + True if the collection has no components, False otherwise. """ return not self._components @is_empty.setter def is_empty(self, _value: bool) -> None: - """Is_empty is a read-only property that indicates whether the - collection has components. + """ + Is_empty is a read-only property that indicates whether the collection has components. Parameters ---------- @@ -143,19 +142,20 @@ def is_empty(self, _value: bool) -> None: @property def unit(self) -> str | sc.Unit | None: - """Get the unit of the ComponentCollection. + """ + Get the unit of the ComponentCollection. Returns ------- str | sc.Unit | None - The unit of the ComponentCollection, - which is the same as the unit of its components. + The unit of the ComponentCollection, which is the same as the unit of its components. """ return self._unit @unit.setter def unit(self, _unit_str: str) -> None: - """Unit is read-only and cannot be set directly. + """ + Unit is read-only and cannot be set directly. Parameters ---------- @@ -174,8 +174,8 @@ def unit(self, _unit_str: str) -> None: ) # noqa: E501 def convert_unit(self, unit: str | sc.Unit) -> None: - """Convert the unit of the ComponentCollection and all its - components. + """ + Convert the unit of the ComponentCollection and all its components. Parameters ---------- @@ -187,8 +187,7 @@ def convert_unit(self, unit: str | sc.Unit) -> None: TypeError : If unit is not a string or sc.Unit. Exception : - If any component cannot be converted to the - specified unit. + If any component cannot be converted to the specified unit. """ if not isinstance(unit, (str, sc.Unit)): @@ -214,24 +213,22 @@ def convert_unit(self, unit: str | sc.Unit) -> None: # ------------------------------------------------------------------ def append_component(self, component: ModelComponent | ComponentCollection) -> None: - """Append a model component or the components from another - ComponentCollection to this ComponentCollection. + """ + Append a model component or the components from another ComponentCollection to this + ComponentCollection. Parameters ---------- component : ModelComponent | ComponentCollection - The component - to append. If a ComponentCollection is provided, all of its - components will be appended. + The component to append. If a ComponentCollection is provided, all of its components + will be appended. Raises ------ TypeError : - If component is not a ModelComponent or - ComponentCollection. + If component is not a ModelComponent or ComponentCollection. ValueError : - If a component with the same unique name already - exists in the collection. + If a component with the same unique name already exists in the collection. """ if not isinstance(component, (ModelComponent, ComponentCollection)): raise TypeError( @@ -253,7 +250,8 @@ def append_component(self, component: ModelComponent | ComponentCollection) -> N self._components.append(comp) def remove_component(self, unique_name: str) -> None: - """Remove a component from the collection by its unique name. + """ + Remove a component from the collection by its unique name. Parameters ---------- @@ -265,8 +263,7 @@ def remove_component(self, unique_name: str) -> None: TypeError : If unique_name is not a string. KeyError : - If no component with the given unique name exists - in the collection. + If no component with the given unique name exists in the collection. """ if not isinstance(unique_name, str): @@ -285,7 +282,8 @@ def remove_component(self, unique_name: str) -> None: @property def components(self) -> list[ModelComponent]: - """Get the list of components in the collection. + """ + Get the list of components in the collection. Returns ------- @@ -296,7 +294,8 @@ def components(self) -> list[ModelComponent]: @components.setter def components(self, components: list[ModelComponent]) -> None: - """Set the components in the collection. + """ + Set the components in the collection. Parameters ---------- @@ -321,8 +320,8 @@ def components(self, components: list[ModelComponent]) -> None: @property def is_empty(self) -> bool: - """Returns True if the collection has no components, otherwise - False. + """ + Returns True if the collection has no components, otherwise False. Returns ------- @@ -333,7 +332,8 @@ def is_empty(self) -> bool: @is_empty.setter def is_empty(self, _value: bool) -> None: - """Is_empty is read-only. + """ + Is_empty is read-only. Parameters ---------- @@ -351,13 +351,13 @@ def is_empty(self, _value: bool) -> None: ) def list_component_names(self) -> list[str]: - """List the names of all components in the model. + """ + List the names of all components in the model. Returns ------- list[str] - List of unique names of the components in the - collection. + List of unique names of the components in the collection. """ return [component.unique_name for component in self._components] @@ -367,17 +367,16 @@ def clear_components(self) -> None: self._components.clear() def normalize_area(self) -> None: - """Normalize the areas of all components so they sum to 1. + """ + Normalize the areas of all components so they sum to 1. - This -is useful for convolutions. + This is useful for convolutions. Raises ------ ValueError : - If there are no components in the model or - if the total area is zero or not finite, which - would prevent normalization. + If there are no components in the model or if the total area is zero or not finite, + which would prevent normalization. """ if not self.components: raise ValueError('No components in the model to normalize.') @@ -411,7 +410,8 @@ def normalize_area(self) -> None: # ------------------------------------------------------------------ def get_all_variables(self) -> list[DescriptorBase]: - """Get all parameters from the model component. + """ + Get all parameters from the model component. Returns ------- @@ -422,7 +422,8 @@ def get_all_variables(self) -> list[DescriptorBase]: return [var for component in self.components for var in component.get_all_variables()] def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: - """Evaluate the sum of all components. + """ + Evaluate the sum of all components. Parameters ---------- @@ -444,7 +445,8 @@ def evaluate_component( x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray, unique_name: str, ) -> np.ndarray: - """Evaluate a single component by name. + """ + Evaluate a single component by name. Parameters ---------- @@ -460,8 +462,7 @@ def evaluate_component( TypeError : If unique_name is not a string. KeyError : - If no component with the given unique name exists - in the collection. + If no component with the given unique name exists in the collection. Returns ------- @@ -499,14 +500,13 @@ def free_all_parameters(self) -> None: # ------------------------------------------------------------------ def __contains__(self, item: str | ModelComponent) -> bool: - """Check if a component with the given name or instance exists - in the ComponentCollection. + """ + Check if a component with the given name or instance exists in the ComponentCollection. Parameters ---------- item : str | ModelComponent - The component name or instance - to check for. + The component name or instance to check for. Returns ------- @@ -523,7 +523,8 @@ def __contains__(self, item: str | ModelComponent) -> bool: return False def __repr__(self) -> str: - """Return a string representation of the ComponentCollection. + """ + Return a string representation of the ComponentCollection. Returns ------- diff --git a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py index 64ade714..ebc70f60 100644 --- a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py +++ b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py @@ -14,15 +14,11 @@ class DampedHarmonicOscillator(CreateParametersMixin, ModelComponent): - r"""Model of a Damped Harmonic Oscillator (DHO). - - The intensity is given by - $$ - I(x) = \frac{2 A x_0^2 \gamma}{\pi \left( (x^2 - x_0^2)^2 + - (2 \gamma x)^2 \right)}, - $$ - where $A$ is the area, $x_0$ is the center, and $\gamma$ is the - width. + r""" + Model of a Damped Harmonic Oscillator (DHO). + + The intensity is given by $$ I(x) = \frac{2 A x_0^2 \gamma}{\pi \left( (x^2 - x_0^2)^2 + (2 + \gamma x)^2 \right)}, $$ where $A$ is the area, $x_0$ is the center, and $\gamma$ is the width. """ def __init__( @@ -34,25 +30,25 @@ def __init__( display_name: str | None = 'DampedHarmonicOscillator', unique_name: str | None = None, ) -> None: - """Initialize the Damped Harmonic Oscillator. + """ + Initialize the Damped Harmonic Oscillator. Parameters ---------- - area : Numeric | Parameter, optional + area : Numeric | Parameter, default=1.0 Area under the curve. By default, 1.0. - center : Numeric | Parameter, optional - Resonance frequency, approximately the - peak position. By default, 1.0. - width : Numeric | Parameter, optional - Damping constant, approximately the - half width at half max (HWHM) of the peaks. By default, 1.0. - unit : str | sc.Unit, optional + center : Numeric | Parameter, default=1.0 + Resonance frequency, approximately the peak position. By default, 1.0. + width : Numeric | Parameter, default=1.0 + Damping constant, approximately the half width at half max (HWHM) of the peaks. By + default, 1.0. + unit : str | sc.Unit, default='meV' Unit of the parameters. By default, 'meV'. - display_name : str | None, optional + display_name : str | None, default='DampedHarmonicOscillator' Display name of the component. By default, 'DampedHarmonicOscillator'. - unique_name : str | None, optional - Unique name of the component. - If None, a unique_name is automatically generated. By default, None. + unique_name : str | None, default=None + Unique name of the component. If None, a unique_name is automatically generated. By + default, None. """ super().__init__( @@ -79,7 +75,8 @@ def __init__( @property def area(self) -> Parameter: - """Get the area parameter. + """ + Get the area parameter. Returns ------- @@ -90,7 +87,8 @@ def area(self) -> Parameter: @area.setter def area(self, value: Numeric) -> None: - """Set the value of the area parameter. + """ + Set the value of the area parameter. Parameters ---------- @@ -108,7 +106,8 @@ def area(self, value: Numeric) -> None: @property def center(self) -> Parameter: - """Get the center parameter. + """ + Get the center parameter. Returns ------- @@ -119,7 +118,8 @@ def center(self) -> Parameter: @center.setter def center(self, value: Numeric) -> None: - """Set the value of the center parameter. + """ + Set the value of the center parameter. Parameters ---------- @@ -142,7 +142,8 @@ def center(self, value: Numeric) -> None: @property def width(self) -> Parameter: - """Get the width parameter. + """ + Get the width parameter. Returns ------- @@ -153,7 +154,8 @@ def width(self) -> Parameter: @width.setter def width(self, value: Numeric) -> None: - """Set the value of the width parameter. + """ + Set the value of the width parameter. Parameters ---------- @@ -176,17 +178,12 @@ def width(self, value: Numeric) -> None: self._width.value = value def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: - r"""Evaluate the Damped Harmonic Oscillator at the given x - values. - - If x is a scipp Variable, the unit of the DHO will be converted - to match x. The intensity is given by - $$ - I(x) = \frac{2 A x_0^2 \gamma}{\pi \left( (x^2 - x_0^2)^2 + - (2 \gamma x)^2 \right)}, - $$ - where $A$ is the area, $x_0$ is the center, and $\gamma$ is the - width. + r""" + Evaluate the Damped Harmonic Oscillator at the given x values. + + If x is a scipp Variable, the unit of the DHO will be converted to match x. The intensity + is given by $$ I(x) = \frac{2 A x_0^2 \gamma}{\pi \left( (x^2 - x_0^2)^2 + (2 \gamma x)^2 + \right)}, $$ where $A$ is the area, $x_0$ is the center, and $\gamma$ is the width. Parameters ---------- @@ -208,14 +205,13 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) return self.area.value * normalization / (denominator) def __repr__(self) -> str: - """Return a string representation of the Damped Harmonic - Oscillator. + """ + Return a string representation of the Damped Harmonic Oscillator. Returns ------- str - A string representation of the Damped Harmonic - Oscillator. + A string representation of the Damped Harmonic Oscillator. """ return ( f'DampedHarmonicOscillator(display_name = {self.display_name}, unit = {self._unit},\n \ diff --git a/src/easydynamics/sample_model/components/delta_function.py b/src/easydynamics/sample_model/components/delta_function.py index dcbd4f6c..213073f8 100644 --- a/src/easydynamics/sample_model/components/delta_function.py +++ b/src/easydynamics/sample_model/components/delta_function.py @@ -16,12 +16,12 @@ class DeltaFunction(CreateParametersMixin, ModelComponent): - """Delta function. + """ + Delta function. - Evaluates to zero everywhere, except in convolutions, where it acts - as an identity. This is handled by the Convolution method. If the - center is not provided, it will be centered at 0 and fixed, which is - typically what you want in QENS. + Evaluates to zero everywhere, except in convolutions, where it acts as an identity. This is + handled by the Convolution method. If the center is not provided, it will be centered at 0 and + fixed, which is typically what you want in QENS. """ def __init__( @@ -32,22 +32,22 @@ def __init__( display_name: str | None = 'DeltaFunction', unique_name: str | None = None, ) -> None: - """Initialize the Delta function. + """ + Initialize the Delta function. Parameters ---------- - center : Numeric | Parameter | None, optional - Center of the delta function. - If None. By default, None. - area : Numeric | Parameter, optional + center : Numeric | Parameter | None, default=None + Center of the delta function. If None. By default, None. + area : Numeric | Parameter, default=1.0 Total area under the curve. By default, 1.0. - unit : str | sc.Unit, optional + unit : str | sc.Unit, default='meV' Unit of the parameters. By default, 'meV'. - display_name : str | None, optional + display_name : str | None, default='DeltaFunction' Name of the component. By default, 'DeltaFunction'. - unique_name : str | None, optional - Unique name of the component. - If None, a unique_name is automatically generated. By default, None. + unique_name : str | None, default=None + Unique name of the component. If None, a unique_name is automatically generated. By + default, None. """ # Validate inputs and create Parameters if not given super().__init__( @@ -67,7 +67,8 @@ def __init__( @property def area(self) -> Parameter: - """Get the area parameter. + """ + Get the area parameter. Returns ------- @@ -79,7 +80,8 @@ def area(self) -> Parameter: @area.setter def area(self, value: Numeric) -> None: - """Set the value of the area parameter. + """ + Set the value of the area parameter. Parameters ---------- @@ -98,7 +100,8 @@ def area(self, value: Numeric) -> None: @property def center(self) -> Parameter: - """Get the center parameter. + """ + Get the center parameter. Returns ------- @@ -110,13 +113,13 @@ def center(self) -> Parameter: @center.setter def center(self, value: Numeric | None) -> None: - """Set the center parameter value. + """ + Set the center parameter value. Parameters ---------- - value : Numeric | None, optional - The new value for the center - parameter. If None. By default, 0 and is fixed. + value : Numeric | None + The new value for the center parameter. If None. By default, 0 and is fixed. Raises ------ @@ -132,11 +135,11 @@ def center(self, value: Numeric | None) -> None: self._center.value = value def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: - """Evaluate the Delta function at the given x values. + """ + Evaluate the Delta function at the given x values. - The Delta function evaluates to zero everywhere, except at the - center. Its numerical integral is equal to the area. It acts as - an identity in convolutions. + The Delta function evaluates to zero everywhere, except at the center. Its numerical + integral is equal to the area. It acts as an identity in convolutions. Parameters ---------- @@ -146,8 +149,7 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) Returns ------- np.ndarray - The evaluated Delta function at the given x - values. + The evaluated Delta function at the given x values. """ # x assumed sorted, 1D numpy array @@ -180,7 +182,8 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) return model def __repr__(self) -> str: - """Return a string representation of the Delta function. + """ + Return a string representation of the Delta function. Returns ------- diff --git a/src/easydynamics/sample_model/components/exponential.py b/src/easydynamics/sample_model/components/exponential.py index 9889aea5..70157f1d 100644 --- a/src/easydynamics/sample_model/components/exponential.py +++ b/src/easydynamics/sample_model/components/exponential.py @@ -14,14 +14,14 @@ class Exponential(CreateParametersMixin, ModelComponent): - r"""Model of an exponential function. + r""" + Model of an exponential function. The intensity is given by $$ I(x) = A e^{B (x-x_0)}, $$ - where $A$ is the amplitude, $x_0$ is the center, and $B$ describes - the rate of decay or growth. + where $A$ is the amplitude, $x_0$ is the center, and $B$ describes the rate of decay or growth. """ def __init__( @@ -33,32 +33,30 @@ def __init__( display_name: str | None = 'Exponential', unique_name: str | None = None, ) -> None: - """Initialize the Exponential component. + """ + Initialize the Exponential component. Parameters ---------- - amplitude : Numeric | Parameter, optional - Amplitude of the - Exponential. By default, 1.0. - center : Numeric | Parameter | None, optional - Center of the Exponential. - If None, the center is fixed at 0. By default, None. - rate : Numeric | Parameter, optional - Decay or growth - constant of the Exponential. By default, 1.0. - unit : str | sc.Unit, optional + amplitude : Numeric | Parameter, default=1.0 + Amplitude of the Exponential. By default, 1.0. + center : Numeric | Parameter | None, default=None + Center of the Exponential. If None, the center is fixed at + 0. By default, None. + rate : Numeric | Parameter, default=1.0 + Decay or growth constant of the Exponential. By default, 1.0. + unit : str | sc.Unit, default='meV' Unit of the parameters. By default, 'meV'. - display_name : str | None, optional + display_name : str | None, default='Exponential' Name of the component. By default, 'Exponential'. - unique_name : str | None, optional - Unique name of the component. if - None, a unique_name is automatically generated. By default, None. + unique_name : str | None, default=None + Unique name of the component. if None, a unique_name is automatically generated. By + default, None. Raises ------ TypeError : - If amplitude, center, or rate are not numbers or - Parameters. + If amplitude, center, or rate are not numbers or Parameters. ValueError : If amplitude, center or rate are not finite numbers. """ @@ -99,7 +97,8 @@ def __init__( @property def amplitude(self) -> Parameter: - """Get the amplitude parameter. + """ + Get the amplitude parameter. Returns ------- @@ -111,7 +110,8 @@ def amplitude(self) -> Parameter: @amplitude.setter def amplitude(self, value: Numeric) -> None: - """Set the value of the amplitude parameter. + """ + Set the value of the amplitude parameter. Parameters ---------- @@ -130,7 +130,8 @@ def amplitude(self, value: Numeric) -> None: @property def center(self) -> Parameter: - """Get the center parameter. + """ + Get the center parameter. Returns ------- @@ -142,13 +143,13 @@ def center(self) -> Parameter: @center.setter def center(self, value: Numeric | None) -> None: - """Set the center parameter value. + """ + Set the center parameter value. Parameters ---------- value : Numeric | None - The new value for the center - parameter. + The new value for the center parameter. Raises ------ @@ -166,7 +167,8 @@ def center(self, value: Numeric | None) -> None: @property def rate(self) -> Parameter: - """Get the rate parameter. + """ + Get the rate parameter. Returns ------- @@ -177,13 +179,13 @@ def rate(self) -> Parameter: @rate.setter def rate(self, value: Numeric) -> None: - """Set the rate parameter value. + """ + Set the rate parameter value. Parameters ---------- value : Numeric - The new value for the rate - parameter. + The new value for the rate parameter. Raises ------ @@ -199,17 +201,13 @@ def evaluate( self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray, ) -> np.ndarray: - r"""Evaluate the Exponential at the given x values. + r""" + Evaluate the Exponential at the given x values. - If x is a scipp Variable, the unit of the Exponential will be - converted to match x. - The intensity is given by - $$ - I(x) = A \exp\left( r (x - x_0) \right) - $$ + If x is a scipp Variable, the unit of the Exponential will be converted to match x. The + intensity is given by $$ I(x) = A \exp\left( r (x - x_0) \right) $$ - where $A$ is the amplitude, $x_0$ is the center, and $r$ is the - rate. + where $A$ is the amplitude, $x_0$ is the center, and $r$ is the rate. Parameters ---------- @@ -219,8 +217,7 @@ def evaluate( Returns ------- np.ndarray - The intensity of the Exponential at the given x - values. + The intensity of the Exponential at the given x values. """ x = self._prepare_x_for_evaluate(x) @@ -229,7 +226,8 @@ def evaluate( return self.amplitude.value * np.exp(exponent) def convert_unit(self, unit: str | sc.Unit) -> None: - """Convert the unit of the Parameters in the component. + """ + Convert the unit of the Parameters in the component. Parameters ---------- @@ -265,7 +263,8 @@ def convert_unit(self, unit: str | sc.Unit) -> None: raise e def __repr__(self) -> str: - """Return a string representation of the Exponential. + """ + Return a string representation of the Exponential. Returns ------- diff --git a/src/easydynamics/sample_model/components/expression_component.py b/src/easydynamics/sample_model/components/expression_component.py index 6adb4f8d..878d8671 100644 --- a/src/easydynamics/sample_model/components/expression_component.py +++ b/src/easydynamics/sample_model/components/expression_component.py @@ -14,16 +14,13 @@ class ExpressionComponent(ModelComponent): - """Model component defined by a symbolic expression. + """ + Model component defined by a symbolic expression. - Example: - expr = ExpressionComponent( - "A * exp(-(x - x0)**2 / (2*sigma**2))", - parameters={"A": 10, "x0": 0, "sigma": 1}, - ) + Example: expr = ExpressionComponent( "A * exp(-(x - x0)**2 / (2*sigma**2))", parameters={"A": + 10, "x0": 0, "sigma": 1}, ) - expr.A = 5 - y = expr.evaluate(x) + expr.A = 5 y = expr.evaluate(x) """ # ------------------------- @@ -77,20 +74,20 @@ def __init__( display_name: str | None = 'Expression', unique_name: str | None = None, ) -> None: - """Initialize the ExpressionComponent. + """ + Initialize the ExpressionComponent. Parameters ---------- expression : str - The symbolic expression as a string. - Must contain 'x' as the independent variable. - parameters : dict[str, Numeric] | None, optional + The symbolic expression as a string. Must contain 'x' as the independent variable. + parameters : dict[str, Numeric] | None, default=None Dictionary of parameter names and their initial values. By default, None. - unit : str | sc.Unit, optional + unit : str | sc.Unit, default='meV' Unit of the output. By default, 'meV'. - display_name : str | None, optional + display_name : str | None, default='Expression' Display name for the component. By default, 'Expression'. - unique_name : str | None, optional + unique_name : str | None, default=None Unique name for the component. By default, None. Raises @@ -194,7 +191,8 @@ def expression(self) -> str: @expression.setter def expression(self, _new_expr: str) -> None: - """Prevent changing the expression after initialization. + """ + Prevent changing the expression after initialization. Parameters ---------- @@ -212,7 +210,8 @@ def evaluate( self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray, ) -> np.ndarray: - """Evaluate the expression for given x values. + """ + Evaluate the expression for given x values. Parameters ---------- @@ -236,7 +235,8 @@ def evaluate( return self._func(*args) def get_all_variables(self) -> list[Parameter]: - """Return all parameters. + """ + Return all parameters. Returns ------- @@ -246,7 +246,8 @@ def get_all_variables(self) -> list[Parameter]: return list(self._parameters.values()) def convert_unit(self, _new_unit: str | sc.Unit) -> None: - """Convert the unit of the expression. + """ + Convert the unit of the expression. Unit conversion is not implemented for ExpressionComponent. @@ -268,7 +269,8 @@ def convert_unit(self, _new_unit: str | sc.Unit) -> None: # ------------------------- def __getattr__(self, name: str) -> Parameter: - """Allow access to parameters as attributes. + """ + Allow access to parameters as attributes. Parameters ---------- @@ -290,7 +292,8 @@ def __getattr__(self, name: str) -> Parameter: raise AttributeError(f"{self.__class__.__name__} has no attribute '{name}'") def __setattr__(self, name: str, value: Numeric) -> None: - """Allow setting parameter values as attributes. + """ + Allow setting parameter values as attributes. Parameters ---------- @@ -316,8 +319,8 @@ def __setattr__(self, name: str, value: Numeric) -> None: super().__setattr__(name, value) def __dir__(self) -> list[str]: - """Include parameter names in dir() output for better IDE - support. + """ + Include parameter names in dir() output for better IDE support. Returns ------- diff --git a/src/easydynamics/sample_model/components/gaussian.py b/src/easydynamics/sample_model/components/gaussian.py index 02097788..b5067865 100644 --- a/src/easydynamics/sample_model/components/gaussian.py +++ b/src/easydynamics/sample_model/components/gaussian.py @@ -14,23 +14,18 @@ class Gaussian(CreateParametersMixin, ModelComponent): - r"""Model of a Gaussian function. + r""" + Model of a Gaussian function. The intensity is given by - $$ - I(x) = \frac{A}{\sigma \sqrt{2\pi}} - \exp\left( - -\frac{1}{2} - \left(\frac{x - x_0}{\sigma}\right)^2 - \right) - $$ + $$ I(x) = \frac{A}{\sigma \sqrt{2\pi}} \exp\left( -\frac{1}{2} \left(\frac{x - + x_0}{\sigma}\right)^2 \right) $$ - where $A$ is the area, $x_0$ is the center, and $\sigma$ is the - width. + where $A$ is the area, $x_0$ is the center, and $\sigma$ is the width. - If the center is not provided, it will be centered at 0 and - fixed, which is typically what you want in QENS. + If the center is not provided, it will be centered at 0 and fixed, which is typically what you + want in QENS. """ def __init__( @@ -42,24 +37,24 @@ def __init__( display_name: str | None = 'Gaussian', unique_name: str | None = None, ) -> None: - """Initialize the Gaussian component. + """ + Initialize the Gaussian component. Parameters ---------- - area : Numeric | Parameter, optional + area : Numeric | Parameter, default=1.0 Area of the Gaussian. By default, 1.0. - center : Numeric | Parameter | None, optional - Center of the - Gaussian. If None. By default, None. - width : Numeric | Parameter, optional + center : Numeric | Parameter | None, default=None + Center of the Gaussian. If None. By default, None. + width : Numeric | Parameter, default=1.0 Standard deviation. By default, 1.0. - unit : str | sc.Unit, optional + unit : str | sc.Unit, default='meV' Unit of the parameters. By default, 'meV'. - display_name : str | None, optional + display_name : str | None, default='Gaussian' Name of the component. By default, 'Gaussian'. - unique_name : str | None, optional - Unique name of the component. - if None, a unique_name is automatically generated. By default, None. + unique_name : str | None, default=None + Unique name of the component. if None, a unique_name is automatically generated. By + default, None. """ # Validate inputs and create Parameters if not given super().__init__( @@ -81,7 +76,8 @@ def __init__( @property def area(self) -> Parameter: - """Get the area parameter. + """ + Get the area parameter. Returns ------- @@ -93,7 +89,8 @@ def area(self) -> Parameter: @area.setter def area(self, value: Numeric) -> None: - """Set the value of the area parameter. + """ + Set the value of the area parameter. Parameters ---------- @@ -112,7 +109,8 @@ def area(self, value: Numeric) -> None: @property def center(self) -> Parameter: - """Get the center parameter. + """ + Get the center parameter. Returns ------- @@ -124,13 +122,13 @@ def center(self) -> Parameter: @center.setter def center(self, value: Numeric | None) -> None: - """Set the center parameter value. + """ + Set the center parameter value. Parameters ---------- - value : Numeric | None, optional - The new value for the center - parameter. If None. By default, 0 and is fixed. + value : Numeric | None + The new value for the center parameter. If None. By default, 0 and is fixed. Raises ------ @@ -147,7 +145,8 @@ def center(self, value: Numeric | None) -> None: @property def width(self) -> Parameter: - """Get the width parameter (standard deviation). + """ + Get the width parameter (standard deviation). Returns ------- @@ -158,13 +157,13 @@ def width(self) -> Parameter: @width.setter def width(self, value: Numeric) -> None: - """Set the width parameter value. + """ + Set the width parameter value. Parameters ---------- value : Numeric - The new value for the width - parameter. + The new value for the width parameter. Raises ------ @@ -185,21 +184,14 @@ def evaluate( self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray, ) -> np.ndarray: - r"""Evaluate the Gaussian at the given x values. - - If x is a scipp Variable, the unit of the Gaussian will be - converted to match x. - The intensity is given by - $$ - I(x) = \frac{A}{\sigma \sqrt{2\pi}} - \exp\left( - -\frac{1}{2} - \left(\frac{x - x_0}{\sigma}\right)^2 - \right) - $$ - - where $A$ is the area, $x_0$ is the center, and $\sigma$ is the - width. + r""" + Evaluate the Gaussian at the given x values. + + If x is a scipp Variable, the unit of the Gaussian will be converted to match x. The + intensity is given by $$ I(x) = \frac{A}{\sigma \sqrt{2\pi}} \exp\left( -\frac{1}{2} + \left(\frac{x - x_0}{\sigma}\right)^2 \right) $$ + + where $A$ is the area, $x_0$ is the center, and $\sigma$ is the width. Parameters ---------- @@ -209,8 +201,7 @@ def evaluate( Returns ------- np.ndarray - The intensity of the Gaussian at the given x - values. + The intensity of the Gaussian at the given x values. """ x = self._prepare_x_for_evaluate(x) @@ -221,7 +212,8 @@ def evaluate( return self.area.value * normalization * np.exp(exponent) def __repr__(self) -> str: - """Return a string representation of the Gaussian. + """ + Return a string representation of the Gaussian. Returns ------- diff --git a/src/easydynamics/sample_model/components/lorentzian.py b/src/easydynamics/sample_model/components/lorentzian.py index bffeada1..dab0c4fc 100644 --- a/src/easydynamics/sample_model/components/lorentzian.py +++ b/src/easydynamics/sample_model/components/lorentzian.py @@ -14,17 +14,15 @@ class Lorentzian(CreateParametersMixin, ModelComponent): - r"""Model of a Lorentzian function. + r""" + Model of a Lorentzian function. - The intensity is given by - $$ - I(x) = \frac{A}{\pi} \frac{\Gamma}{(x - x_0)^2 + \Gamma^2}, - $$ - where $A$ is the area, $x_0$ is the center, and $\Gamma$ is the - half width at half maximum (HWHM). + The intensity is given by $$ I(x) = \frac{A}{\pi} \frac{\Gamma}{(x - x_0)^2 + \Gamma^2}, $$ + where $A$ is the area, $x_0$ is the center, and $\Gamma$ is the half width at half maximum + (HWHM). - If the center is not provided, it will be centered at 0 - and fixed, which is typically what you want in QENS. + If the center is not provided, it will be centered at 0 and fixed, which is typically what you + want in QENS. """ def __init__( @@ -36,25 +34,24 @@ def __init__( display_name: str | None = 'Lorentzian', unique_name: str | None = None, ) -> None: - """Initialize the Lorentzian component. + """ + Initialize the Lorentzian component. Parameters ---------- - area : Numeric | Parameter, optional + area : Numeric | Parameter, default=1.0 Area of the Lorentzian. By default, 1.0. - center : Numeric | Parameter | None, optional - Center of the - Lorentzian. If None. By default, None. - width : Numeric | Parameter, optional - Half width at half maximum - (HWHM). By default, 1.0. - unit : str | sc.Unit, optional + center : Numeric | Parameter | None, default=None + Center of the Lorentzian. If None. By default, None. + width : Numeric | Parameter, default=1.0 + Half width at half maximum (HWHM). By default, 1.0. + unit : str | sc.Unit, default='meV' Unit of the parameters. By default, 'meV'. - display_name : str | None, optional + display_name : str | None, default='Lorentzian' Name of the component. By default, 'Lorentzian'. - unique_name : str | None, optional - Unique name of the component. If - None, a unique_name is automatically generated. By default, None. + unique_name : str | None, default=None + Unique name of the component. If None, a unique_name is automatically generated. By + default, None. """ super().__init__( @@ -76,7 +73,8 @@ def __init__( @property def area(self) -> Parameter: - """Get the area parameter. + """ + Get the area parameter. Returns ------- @@ -87,7 +85,8 @@ def area(self) -> Parameter: @area.setter def area(self, value: Numeric) -> None: - """Set the value of the area parameter. + """ + Set the value of the area parameter. Parameters ---------- @@ -105,7 +104,8 @@ def area(self, value: Numeric) -> None: @property def center(self) -> Parameter: - """Get the center parameter. + """ + Get the center parameter. Returns ------- @@ -116,13 +116,13 @@ def center(self) -> Parameter: @center.setter def center(self, value: Numeric | None) -> None: - """Set the value of the center parameter. + """ + Set the value of the center parameter. Parameters ---------- - value : Numeric | None, optional - The new value for the center - parameter. If None. By default, 0 and is fixed. + value : Numeric | None + The new value for the center parameter. If None. By default, 0 and is fixed. Raises ------ @@ -139,7 +139,8 @@ def center(self, value: Numeric | None) -> None: @property def width(self) -> Parameter: - """Get the width parameter (HWHM). + """ + Get the width parameter (HWHM). Returns ------- @@ -150,13 +151,13 @@ def width(self) -> Parameter: @width.setter def width(self, value: Numeric) -> None: - """Set the width parameter value (HWHM). + """ + Set the width parameter value (HWHM). Parameters ---------- value : Numeric - The new value for the width - parameter. + The new value for the width parameter. Raises ------ @@ -173,18 +174,16 @@ def width(self, value: Numeric) -> None: self._width.value = value def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: - r"""Evaluate the Lorentzian at the given x values. + r""" + Evaluate the Lorentzian at the given x values. - If x is a scipp Variable, the unit of the Lorentzian will be - converted to match x. The intensity is given by + If x is a scipp Variable, the unit of the Lorentzian will be converted to match x. The + intensity is given by - $$ - I(x) = \frac{A}{\pi} \frac{\Gamma}{(x - - x_0)^2 + \Gamma^2}, - $$ + $$ I(x) = \frac{A}{\pi} \frac{\Gamma}{(x - x_0)^2 + \Gamma^2}, $$ - where $A$ is the area, $x_0$ is the center, and $\Gamma$ is - the half width at half maximum (HWHM). + where $A$ is the area, $x_0$ is the center, and $\Gamma$ is the half width at half maximum + (HWHM). Parameters ---------- @@ -194,8 +193,7 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) Returns ------- np.ndarray - The intensity of the Lorentzian at the given x - values. + The intensity of the Lorentzian at the given x values. """ x = self._prepare_x_for_evaluate(x) @@ -206,7 +204,8 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) return self.area.value * normalization / denominator def __repr__(self) -> str: - """Return a string representation of the Lorentzian. + """ + Return a string representation of the Lorentzian. Returns ------- diff --git a/src/easydynamics/sample_model/components/mixins.py b/src/easydynamics/sample_model/components/mixins.py index 3bd07e67..a7217566 100644 --- a/src/easydynamics/sample_model/components/mixins.py +++ b/src/easydynamics/sample_model/components/mixins.py @@ -15,12 +15,11 @@ class CreateParametersMixin: - """Provides parameter creation and validation methods for model - components. + """ + Provides parameter creation and validation methods for model components. - This mixin provides methods to create and validate common physics - parameters (area, center, width) with appropriate bounds and type - checking. + This mixin provides methods to create and validate common physics parameters (area, center, + width) with appropriate bounds and type checking. """ def _create_area_parameter( @@ -30,12 +29,11 @@ def _create_area_parameter( unit: str | sc.Unit = 'meV', minimum_area: float = MINIMUM_AREA, ) -> Parameter: - """Validate and convert a number to a Parameter describing the - area of a function. + """ + Validate and convert a number to a Parameter describing the area of a function. - If the area is negative, a warning is raised. - If the area is non-negative, its minimum is set to 0 to avoid it - accidentally becoming negative during fitting. + If the area is negative, a warning is raised. If the area is non-negative, its minimum is + set to 0 to avoid it accidentally becoming negative during fitting. Parameters ---------- @@ -43,9 +41,9 @@ def _create_area_parameter( The area value or Parameter. name : str The name of the model component. - unit : str | sc.Unit, optional + unit : str | sc.Unit, default='meV' The unit of the area Parameter. By default, 'meV'. - minimum_area : float, optional + minimum_area : float, default=MINIMUM_AREA The minimum allowed area. By default, MINIMUM_AREA. Raises @@ -53,8 +51,7 @@ def _create_area_parameter( TypeError : If area is not a number or a Parameter. ValueError : - If area is not a finite number or if the area - Parameter has a non-finite value. + If area is not a finite number or if the area Parameter has a non-finite value. Returns ------- @@ -89,34 +86,30 @@ def _create_center_parameter( unit: str | sc.Unit = 'meV', enforce_minimum_center: bool = False, ) -> Parameter: - """Validate and convert a number to a Parameter describing the - center of a function. + """ + Validate and convert a number to a Parameter describing the center of a function. Parameters ---------- center : Numeric | Parameter | None - The center value or - Parameter. + The center value or Parameter. name : str The name of the model component. fix_if_none : bool - Whether to fix the center Parameter - if center is None. - unit : str | sc.Unit, optional - The unit of the center - Parameter. By default, 'meV'. - enforce_minimum_center : bool, optional - Whether to - enforce a minimum center value to avoid zero center in - DHO. By default, False. + Whether to fix the center Parameter if center is None. + unit : str | sc.Unit, default='meV' + The unit of the center Parameter. By default, 'meV'. + enforce_minimum_center : bool, default=False + Whether to enforce a minimum center value to avoid zero center in DHO. By default, + False. Raises ------ TypeError : If center is not None, a number, or a Parameter. ValueError : - If center is a number but not finite, or if - center is a Parameter but has a non-finite value. + If center is a number but not finite, or if center is a Parameter but has a non-finite + value. Returns ------- @@ -150,8 +143,8 @@ def _create_width_parameter( unit: str | sc.Unit = 'meV', minimum_width: float = MINIMUM_WIDTH, ) -> Parameter: - """Validate and convert a number to a Parameter describing the - width of a function. + """ + Validate and convert a number to a Parameter describing the width of a function. Parameters ---------- @@ -159,13 +152,12 @@ def _create_width_parameter( The width value or Parameter. name : str The name of the model component. - param_name : str, optional + param_name : str, default='width' The name of the width parameter. By default, 'width'. - unit : str | sc.Unit, optional + unit : str | sc.Unit, default='meV' The unit of the width Parameter. By default, 'meV'. - minimum_width : float, optional - The minimum - allowed width. By default, MINIMUM_WIDTH. + minimum_width : float, default=MINIMUM_WIDTH + The minimum allowed width. By default, MINIMUM_WIDTH. Raises ------ diff --git a/src/easydynamics/sample_model/components/model_component.py b/src/easydynamics/sample_model/components/model_component.py index 4778bea6..1b5ccf4e 100644 --- a/src/easydynamics/sample_model/components/model_component.py +++ b/src/easydynamics/sample_model/components/model_component.py @@ -23,18 +23,17 @@ def __init__( display_name: str | None = None, unique_name: str | None = None, ) -> None: - """Initialize the ModelComponent. + """ + Initialize the ModelComponent. Parameters ---------- - unit : str | sc.Unit, optional + unit : str | sc.Unit, default='meV' The unit of the model component. By default, 'meV'. - display_name : str | None, optional - A human-readable name for the - component. By default, None. - unique_name : str | None, optional - A unique identifier for the - component. By default, None. + display_name : str | None, default=None + A human-readable name for the component. By default, None. + unique_name : str | None, default=None + A unique identifier for the component. By default, None. """ self.validate_unit(unit) super().__init__(display_name=display_name, unique_name=unique_name) @@ -42,7 +41,8 @@ def __init__( @property def unit(self) -> str: - """Get the unit. + """ + Get the unit. Returns ------- @@ -53,11 +53,11 @@ def unit(self) -> str: @unit.setter def unit(self, _unit_str: str) -> None: - """Unit is read-only. + """ + Unit is read-only. - Use convert_unit to change the unit -between allowed types or create a new ModelComponent with the - desired unit. + Use convert_unit to change the unit between allowed types or create a new ModelComponent + with the desired unit. Parameters ---------- @@ -89,8 +89,8 @@ def free_all_parameters(self) -> None: def _prepare_x_for_evaluate( self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray ) -> np.ndarray: - """Prepare the input x for evaluation by handling units and - converting to a numpy array. + """ + Prepare the input x for evaluation by handling units and converting to a numpy array. Parameters ---------- @@ -100,11 +100,10 @@ def _prepare_x_for_evaluate( Raises ------ ValueError : - If x contains NaN or infinite values, or if a - sc.DataArray has more than one coordinate. + If x contains NaN or infinite values, or if a sc.DataArray has more than one + coordinate. UnitError : - If x has incompatible units that cannot be - converted to the component's unit. + If x has incompatible units that cannot be converted to the component's unit. Returns ------- @@ -166,7 +165,8 @@ def _prepare_x_for_evaluate( @staticmethod def validate_unit(unit: str | sc.Unit | None) -> None: - """Validate that the unit is either a string or a scipp Unit. + """ + Validate that the unit is either a string or a scipp Unit. Parameters ---------- @@ -184,7 +184,8 @@ def validate_unit(unit: str | sc.Unit | None) -> None: ) def convert_unit(self, unit: str | sc.Unit) -> None: - """Convert the unit of the Parameters in the component. + """ + Convert the unit of the Parameters in the component. Parameters ---------- @@ -196,8 +197,7 @@ def convert_unit(self, unit: str | sc.Unit) -> None: TypeError : If the provided unit is not a str or sc.Unit. Exception : - If the provided unit is invalid or incompatible - with the component's parameters. + If the provided unit is invalid or incompatible with the component's parameters. """ if not isinstance(unit, (str, sc.Unit)): raise TypeError(f'Unit must be a string or sc.Unit, got {type(unit).__name__}') @@ -220,7 +220,8 @@ def convert_unit(self, unit: str | sc.Unit) -> None: @abstractmethod def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: - """Abstract method to evaluate the model component at input x. + """ + Abstract method to evaluate the model component at input x. Must be implemented by subclasses. @@ -237,7 +238,8 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) pass def __repr__(self) -> str: - """Return a string representation of the ModelComponent. + """ + Return a string representation of the ModelComponent. Returns ------- diff --git a/src/easydynamics/sample_model/components/polynomial.py b/src/easydynamics/sample_model/components/polynomial.py index 7d4033d6..9f73a28d 100644 --- a/src/easydynamics/sample_model/components/polynomial.py +++ b/src/easydynamics/sample_model/components/polynomial.py @@ -18,13 +18,11 @@ class Polynomial(ModelComponent): - r"""Polynomial function component. + r""" + Polynomial function component. - The intensity is given by - $$ - I(x) = c_0 + c_1 x + c_2 x^2 + ... + c_N x^N, - $$ - where $C_i$ are the coefficients. + The intensity is given by $$ I(x) = c_0 + c_1 x + c_2 x^2 + ... + c_N x^N, $$ where $C_i$ are + the coefficients. """ def __init__( @@ -34,29 +32,26 @@ def __init__( display_name: str | None = 'Polynomial', unique_name: str | None = None, ) -> None: - """Initialize the Polynomial component. + """ + Initialize the Polynomial component. Parameters ---------- - coefficients : Sequence[Numeric | Parameter], optional + coefficients : Sequence[Numeric | Parameter], default=(0.0,) Coefficients c0, c1, ..., cN. By default, (0.0,). - unit : str | sc.Unit, optional - Unit of the Polynomial - component. By default, 'meV'. - display_name : str | None, optional - Display - name of the Polynomial component. By default, 'Polynomial'. - unique_name : str | None, optional - Unique name of the - component. If None, a unique_name is automatically - generated. By default, None. + unit : str | sc.Unit, default='meV' + Unit of the Polynomial component. By default, 'meV'. + display_name : str | None, default='Polynomial' + Display name of the Polynomial component. By default, 'Polynomial'. + unique_name : str | None, default=None + Unique name of the component. If None, a unique_name is automatically generated. By + default, None. Raises ------ TypeError : - If coefficients is not a sequence of numbers or - Parameters or if any item in coefficients is not a - number or Parameter. + If coefficients is not a sequence of numbers or Parameters or if any item in + coefficients is not a number or Parameter. ValueError : If coefficients is an empty sequence. """ @@ -91,8 +86,8 @@ def __init__( @property def coefficients(self) -> list[Parameter]: - """Get the coefficients of the polynomial as a list of - Parameters. + """ + Get the coefficients of the polynomial as a list of Parameters. Returns ------- @@ -103,24 +98,23 @@ def coefficients(self) -> list[Parameter]: @coefficients.setter def coefficients(self, coeffs: Sequence[Numeric | Parameter]) -> None: - """Set the coefficients of the polynomial. + """ + Set the coefficients of the polynomial. Length must match current number of coefficients. Parameters ---------- coeffs : Sequence[Numeric | Parameter] - New coefficients as - a sequence of numbers or Parameters. + New coefficients as a sequence of numbers or Parameters. Raises ------ TypeError : - If coeffs is not a sequence of numbers or - Parameters or if any item in coeffs is not a number or Parameter. + If coeffs is not a sequence of numbers or Parameters or if any item in coeffs is not a + number or Parameter. ValueError : - If the length of coeffs does not match the - existing number of coefficients. + If the length of coeffs does not match the existing number of coefficients. """ if not isinstance(coeffs, (list, tuple, np.ndarray)): raise TypeError( @@ -140,7 +134,8 @@ def coefficients(self, coeffs: Sequence[Numeric | Parameter]) -> None: raise TypeError('Each coefficient must be either a numeric value or a Parameter.') def coefficient_values(self) -> list[float]: - """Get the coefficients of the polynomial as a list. + """ + Get the coefficients of the polynomial as a list. Returns ------- @@ -150,13 +145,11 @@ def coefficient_values(self) -> list[float]: return [param.value for param in self._coefficients] def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: - r"""Evaluate the Polynomial at the given x values. + r""" + Evaluate the Polynomial at the given x values. - The intensity is given by - $$ - I(x) = c_0 + c_1 x + c_2 x^2 + ... + c_N x^N, - $$ - where $C_i$ are the coefficients. + The intensity is given by $$ I(x) = c_0 + c_1 x + c_2 x^2 + ... + + c_N x^N, $$ where $C_i$ are the coefficients. Parameters ---------- @@ -166,8 +159,7 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) Returns ------- np.ndarray - The evaluated Polynomial at the given x - values. + The evaluated Polynomial at the given x values. """ x = self._prepare_x_for_evaluate(x) @@ -187,7 +179,8 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) @property def degree(self) -> int: - """Get the degree of the polynomial. + """ + Get the degree of the polynomial. Returns ------- @@ -198,8 +191,8 @@ def degree(self) -> int: @degree.setter def degree(self, _value: int) -> None: - """The degree is determined by the number of coefficients and - cannot be set directly. + """ + The degree is determined by the number of coefficients and cannot be set directly. Parameters ---------- @@ -209,8 +202,7 @@ def degree(self, _value: int) -> None: Raises ------ AttributeError : - Always raised since degree cannot be set - directly. + Always raised since degree cannot be set directly. """ raise AttributeError( 'The degree of the polynomial is determined by the number of coefficients ' @@ -218,7 +210,8 @@ def degree(self, _value: int) -> None: ) def get_all_variables(self) -> list[DescriptorBase]: - """Get all variables from the model component. + """ + Get all variables from the model component. Returns ------- @@ -228,7 +221,8 @@ def get_all_variables(self) -> list[DescriptorBase]: return list(self._coefficients) def convert_unit(self, unit: str | sc.Unit) -> None: - """Convert the unit of the polynomial. + """ + Convert the unit of the polynomial. Parameters ---------- @@ -257,7 +251,8 @@ def convert_unit(self, unit: str | sc.Unit) -> None: self._unit = unit def __repr__(self) -> str: - """Return a string representation of the Polynomial. + """ + Return a string representation of the Polynomial. Returns ------- diff --git a/src/easydynamics/sample_model/components/voigt.py b/src/easydynamics/sample_model/components/voigt.py index 61ab2aa9..60fa7c64 100644 --- a/src/easydynamics/sample_model/components/voigt.py +++ b/src/easydynamics/sample_model/components/voigt.py @@ -15,11 +15,11 @@ class Voigt(CreateParametersMixin, ModelComponent): - r"""Voigt profile, a convolution of Gaussian and Lorentzian. + r""" + Voigt profile, a convolution of Gaussian and Lorentzian. - If the -center is not provided, it will be centered at 0 and fixed, which is - typically what you want in QENS. + If the center is not provided, it will be centered at 0 and fixed, which is typically what you + want in QENS. Use scipy.special.voigt_profile to evaluate the Voigt profile. """ @@ -34,27 +34,26 @@ def __init__( display_name: str | None = 'Voigt', unique_name: str | None = None, ) -> None: - """Initialize a Voigt component. + """ + Initialize a Voigt component. Parameters ---------- - area : Numeric | Parameter, optional + area : Numeric | Parameter, default=1.0 Total area under the curve. By default, 1.0. - center : Numeric | Parameter | None, optional + center : Numeric | Parameter | None, default=None Center of the Voigt profile. By default, None. - gaussian_width : Numeric | Parameter, optional - Standard deviation of the - Gaussian part. By default, 1.0. - lorentzian_width : Numeric | Parameter, optional - Half width at half max - (HWHM) of the Lorentzian part. By default, 1.0. - unit : str | sc.Unit, optional + gaussian_width : Numeric | Parameter, default=1.0 + Standard deviation of the Gaussian part. By default, 1.0. + lorentzian_width : Numeric | Parameter, default=1.0 + Half width at half max (HWHM) of the Lorentzian part. By default, 1.0. + unit : str | sc.Unit, default='meV' Unit of the parameters. By default, 'meV'. - display_name : str | None, optional + display_name : str | None, default='Voigt' Display name of the component. By default, 'Voigt'. - unique_name : str | None, optional - Unique name of the component. - If None, a unique_name is automatically generated. By default, None. + unique_name : str | None, default=None + Unique name of the component. If None, a unique_name is automatically generated. By + default, None. """ super().__init__( @@ -88,7 +87,8 @@ def __init__( @property def area(self) -> Parameter: - """Get the area parameter. + """ + Get the area parameter. Returns ------- @@ -99,7 +99,8 @@ def area(self) -> Parameter: @area.setter def area(self, value: Numeric) -> None: - """Set the value of the area parameter. + """ + Set the value of the area parameter. Parameters ---------- @@ -117,7 +118,8 @@ def area(self, value: Numeric) -> None: @property def center(self) -> Parameter: - """Get the center parameter. + """ + Get the center parameter. Returns ------- @@ -128,13 +130,13 @@ def center(self) -> Parameter: @center.setter def center(self, value: Numeric | None) -> None: - """Set the value of the center parameter. + """ + Set the value of the center parameter. Parameters ---------- - value : Numeric | None, optional - The new value for the center - parameter. If None. By default, 0 and is fixed. + value : Numeric | None + The new value for the center parameter. If None. By default, 0 and is fixed. Raises ------ @@ -150,7 +152,8 @@ def center(self, value: Numeric | None) -> None: @property def gaussian_width(self) -> Parameter: - """Get the Gaussian width parameter. + """ + Get the Gaussian width parameter. Returns ------- @@ -161,13 +164,13 @@ def gaussian_width(self) -> Parameter: @gaussian_width.setter def gaussian_width(self, value: Numeric) -> None: - """Set the width parameter value. + """ + Set the width parameter value. Parameters ---------- value : Numeric - The new value for the width - parameter. + The new value for the width parameter. Raises ------ @@ -184,7 +187,8 @@ def gaussian_width(self, value: Numeric) -> None: @property def lorentzian_width(self) -> Parameter: - """Get the Lorentzian width parameter (HWHM). + """ + Get the Lorentzian width parameter (HWHM). Returns ------- @@ -195,13 +199,13 @@ def lorentzian_width(self) -> Parameter: @lorentzian_width.setter def lorentzian_width(self, value: Numeric) -> None: - """Set the value of the Lorentzian width parameter. + """ + Set the value of the Lorentzian width parameter. Parameters ---------- value : Numeric - The new value for the Lorentzian width - parameter. + The new value for the Lorentzian width parameter. Raises ------ @@ -217,13 +221,12 @@ def lorentzian_width(self, value: Numeric) -> None: self._lorentzian_width.value = value def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) -> np.ndarray: - r"""Evaluate the Voigt at the given x values. + r""" + Evaluate the Voigt at the given x values. - If x is a scipp Variable, the unit of the Voigt will be - converted to match x. The Voigt evaluates to the convolution of - a Gaussian with sigma gaussian_width and a Lorentzian with half - width at half max lorentzian_width, centered at center, with - area equal to area. + If x is a scipp Variable, the unit of the Voigt will be converted to match x. The Voigt + evaluates to the convolution of a Gaussian with sigma gaussian_width and a Lorentzian with + half width at half max lorentzian_width, centered at center, with area equal to area. Parameters ---------- @@ -233,8 +236,7 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) Returns ------- np.ndarray - The intensity of the Voigt at the given x - values. + The intensity of the Voigt at the given x values. """ x = self._prepare_x_for_evaluate(x) @@ -246,7 +248,8 @@ def evaluate(self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray) ) def __repr__(self) -> str: - """Return a string representation of the Voigt. + """ + Return a string representation of the Voigt. Returns ------- diff --git a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py index 547baab5..0848e88e 100644 --- a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py @@ -18,24 +18,20 @@ class BrownianTranslationalDiffusion(DiffusionModelBase): - r"""Model of Brownian translational diffusion, consisting of a - Lorentzian function for each Q-value, where the width is given by $D - Q^2$, where $D$ is the diffusion coefficient. The area of the - Lorentzians is given by the scale parameter multiplied by the QISF, - which is 1 for this model. The EISF is 0 for this model, so there is - no delta function component. Q is assumed to have units of - 1/angstrom. Creates ComponentCollections with Lorentzian components - for given Q-values. - - Example: - >>>Q=np.linspace(0.5,2,7) - >>>energy=np.linspace(-2, 2, 501) - >>>scale=1.0 + r""" + Model of Brownian translational diffusion, consisting of a Lorentzian function for each + Q-value, where the width is given by $D Q^2$, where $D$ is the diffusion coefficient. The area + of the Lorentzians is given by the scale parameter multiplied by the QISF, which is 1 for this + model. The EISF is 0 for this model, so there is no delta function component. Q is assumed to + have units of 1/angstrom. Creates ComponentCollections with Lorentzian components for given + Q-values. + + Example: >>>Q=np.linspace(0.5,2,7) >>>energy=np.linspace(-2, 2, 501) >>>scale=1.0 >>>diffusion_coefficient = 2.4e-9 # m^2/s >>>diffusion_model=BrownianTranslationalDiffusion(display_name="DiffusionModel", >>>scale=scale, diffusion_coefficient= diffusion_coefficient) - >>>component_collections=diffusion_model.create_component_collections(Q) - See also the tutorials. + >>>component_collections=diffusion_model.create_component_collections(Q) See also the + tutorials. """ def __init__( @@ -46,30 +42,27 @@ def __init__( scale: Numeric = 1.0, diffusion_coefficient: Numeric = 1.0, ) -> None: - """Initialize a new BrownianTranslationalDiffusion model. + """ + Initialize a new BrownianTranslationalDiffusion model. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='BrownianTranslationalDiffusion' Display name of the diffusion model. By default, 'BrownianTranslationalDiffusion'. - unique_name : str | None, optional - Unique name of the diffusion - model. If None, a unique name will be generated. By default, None. - unit : str | sc.Unit, optional - Unit of the diffusion model. Must be - convertible to meV. By default, 'meV'. - scale : Numeric, optional - Scale factor for the diffusion model. Must - be a non-negative number. By default, 1.0. - diffusion_coefficient : Numeric, optional - Diffusion coefficient D in - m^2/s. By default, 1.0. + unique_name : str | None, default=None + Unique name of the diffusion model. If None, a unique name will be generated. By + default, None. + unit : str | sc.Unit, default='meV' + Unit of the diffusion model. Must be convertible to meV. By default, 'meV'. + scale : Numeric, default=1.0 + Scale factor for the diffusion model. Must be a non-negative number. By default, 1.0. + diffusion_coefficient : Numeric, default=1.0 + Diffusion coefficient D in m^2/s. By default, 1.0. Raises ------ TypeError : - If scale or diffusion_coefficient is not a - number. + If scale or diffusion_coefficient is not a number. """ if not isinstance(scale, Numeric): raise TypeError('scale must be a number.') @@ -100,7 +93,8 @@ def __init__( @property def diffusion_coefficient(self) -> Parameter: - """Get the diffusion coefficient parameter D. + """ + Get the diffusion coefficient parameter D. Returns ------- @@ -111,13 +105,13 @@ def diffusion_coefficient(self) -> Parameter: @diffusion_coefficient.setter def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: - """Set the diffusion coefficient parameter D. + """ + Set the diffusion coefficient parameter D. Parameters ---------- diffusion_coefficient : Numeric - The new value for the - diffusion coefficient D in m^2/s. + The new value for the diffusion coefficient D in m^2/s. Raises ------ @@ -138,8 +132,8 @@ def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: # ------------------------------------------------------------------ def calculate_width(self, Q: Q_type) -> np.ndarray: - """Calculate the half-width at half-maximum (HWHM) for the - diffusion model. + """ + Calculate the half-width at half-maximum (HWHM) for the diffusion model. Parameters ---------- @@ -149,8 +143,7 @@ def calculate_width(self, Q: Q_type) -> np.ndarray: Returns ------- np.ndarray - HWHM values in the unit of the model - (e.g., meV). + HWHM values in the unit of the model (e.g., meV). """ Q = _validate_and_convert_Q(Q) @@ -160,14 +153,14 @@ def calculate_width(self, Q: Q_type) -> np.ndarray: return Q**2 * unit_conversion_factor.value def calculate_EISF(self, Q: Q_type) -> np.ndarray: - """Calculate the Elastic Incoherent Structure Factor (EISF) for - the Brownian translational diffusion model. + """ + Calculate the Elastic Incoherent Structure Factor (EISF) for the Brownian translational + diffusion model. Parameters ---------- Q : Q_type - Scattering - vector in 1/angstrom. + Scattering vector in 1/angstrom. Returns ------- @@ -178,8 +171,8 @@ def calculate_EISF(self, Q: Q_type) -> np.ndarray: return np.zeros_like(Q) def calculate_QISF(self, Q: Q_type) -> np.ndarray: - """Calculate the Quasi-Elastic Incoherent Structure Factor - (QISF). + """ + Calculate the Quasi-Elastic Incoherent Structure Factor (QISF). Parameters ---------- @@ -200,14 +193,15 @@ def create_component_collections( Q: Q_type, component_display_name: str = 'Brownian diffusion', ) -> list[ComponentCollection]: - r"""Create ComponentCollection components for the Brownian - translational diffusion model at given Q values. + r""" + Create ComponentCollection components for the Brownian translational diffusion model at + given Q values. Parameters ---------- Q : Q_type Scattering vector values. - component_display_name : str, optional + component_display_name : str, default='Brownian diffusion' Name of the Lorentzian component. By default, 'Brownian diffusion'. Raises @@ -218,11 +212,9 @@ def create_component_collections( Returns ------- list[ComponentCollection] - List of ComponentCollections with - Lorentzian components for each Q value. Each Lorentzian - has a width given by $D*Q^2$ and an area given by the - scale parameter multiplied by the QISF (which is 1 for - this model). + List of ComponentCollections with Lorentzian components for each Q value. Each + Lorentzian has a width given by $D*Q^2$ and an area given by the scale parameter + multiplied by the QISF (which is 1 for this model). """ Q = _validate_and_convert_Q(Q) @@ -273,8 +265,9 @@ def create_component_collections( # ------------------------------------------------------------------ def _write_width_dependency_expression(self, Q: float) -> str: - """Write the dependency expression for the width as a function - of Q to make dependent Parameters. + """ + Write the dependency expression for the width as a function of Q to make dependent + Parameters. Parameters ---------- @@ -298,8 +291,8 @@ def _write_width_dependency_expression(self, Q: float) -> str: return f'hbar * D* {Q} **2*1/(angstrom**2)' def _write_width_dependency_map_expression(self) -> dict[str, DescriptorNumber]: - """Write the dependency map expression to make dependent - Parameters. + """ + Write the dependency map expression to make dependent Parameters. Returns ------- @@ -313,8 +306,8 @@ def _write_width_dependency_map_expression(self) -> dict[str, DescriptorNumber]: } def _write_area_dependency_expression(self, QISF: float) -> str: - """Write the dependency expression for the area to make - dependent Parameters. + """ + Write the dependency expression for the area to make dependent Parameters. Parameters ---------- @@ -337,8 +330,8 @@ def _write_area_dependency_expression(self, QISF: float) -> str: return f'{QISF} * scale' def _write_area_dependency_map_expression(self) -> dict[str, DescriptorNumber]: - """Write the dependency map expression to make dependent - Parameters. + """ + Write the dependency map expression to make dependent Parameters. Returns ------- @@ -354,14 +347,13 @@ def _write_area_dependency_map_expression(self) -> dict[str, DescriptorNumber]: # ------------------------------------------------------------------ def __repr__(self) -> str: - """String representation of the BrownianTranslationalDiffusion - model. + """ + String representation of the BrownianTranslationalDiffusion model. Returns ------- str - String representation of the - BrownianTranslationalDiffusion model. + String representation of the BrownianTranslationalDiffusion model. """ return ( f'BrownianTranslationalDiffusion(display_name={self.display_name},' diff --git a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py index 32843579..9956d300 100644 --- a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py +++ b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py @@ -20,29 +20,27 @@ def __init__( scale: Numeric = 1.0, unit: str | sc.Unit = 'meV', ) -> None: - """Initialize a new DiffusionModel. + """ + Initialize a new DiffusionModel. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='MyDiffusionModel' Display name of the diffusion model. By default, 'MyDiffusionModel'. - unique_name : str | None, optional - Unique name of the diffusion - model. If None, a unique name will be generated. By default, None. - scale : Numeric, optional - Scale factor for the diffusion model. Must - be a non-negative number. By default, 1.0. - unit : str | sc.Unit, optional - Unit of the diffusion model. Must be - convertible to meV. By default, 'meV'. + unique_name : str | None, default=None + Unique name of the diffusion model. If None, a unique name will be generated. By + default, None. + scale : Numeric, default=1.0 + Scale factor for the diffusion model. Must be a non-negative number. By default, 1.0. + unit : str | sc.Unit, default='meV' + Unit of the diffusion model. Must be convertible to meV. By default, 'meV'. Raises ------ TypeError : If scale is not a number. UnitError : - If unit is not a string or scipp Unit, or if it - cannot be converted to meV. + If unit is not a string or scipp Unit, or if it cannot be converted to meV. """ try: @@ -68,7 +66,8 @@ def __init__( @property def unit(self) -> str | sc.Unit | None: - """Get the unit of the energy axis of the DiffusionModel. + """ + Get the unit of the energy axis of the DiffusionModel. Returns ------- @@ -79,11 +78,10 @@ def unit(self) -> str | sc.Unit | None: @unit.setter def unit(self, _unit_str: str) -> None: - """The unit of the energy axis is read-only. + """ + The unit of the energy axis is read-only. - To change the unit, -use convert_unit or create a new DiffusionModel with the desired - unit. + To change the unit, use convert_unit or create a new DiffusionModel with the desired unit. Parameters ---------- @@ -102,7 +100,8 @@ def unit(self, _unit_str: str) -> None: @property def scale(self) -> Parameter: - """Get the scale parameter of the diffusion model. + """ + Get the scale parameter of the diffusion model. Returns ------- @@ -113,13 +112,13 @@ def scale(self) -> Parameter: @scale.setter def scale(self, scale: Numeric) -> None: - """Set the scale parameter of the diffusion model. + """ + Set the scale parameter of the diffusion model. Parameters ---------- scale : Numeric - The new value for the scale parameter. Must - be a non-negative number. + The new value for the scale parameter. Must be a non-negative number. Raises ------ @@ -140,7 +139,8 @@ def scale(self, scale: Numeric) -> None: # ------------------------------------------------------------------ def __repr__(self) -> str: - """String representation of the Diffusion model. + """ + String representation of the Diffusion model. Returns ------- diff --git a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py index 6493b19a..cf6d4101 100644 --- a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py @@ -18,31 +18,22 @@ class JumpTranslationalDiffusion(DiffusionModelBase): - r"""Model of Jump translational diffusion. - - The model consists of a -Lorentzian function for each Q-value, where the width is given by - - $$ - \Gamma(Q) = \frac{Q^2}{1+D t Q^2}. - $$ - - where $D$ is the diffusion coefficient and $t$ is the relaxation - time. Q is assumed to have units of 1/angstrom. Creates - ComponentCollections with Lorentzian components for given Q-values. - - Example: - >>> Q = np.linspace(0.5, 2, 7) - >>> energy = np.linspace(-2, 2, 501) - >>> scale = 1.0 - >>> diffusion_coefficient = 2.4e-9 # m^2/s - >>> relaxation_time = 1.0 # ps - >>> diffusion_model=JumpTranslationalDiffusion( - >>> scale = scale, diffusion_coefficient = (diffusion_coefficient,) - >>> relaxation_time=relaxation_time) - >>> component_collections= - >>> diffusion_model.create_component_collections(Q) - See also the tutorials.. + r""" + Model of Jump translational diffusion. + + The model consists of a Lorentzian function for each Q-value, where the width is given by + + $$ \Gamma(Q) = \frac{Q^2}{1+D t Q^2}. $$ + + where $D$ is the diffusion coefficient and $t$ is the relaxation time. Q is assumed to have + units of 1/angstrom. Creates ComponentCollections with Lorentzian components for given + Q-values. + + Example: >>> Q = np.linspace(0.5, 2, 7) >>> energy = np.linspace(-2, 2, 501) >>> scale = 1.0 + >>> diffusion_coefficient = 2.4e-9 # m^2/s >>> relaxation_time = 1.0 # ps >>> + diffusion_model=JumpTranslationalDiffusion( >>> scale = scale, diffusion_coefficient = + (diffusion_coefficient,) >>> relaxation_time=relaxation_time) >>> component_collections= >>> + diffusion_model.create_component_collections(Q) See also the tutorials.. """ def __init__( @@ -54,32 +45,29 @@ def __init__( diffusion_coefficient: Numeric = 1.0, relaxation_time: Numeric = 1.0, ) -> None: - """Initialize a new JumpTranslationalDiffusion model. + """ + Initialize a new JumpTranslationalDiffusion model. Parameters ---------- - display_name : str | None, optional + display_name : str | None, default='JumpTranslationalDiffusion' Display name of the diffusion model. By default, 'JumpTranslationalDiffusion'. - unique_name : str | None, optional - Unique name of the diffusion - model. If None, a unique name will be generated. By default, None. - unit : str | sc.Unit, optional - Unit of the diffusion model. Must be - convertible to meV. By default, 'meV'. - scale : Numeric, optional - Scale factor for the diffusion model. Must - be a non-negative number. By default, 1.0. - diffusion_coefficient : Numeric, optional - Diffusion coefficient D in - m^2/s. By default, 1.0. - relaxation_time : Numeric, optional + unique_name : str | None, default=None + Unique name of the diffusion model. If None, a unique name will be generated. By + default, None. + unit : str | sc.Unit, default='meV' + Unit of the diffusion model. Must be convertible to meV. By default, 'meV'. + scale : Numeric, default=1.0 + Scale factor for the diffusion model. Must be a non-negative number. By default, 1.0. + diffusion_coefficient : Numeric, default=1.0 + Diffusion coefficient D in m^2/s. By default, 1.0. + relaxation_time : Numeric, default=1.0 Relaxation time t in ps. By default, 1.0. Raises ------ TypeError : - If scale, diffusion_coefficient, or - relaxation_time are not numbers. + If scale, diffusion_coefficient, or relaxation_time are not numbers. """ super().__init__( display_name=display_name, @@ -119,7 +107,8 @@ def __init__( @property def diffusion_coefficient(self) -> Parameter: - """Get the diffusion coefficient parameter D. + """ + Get the diffusion coefficient parameter D. Returns ------- @@ -130,13 +119,13 @@ def diffusion_coefficient(self) -> Parameter: @diffusion_coefficient.setter def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: - """Set the diffusion coefficient parameter D. + """ + Set the diffusion coefficient parameter D. Parameters ---------- diffusion_coefficient : Numeric - Diffusion coefficient D in - m^2/s. + Diffusion coefficient D in m^2/s. Raises ------ @@ -153,7 +142,8 @@ def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: @property def relaxation_time(self) -> Parameter: - """Get the relaxation time parameter t. + """ + Get the relaxation time parameter t. Returns ------- @@ -164,7 +154,8 @@ def relaxation_time(self) -> Parameter: @relaxation_time.setter def relaxation_time(self, relaxation_time: Numeric) -> None: - """Set the relaxation time parameter t. + """ + Set the relaxation time parameter t. Parameters ---------- @@ -190,21 +181,19 @@ def relaxation_time(self, relaxation_time: Numeric) -> None: ################################ def calculate_width(self, Q: Q_type) -> np.ndarray: - r"""Calculate the half-width at half-maximum (HWHM) for the - diffusion model. $\Gamma(Q) = Q^2/(1+D t Q^2)$, where $D$ is the - diffusion coefficient and $t$ is the relaxation time. + r""" + Calculate the half-width at half-maximum (HWHM) for the diffusion model. $\Gamma(Q) = + Q^2/(1+D t Q^2)$, where $D$ is the diffusion coefficient and $t$ is the relaxation time. Parameters ---------- Q : Q_type - Scattering vector in 1/angstrom. Can be a single - value or an array of values. + Scattering vector in 1/angstrom. Can be a single value or an array of values. Returns ------- np.ndarray - HWHM values in the unit of the model (e.g., - meV). + HWHM values in the unit of the model (e.g., meV). """ Q = _validate_and_convert_Q(Q) @@ -226,13 +215,13 @@ def calculate_width(self, Q: Q_type) -> np.ndarray: return numerator / denominator def calculate_EISF(self, Q: Q_type) -> np.ndarray: - """Calculate the Elastic Incoherent Structure Factor (EISF). + """ + Calculate the Elastic Incoherent Structure Factor (EISF). Parameters ---------- Q : Q_type - Scattering vector in 1/angstrom. Can be a single - value or an array of values. + Scattering vector in 1/angstrom. Can be a single value or an array of values. Returns ------- @@ -243,14 +232,13 @@ def calculate_EISF(self, Q: Q_type) -> np.ndarray: return np.zeros_like(Q) def calculate_QISF(self, Q: Q_type) -> np.ndarray: - """Calculate the Quasi-Elastic Incoherent Structure Factor - (QISF). + """ + Calculate the Quasi-Elastic Incoherent Structure Factor (QISF). Parameters ---------- Q : Q_type - Scattering vector in 1/angstrom. Can be a single - value or an array of values. + Scattering vector in 1/angstrom. Can be a single value or an array of values. Returns ------- @@ -265,16 +253,16 @@ def create_component_collections( Q: Q_type, component_display_name: str = 'Jump translational diffusion', ) -> list[ComponentCollection]: - """Create ComponentCollection components for the diffusion model - at given Q values. + """ + Create ComponentCollection components for the diffusion model at given Q values. Parameters ---------- Q : Q_type - Scattering vector in 1/angstrom. Can be a single - value or an array of values. - component_display_name : str, optional - Name of the Jump Diffusion Lorentzian component. By default, 'Jump translational diffusion'. + Scattering vector in 1/angstrom. Can be a single value or an array of values. + component_display_name : str, default='Jump translational diffusion' + Name of the Jump Diffusion Lorentzian component. By default, 'Jump translational + diffusion'. Raises ------ @@ -284,8 +272,7 @@ def create_component_collections( Returns ------- list[ComponentCollection] - List of ComponentCollections with - Jump Diffusion Lorentzian components. + List of ComponentCollections with Jump Diffusion Lorentzian components. """ Q = _validate_and_convert_Q(Q) @@ -336,8 +323,9 @@ def create_component_collections( ################################ def _write_width_dependency_expression(self, Q: float) -> str: - """Write the dependency expression for the width as a function - of Q to make dependent Parameters. + """ + Write the dependency expression for the width as a function of Q to make dependent + Parameters. Parameters ---------- @@ -361,8 +349,8 @@ def _write_width_dependency_expression(self, Q: float) -> str: return f'hbar * D* {Q} **2/(angstrom**2)/(1 + (D * t* {Q} **2/(angstrom**2)))' def _write_width_dependency_map_expression(self) -> dict[str, DescriptorNumber]: - """Write the dependency map expression to make dependent - Parameters. + """ + Write the dependency map expression to make dependent Parameters. Returns ------- @@ -377,8 +365,8 @@ def _write_width_dependency_map_expression(self) -> dict[str, DescriptorNumber]: } def _write_area_dependency_expression(self, QISF: float) -> str: - """Write the dependency expression for the area to make - dependent Parameters. + """ + Write the dependency expression for the area to make dependent Parameters. Parameters ---------- @@ -402,8 +390,8 @@ def _write_area_dependency_expression(self, QISF: float) -> str: return f'{QISF} * scale' def _write_area_dependency_map_expression(self) -> dict[str, DescriptorNumber]: - """Write the dependency map expression to make dependent - Parameters. + """ + Write the dependency map expression to make dependent Parameters. Returns ------- @@ -419,14 +407,13 @@ def _write_area_dependency_map_expression(self) -> dict[str, DescriptorNumber]: ################################ def __repr__(self) -> str: - """String representation of the JumpTranslationalDiffusion - model. + """ + String representation of the JumpTranslationalDiffusion model. Returns ------- str - String representation of the JumpTranslationalDiffusion - model. + String representation of the JumpTranslationalDiffusion model. """ return ( f'JumpTranslationalDiffusion(display_name={self.display_name}, ' diff --git a/src/easydynamics/sample_model/instrument_model.py b/src/easydynamics/sample_model/instrument_model.py index a677fda6..2d4e6e1b 100644 --- a/src/easydynamics/sample_model/instrument_model.py +++ b/src/easydynamics/sample_model/instrument_model.py @@ -17,11 +17,11 @@ class InstrumentModel(NewBase): - """InstrumentModel represents a model of the instrument in an - experiment at various Q. + """ + InstrumentModel represents a model of the instrument in an experiment at various Q. - It can contain a model of the resolution function for convolutions, - of the background and an offset in the energy axis. + It can contain a model of the resolution function for convolutions, of the background and an + offset in the energy axis. """ def __init__( @@ -34,40 +34,35 @@ def __init__( energy_offset: Numeric | None = None, unit: str | sc.Unit = 'meV', ) -> None: - """Initialize an InstrumentModel. + """ + Initialize an InstrumentModel. Parameters ---------- - display_name : str, optional - The display name of the - InstrumentModel. By default, 'MyInstrumentModel'. - unique_name : str | None, optional - The unique name of the - InstrumentModel. By default, None. - Q : Q_type | None, optional + display_name : str, default='MyInstrumentModel' + The display name of the InstrumentModel. By default, 'MyInstrumentModel'. + unique_name : str | None, default=None + The unique name of the InstrumentModel. By default, None. + Q : Q_type | None, default=None The Q values where the instrument is modelled. By default, None. - resolution_model : ResolutionModel | None, optional - The resolution - model of the instrument. If None, an empty resolution - model is created and no resolution convolution is - carried out. By default, None. - background_model : BackgroundModel | None, optional - The background - model of the instrument. If None, an empty background - model is created, and the background evaluates to 0. By default, None. - energy_offset : Numeric | None, optional - Template energy offset - of the instrument. Will be copied to each Q value. If - None, the energy offset will be 0. By default, None. - unit : str | sc.Unit, optional + resolution_model : ResolutionModel | None, default=None + The resolution model of the instrument. If None, an empty resolution model is created + and no resolution convolution is carried out. By default, None. + background_model : BackgroundModel | None, default=None + The background model of the instrument. If None, an empty background model is created, + and the background evaluates to + 0. By default, None. + energy_offset : Numeric | None, default=None + Template energy offset of the instrument. Will be copied to each Q value. If None, the + energy offset will be 0. By default, None. + unit : str | sc.Unit, default='meV' The unit of the energy axis. By default, 'meV'. Raises ------ TypeError : - If resolution_model is not a ResolutionModel or - None, or if background_model is not a BackgroundModel or None, or - if energy_offset is not a number or None. + If resolution_model is not a ResolutionModel or None, or if background_model is not a + BackgroundModel or None, or if energy_offset is not a number or None. """ super().__init__( display_name=display_name, @@ -117,7 +112,8 @@ def __init__( @property def resolution_model(self) -> ResolutionModel: - """Get the resolution model of the instrument. + """ + Get the resolution model of the instrument. Returns ------- @@ -128,13 +124,13 @@ def resolution_model(self) -> ResolutionModel: @resolution_model.setter def resolution_model(self, value: ResolutionModel) -> None: - """Set the resolution model of the instrument. + """ + Set the resolution model of the instrument. Parameters ---------- value : ResolutionModel - The new resolution model of the - instrument. + The new resolution model of the instrument. Raises ------ @@ -150,7 +146,8 @@ def resolution_model(self, value: ResolutionModel) -> None: @property def background_model(self) -> BackgroundModel: - """Get the background model of the instrument. + """ + Get the background model of the instrument. Returns ------- @@ -162,13 +159,13 @@ def background_model(self) -> BackgroundModel: @background_model.setter def background_model(self, value: BackgroundModel) -> None: - """Set the background model of the instrument. + """ + Set the background model of the instrument. Parameters ---------- value : BackgroundModel - The new background model of the - instrument. + The new background model of the instrument. Raises ------ @@ -185,36 +182,34 @@ def background_model(self, value: BackgroundModel) -> None: @property def Q(self) -> np.ndarray | None: - """Get the Q values of the InstrumentModel. + """ + Get the Q values of the InstrumentModel. Returns ------- np.ndarray | None - The Q values of the InstrumentModel, or - None if not set. + The Q values of the InstrumentModel, or None if not set. """ return self._Q @Q.setter def Q(self, value: Q_type | None) -> None: - """Set the Q values of the InstrumentModel. + """ + Set the Q values of the InstrumentModel. - If Q is already set, -it raises an error if the new Q values are not similar to the - old ones to prevent accidental changes to the background and - resolution models. To change Q values, first run clear_Q(). + If Q is already set, it raises an error if the new Q values are not similar to the old ones + to prevent accidental changes to the background and resolution models. To change Q values, + first run clear_Q(). Parameters ---------- value : Q_type | None - The new Q values to set. - If None, Q values are not changed. + The new Q values to set. If None, Q values are not changed. Raises ------ ValueError : - If the new Q values are not similar to the old - ones when Q is not None. + If the new Q values are not similar to the old ones when Q is not None. """ if value is None: return @@ -234,7 +229,8 @@ def Q(self, value: Q_type | None) -> None: @property def unit(self) -> str | sc.Unit: - """Get the unit of the InstrumentModel. + """ + Get the unit of the InstrumentModel. Returns ------- @@ -245,18 +241,16 @@ def unit(self) -> str | sc.Unit: @unit.setter def unit(self, _unit_str: str) -> None: - """Set the unit of the InstrumentModel. + """ + Set the unit of the InstrumentModel. - The unit is read-only -and cannot be set directly. Use convert_unit to change the unit - between allowed types or create a new InstrumentModel with the - desired unit. + The unit is read-only and cannot be set directly. Use convert_unit to change the unit + between allowed types or create a new InstrumentModel with the desired unit. Parameters ---------- _unit_str : str - The new unit for the InstrumentModel - (ignored). + The new unit for the InstrumentModel (ignored). Raises ------ @@ -270,26 +264,25 @@ def unit(self, _unit_str: str) -> None: @property def energy_offset(self) -> Parameter: - """Get the energy offset template parameter of the instrument - model. + """ + Get the energy offset template parameter of the instrument model. Returns ------- Parameter - The energy offset template parameter of the - instrument model. + The energy offset template parameter of the instrument model. """ return self._energy_offset @energy_offset.setter def energy_offset(self, value: Numeric) -> None: - """Set the offset parameter of the instrument model. + """ + Set the offset parameter of the instrument model. Parameters ---------- value : Numeric - The new value for the energy offset - parameter. Will be copied to all Q values. + The new value for the energy offset parameter. Will be copied to all Q values. Raises ------ @@ -307,15 +300,14 @@ def energy_offset(self, value: Numeric) -> None: # -------------------------------------------------------------- def clear_Q(self, confirm: bool = False) -> None: - """Clear the Q values of the InstrumentModel and any associated - ResolutionModel and BackgroundModel, removing all component - collections and their associated Parameters. + """ + Clear the Q values of the InstrumentModel and any associated ResolutionModel and + BackgroundModel, removing all component collections and their associated Parameters. Parameters ---------- - confirm : bool, optional - Confirmation to clear Q - values. By default, False. + confirm : bool, default=False + Confirmation to clear Q values. By default, False. Raises ------ @@ -332,7 +324,8 @@ def clear_Q(self, confirm: bool = False) -> None: self._on_Q_change() def convert_unit(self, unit_str: str | sc.Unit) -> None: - """Convert the unit of the InstrumentModel. + """ + Convert the unit of the InstrumentModel. Parameters ---------- @@ -342,8 +335,7 @@ def convert_unit(self, unit_str: str | sc.Unit) -> None: Raises ------ ValueError : - If unit_str is not a valid unit string or - scipp Unit. + If unit_str is not a valid unit string or scipp Unit. """ unit = _validate_unit(unit_str) if unit is None: @@ -358,30 +350,28 @@ def convert_unit(self, unit_str: str | sc.Unit) -> None: self._unit = unit def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: - """Get all variables in the InstrumentModel. + """ + Get all variables in the InstrumentModel. Parameters ---------- - Q_index : int | None, optional - The index of the Q value to get - variables for. If None, get variables for all Q values. By default, None. + Q_index : int | None, default=None + The index of the Q value to get variables for. If None, get variables for all Q values. + By default, None. Raises ------ TypeError : If Q_index is not an int or None. IndexError : - If Q_index is out of bounds for the Q values in - the InstrumentModel. + If Q_index is out of bounds for the Q values in the InstrumentModel. Returns ------- list[Parameter] - A list of all variables in the - InstrumentModel. If Q_index is specified, only variables - from the ComponentCollection at the given Q index are - included. Otherwise, all variables in the - InstrumentModel are included. + A list of all variables in the InstrumentModel. If Q_index is specified, only variables + from the ComponentCollection at the given Q index are included. Otherwise, all + variables in the InstrumentModel are included. """ if self._Q is None: return [] @@ -418,13 +408,14 @@ def get_energy_offset( self, Q_index: int | None = None, ) -> Parameter | list[Parameter]: - """Get the energy offset Parameter at a specific Q index. + """ + Get the energy offset Parameter at a specific Q index. Parameters ---------- - Q_index : int | None, optional - The index of the Q value to get the energy - offset for. If None, get the energy offset for all Q values. By default, None. + Q_index : int | None, default=None + The index of the Q value to get the energy offset for. If None, get the energy offset + for all Q values. By default, None. Raises ------ @@ -438,8 +429,8 @@ def get_energy_offset( Returns ------- Parameter | list[Parameter] - The energy offset Parameter at the specified Q - index, or a list of Parameters if Q_index is None. + The energy offset Parameter at the specified Q index, or a list of Parameters if + Q_index is None. """ if self._Q is None: raise ValueError('No Q values are set in the InstrumentModel.') @@ -456,34 +447,32 @@ def get_energy_offset( return self._energy_offsets[Q_index] def fix_energy_offset(self, Q_index: int | None = None) -> None: - """Fix energy offset parameters. + """ + Fix energy offset parameters. - If Q_index is specified, only -fix the energy offset for that Q value. If Q_index is None, fix - energy offsets for all Q values. + If Q_index is specified, only fix the energy offset for that Q value. If Q_index is None, + fix energy offsets for all Q values. Parameters ---------- - Q_index : int | None, optional - The index of the Q value - to fix the energy offset for. If None, fix energy - offsets for all Q values. By default, None. + Q_index : int | None, default=None + The index of the Q value to fix the energy offset for. If None, fix energy offsets for + all Q values. By default, None. """ self._fix_or_free_energy_offset(Q_index, fixed=True) def free_energy_offset(self, Q_index: int | None = None) -> None: - """Free energy offset parameters. + """ + Free energy offset parameters. - If Q_index is specified, only -free the energy offset for that Q value. If Q_index is None, + If Q_index is specified, only free the energy offset for that Q value. If Q_index is None, free energy offsets for all Q values. Parameters ---------- - Q_index : int | None, optional - The index of the Q value - to free the energy offset for. If None, free energy - offsets for all Q values. By default, None. + Q_index : int | None, default=None + The index of the Q value to free the energy offset for. If None, free energy offsets + for all Q values. By default, None. """ self._fix_or_free_energy_offset(Q_index, fixed=False) @@ -491,29 +480,26 @@ def free_energy_offset(self, Q_index: int | None = None) -> None: # Private methods # -------------------------------------------------------------- def _fix_or_free_energy_offset(self, Q_index: int | None = None, fixed: bool = True) -> None: - """Fix or free energy offset parameters. + """ + Fix or free energy offset parameters. - If Q_index is -specified, only fix or free the energy offset for that Q value. - If Q_index is None, fix or free energy offsets for all Q values. + If Q_index is specified, only fix or free the energy offset for that Q value. If Q_index is + None, fix or free energy offsets for all Q values. Parameters ---------- - Q_index : int | None, optional - The index of the Q value - to fix or free the energy offset for. If None, fix or - free energy offsets for all Q values. By default, None. - fixed : bool, optional - Whether to fix (True) or free - (False) the energy offset. By default, True. + Q_index : int | None, default=None + The index of the Q value to fix or free the energy offset for. If None, fix or free + energy offsets for all Q values. By default, None. + fixed : bool, default=True + Whether to fix (True) or free (False) the energy offset. By default, True. Raises ------ TypeError : If Q_index is not an int or None. IndexError : - If Q_index is out of bounds for the Q values in - the InstrumentModel. + If Q_index is out of bounds for the Q values in the InstrumentModel. """ if Q_index is None: @@ -561,7 +547,8 @@ def _on_background_model_change(self) -> None: # ------------------------------------------------------------- def __repr__(self) -> str: - """Return a string representation of the InstrumentModel. + """ + Return a string representation of the InstrumentModel. Returns ------- diff --git a/src/easydynamics/sample_model/model_base.py b/src/easydynamics/sample_model/model_base.py index 35b33515..384c6204 100644 --- a/src/easydynamics/sample_model/model_base.py +++ b/src/easydynamics/sample_model/model_base.py @@ -17,10 +17,10 @@ class ModelBase(EasyScienceModelBase): - """Base class for Sample Models. + """ + Base class for Sample Models. - Contains common functionality for models with components and Q - dependence. + Contains common functionality for models with components and Q dependence. """ def __init__( @@ -31,24 +31,22 @@ def __init__( components: ModelComponent | ComponentCollection | None = None, Q: Q_type | None = None, ) -> None: - """Initialize the ModelBase. + """ + Initialize the ModelBase. Parameters ---------- - display_name : str, optional + display_name : str, default='MyModelBase' Display name of the model. By default, 'MyModelBase'. - unique_name : str | None, optional - Unique name of the model. If None, - a unique name will be generated. By default, None. - unit : str | sc.Unit | None, optional + unique_name : str | None, default=None + Unique name of the model. If None, a unique name will be generated. By default, None. + unit : str | sc.Unit | None, default='meV' Unit of the model. By default, 'meV'. - components : ModelComponent | ComponentCollection | None, optional - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. By default, None. - Q : Q_type | None, optional - Q values for the model. - If None, Q is not set. By default, None. + components : ModelComponent | ComponentCollection | None, default=None + Template components of the model. If None, no components are added. These components + are copied into ComponentCollections for each Q value. By default, None. + Q : Q_type | None, default=None + Q values for the model. If None, Q is not set. By default, None. Raises ------ @@ -79,28 +77,26 @@ def __init__( def evaluate( self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray ) -> list[np.ndarray]: - """Evaluate the sample model at all Q for the given x values. + """ + Evaluate the sample model at all Q for the given x values. Parameters ---------- x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray - Energy axis values to evaluate the model at. If a scipp - Variable or DataArray is provided, the unit of the model - will be converted to match the unit of x for evaluation, and - the result will be returned in the same unit as x. + Energy axis values to evaluate the model at. If a scipp Variable or DataArray is + provided, the unit of the model will be converted to match the unit of x for + evaluation, and the result will be returned in the same unit as x. Raises ------ ValueError : - If there are no components in the model to - evaluate. + If there are no components in the model to evaluate. Returns ------- list[np.ndarray] - A list of numpy arrays containing the - evaluated model values for each Q. The length of the - list will match the number of Q values in the model. + A list of numpy arrays containing the evaluated model values for each Q. The length of + the list will match the number of Q values in the model. """ if not self._component_collections: @@ -114,27 +110,25 @@ def evaluate( # Component management # ------------------------------------------------------------------ def append_component(self, component: ModelComponent | ComponentCollection) -> None: - """Append a ModelComponent or ComponentCollection to the - SampleModel. + """ + Append a ModelComponent or ComponentCollection to the SampleModel. Parameters ---------- component : ModelComponent | ComponentCollection - The - ModelComponent or ComponentCollection to append. + The ModelComponent or ComponentCollection to append. """ self._components.append_component(component) self._on_components_change() def remove_component(self, unique_name: str) -> None: - """Remove a ModelComponent from the SampleModel by its unique - name. + """ + Remove a ModelComponent from the SampleModel by its unique name. Parameters ---------- unique_name : str - The unique name of the ModelComponent - to remove. + The unique name of the ModelComponent to remove. """ self._components.remove_component(unique_name) self._on_components_change() @@ -150,7 +144,8 @@ def clear_components(self) -> None: @property def unit(self) -> str | sc.Unit | None: - """Get the unit of the ComponentCollection. + """ + Get the unit of the ComponentCollection. Returns ------- @@ -162,7 +157,8 @@ def unit(self) -> str | sc.Unit | None: @unit.setter def unit(self, _unit_str: str) -> None: - """Unit is read-only and cannot be set directly. + """ + Unit is read-only and cannot be set directly. Parameters ---------- @@ -172,8 +168,7 @@ def unit(self, _unit_str: str) -> None: Raises ------ AttributeError : - Always raised to indicate that the unit is - read-only. + Always raised to indicate that the unit is read-only. """ raise AttributeError( f'Unit is read-only. Use convert_unit to change the unit between allowed types ' @@ -181,8 +176,8 @@ def unit(self, _unit_str: str) -> None: ) # noqa: E501 def convert_unit(self, unit: str | sc.Unit) -> None: - """Convert the unit of the ComponentCollection and all its - components. + """ + Convert the unit of the ComponentCollection and all its components. Parameters ---------- @@ -194,8 +189,7 @@ def convert_unit(self, unit: str | sc.Unit) -> None: TypeError : If the provided unit is not a string or sc.Unit. Exception : - If the provided unit is not compatible with the - current unit. + If the provided unit is not compatible with the current unit. """ old_unit = self._unit @@ -218,7 +212,8 @@ def convert_unit(self, unit: str | sc.Unit) -> None: @property def components(self) -> list[ModelComponent]: - """Get the components of the SampleModel. + """ + Get the components of the SampleModel. Returns ------- @@ -229,19 +224,18 @@ def components(self) -> list[ModelComponent]: @components.setter def components(self, value: ModelComponent | ComponentCollection | None) -> None: - """Set the components of the SampleModel. + """ + Set the components of the SampleModel. Parameters ---------- value : ModelComponent | ComponentCollection | None - The new - components to set. If None, all components will be cleared. + The new components to set. If None, all components will be cleared. Raises ------ TypeError : - If value is not a ModelComponent, - ComponentCollection, or None. + If value is not a ModelComponent, ComponentCollection, or None. """ if not isinstance(value, (ModelComponent, ComponentCollection, type(None))): raise TypeError('Components must be a ModelComponent or a ComponentCollection') @@ -252,35 +246,33 @@ def components(self, value: ModelComponent | ComponentCollection | None) -> None @property def Q(self) -> np.ndarray | None: - """Get the Q values of the SampleModel. + """ + Get the Q values of the SampleModel. Returns ------- np.ndarray | None - The Q values of the SampleModel, or None - if not set. + The Q values of the SampleModel, or None if not set. """ return self._Q @Q.setter def Q(self, value: Q_type | None) -> None: - """Set the Q values of the SampleModel. + """ + Set the Q values of the SampleModel. - If Q is already set, it -throws an error if the new Q values are not similar to the old + If Q is already set, it throws an error if the new Q values are not similar to the old ones. To change Q values, first run clear_Q(). Parameters ---------- value : Q_type | None - The new Q values to set. - If None, Q values are not changed. + The new Q values to set. If None, Q values are not changed. Raises ------ ValueError : - If the new Q values are not similar to the old - ones when Q is already set. + If the new Q values are not similar to the old ones when Q is already set. """ if value is None: return @@ -299,12 +291,13 @@ def Q(self, value: Q_type | None) -> None: ) def clear_Q(self, confirm: bool = False) -> None: - """Clear the Q values of the SampleModel, removing all component - collections and their associated Parameters. + """ + Clear the Q values of the SampleModel, removing all component collections and their + associated Parameters. Parameters ---------- - confirm : bool, optional + confirm : bool, default=False Confirmation to clear Q values. By default, False. Raises @@ -333,16 +326,15 @@ def free_all_parameters(self) -> None: par.fixed = False def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: - """Get all Parameters and Descriptors from all - ComponentCollections in the ModelBase. Parameters Ignores the - Parameters and Descriptors in self._components as these are just + """ + Get all Parameters and Descriptors from all ComponentCollections in the ModelBase. + Parameters Ignores the Parameters and Descriptors in self._components as these are just templates. Parameters ---------- - Q_index : int | None, optional - If None, get variables for all - ComponentCollections. If int, get variables for the + Q_index : int | None, default=None + If None, get variables for all ComponentCollections. If int, get variables for the ComponentCollection at this index. By default, None. Raises @@ -350,14 +342,13 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: TypeError : If Q_index is not an int or None. IndexError : - If Q_index is out of bounds for the number of - ComponentCollections. + If Q_index is out of bounds for the number of ComponentCollections. Returns ------- list[Parameter] - A list of all Parameters and Descriptors - from the ComponentCollections in the ModelBase. + A list of all Parameters and Descriptors from the ComponentCollections in the + ModelBase. """ if Q_index is None: @@ -378,7 +369,8 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: return all_vars def get_component_collection(self, Q_index: int) -> ComponentCollection: - """Get the ComponentCollection at the given Q index. + """ + Get the ComponentCollection at the given Q index. Parameters ---------- @@ -390,14 +382,13 @@ def get_component_collection(self, Q_index: int) -> ComponentCollection: TypeError : If Q_index is not an int. IndexError : - If Q_index is out of bounds for the number of - ComponentCollections. + If Q_index is out of bounds for the number of ComponentCollections. Returns ------- ComponentCollection The ComponentCollection at the. - specified Q index. + ComponentCollection """ if not isinstance(Q_index, int): raise TypeError(f'Q_index must be an int, got {type(Q_index).__name__}') @@ -441,7 +432,8 @@ def _on_components_change(self) -> None: # ------------------------------------------------------------------ def __repr__(self) -> str: - """Return a string representation of the ModelBase. + """ + Return a string representation of the ModelBase. Returns ------- diff --git a/src/easydynamics/sample_model/resolution_model.py b/src/easydynamics/sample_model/resolution_model.py index 154ce397..e4ba1b63 100644 --- a/src/easydynamics/sample_model/resolution_model.py +++ b/src/easydynamics/sample_model/resolution_model.py @@ -13,8 +13,8 @@ class ResolutionModel(ModelBase): - """ResolutionModel represents a model of the instrment resolution in - an experiment at various Q. + """ + ResolutionModel represents a model of the instrment resolution in an experiment at various Q. """ def __init__( @@ -25,24 +25,22 @@ def __init__( components: ModelComponent | ComponentCollection | None = None, Q: Q_type | None = None, ) -> None: - """Initialize a ResolutionModel. + """ + Initialize a ResolutionModel. Parameters ---------- - display_name : str, optional + display_name : str, default='MyResolutionModel' Display name of the model. By default, 'MyResolutionModel'. - unique_name : str | None, optional - Unique name of the model. If None, - a unique name will be generated. By default, None. - unit : str | sc.Unit, optional + unique_name : str | None, default=None + Unique name of the model. If None, a unique name will be generated. By default, None. + unit : str | sc.Unit, default='meV' Unit of the model. By default, 'meV'. - components : ModelComponent | ComponentCollection | None, optional - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. By default, None. - Q : Q_type | None, optional - Q values for the model. If None, Q is not - set. By default, None. + components : ModelComponent | ComponentCollection | None, default=None + Template components of the model. If None, no components are added. These components + are copied into ComponentCollections for each Q value. By default, None. + Q : Q_type | None, default=None + Q values for the model. If None, Q is not set. By default, None. """ super().__init__( @@ -54,10 +52,11 @@ def __init__( ) def append_component(self, component: ModelComponent | ComponentCollection) -> None: - """Append a component to the ResolutionModel. + """ + Append a component to the ResolutionModel. - Does not allow DeltaFunction or Polynomial components, as these - are not physical resolution components. + Does not allow DeltaFunction or Polynomial components, as these are not physical resolution + components. Parameters ---------- diff --git a/src/easydynamics/sample_model/sample_model.py b/src/easydynamics/sample_model/sample_model.py index b9cc587b..d01e2e34 100644 --- a/src/easydynamics/sample_model/sample_model.py +++ b/src/easydynamics/sample_model/sample_model.py @@ -18,9 +18,9 @@ class SampleModel(ModelBase): - """SampleModel represents a model of a sample with components and - diffusion models, parameterized by Q and optionally temperature. - Generates ComponentCollections for each Q value, combining + """ + SampleModel represents a model of a sample with components and diffusion models, parameterized + by Q and optionally temperature. Generates ComponentCollections for each Q value, combining components from the base model and diffusion models. Applies detailed balancing based on temperature if provided. @@ -38,42 +38,38 @@ def __init__( temperature_unit: str | sc.Unit = 'K', divide_by_temperature: bool = True, ) -> None: - """Initialize the SampleModel. + """ + Initialize the SampleModel. Parameters ---------- - display_name : str, optional + display_name : str, default='MySampleModel' Display name of the model. By default, 'MySampleModel'. - unique_name : str | None, optional - Unique name of the model. If None, - a unique name will be generated. By default, None. - unit : str | sc.Unit, optional + unique_name : str | None, default=None + Unique name of the model. If None, a unique name will be generated. By default, None. + unit : str | sc.Unit, default='meV' Unit of the model. If None,. By default, 'meV'. - components : ModelComponent | ComponentCollection | None, optional - Template components of the model. If None, no components - are added. These components are copied into - ComponentCollections for each Q value. By default, None. - Q : Q_type | None, optional + components : ModelComponent | ComponentCollection | None, default=None + Template components of the model. If None, no components are added. These components + are copied into ComponentCollections for each Q value. By default, None. + Q : Q_type | None, default=None Q values for the model. If None, Q is not set. By default, None. - diffusion_models : DiffusionModelBase | list[DiffusionModelBase] | None, optional - Diffusion models to include in the SampleModel. If None, - no diffusion models are added. By default, None. - temperature : float | None, optional - Temperature for detailed - balancing. If None, no detailed balancing is applied. By default, None. - temperature_unit : str | sc.Unit, optional + diffusion_models : DiffusionModelBase | list[DiffusionModelBase] | None, default=None + Diffusion models to include in the SampleModel. If None, no diffusion models are added. + By default, None. + temperature : float | None, default=None + Temperature for detailed balancing. If None, no detailed balancing is applied. By + default, None. + temperature_unit : str | sc.Unit, default='K' Unit of the temperature. By default, 'K'. - divide_by_temperature : bool, optional - Whether to divide the detailed - balance factor by temperature. By default, True. + divide_by_temperature : bool, default=True + Whether to divide the detailed balance factor by temperature. By default, True. Raises ------ TypeError : - If diffusion_models is not a DiffusionModelBase, - a list of DiffusionModelBase, or None, or if temperature - is not a number or None, or if divide_by_temperature is - not a bool. + If diffusion_models is not a DiffusionModelBase, a list of DiffusionModelBase, or None, + or if temperature is not a number or None, or if divide_by_temperature is not a bool. ValueError : If temperature is negative. """ @@ -125,19 +121,18 @@ def __init__( # ------------------------------------------------------------------ def append_diffusion_model(self, diffusion_model: DiffusionModelBase) -> None: - """Append a DiffusionModel to the SampleModel. + """ + Append a DiffusionModel to the SampleModel. Parameters ---------- diffusion_model : DiffusionModelBase - The DiffusionModel - to append. + The DiffusionModel to append. Raises ------ TypeError : - If the diffusion_model is not a - DiffusionModelBase. + If the diffusion_model is not a DiffusionModelBase. """ if not isinstance(diffusion_model, DiffusionModelBase): @@ -149,7 +144,8 @@ def append_diffusion_model(self, diffusion_model: DiffusionModelBase) -> None: self._generate_component_collections() def remove_diffusion_model(self, name: 'str') -> None: - """Remove a DiffusionModel from the SampleModel by unique name. + """ + Remove a DiffusionModel from the SampleModel by unique name. Parameters ---------- @@ -159,8 +155,7 @@ def remove_diffusion_model(self, name: 'str') -> None: Raises ------ ValueError : - If no DiffusionModel with the given unique name - is found. + If no DiffusionModel with the given unique name is found. """ for i, dm in enumerate(self._diffusion_models): if dm.unique_name == name: @@ -183,13 +178,13 @@ def clear_diffusion_models(self) -> None: @property def diffusion_models(self) -> list[DiffusionModelBase]: - """Get the diffusion models of the SampleModel. + """ + Get the diffusion models of the SampleModel. Returns ------- list[DiffusionModelBase] - The diffusion models of the - SampleModel. + The diffusion models of the SampleModel. """ return self._diffusion_models @@ -197,20 +192,19 @@ def diffusion_models(self) -> list[DiffusionModelBase]: def diffusion_models( self, value: DiffusionModelBase | list[DiffusionModelBase] | None ) -> None: - """Set the diffusion models of the SampleModel. + """ + Set the diffusion models of the SampleModel. Parameters ---------- value : DiffusionModelBase | list[DiffusionModelBase] | None - The diffusion model(s) to set. Can be a single - DiffusionModelBase, a list of DiffusionModelBase, or - None to clear all diffusion models. + The diffusion model(s) to set. Can be a single DiffusionModelBase, a list of + DiffusionModelBase, or None to clear all diffusion models. Raises ------ TypeError : - If value is not a DiffusionModelBase, a list of - DiffusionModelBase, or None. + If value is not a DiffusionModelBase, a list of DiffusionModelBase, or None. """ if value is None: @@ -231,25 +225,25 @@ def diffusion_models( @property def temperature(self) -> Parameter | None: - """Get the temperature of the SampleModel. + """ + Get the temperature of the SampleModel. Returns ------- Parameter | None - The temperature Parameter of the - SampleModel, or None if not set. + The temperature Parameter of the SampleModel, or None if not set. """ return self._temperature @temperature.setter def temperature(self, value: Numeric | None) -> None: - """Set the temperature of the SampleModel. + """ + Set the temperature of the SampleModel. Parameters ---------- value : Numeric | None - The temperature value to set. Can be - a number or None to unset the temperature. + The temperature value to set. Can be a number or None to unset the temperature. Raises ------ @@ -281,7 +275,8 @@ def temperature(self, value: Numeric | None) -> None: @property def temperature_unit(self) -> str | sc.Unit: - """Get the temperature unit of the SampleModel. + """ + Get the temperature unit of the SampleModel. Returns ------- @@ -292,13 +287,13 @@ def temperature_unit(self) -> str | sc.Unit: @temperature_unit.setter def temperature_unit(self, _value: str | sc.Unit) -> None: - """The temperature unit of the SampleModel is read-only. + """ + The temperature unit of the SampleModel is read-only. Parameters ---------- _value : str | sc.Unit - The unit to set for the temperature - Parameter. + The unit to set for the temperature Parameter. Raises ------ @@ -312,13 +307,13 @@ def temperature_unit(self, _value: str | sc.Unit) -> None: ) # noqa: E501 def convert_temperature_unit(self, unit: str | sc.Unit) -> None: - """Convert the unit of the temperature Parameter. + """ + Convert the unit of the temperature Parameter. Parameters ---------- unit : str | sc.Unit - The unit to convert the temperature - Parameter to. + The unit to convert the temperature Parameter to. Raises ------ @@ -344,27 +339,25 @@ def convert_temperature_unit(self, unit: str | sc.Unit) -> None: @property def divide_by_temperature(self) -> bool: - """Get whether to divide the detailed balance factor by - temperature. + """ + Get whether to divide the detailed balance factor by temperature. Returns ------- bool - True if the detailed balance factor is divided by - temperature, False otherwise. + True if the detailed balance factor is divided by temperature, False otherwise. """ return self._divide_by_temperature @divide_by_temperature.setter def divide_by_temperature(self, value: bool) -> None: - """Set whether to divide the detailed balance factor by - temperature. + """ + Set whether to divide the detailed balance factor by temperature. Parameters ---------- value : bool - True to divide the detailed balance factor by - temperature, False otherwise. + True to divide the detailed balance factor by temperature, False otherwise. Raises ------ @@ -382,13 +375,14 @@ def divide_by_temperature(self, value: bool) -> None: def evaluate( self, x: Numeric | list | np.ndarray | sc.Variable | sc.DataArray ) -> list[np.ndarray]: - """Evaluate the sample model at all Q for the given x values. + """ + Evaluate the sample model at all Q for the given x values. Parameters ---------- x : Numeric | list | np.ndarray | sc.Variable | sc.DataArray - The x values to evaluate the model at. Can be a number, - list, numpy array, scipp Variable, or scipp DataArray. + The x values to evaluate the model at. Can be a number, list, numpy array, scipp + Variable, or scipp DataArray. Returns ------- @@ -410,26 +404,23 @@ def evaluate( return y def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: - """Get all Parameters and Descriptors from all - ComponentCollections in the SampleModel. + """ + Get all Parameters and Descriptors from all ComponentCollections in the SampleModel. - Also includes temperature if set and all variables from - diffusion models. Ignores the Parameters and Descriptors in - self._components as these are just templates. + Also includes temperature if set and all variables from diffusion models. Ignores the + Parameters and Descriptors in self._components as these are just templates. Parameters ---------- - Q_index : int | None, optional - If specified, only get variables from - the ComponentCollection at the given Q index. If None, - get variables from all ComponentCollections. By default, None. + Q_index : int | None, default=None + If specified, only get variables from the ComponentCollection at the given Q index. If + None, get variables from all ComponentCollections. By default, None. Returns ------- list[Parameter] - List of all Parameters and Descriptors, - including temperature if set and all variables from - diffusion models. + List of all Parameters and Descriptors, including temperature if set and all variables + from diffusion models. """ all_vars = super().get_all_variables(Q_index=Q_index) @@ -446,8 +437,9 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: # ------------------------------------------------------------------ def _generate_component_collections(self) -> None: - """Generate ComponentCollections from the DiffusionModels for - each Q and add the components from self._components. + """ + Generate ComponentCollections from the DiffusionModels for each Q and add the components + from self._components. """ # TODO regenerate automatically if Q, diffusion models # or components have changed @@ -474,7 +466,8 @@ def _on_diffusion_models_change(self) -> None: # ------------------------------------------------------------------ def __repr__(self) -> str: - """Return a string representation of the SampleModel. + """ + Return a string representation of the SampleModel. Returns ------- diff --git a/src/easydynamics/utils/detailed_balance.py b/src/easydynamics/utils/detailed_balance.py index 00f36949..e2cfcdee 100644 --- a/src/easydynamics/utils/detailed_balance.py +++ b/src/easydynamics/utils/detailed_balance.py @@ -29,61 +29,46 @@ def detailed_balance_factor( temperature_unit: str | sc.Unit = 'K', divide_by_temperature: bool = True, ) -> np.ndarray: - r"""Compute the detailed balance factor (DBF): - $$ - DBF(E, T) = E(n(E)+1)=\frac{E}{(1 - e^{-E / (k_B*T)})}}, - $$ - where $n(E)$ is the Bose-Einstein distribution, $E$ is the energy - transfer, and $T$ is the temperature. $k_B$ is the Boltzmann - constant. - If divide_by_temperature is True, the result is normalized by - $k_B*T$ to have value 1 at $E=0$. + r""" + Compute the detailed balance factor (DBF): $$ DBF(E, T) = E(n(E)+1)=\frac{E}{(1 - e^{-E / + (k_B*T)})}}, $$ where $n(E)$ is the Bose-Einstein distribution, $E$ is the energy transfer, and + $T$ is the temperature. $k_B$ is the Boltzmann constant. If divide_by_temperature is True, the + result is normalized by $k_B*T$ to have value 1 at $E=0$. Parameters ---------- energy : int | float | list | np.ndarray | sc.Variable - The energy - transfer. If number, assumed to be in meV unless energy_unit - is set. + The energy transfer. If number, assumed to be in meV unless energy_unit is set. temperature : int | float | sc.Variable | Parameter - The - temperature. If number, assumed to be in K unless - temperature_unit is set. - energy_unit : str | sc.Unit, optional - Unit for energy if energy is - given as a number or list. By default, 'meV'. - temperature_unit : str | sc.Unit, optional - Unit for temperature if - temperature is given as a number. By default, 'K'. - divide_by_temperature : bool, optional - If True, divide the result - by $k_B*T$ to make it dimensionless and have value 1 at E=0. By default, True. + The temperature. If number, assumed to be in K unless temperature_unit is set. + energy_unit : str | sc.Unit, default='meV' + Unit for energy if energy is given as a number or list. By default, 'meV'. + temperature_unit : str | sc.Unit, default='K' + Unit for temperature if temperature is given as a number. By default, 'K'. + divide_by_temperature : bool, default=True + If True, divide the result by $k_B*T$ to make it dimensionless and have value 1 at E=0. By + default, True. Raises ------ TypeError : - If energy or temperature is not a number, list, - numpy array, or scipp Variable, or if energy_unit or - temperature_unit is not a string or scipp Unit, - or if divide_by_temperature is not a boolean. + If energy or temperature is not a number, list, numpy array, or scipp Variable, or if + energy_unit or temperature_unit is not a string or scipp Unit, or if divide_by_temperature + is not a boolean. ValueError : - If temperature is negative, or if energy is a numpy - array with more than 1 dimension, or if temperature is a - scipp Variable that does not have a single dimension named - 'temperature', or if energy is a scipp Variable that does - not have a single dimension named 'energy'. + If temperature is negative, or if energy is a numpy array with more than 1 dimension, or if + temperature is a scipp Variable that does not have a single dimension named 'temperature', + or if energy is a scipp Variable that does not have a single dimension named 'energy'. UnitError : - If the provided energy_unit or temperature_unit is - invalid, or if the units of energy or temperature cannot be - converted to the expected units. + If the provided energy_unit or temperature_unit is invalid, or if the units of energy or + temperature cannot be converted to the expected units. ZeroDivisionError : If divide_by_temperature is True and temperature is zero. Returns ------- np.ndarray - Detailed balance factor evaluated at the - given energy and temperature. + Detailed balance factor evaluated at the given energy and temperature. Examples -------- @@ -198,36 +183,32 @@ def _convert_to_scipp_variable( name: str, unit: str | None = None, ) -> sc.Variable: - """Convert various input types to a scipp Variable with proper - units. + """ + Convert various input types to a scipp Variable with proper units. Parameters ---------- value : int | float | list | np.ndarray | Parameter | sc.Variable - The value to convert. Can be a number, list, numpy array, - Parameter, or scipp Variable. If a number or list, the unit - must be specified in the unit argument. + The value to convert. Can be a number, list, numpy array, Parameter, or scipp Variable. If + a number or list, the unit must be specified in the unit argument. name : str The name of the variable, used for error messages. - unit : str | None, optional - The unit to use if value is a number or list. - Must be specified if value is a number or list. Ignored if - value is a Parameter or sc.Variable, which have their own - units. By default, None. + unit : str | None, default=None + The unit to use if value is a number or list. Must be specified if value is a number or + list. Ignored if value is a Parameter or sc.Variable, which have their own units. By + default, None. Raises ------ TypeError : - If value is not one of the accepted types, or if unit - is not a string when needed. + If value is not one of the accepted types, or if unit is not a string when needed. UnitError : If the provided unit is invalid. Returns ------- sc.Variable - The input value converted to a scipp Variable with - appropriate units. + The input value converted to a scipp Variable with appropriate units. """ if isinstance(value, sc.Variable): return value diff --git a/src/easydynamics/utils/utils.py b/src/easydynamics/utils/utils.py index 6cb8bd5b..738c17ea 100644 --- a/src/easydynamics/utils/utils.py +++ b/src/easydynamics/utils/utils.py @@ -19,7 +19,8 @@ def _validate_and_convert_Q( Q: np.ndarray | Numeric | list | ArrayLike | sc.Variable | None, ) -> np.ndarray | None: - """Validate and convert Q to a numpy array. + """ + Validate and convert Q to a numpy array. Parameters ---------- @@ -29,11 +30,10 @@ def _validate_and_convert_Q( Raises ------ TypeError : - If Q is not a number, list, numpy array, or scipp - Variable. + If Q is not a number, list, numpy array, or scipp Variable. ValueError : - If Q is a numpy array with more than 1 dimension, or - if Q is a scipp Variable that does not have a single dimension named 'Q'. + If Q is a numpy array with more than 1 dimension, or if Q is a scipp Variable that does not + have a single dimension named 'Q'. Returns ------- @@ -63,7 +63,8 @@ def _validate_and_convert_Q( def _validate_unit(unit: str | sc.Unit | None) -> sc.Unit | None: - """Validate that the unit is a string or scipp Unit. + """ + Validate that the unit is a string or scipp Unit. Parameters ---------- @@ -89,7 +90,8 @@ def _validate_unit(unit: str | sc.Unit | None) -> sc.Unit | None: def _in_notebook() -> bool: - """Check if the code is running in a Jupyter notebook. + """ + Check if the code is running in a Jupyter notebook. Returns ------- From 72070bd5eb692a1b98c4fc1c5fad7c9d2d72440a Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 10:14:27 +0200 Subject: [PATCH 06/12] Reformat pyproject.toml --- pyproject.toml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7cc49a0c..f7fcef4f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -176,12 +176,10 @@ testpaths = ['tests'] # https://docs.astral.sh/ruff/rules/ [tool.ruff] -exclude = [ - 'tmp', -] +exclude = ['tmp'] indent-width = 4 -line-length = 99 # See also `max-line-length` in [tool.ruff.lint.pycodestyle] -preview = true # Enable new rules that are not yet stable, like DOC +line-length = 99 # See also `max-line-length` in [tool.ruff.lint.pycodestyle] +preview = true # Enable new rules that are not yet stable, like DOC # Formatting options for Ruff @@ -199,7 +197,7 @@ select = [ # Various rules #'C90', # https://docs.astral.sh/ruff/rules/#mccabe-c90 #'D', # https://docs.astral.sh/ruff/rules/#pydocstyle-d - 'F', # https://docs.astral.sh/ruff/rules/#pyflakes-f + 'F', # https://docs.astral.sh/ruff/rules/#pyflakes-f #'FLY', # https://docs.astral.sh/ruff/rules/#flynt-fly #'FURB', # https://docs.astral.sh/ruff/rules/#refurb-furb 'I', # https://docs.astral.sh/ruff/rules/#isort-i From 7f6688e10d624e355975e05eb3993147acbf9295 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 10:21:35 +0200 Subject: [PATCH 07/12] Remove unnecessary semicolons in docstrings --- pixi.lock | 4 +-- src/easydynamics/analysis/analysis.py | 18 +++++----- src/easydynamics/analysis/analysis1d.py | 10 +++--- src/easydynamics/analysis/analysis_base.py | 20 +++++------ .../convolution/analytical_convolution.py | 2 +- src/easydynamics/convolution/convolution.py | 2 +- .../convolution/convolution_base.py | 16 ++++----- .../convolution/numerical_convolution_base.py | 16 ++++----- src/easydynamics/experiment/experiment.py | 34 +++++++++---------- .../sample_model/component_collection.py | 32 ++++++++--------- .../components/damped_harmonic_oscillator.py | 10 +++--- .../sample_model/components/delta_function.py | 4 +-- .../sample_model/components/exponential.py | 14 ++++---- .../components/expression_component.py | 12 +++---- .../sample_model/components/gaussian.py | 8 ++--- .../sample_model/components/lorentzian.py | 8 ++--- .../sample_model/components/mixins.py | 12 +++---- .../components/model_component.py | 12 +++---- .../sample_model/components/polynomial.py | 12 +++---- .../sample_model/components/voigt.py | 12 +++---- .../brownian_translational_diffusion.py | 12 +++---- .../diffusion_model/diffusion_model_base.py | 10 +++--- .../jump_translational_diffusion.py | 16 ++++----- .../sample_model/instrument_model.py | 30 ++++++++-------- src/easydynamics/sample_model/model_base.py | 24 ++++++------- .../sample_model/resolution_model.py | 2 +- src/easydynamics/sample_model/sample_model.py | 22 ++++++------ src/easydynamics/utils/detailed_balance.py | 12 +++---- src/easydynamics/utils/utils.py | 6 ++-- 29 files changed, 196 insertions(+), 196 deletions(-) diff --git a/pixi.lock b/pixi.lock index f2a8e7c2..6e9e5a0a 100644 --- a/pixi.lock +++ b/pixi.lock @@ -4071,8 +4071,8 @@ packages: requires_python: '>=3.5' - pypi: ./ name: easydynamics - version: 0.4.0+devdirty6 - sha256: 5b1107b6daf15e96707835633212fc434e3dbfbbd839c89739505f1abcf44453 + version: 0.4.0+dev7 + sha256: 40c3e02a9d2dd9d645f2093effab8e2330e9c255eb924b4897ce7b716b0570de requires_dist: - darkdetect - easyscience diff --git a/src/easydynamics/analysis/analysis.py b/src/easydynamics/analysis/analysis.py index eb7496ea..a37d9f16 100644 --- a/src/easydynamics/analysis/analysis.py +++ b/src/easydynamics/analysis/analysis.py @@ -118,7 +118,7 @@ def analysis_list(self, _value: list[Analysis1d]) -> None: Raises ------ - AttributeError : + AttributeError Always raised, since analysis_list is read-only. """ @@ -185,7 +185,7 @@ def fit( Raises ------ - ValueError : + ValueError If fit_method is not "independent" or "simultaneous" or if there are no Q values available for fitting. @@ -243,12 +243,12 @@ def plot_data_and_model( Raises ------ - ValueError : + ValueError If Q_index is out of bounds, or if there is no data to plot, or if there are no Q values available for plotting. - RuntimeError : + RuntimeError If not in a Jupyter notebook environment. - TypeError : + TypeError If plot_components or add_background is not True or False. Returns @@ -330,7 +330,7 @@ def parameters_to_dataset(self) -> sc.Dataset: Raises ------ - UnitError : + UnitError If there are inconsistent units for the same parameter across different Q values. Returns @@ -408,9 +408,9 @@ def plot_parameters( Raises ------ - TypeError : + TypeError If names is not a string, list of strings, or None. - ValueError : + ValueError If any of the specified parameter names are not found in the dataset. Returns @@ -644,7 +644,7 @@ def _create_components_dataset( Raises ------ - TypeError : + TypeError If add_background is not True or False. Returns diff --git a/src/easydynamics/analysis/analysis1d.py b/src/easydynamics/analysis/analysis1d.py index 866b10f9..3031a537 100644 --- a/src/easydynamics/analysis/analysis1d.py +++ b/src/easydynamics/analysis/analysis1d.py @@ -176,7 +176,7 @@ def fit(self) -> FitResults: Raises ------ - ValueError : + ValueError If no experiment is associated with this Analysis. Returns @@ -284,7 +284,7 @@ def plot_data_and_model( Raises ------ - ValueError : + ValueError If no data is available to plot. Returns @@ -357,7 +357,7 @@ def _require_Q_index(self) -> int: Raises ------ - ValueError : + ValueError If the Q index is not set. Returns @@ -391,7 +391,7 @@ def _verify_energy(self, energy: sc.Variable | None) -> sc.Variable | None: Raises ------ - TypeError : + TypeError If energy is not a sc.Variable or None. Returns @@ -421,7 +421,7 @@ def _calculate_energy_with_offset( Raises ------ - sc.UnitError : + sc.UnitError If the energy and energy offset have incompatible units. Returns diff --git a/src/easydynamics/analysis/analysis_base.py b/src/easydynamics/analysis/analysis_base.py index 2dbd9681..8536986a 100644 --- a/src/easydynamics/analysis/analysis_base.py +++ b/src/easydynamics/analysis/analysis_base.py @@ -56,7 +56,7 @@ def __init__( Raises ------ - TypeError : + TypeError If experiment is not an Experiment or None or if sample_model is not a SampleModel or None or if instrument_model is not an InstrumentModel or None or if extra_parameters is not a Parameter, a list of Parameters, or None. @@ -128,7 +128,7 @@ def experiment(self, value: Experiment) -> None: Raises ------ - TypeError : + TypeError If value is not an Experiment. """ @@ -162,7 +162,7 @@ def sample_model(self, value: SampleModel) -> None: Raises ------ - TypeError : + TypeError If value is not a SampleModel. """ if not isinstance(value, SampleModel): @@ -194,7 +194,7 @@ def instrument_model(self, value: InstrumentModel) -> None: Raises ------ - TypeError : + TypeError If value is not an InstrumentModel. """ if not isinstance(value, InstrumentModel): @@ -226,7 +226,7 @@ def Q(self, _value: sc.Variable) -> None: Raises ------ - AttributeError : + AttributeError If trying to set Q. """ raise AttributeError('Q is a read-only property derived from the Experiment.') @@ -257,7 +257,7 @@ def energy(self, _value: sc.Variable) -> None: Raises ------ - AttributeError : + AttributeError If trying to set energy. """ @@ -289,7 +289,7 @@ def temperature(self, _value: np.ndarray | Parameter) -> None: Raises ------ - AttributeError : + AttributeError If trying to set temperature. """ @@ -319,7 +319,7 @@ def extra_parameters(self, value: Parameter | list[Parameter]) -> None: Raises ------ - TypeError : + TypeError If value is not a Parameter, a list of Parameters, or None. """ if isinstance(value, Parameter): @@ -377,9 +377,9 @@ def _verify_Q_index(self, Q_index: int | None) -> int | None: Raises ------ - TypeError : + TypeError If Q_index is not an integer or None. - IndexError : + IndexError If the Q index is not valid. Returns diff --git a/src/easydynamics/convolution/analytical_convolution.py b/src/easydynamics/convolution/analytical_convolution.py index 2940dc81..d94e4ad7 100644 --- a/src/easydynamics/convolution/analytical_convolution.py +++ b/src/easydynamics/convolution/analytical_convolution.py @@ -140,7 +140,7 @@ def _convolute_analytic_pair( Raises ------ - ValueError : + ValueError If the component pair cannot be handled analytically. Returns diff --git a/src/easydynamics/convolution/convolution.py b/src/easydynamics/convolution/convolution.py index 6694e057..36d88bd6 100644 --- a/src/easydynamics/convolution/convolution.py +++ b/src/easydynamics/convolution/convolution.py @@ -176,7 +176,7 @@ def _check_if_pair_is_analytic( Raises ------ - TypeError : + TypeError If either component is not a ModelComponent, or if the resolution component is a DeltaFunction. diff --git a/src/easydynamics/convolution/convolution_base.py b/src/easydynamics/convolution/convolution_base.py index 1f94d2fc..784f5e84 100644 --- a/src/easydynamics/convolution/convolution_base.py +++ b/src/easydynamics/convolution/convolution_base.py @@ -43,7 +43,7 @@ def __init__( Raises ------ - TypeError : + TypeError If energy is not a numpy ndarray or a scipp Variable or if energy_unit is not a string or scipp unit, or if energy_offset is not a number or a Parameter, or if sample_components is not a ComponentCollection or ModelComponent, or if @@ -117,7 +117,7 @@ def energy_offset(self, energy_offset: Numeric | Parameter) -> None: Raises ------ - TypeError : + TypeError If energy_offset is not a number or a Parameter. """ if not isinstance(energy_offset, Parameter | Numeric): @@ -155,7 +155,7 @@ def energy_with_offset(self, _value: sc.Variable) -> None: Raises ------ - AttributeError : + AttributeError Always raised since energy_with_offset is read-only. """ raise AttributeError( @@ -187,7 +187,7 @@ def energy(self, energy: np.ndarray | sc.Variable) -> None: Raises ------ - TypeError : + TypeError If energy is not a numpy ndarray or a scipp Variable. """ @@ -235,9 +235,9 @@ def convert_energy_unit(self, energy_unit: str | sc.Unit) -> None: Raises ------ - TypeError : + TypeError If energy_unit is not a string or scipp unit. - Exception : + Exception If energy cannot be converted to the specified unit. """ if not isinstance(energy_unit, (str, sc.Unit)): @@ -283,7 +283,7 @@ def sample_components(self, sample_components: ComponentCollection | ModelCompon Raises ------ - TypeError : + TypeError If sample_components is not a ComponentCollection or ModelComponent. """ if not isinstance(sample_components, (ComponentCollection, ModelComponent)): @@ -322,7 +322,7 @@ def resolution_components( Raises ------ - TypeError : + TypeError If resolution_components is not a ComponentCollection or ModelComponent. """ if not isinstance(resolution_components, (ComponentCollection, ModelComponent)): diff --git a/src/easydynamics/convolution/numerical_convolution_base.py b/src/easydynamics/convolution/numerical_convolution_base.py index f93a7447..5d324c85 100644 --- a/src/easydynamics/convolution/numerical_convolution_base.py +++ b/src/easydynamics/convolution/numerical_convolution_base.py @@ -73,7 +73,7 @@ def __init__( Raises ------ - TypeError : + TypeError If temperature is not None, a number, or a Parameter, or if temperature_unit is not a string or sc.Unit, or if upsample_factor is not a number or None, or if extension_factor is not a number, or if normalize_detailed_balance is not a bool. @@ -144,9 +144,9 @@ def upsample_factor(self, factor: Numeric | None) -> None: Raises ------ - TypeError : + TypeError If factor is not a number or None. - ValueError : + ValueError If factor is not greater than 1. """ if factor is None: @@ -196,9 +196,9 @@ def extension_factor(self, factor: Numeric) -> None: Raises ------ - TypeError : + TypeError If factor is not a number. - ValueError : + ValueError If factor is negative. """ @@ -239,7 +239,7 @@ def temperature(self, temp: Parameter | Numeric | None) -> None: Raises ------ - TypeError : + TypeError If temp is not a Numeric, Parameter, or None. """ @@ -289,7 +289,7 @@ def normalize_detailed_balance(self, normalize: bool) -> None: Raises ------ - TypeError : + TypeError If normalize is not a bool. """ @@ -309,7 +309,7 @@ def _create_energy_grid( Raises ------ - ValueError : + ValueError If energy array is not uniformly spaced when upsample_factor is None, or if energy array has less than 2 points. diff --git a/src/easydynamics/experiment/experiment.py b/src/easydynamics/experiment/experiment.py index 2d5a53ab..3ba98185 100644 --- a/src/easydynamics/experiment/experiment.py +++ b/src/easydynamics/experiment/experiment.py @@ -43,7 +43,7 @@ def __init__( Raises ------ - TypeError : + TypeError If data is not a sc.DataArray, a string, or None. """ super().__init__( @@ -95,7 +95,7 @@ def data(self, value: sc.DataArray) -> None: Raises ------ - TypeError : + TypeError If the value is not a sc.DataArray. """ if not isinstance(value, sc.DataArray): @@ -132,7 +132,7 @@ def binned_data(self, _value: sc.DataArray) -> None: Raises ------ - AttributeError : + AttributeError Always, since binned_data is read-only. """ raise AttributeError('binned_data is a read-only property. Use rebin() to rebin the data') @@ -165,7 +165,7 @@ def Q(self, _value: sc.Variable) -> None: Raises ------ - AttributeError : + AttributeError Always, since Q is read-only. """ raise AttributeError('Q is a read-only property derived from the data.') @@ -198,7 +198,7 @@ def energy(self, _value: sc.Variable) -> None: Raises ------ - AttributeError : + AttributeError Always, since energy is read-only. """ raise AttributeError('energy is a read-only property derived from the data.') @@ -215,7 +215,7 @@ def get_masked_energy(self, Q_index: int) -> sc.Variable | None: Raises ------ - IndexError : + IndexError If Q_index is not a valid index for the Q values. Returns @@ -256,7 +256,7 @@ def load_hdf5(self, filename: str, display_name: str | None = None) -> None: Raises ------ - TypeError : + TypeError If filename is not a string or if display_name is not a string or None or if the loaded data is not a sc.DataArray. """ @@ -290,9 +290,9 @@ def save_hdf5(self, filename: str | None = None) -> None: Raises ------ - TypeError : + TypeError If filename is not a string or None. - ValueError : + ValueError If there is no data to save. """ @@ -326,11 +326,11 @@ def rebin(self, dimensions: dict[str, int | sc.Variable]) -> None: Raises ------ - TypeError : + TypeError If dimensions is not a dictionary or if keys/values are of incorrect types. - ValueError : + ValueError If there is no data to rebin. - KeyError : + KeyError If a specified dimension is not in the dataset. """ @@ -386,9 +386,9 @@ def plot_data(self, slicer: bool = False, **kwargs: dict) -> None: Raises ------ - ValueError : + ValueError If there is no data to plot. - RuntimeError : + RuntimeError If not in a Jupyter notebook environment. """ @@ -438,9 +438,9 @@ def _validate_coordinates(data: sc.DataArray) -> None: Raises ------ - TypeError : + TypeError If data is not a sc.DataArray. - ValueError : + ValueError If required coordinates are missing. """ if not isinstance(data, sc.DataArray): @@ -506,7 +506,7 @@ def _extract_x_y_weights_only_finite( Raises ------ - ValueError : + ValueError If any variances are zero after removing NaNs and Infs, since this would lead to infinite weights. diff --git a/src/easydynamics/sample_model/component_collection.py b/src/easydynamics/sample_model/component_collection.py index 966d9916..4b65a68d 100644 --- a/src/easydynamics/sample_model/component_collection.py +++ b/src/easydynamics/sample_model/component_collection.py @@ -44,7 +44,7 @@ def __init__( Raises ------ - TypeError : + TypeError If unit is not a string or sc.Unit, or if components is not a list of ModelComponent. """ @@ -93,7 +93,7 @@ def components(self, components: list[ModelComponent]) -> None: Raises ------ - TypeError : + TypeError If components is not a list of ModelComponent. """ @@ -132,7 +132,7 @@ def is_empty(self, _value: bool) -> None: Raises ------ - AttributeError : + AttributeError Always raised since is_empty is read-only. """ raise AttributeError( @@ -164,7 +164,7 @@ def unit(self, _unit_str: str) -> None: Raises ------ - AttributeError : + AttributeError Always raised since unit is read-only. """ @@ -184,9 +184,9 @@ def convert_unit(self, unit: str | sc.Unit) -> None: Raises ------ - TypeError : + TypeError If unit is not a string or sc.Unit. - Exception : + Exception If any component cannot be converted to the specified unit. """ @@ -225,9 +225,9 @@ def append_component(self, component: ModelComponent | ComponentCollection) -> N Raises ------ - TypeError : + TypeError If component is not a ModelComponent or ComponentCollection. - ValueError : + ValueError If a component with the same unique name already exists in the collection. """ if not isinstance(component, (ModelComponent, ComponentCollection)): @@ -260,9 +260,9 @@ def remove_component(self, unique_name: str) -> None: Raises ------ - TypeError : + TypeError If unique_name is not a string. - KeyError : + KeyError If no component with the given unique name exists in the collection. """ @@ -304,7 +304,7 @@ def components(self, components: list[ModelComponent]) -> None: Raises ------ - TypeError : + TypeError If components is not a list of ModelComponent. """ if not isinstance(components, list): @@ -342,7 +342,7 @@ def is_empty(self, _value: bool) -> None: Raises ------ - AttributeError : + AttributeError Always raised since is_empty is read-only. """ raise AttributeError( @@ -374,7 +374,7 @@ def normalize_area(self) -> None: Raises ------ - ValueError : + ValueError If there are no components in the model or if the total area is zero or not finite, which would prevent normalization. """ @@ -457,11 +457,11 @@ def evaluate_component( Raises ------ - ValueError : + ValueError If there are no components in the model. - TypeError : + TypeError If unique_name is not a string. - KeyError : + KeyError If no component with the given unique name exists in the collection. Returns diff --git a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py index ebc70f60..99515270 100644 --- a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py +++ b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py @@ -97,7 +97,7 @@ def area(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ if not isinstance(value, Numeric): @@ -128,9 +128,9 @@ def center(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. - ValueError : + ValueError If the value is not positive. """ if not isinstance(value, Numeric): @@ -164,9 +164,9 @@ def width(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. - ValueError : + ValueError If the value is not positive. """ if not isinstance(value, Numeric): diff --git a/src/easydynamics/sample_model/components/delta_function.py b/src/easydynamics/sample_model/components/delta_function.py index 213073f8..256c8733 100644 --- a/src/easydynamics/sample_model/components/delta_function.py +++ b/src/easydynamics/sample_model/components/delta_function.py @@ -90,7 +90,7 @@ def area(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ @@ -123,7 +123,7 @@ def center(self, value: Numeric | None) -> None: Raises ------ - TypeError : + TypeError If the value is not a number or None. """ diff --git a/src/easydynamics/sample_model/components/exponential.py b/src/easydynamics/sample_model/components/exponential.py index 70157f1d..c30553c9 100644 --- a/src/easydynamics/sample_model/components/exponential.py +++ b/src/easydynamics/sample_model/components/exponential.py @@ -55,9 +55,9 @@ def __init__( Raises ------ - TypeError : + TypeError If amplitude, center, or rate are not numbers or Parameters. - ValueError : + ValueError If amplitude, center or rate are not finite numbers. """ # Validate inputs and create Parameters if not given @@ -120,7 +120,7 @@ def amplitude(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ @@ -153,7 +153,7 @@ def center(self, value: Numeric | None) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ @@ -189,7 +189,7 @@ def rate(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ if not isinstance(value, Numeric): @@ -236,9 +236,9 @@ def convert_unit(self, unit: str | sc.Unit) -> None: Raises ------ - TypeError : + TypeError If unit is not a string or sc.Unit. - Exception : + Exception If conversion fails for any parameter. """ diff --git a/src/easydynamics/sample_model/components/expression_component.py b/src/easydynamics/sample_model/components/expression_component.py index 878d8671..16246b82 100644 --- a/src/easydynamics/sample_model/components/expression_component.py +++ b/src/easydynamics/sample_model/components/expression_component.py @@ -92,9 +92,9 @@ def __init__( Raises ------ - ValueError : + ValueError If the expression is invalid or does not contain 'x'. - TypeError : + TypeError If any parameter value is not numeric. """ super().__init__(unit=unit, display_name=display_name, unique_name=unique_name) @@ -201,7 +201,7 @@ def expression(self, _new_expr: str) -> None: Raises ------ - AttributeError : + AttributeError Always raised to prevent changing the expression. """ raise AttributeError('Expression cannot be changed after initialization') @@ -258,7 +258,7 @@ def convert_unit(self, _new_unit: str | sc.Unit) -> None: Raises ------ - NotImplementedError : + NotImplementedError Always raised to indicate unit conversion is not supported. """ @@ -279,7 +279,7 @@ def __getattr__(self, name: str) -> Parameter: Raises ------ - AttributeError : + AttributeError If the parameter does not exist. Returns @@ -304,7 +304,7 @@ def __setattr__(self, name: str, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not numeric. """ if '_parameters' in self.__dict__ and name in self._parameters: diff --git a/src/easydynamics/sample_model/components/gaussian.py b/src/easydynamics/sample_model/components/gaussian.py index b5067865..073b4195 100644 --- a/src/easydynamics/sample_model/components/gaussian.py +++ b/src/easydynamics/sample_model/components/gaussian.py @@ -99,7 +99,7 @@ def area(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ @@ -132,7 +132,7 @@ def center(self, value: Numeric | None) -> None: Raises ------ - TypeError : + TypeError If the value is not a number or None. """ @@ -167,9 +167,9 @@ def width(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number or None. - ValueError : + ValueError If the value is not positive. """ if not isinstance(value, Numeric): diff --git a/src/easydynamics/sample_model/components/lorentzian.py b/src/easydynamics/sample_model/components/lorentzian.py index dab0c4fc..41629210 100644 --- a/src/easydynamics/sample_model/components/lorentzian.py +++ b/src/easydynamics/sample_model/components/lorentzian.py @@ -95,7 +95,7 @@ def area(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ if not isinstance(value, Numeric): @@ -126,7 +126,7 @@ def center(self, value: Numeric | None) -> None: Raises ------ - TypeError : + TypeError If the value is not a number or None. """ @@ -161,9 +161,9 @@ def width(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. - ValueError : + ValueError If the value is not positive. """ if not isinstance(value, Numeric): diff --git a/src/easydynamics/sample_model/components/mixins.py b/src/easydynamics/sample_model/components/mixins.py index a7217566..64db6bc0 100644 --- a/src/easydynamics/sample_model/components/mixins.py +++ b/src/easydynamics/sample_model/components/mixins.py @@ -48,9 +48,9 @@ def _create_area_parameter( Raises ------ - TypeError : + TypeError If area is not a number or a Parameter. - ValueError : + ValueError If area is not a finite number or if the area Parameter has a non-finite value. Returns @@ -105,9 +105,9 @@ def _create_center_parameter( Raises ------ - TypeError : + TypeError If center is not None, a number, or a Parameter. - ValueError : + ValueError If center is a number but not finite, or if center is a Parameter but has a non-finite value. @@ -161,9 +161,9 @@ def _create_width_parameter( Raises ------ - TypeError : + TypeError If width is not a number or a Parameter. - ValueError : + ValueError If width is non-positive. Returns diff --git a/src/easydynamics/sample_model/components/model_component.py b/src/easydynamics/sample_model/components/model_component.py index 1b5ccf4e..ab21a4bc 100644 --- a/src/easydynamics/sample_model/components/model_component.py +++ b/src/easydynamics/sample_model/components/model_component.py @@ -66,7 +66,7 @@ def unit(self, _unit_str: str) -> None: Raises ------ - AttributeError : + AttributeError Always raised since unit is read-only. """ raise AttributeError( @@ -99,10 +99,10 @@ def _prepare_x_for_evaluate( Raises ------ - ValueError : + ValueError If x contains NaN or infinite values, or if a sc.DataArray has more than one coordinate. - UnitError : + UnitError If x has incompatible units that cannot be converted to the component's unit. Returns @@ -175,7 +175,7 @@ def validate_unit(unit: str | sc.Unit | None) -> None: Raises ------ - TypeError : + TypeError If unit is not a string or scipp Unit. """ if unit is not None and not isinstance(unit, (str, sc.Unit)): @@ -194,9 +194,9 @@ def convert_unit(self, unit: str | sc.Unit) -> None: Raises ------ - TypeError : + TypeError If the provided unit is not a str or sc.Unit. - Exception : + Exception If the provided unit is invalid or incompatible with the component's parameters. """ if not isinstance(unit, (str, sc.Unit)): diff --git a/src/easydynamics/sample_model/components/polynomial.py b/src/easydynamics/sample_model/components/polynomial.py index 9f73a28d..9bd5b712 100644 --- a/src/easydynamics/sample_model/components/polynomial.py +++ b/src/easydynamics/sample_model/components/polynomial.py @@ -49,10 +49,10 @@ def __init__( Raises ------ - TypeError : + TypeError If coefficients is not a sequence of numbers or Parameters or if any item in coefficients is not a number or Parameter. - ValueError : + ValueError If coefficients is an empty sequence. """ @@ -110,10 +110,10 @@ def coefficients(self, coeffs: Sequence[Numeric | Parameter]) -> None: Raises ------ - TypeError : + TypeError If coeffs is not a sequence of numbers or Parameters or if any item in coeffs is not a number or Parameter. - ValueError : + ValueError If the length of coeffs does not match the existing number of coefficients. """ if not isinstance(coeffs, (list, tuple, np.ndarray)): @@ -201,7 +201,7 @@ def degree(self, _value: int) -> None: Raises ------ - AttributeError : + AttributeError Always raised since degree cannot be set directly. """ raise AttributeError( @@ -231,7 +231,7 @@ def convert_unit(self, unit: str | sc.Unit) -> None: Raises ------ - UnitError : + UnitError If the provided unit is not a string or sc.Unit. """ diff --git a/src/easydynamics/sample_model/components/voigt.py b/src/easydynamics/sample_model/components/voigt.py index 60fa7c64..153bbee3 100644 --- a/src/easydynamics/sample_model/components/voigt.py +++ b/src/easydynamics/sample_model/components/voigt.py @@ -109,7 +109,7 @@ def area(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ if not isinstance(value, Numeric): @@ -140,7 +140,7 @@ def center(self, value: Numeric | None) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. """ if value is None: @@ -174,9 +174,9 @@ def gaussian_width(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. - ValueError : + ValueError If the value is not positive. """ if not isinstance(value, Numeric): @@ -209,9 +209,9 @@ def lorentzian_width(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If the value is not a number. - ValueError : + ValueError If the value is not positive. """ if not isinstance(value, Numeric): diff --git a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py index 0848e88e..b8dbb6be 100644 --- a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py @@ -61,7 +61,7 @@ def __init__( Raises ------ - TypeError : + TypeError If scale or diffusion_coefficient is not a number. """ if not isinstance(scale, Numeric): @@ -115,9 +115,9 @@ def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: Raises ------ - TypeError : + TypeError If diffusion_coefficient is not a number. - ValueError : + ValueError If diffusion_coefficient is negative. """ if not isinstance(diffusion_coefficient, Numeric): @@ -206,7 +206,7 @@ def create_component_collections( Raises ------ - TypeError : + TypeError If component_display_name is not a string. Returns @@ -276,7 +276,7 @@ def _write_width_dependency_expression(self, Q: float) -> str: Raises ------ - TypeError : + TypeError If Q is not a float. Returns @@ -316,7 +316,7 @@ def _write_area_dependency_expression(self, QISF: float) -> str: Raises ------ - TypeError : + TypeError If QISF is not a float. Returns diff --git a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py index 9956d300..3ecd5b05 100644 --- a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py +++ b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py @@ -37,9 +37,9 @@ def __init__( Raises ------ - TypeError : + TypeError If scale is not a number. - UnitError : + UnitError If unit is not a string or scipp Unit, or if it cannot be converted to meV. """ @@ -90,7 +90,7 @@ def unit(self, _unit_str: str) -> None: Raises ------ - AttributeError : + AttributeError Always, since the unit is read-only. """ raise AttributeError( @@ -122,9 +122,9 @@ def scale(self, scale: Numeric) -> None: Raises ------ - TypeError : + TypeError If scale is not a number. - ValueError : + ValueError If scale is negative. """ if not isinstance(scale, Numeric): diff --git a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py index cf6d4101..846a682d 100644 --- a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py @@ -66,7 +66,7 @@ def __init__( Raises ------ - TypeError : + TypeError If scale, diffusion_coefficient, or relaxation_time are not numbers. """ super().__init__( @@ -129,9 +129,9 @@ def diffusion_coefficient(self, diffusion_coefficient: Numeric) -> None: Raises ------ - TypeError : + TypeError If diffusion_coefficient is not a number. - ValueError : + ValueError If diffusion_coefficient is negative. """ if not isinstance(diffusion_coefficient, Numeric): @@ -164,9 +164,9 @@ def relaxation_time(self, relaxation_time: Numeric) -> None: Raises ------ - TypeError : + TypeError If relaxation_time is not a number. - ValueError : + ValueError If relaxation_time is negative. """ if not isinstance(relaxation_time, Numeric): @@ -266,7 +266,7 @@ def create_component_collections( Raises ------ - TypeError : + TypeError If component_display_name is not a string. Returns @@ -334,7 +334,7 @@ def _write_width_dependency_expression(self, Q: float) -> str: Raises ------ - TypeError : + TypeError If Q is not a float. Returns @@ -375,7 +375,7 @@ def _write_area_dependency_expression(self, QISF: float) -> str: Raises ------ - TypeError : + TypeError If QISF is not a float. Returns diff --git a/src/easydynamics/sample_model/instrument_model.py b/src/easydynamics/sample_model/instrument_model.py index 2d4e6e1b..b734015b 100644 --- a/src/easydynamics/sample_model/instrument_model.py +++ b/src/easydynamics/sample_model/instrument_model.py @@ -60,7 +60,7 @@ def __init__( Raises ------ - TypeError : + TypeError If resolution_model is not a ResolutionModel or None, or if background_model is not a BackgroundModel or None, or if energy_offset is not a number or None. """ @@ -134,7 +134,7 @@ def resolution_model(self, value: ResolutionModel) -> None: Raises ------ - TypeError : + TypeError If value is not a ResolutionModel. """ if not isinstance(value, ResolutionModel): @@ -169,7 +169,7 @@ def background_model(self, value: BackgroundModel) -> None: Raises ------ - TypeError : + TypeError If value is not a BackgroundModel. """ @@ -208,7 +208,7 @@ def Q(self, value: Q_type | None) -> None: Raises ------ - ValueError : + ValueError If the new Q values are not similar to the old ones when Q is not None. """ if value is None: @@ -254,7 +254,7 @@ def unit(self, _unit_str: str) -> None: Raises ------ - AttributeError : + AttributeError Always, as the unit is read-only. """ raise AttributeError( @@ -286,7 +286,7 @@ def energy_offset(self, value: Numeric) -> None: Raises ------ - TypeError : + TypeError If value is not a number. """ if not isinstance(value, Numeric): @@ -311,7 +311,7 @@ def clear_Q(self, confirm: bool = False) -> None: Raises ------ - ValueError : + ValueError If confirm is not True. """ if not confirm: @@ -334,7 +334,7 @@ def convert_unit(self, unit_str: str | sc.Unit) -> None: Raises ------ - ValueError : + ValueError If unit_str is not a valid unit string or scipp Unit. """ unit = _validate_unit(unit_str) @@ -361,9 +361,9 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: Raises ------ - TypeError : + TypeError If Q_index is not an int or None. - IndexError : + IndexError If Q_index is out of bounds for the Q values in the InstrumentModel. Returns @@ -419,11 +419,11 @@ def get_energy_offset( Raises ------ - ValueError : + ValueError If no Q values are set in the InstrumentModel. - IndexError : + IndexError If Q_index is out of bounds. - TypeError : + TypeError If Q_index is not an int or None. Returns @@ -496,9 +496,9 @@ def _fix_or_free_energy_offset(self, Q_index: int | None = None, fixed: bool = T Raises ------ - TypeError : + TypeError If Q_index is not an int or None. - IndexError : + IndexError If Q_index is out of bounds for the Q values in the InstrumentModel. """ diff --git a/src/easydynamics/sample_model/model_base.py b/src/easydynamics/sample_model/model_base.py index 384c6204..3b50a2d2 100644 --- a/src/easydynamics/sample_model/model_base.py +++ b/src/easydynamics/sample_model/model_base.py @@ -50,7 +50,7 @@ def __init__( Raises ------ - TypeError : + TypeError If components is not a ModelComponent or ComponentCollection. """ super().__init__( @@ -89,7 +89,7 @@ def evaluate( Raises ------ - ValueError : + ValueError If there are no components in the model to evaluate. Returns @@ -167,7 +167,7 @@ def unit(self, _unit_str: str) -> None: Raises ------ - AttributeError : + AttributeError Always raised to indicate that the unit is read-only. """ raise AttributeError( @@ -186,9 +186,9 @@ def convert_unit(self, unit: str | sc.Unit) -> None: Raises ------ - TypeError : + TypeError If the provided unit is not a string or sc.Unit. - Exception : + Exception If the provided unit is not compatible with the current unit. """ @@ -234,7 +234,7 @@ def components(self, value: ModelComponent | ComponentCollection | None) -> None Raises ------ - TypeError : + TypeError If value is not a ModelComponent, ComponentCollection, or None. """ if not isinstance(value, (ModelComponent, ComponentCollection, type(None))): @@ -271,7 +271,7 @@ def Q(self, value: Q_type | None) -> None: Raises ------ - ValueError : + ValueError If the new Q values are not similar to the old ones when Q is already set. """ if value is None: @@ -302,7 +302,7 @@ def clear_Q(self, confirm: bool = False) -> None: Raises ------ - ValueError : + ValueError If confirm is not True. """ if not confirm: @@ -339,9 +339,9 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: Raises ------ - TypeError : + TypeError If Q_index is not an int or None. - IndexError : + IndexError If Q_index is out of bounds for the number of ComponentCollections. Returns @@ -379,9 +379,9 @@ def get_component_collection(self, Q_index: int) -> ComponentCollection: Raises ------ - TypeError : + TypeError If Q_index is not an int. - IndexError : + IndexError If Q_index is out of bounds for the number of ComponentCollections. Returns diff --git a/src/easydynamics/sample_model/resolution_model.py b/src/easydynamics/sample_model/resolution_model.py index e4ba1b63..5a140863 100644 --- a/src/easydynamics/sample_model/resolution_model.py +++ b/src/easydynamics/sample_model/resolution_model.py @@ -65,7 +65,7 @@ def append_component(self, component: ModelComponent | ComponentCollection) -> N Raises ------ - TypeError : + TypeError If the component is a DeltaFunction or Polynomial. """ if isinstance(component, ComponentCollection): diff --git a/src/easydynamics/sample_model/sample_model.py b/src/easydynamics/sample_model/sample_model.py index d01e2e34..39b66271 100644 --- a/src/easydynamics/sample_model/sample_model.py +++ b/src/easydynamics/sample_model/sample_model.py @@ -67,10 +67,10 @@ def __init__( Raises ------ - TypeError : + TypeError If diffusion_models is not a DiffusionModelBase, a list of DiffusionModelBase, or None, or if temperature is not a number or None, or if divide_by_temperature is not a bool. - ValueError : + ValueError If temperature is negative. """ if diffusion_models is None: @@ -131,7 +131,7 @@ def append_diffusion_model(self, diffusion_model: DiffusionModelBase) -> None: Raises ------ - TypeError : + TypeError If the diffusion_model is not a DiffusionModelBase. """ @@ -154,7 +154,7 @@ def remove_diffusion_model(self, name: 'str') -> None: Raises ------ - ValueError : + ValueError If no DiffusionModel with the given unique name is found. """ for i, dm in enumerate(self._diffusion_models): @@ -203,7 +203,7 @@ def diffusion_models( Raises ------ - TypeError : + TypeError If value is not a DiffusionModelBase, a list of DiffusionModelBase, or None. """ @@ -247,9 +247,9 @@ def temperature(self, value: Numeric | None) -> None: Raises ------ - TypeError : + TypeError If value is not a number or None. - ValueError : + ValueError If value is negative. """ if value is None: @@ -297,7 +297,7 @@ def temperature_unit(self, _value: str | sc.Unit) -> None: Raises ------ - AttributeError : + AttributeError Always, as temperature_unit is read-only. """ @@ -317,9 +317,9 @@ def convert_temperature_unit(self, unit: str | sc.Unit) -> None: Raises ------ - ValueError : + ValueError If temperature is not set or conversion fails. - Exception : + Exception If the provided unit is invalid or cannot be converted. """ @@ -361,7 +361,7 @@ def divide_by_temperature(self, value: bool) -> None: Raises ------ - TypeError : + TypeError If value is not a bool. """ if not isinstance(value, bool): diff --git a/src/easydynamics/utils/detailed_balance.py b/src/easydynamics/utils/detailed_balance.py index e2cfcdee..866e4788 100644 --- a/src/easydynamics/utils/detailed_balance.py +++ b/src/easydynamics/utils/detailed_balance.py @@ -51,18 +51,18 @@ def detailed_balance_factor( Raises ------ - TypeError : + TypeError If energy or temperature is not a number, list, numpy array, or scipp Variable, or if energy_unit or temperature_unit is not a string or scipp Unit, or if divide_by_temperature is not a boolean. - ValueError : + ValueError If temperature is negative, or if energy is a numpy array with more than 1 dimension, or if temperature is a scipp Variable that does not have a single dimension named 'temperature', or if energy is a scipp Variable that does not have a single dimension named 'energy'. - UnitError : + UnitError If the provided energy_unit or temperature_unit is invalid, or if the units of energy or temperature cannot be converted to the expected units. - ZeroDivisionError : + ZeroDivisionError If divide_by_temperature is True and temperature is zero. Returns @@ -200,9 +200,9 @@ def _convert_to_scipp_variable( Raises ------ - TypeError : + TypeError If value is not one of the accepted types, or if unit is not a string when needed. - UnitError : + UnitError If the provided unit is invalid. Returns diff --git a/src/easydynamics/utils/utils.py b/src/easydynamics/utils/utils.py index 738c17ea..3d383d9c 100644 --- a/src/easydynamics/utils/utils.py +++ b/src/easydynamics/utils/utils.py @@ -29,9 +29,9 @@ def _validate_and_convert_Q( Raises ------ - TypeError : + TypeError If Q is not a number, list, numpy array, or scipp Variable. - ValueError : + ValueError If Q is a numpy array with more than 1 dimension, or if Q is a scipp Variable that does not have a single dimension named 'Q'. @@ -73,7 +73,7 @@ def _validate_unit(unit: str | sc.Unit | None) -> sc.Unit | None: Raises ------ - TypeError : + TypeError If unit is not None, a string, or a scipp Unit. Returns From 6db0067b5cd23b59c07bb0000132d52aa9de5abd Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 10:24:47 +0200 Subject: [PATCH 08/12] Remove redundant lines in docstrings --- src/easydynamics/analysis/analysis_base.py | 1 - src/easydynamics/sample_model/model_base.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/easydynamics/analysis/analysis_base.py b/src/easydynamics/analysis/analysis_base.py index 8536986a..6c606373 100644 --- a/src/easydynamics/analysis/analysis_base.py +++ b/src/easydynamics/analysis/analysis_base.py @@ -240,7 +240,6 @@ def energy(self) -> sc.Variable | None: ------- sc.Variable | None The energy values from the associated. - sc.Variable | None """ return self.experiment.energy diff --git a/src/easydynamics/sample_model/model_base.py b/src/easydynamics/sample_model/model_base.py index 3b50a2d2..53fc74ba 100644 --- a/src/easydynamics/sample_model/model_base.py +++ b/src/easydynamics/sample_model/model_base.py @@ -388,7 +388,6 @@ def get_component_collection(self, Q_index: int) -> ComponentCollection: ------- ComponentCollection The ComponentCollection at the. - ComponentCollection """ if not isinstance(Q_index, int): raise TypeError(f'Q_index must be an int, got {type(Q_index).__name__}') From 0fb8e1ab295080bccc6d103083cdb49610bde869 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 10:27:20 +0200 Subject: [PATCH 09/12] Add tutorial for Magnetic nanoparticles to TOC --- docs/mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index cfde9673..a821a82f 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -182,6 +182,7 @@ nav: - Tutorials: tutorials/index.md - Getting Started: - Tutorial 1. Brownian Diffusion: tutorials/tutorial1_brownian.ipynb + - Tutorial 2. Magnetic nanoparticles: tutorials/tutorial2_nanoparticles.ipynb - Classes and Methods: - Components: tutorials/components.ipynb - Component collection: tutorials/component_collection.ipynb From 236009e7e1150991480328ce5bae56984af765b5 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Thu, 2 Apr 2026 10:33:37 +0200 Subject: [PATCH 10/12] Remove temporary ignored linting rules --- pixi.lock | 4 ++-- pyproject.toml | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/pixi.lock b/pixi.lock index 6e9e5a0a..1665d1a6 100644 --- a/pixi.lock +++ b/pixi.lock @@ -4071,8 +4071,8 @@ packages: requires_python: '>=3.5' - pypi: ./ name: easydynamics - version: 0.4.0+dev7 - sha256: 40c3e02a9d2dd9d645f2093effab8e2330e9c255eb924b4897ce7b716b0570de + version: 0.4.0+devdirty10 + sha256: bd1d44f7263fe45e52e8b62d2740c303be86c7bcc89e3cbec95ec663568953b1 requires_dist: - darkdetect - easyscience diff --git a/pyproject.toml b/pyproject.toml index f7fcef4f..49f35979 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -260,10 +260,6 @@ ignore = [ 'DOC', # https://docs.astral.sh/ruff/rules/#pydoclint-doc # Disable, as [tool.format_docstring] split one-line docstrings into the canonical multi-line layout 'D200', # https://docs.astral.sh/ruff/rules/unnecessary-multiline-docstring/ - # Temporary: - 'D100', # https://docs.astral.sh/ruff/rules/undocumented-public-module/#undocumented-publi-module-d100 - 'D104', # https://docs.astral.sh/ruff/rules/undocumented-public-package/#undocumented-public-package-d104 - 'DTZ005', # https://docs.astral.sh/ruff/rules/call-datetime-now-without-tzinfo/#call-datetime-now-without-tzinfo-dtz005 ] # Ignore specific rules in certain files or directories From 06f51bfc027a8b5a39e0e0b9ba93e36e8aa86f78 Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Sun, 5 Apr 2026 12:14:31 +0200 Subject: [PATCH 11/12] Apply latest templates --- .copier-answers.yml | 2 +- .github/workflows/coverage.yml | 10 +- pixi.toml | 4 +- tools/param_consistency.py | 677 --------------------------------- 4 files changed, 8 insertions(+), 685 deletions(-) delete mode 100644 tools/param_consistency.py diff --git a/.copier-answers.yml b/.copier-answers.yml index c497a08f..c3886bcb 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,6 +1,6 @@ # WARNING: Do not edit this file manually. # Any changes will be overwritten by Copier. -_commit: v0.10.1-35-g96726f0 +_commit: v0.10.1-38-g85fbe04 _src_path: gh:easyscience/templates app_docs_url: https://easyscience.github.io/dynamics-app app_doi: 10.5281/zenodo.18877180 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index cd9ff1e0..e1e44d41 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,8 +1,10 @@ name: Coverage checks on: - # Trigger the workflow on push + # Trigger the workflow on push to develop push: + branches: + - develop # Do not run on version tags (those are handled by other workflows) tags-ignore: ['v*'] # Trigger the workflow on pull request @@ -15,11 +17,11 @@ permissions: actions: write contents: read -# Allow only one concurrent workflow, skipping runs queued between the run -# in-progress and latest queued. And cancel in-progress runs. +# Allow only one concurrent workflow per PR or branch ref. +# Cancel in-progress runs only for pull requests, but let branch push runs finish. concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.event_name == 'pull_request' }} # Set the environment variables to be used in all jobs defined in this workflow env: diff --git a/pixi.toml b/pixi.toml index e39b7d48..ac6a7e02 100644 --- a/pixi.toml +++ b/pixi.toml @@ -102,7 +102,6 @@ test = { depends-on = ['unit-tests'] } ########### pyproject-check = 'python -m validate_pyproject pyproject.toml' -param-docstring-check = 'python tools/param_consistency.py src/ --check' docstring-lint-check = 'pydoclint --quiet src/' notebook-lint-check = 'nbqa ruff docs/docs/tutorials/' py-lint-check = 'ruff check src/ tests/ docs/docs/tutorials/' @@ -116,9 +115,8 @@ check = 'pre-commit run --hook-stage manual --all-files' # 🛠️ Fixes ########## -param-docstring-fix = 'python tools/param_consistency.py src/ --fix' -docstring-format-fix = 'format-docstring src/' docstring-transform = 'pixi run docstripy src/ -s=numpy -w' +docstring-format-fix = 'format-docstring src/' notebook-lint-fix = 'nbqa ruff --fix docs/docs/tutorials/' py-lint-fix = 'ruff check --fix src/ tests/ docs/docs/tutorials/' py-lint-fix-unsafe = 'ruff check --fix --unsafe-fixes src/ tests/ docs/docs/tutorials/' diff --git a/tools/param_consistency.py b/tools/param_consistency.py deleted file mode 100644 index cd63989c..00000000 --- a/tools/param_consistency.py +++ /dev/null @@ -1,677 +0,0 @@ -"""Check and fix consistency between Parameter/Descriptor -definitions and their public property docstrings and type -annotations. - -Usage:: - - python param_consistency.py --check - python param_consistency.py --fix - python param_consistency.py src/mypackage/ --check - -Template (see architecture.md §9.8 for the full spec) ------------------------------------------------------- -Given ``description='Length of the a axis of the unit -cell.'``, ``units='Å'``, and type ``Parameter``: - -Writable:: - - @property - def length_a(self) -> Parameter: - \"""Length of the a axis of the unit cell (Å). - - Reading this property returns the underlying - ``Parameter`` object. Assigning to it updates - the parameter value. - \""" - return self._length_a - - @length_a.setter - def length_a(self, value: float) -> None: - self._length_a.value = value - -Read-only:: - - @property - def length_a(self) -> Parameter: - \"""Length of the a axis of the unit cell (Å). - - Reading this property returns the underlying - ``Parameter`` object. - \""" - return self._length_a - -Rules: - -- ``{desc}`` = description without trailing period - (single source of truth). -- ``{units}`` = units string; omit ``({units})`` when - absent or empty. -- Getter summary: ``{desc} ({units}).`` or ``{desc}.`` -- Getter body mentions the descriptor class and, for - writable properties, notes that assignment updates - the value. -- Setter has **no** docstring. -- Getter return annotation: the descriptor class name. -- Setter value annotation: ``float`` for numeric, - ``str`` for string. -- Setter return annotation: ``None``. - -Exit code 0 when all checks pass (or fix succeeds), -1 otherwise. -""" - -from __future__ import annotations - -import argparse -import ast -import sys -from dataclasses import dataclass -from dataclasses import field -from pathlib import Path - -# --------------------------------------------------------- -# Constants -# --------------------------------------------------------- - -_SRC_ROOT = ( - Path(__file__).resolve().parents[1] - / 'src' - / 'easydiffraction' -) - -_DESCRIPTOR_TYPES = frozenset( - {'Parameter', 'NumericDescriptor', 'StringDescriptor'} -) - -# Canonical setter value annotation per descriptor family. -_SETTER_ANN: dict[str, str] = { - 'Parameter': 'float', - 'NumericDescriptor': 'float', - 'StringDescriptor': 'str', -} - - -# --------------------------------------------------------- -# Data structures -# --------------------------------------------------------- - - -@dataclass -class DescriptorInfo: - """Descriptor definition from ``__init__``.""" - - attr_name: str # e.g. '_length_a' - prop_name: str # e.g. 'length_a' - type_name: str # 'Parameter' | … - description: str # e.g. 'Length of …' - units: str | None # e.g. 'Å', or None - - -@dataclass -class PropertyInfo: - """Property getter / setter AST nodes.""" - - name: str - getter: ast.FunctionDef - setter: ast.FunctionDef | None = None - - -@dataclass -class Edit: - """A source-level edit. - - Replace ``lines[start:end]`` with *new_text*. - When ``start == end`` the edit is an insertion - before that line. - """ - - start: int # 0-based inclusive - end: int # 0-based exclusive - new_text: str - - -@dataclass -class FileResult: - """Analysis result for one source file.""" - - path: Path - issues: list[str] = field(default_factory=list) - edits: list[Edit] = field(default_factory=list) - - -# --------------------------------------------------------- -# Template helpers -# --------------------------------------------------------- - - -def _strip_dot(s: str) -> str: - """Remove trailing period and whitespace.""" - s = s.rstrip() - if s.endswith('.'): - s = s[:-1].rstrip() - return s - - -def _getter_docstring( - desc: str, - units: str | None, - type_name: str, - has_setter: bool, - indent: str, -) -> str: - """Build the expected getter docstring.""" - d = _strip_dot(desc) - summary = f'{d} ({units}).' if units else f'{d}.' - - if has_setter: - body = ( - f'Reading this property returns the underlying ' - f'``{type_name}`` object. ' - f'Assigning to it updates the parameter value.' - ) - else: - body = ( - f'Reading this property returns the underlying ' - f'``{type_name}`` object.' - ) - - return ( - f'{indent}"""{summary}\n' - f'\n' - f'{indent}{body}\n' - f'{indent}"""\n' - ) - - -def _normalize(text: str) -> str: - """Collapse whitespace for comparison.""" - return ' '.join(text.split()).lower() - - -# --------------------------------------------------------- -# AST helpers -# --------------------------------------------------------- - - -def _call_name(node: ast.Call) -> str | None: - """Return the simple name of a Call's func.""" - if isinstance(node.func, ast.Name): - return node.func.id - if isinstance(node.func, ast.Attribute): - return node.func.attr - return None - - -def _kwarg_str( - call: ast.Call, - name: str, -) -> str | None: - """Extract a string keyword argument.""" - for kw in call.keywords: - if ( - kw.arg == name - and isinstance(kw.value, ast.Constant) - and isinstance(kw.value.value, str) - ): - return kw.value.value - return None - - -def _ann_str(ann: ast.expr | None) -> str | None: - """Return annotation as a source string.""" - if ann is None: - return None - if isinstance(ann, ast.Name): - return ann.id - if isinstance(ann, ast.Constant) and isinstance( - ann.value, str - ): - return ann.value # forward reference - return ast.unparse(ann) - - -def _body_indent( - func: ast.FunctionDef, - lines: list[str], -) -> str: - """Compute the indentation for the body.""" - def_line = lines[func.lineno - 1] - return ' ' * ( - len(def_line) - len(def_line.lstrip()) + 4 - ) - - -def _def_line_range( - func: ast.FunctionDef, - lines: list[str], -) -> tuple[int, int]: - """Return 0-based [start, end) of the def.""" - start = func.lineno - 1 - for i in range(start, min(start + 10, len(lines))): - if lines[i].rstrip().endswith(':'): - return start, i + 1 - if func.body and i + 1 >= func.body[0].lineno: - break - return start, start + 1 - - -def _docstring_range( - func: ast.FunctionDef, -) -> tuple[str | None, int, int]: - """Return (text, start_0, end_exclusive_0).""" - if not func.body: - return None, -1, -1 - first = func.body[0] - if ( - isinstance(first, ast.Expr) - and isinstance(first.value, ast.Constant) - and isinstance(first.value.value, str) - ): - # end_lineno is 1-based inclusive - return ( - first.value.value, - first.lineno - 1, - first.end_lineno, - ) - return None, -1, -1 - - -# --------------------------------------------------------- -# Extraction -# --------------------------------------------------------- - - -def _extract_descriptors( - cls: ast.ClassDef, -) -> dict[str, DescriptorInfo]: - """Find self._xxx = DescriptorType(...) in init.""" - result: dict[str, DescriptorInfo] = {} - - init = next( - ( - n - for n in cls.body - if isinstance(n, ast.FunctionDef) - and n.name == '__init__' - ), - None, - ) - if init is None: - return result - - for stmt in ast.walk(init): - if ( - isinstance(stmt, ast.Assign) - and len(stmt.targets) == 1 - ): - target = stmt.targets[0] - value = stmt.value - elif ( - isinstance(stmt, ast.AnnAssign) - and stmt.value is not None - ): - target = stmt.target - value = stmt.value - else: - continue - - # Target must be self._xxx - if not ( - isinstance(target, ast.Attribute) - and isinstance(target.value, ast.Name) - and target.value.id == 'self' - and target.attr.startswith('_') - ): - continue - - if not isinstance(value, ast.Call): - continue - - name = _call_name(value) - if name not in _DESCRIPTOR_TYPES: - continue - - desc_str = _kwarg_str(value, 'description') - if not desc_str or not _strip_dot(desc_str): - continue - - units = _kwarg_str(value, 'units') or None - prop = target.attr.lstrip('_') - result[prop] = DescriptorInfo( - target.attr, prop, name, desc_str, units - ) - - return result - - -def _extract_properties( - cls: ast.ClassDef, -) -> dict[str, PropertyInfo]: - """Find property getters and setters.""" - result: dict[str, PropertyInfo] = {} - - for item in cls.body: - if not isinstance(item, ast.FunctionDef): - continue - for dec in item.decorator_list: - # @property - if ( - isinstance(dec, ast.Name) - and dec.id == 'property' - ): - result[item.name] = PropertyInfo( - item.name, item - ) - break - # @xxx.setter - if ( - isinstance(dec, ast.Attribute) - and dec.attr == 'setter' - and isinstance(dec.value, ast.Name) - and dec.value.id in result - ): - result[dec.value.id].setter = item - break - - return result - - -# --------------------------------------------------------- -# Analysis (shared by --check and --fix) -# --------------------------------------------------------- - - -def _analyze_file(path: Path) -> FileResult: - """Analyze one file, return issues and edits.""" - result = FileResult(path) - try: - source = path.read_text(encoding='utf-8') - except Exception: # noqa: BLE001 - return result - - lines = source.splitlines(keepends=True) - - try: - tree = ast.parse(source, filename=str(path)) - except SyntaxError: - return result - - for node in tree.body: - if not isinstance(node, ast.ClassDef): - continue - - descriptors = _extract_descriptors(node) - properties = _extract_properties(node) - - for prop_name, prop in properties.items(): - if prop_name not in descriptors: - continue - desc = descriptors[prop_name] - _analyze_property( - node.name, prop, desc, lines, result - ) - - return result - - -def _analyze_property( - cls_name: str, - prop: PropertyInfo, - desc: DescriptorInfo, - lines: list[str], - result: FileResult, -) -> None: - """Check one property against the template.""" - loc = f'{cls_name}.{prop.name}' - indent = _body_indent(prop.getter, lines) - has_setter = prop.setter is not None - - # --- Getter return annotation --- - actual_ret = _ann_str(prop.getter.returns) - expected_ret = desc.type_name - if actual_ret != expected_ret: - result.issues.append( - f'{loc}: getter annotation ' - f'-> {actual_ret} (expected {expected_ret})' - ) - ds, de = _def_line_range(prop.getter, lines) - def_indent = lines[ds][ - : len(lines[ds]) - len(lines[ds].lstrip()) - ] - new_def = ( - f'{def_indent}def {prop.name}' - f'(self) -> {expected_ret}:\n' - ) - result.edits.append(Edit(ds, de, new_def)) - - # --- Getter docstring --- - expected_doc = _getter_docstring( - desc.description, - desc.units, - desc.type_name, - has_setter, - indent, - ) - actual_doc_text, doc_s, doc_e = _docstring_range( - prop.getter - ) - - if actual_doc_text is None: - result.issues.append( - f'{loc}: getter missing docstring' - ) - _, def_end = _def_line_range(prop.getter, lines) - result.edits.append( - Edit(def_end, def_end, expected_doc) - ) - else: - actual_src = ''.join(lines[doc_s:doc_e]) - if _normalize(actual_src) != _normalize( - expected_doc - ): - result.issues.append( - f'{loc}: getter docstring ' - 'does not match template' - ) - result.edits.append( - Edit(doc_s, doc_e, expected_doc) - ) - - # --- Setter --- - if prop.setter is None: - return - - # Setter def-line annotations - setter_args = prop.setter.args.args - setter_param = ( - setter_args[1].arg - if len(setter_args) >= 2 - else 'value' - ) - expected_ann = _SETTER_ANN[desc.type_name] - - actual_val_ann = None - if ( - len(setter_args) >= 2 - and setter_args[1].annotation - ): - actual_val_ann = _ann_str( - setter_args[1].annotation - ) - - actual_ret_ann = _ann_str(prop.setter.returns) - - if ( - actual_val_ann != expected_ann - or actual_ret_ann != 'None' - ): - parts: list[str] = [] - if actual_val_ann != expected_ann: - parts.append( - f'value: {actual_val_ann} ' - f'(expected {expected_ann})' - ) - if actual_ret_ann != 'None': - parts.append( - f'return: {actual_ret_ann} ' - '(expected None)' - ) - result.issues.append( - f'{loc}: setter annotation ' - f'— {", ".join(parts)}' - ) - - ds, de = _def_line_range(prop.setter, lines) - def_indent = lines[ds][ - : len(lines[ds]) - len(lines[ds].lstrip()) - ] - new_def = ( - f'{def_indent}def {prop.name}' - f'(self, {setter_param}: ' - f'{expected_ann}) -> None:\n' - ) - result.edits.append(Edit(ds, de, new_def)) - - # Setter docstring — should not exist - setter_doc_text, sd_s, sd_e = _docstring_range( - prop.setter - ) - if setter_doc_text is not None: - result.issues.append( - f'{loc}: setter has docstring ' - '(should have none)' - ) - result.edits.append(Edit(sd_s, sd_e, '')) - - -# --------------------------------------------------------- -# Apply edits -# --------------------------------------------------------- - - -def _apply_edits( - lines: list[str], - edits: list[Edit], -) -> list[str]: - """Apply edits bottom-up to preserve line numbers.""" - sorted_edits = sorted( - edits, key=lambda e: e.start, reverse=True - ) - result = list(lines) - for edit in sorted_edits: - new_lines = edit.new_text.splitlines(keepends=True) - result[edit.start : edit.end] = new_lines - return result - - -# --------------------------------------------------------- -# Entry point -# --------------------------------------------------------- - - -def _collect_py_files(paths: list[str]) -> list[Path]: - """Resolve paths to a sorted list of .py files. - - Each entry can be a directory (recursively globbed) - or a single .py file. When *paths* is empty, - defaults to ``_SRC_ROOT``. - """ - if not paths: - return sorted(_SRC_ROOT.rglob('*.py')) - - result: list[Path] = [] - for raw in paths: - p = Path(raw).resolve() - if p.is_dir(): - result.extend(p.rglob('*.py')) - elif p.is_file() and p.suffix == '.py': - result.append(p) - return sorted(set(result)) - - -def main() -> int: - """Run param-consistency check or fix.""" - parser = argparse.ArgumentParser( - description=( - 'Parameter / property consistency: ' - 'docstrings and type hints.' - ), - ) - parser.add_argument( - 'paths', - nargs='*', - help=( - 'Directories or .py files to scan ' - '(default: src/easydiffraction/)' - ), - ) - group = parser.add_mutually_exclusive_group() - group.add_argument( - '--check', - action='store_true', - help='Validate consistency (default)', - ) - group.add_argument( - '--fix', - action='store_true', - help='Auto-fix docstrings and type hints', - ) - args = parser.parse_args() - - py_files = _collect_py_files(args.paths) - repo_root = Path(__file__).resolve().parents[1] - total_issues = 0 - total_fixed = 0 - files_touched = 0 - - for path in py_files: - result = _analyze_file(path) - if not result.issues: - continue - - try: - rel = path.relative_to(repo_root) - except ValueError: - rel = path - - if args.fix: - source_lines = path.read_text( - encoding='utf-8' - ).splitlines(keepends=True) - fixed_lines = _apply_edits( - source_lines, result.edits - ) - path.write_text( - ''.join(fixed_lines), encoding='utf-8' - ) - count = len(result.issues) - total_fixed += count - files_touched += 1 - print( - f'📝 {rel}: fixed {count} issue(s)' - ) - else: - for issue in result.issues: - print(f' ❌ {rel}: {issue}') - total_issues += len(result.issues) - - # Summary - print() - if args.fix: - print( - f'✅ Fixed {total_fixed} issue(s) ' - f'in {files_touched} file(s).' - ) - return 0 - if total_issues: - print( - f'❌ {total_issues} consistency ' - 'issue(s) found.' - ) - return 1 - print('✅ All properties match the template.') - return 0 - - -if __name__ == '__main__': - sys.exit(main()) From 17c04be31a15756ebf8e72649097f1e82f0b54ca Mon Sep 17 00:00:00 2001 From: Andrew Sazonov Date: Sun, 5 Apr 2026 12:36:10 +0200 Subject: [PATCH 12/12] Get rid of "By default..." in argument descriptions --- src/easydynamics/analysis/analysis.py | 42 +++++++-------- src/easydynamics/analysis/analysis1d.py | 54 +++++++++---------- src/easydynamics/analysis/analysis_base.py | 10 ++-- .../convolution/analytical_convolution.py | 8 +-- src/easydynamics/convolution/convolution.py | 15 +++--- .../convolution/convolution_base.py | 8 +-- .../convolution/numerical_convolution.py | 15 +++--- .../convolution/numerical_convolution_base.py | 14 ++--- src/easydynamics/experiment/experiment.py | 13 +++-- .../sample_model/background_model.py | 10 ++-- .../sample_model/component_collection.py | 8 +-- .../components/damped_harmonic_oscillator.py | 8 +-- .../sample_model/components/delta_function.py | 10 ++-- .../sample_model/components/exponential.py | 11 ++-- .../components/expression_component.py | 8 +-- .../sample_model/components/gaussian.py | 12 ++--- .../sample_model/components/lorentzian.py | 12 ++--- .../sample_model/components/mixins.py | 15 +++--- .../components/model_component.py | 6 +-- .../sample_model/components/polynomial.py | 6 +-- .../sample_model/components/voigt.py | 14 ++--- .../brownian_translational_diffusion.py | 10 ++-- .../diffusion_model/diffusion_model_base.py | 6 +-- .../jump_translational_diffusion.py | 13 +++-- .../sample_model/instrument_model.py | 29 +++++----- src/easydynamics/sample_model/model_base.py | 14 ++--- .../sample_model/resolution_model.py | 10 ++-- src/easydynamics/sample_model/sample_model.py | 17 +++--- src/easydynamics/utils/detailed_balance.py | 4 +- 29 files changed, 194 insertions(+), 208 deletions(-) diff --git a/src/easydynamics/analysis/analysis.py b/src/easydynamics/analysis/analysis.py index a37d9f16..bb937e34 100644 --- a/src/easydynamics/analysis/analysis.py +++ b/src/easydynamics/analysis/analysis.py @@ -41,22 +41,20 @@ def __init__( Parameters ---------- display_name : str | None, default='MyAnalysis' - Display name of the analysis. By default, 'MyAnalysis'. + Display name of the analysis. unique_name : str | None, default=None - Unique name of the analysis. If None, a unique name is automatically generated. By - default, None. + Unique name of the analysis. If None, a unique name is automatically generated. experiment : Experiment | None, default=None The Experiment associated with this Analysis. If None, a default Experiment is created. - By default, None. sample_model : SampleModel | None, default=None The SampleModel associated with this Analysis. If None, a default SampleModel is - created. By default, None. + created. instrument_model : InstrumentModel | None, default=None The InstrumentModel associated with this Analysis. If None, a default InstrumentModel - is created. By default, None. + is created. extra_parameters : Parameter | list[Parameter] | None, default=None Extra parameters to be included in the analysis for advanced users. If None, no extra - parameters are added. By default, None. + parameters are added. """ # Avoid triggering updates before the object is fully @@ -144,11 +142,10 @@ def calculate( Parameters ---------- Q_index : int | None, default=None - Index of the Q value to calculate for. If None, calculate for all Q values. By default, - None. + Index of the Q value to calculate for. If None, calculate for all Q values. energy : sc.Variable | None, default=None The energy values to use for calculating the model. If None, uses the energy from the - experiment. By default, None. + experiment. Returns ------- @@ -177,11 +174,10 @@ def fit( ---------- fit_method : str, default='independent' Method to use for fitting. Options are "independent" (fit each Q index independently, - one after the other) or "simultaneous" (fit all Q indices simultaneously). By default, - 'independent'. + one after the other) or "simultaneous" (fit all Q indices simultaneously). Q_index : int | None, default=None If fit_method is "independent", specify which Q index to fit. If None, fit all Q - indices independently. Ignored if fit_method is "simultaneous". By default, None. + indices independently. Ignored if fit_method is "simultaneous". Raises ------ @@ -229,15 +225,15 @@ def plot_data_and_model( Parameters ---------- Q_index : int | None, default=None - Index of the Q value to plot. If None, plot all Q values. By default, None. + Index of the Q value to plot. If None, plot all Q values. plot_components : bool, default=True - Whether to plot the individual components. By default, True. + Whether to plot the individual components. add_background : bool, default=True Whether to add background components to the sample model components when plotting. - Default is True. By default, True. + Default is True. energy : sc.Variable | None, default=None The energy values to use for calculating the model. If None, uses the energy from the - experiment. By default, None. + experiment. **kwargs : dict[str, Any] Additional keyword arguments passed to plopp for customizing the plot. @@ -401,7 +397,7 @@ def plot_parameters( Parameters ---------- names : str | list[str] | None, default=None - Name(s) of the parameter(s) to plot. If None, plots all parameters. By default, None. + Name(s) of the parameter(s) to plot. If None, plots all parameters. **kwargs : dict[str, Any] Additional keyword arguments passed to plopp.slicer for customizing the plot (e.g., title, linestyle, marker, color). @@ -459,7 +455,7 @@ def fix_energy_offset(self, Q_index: int | None = None) -> None: ---------- Q_index : int | None, default=None Index of the Q value to fix the energy offset for. If None, fixes the energy offset for - all Q values. By default, None. + all Q values. """ if Q_index is not None: Q_index = self._verify_Q_index(Q_index) @@ -477,7 +473,7 @@ def free_energy_offset(self, Q_index: int | None = None) -> None: ---------- Q_index : int | None, default=None Index of the Q value to free the energy offset for. If None, frees the energy offset - for all Q values. By default, None. + for all Q values. """ if Q_index is not None: Q_index = self._verify_Q_index(Q_index) @@ -610,7 +606,7 @@ def _create_model_array(self, energy: sc.Variable | None = None) -> sc.DataArray ---------- energy : sc.Variable | None, default=None The energy values to use for calculating the model. If None, uses the energy from the - experiment. By default, None. + experiment. Returns ------- @@ -637,10 +633,10 @@ def _create_components_dataset( ---------- add_background : bool, default=True Whether to add background components to the sample model components when creating the - dataset. By default, True. + dataset. energy : sc.Variable | None, default=None The energy values to use for calculating the components. If None, uses the energy from - the experiment. By default, None. + the experiment. Raises ------ diff --git a/src/easydynamics/analysis/analysis1d.py b/src/easydynamics/analysis/analysis1d.py index 3031a537..36cc7c8c 100644 --- a/src/easydynamics/analysis/analysis1d.py +++ b/src/easydynamics/analysis/analysis1d.py @@ -43,25 +43,25 @@ def __init__( Parameters ---------- display_name : str | None, default='MyAnalysis' - Display name of the analysis. By default, 'MyAnalysis'. + Display name of the analysis. unique_name : str | None, default=None Unique name of the analysis. If None, a unique name is automatically generated. By default, None. experiment : Experiment | None, default=None The Experiment associated with this Analysis. If None, a default Experiment is created. - By default, None. + sample_model : SampleModel | None, default=None The SampleModel associated with this Analysis. If None, a default SampleModel is - created. By default, None. + created. instrument_model : InstrumentModel | None, default=None The InstrumentModel associated with this Analysis. If None, a default InstrumentModel - is created. By default, None. + is created. Q_index : int | None, default=None The Q index to analyze. If None, the analysis will not be able to calculate or fit - until a Q index is set. By default, None. + until a Q index is set. extra_parameters : Parameter | list[Parameter] | None, default=None Extra parameters to be included in the analysis for advanced users. If None, no extra - parameters are added. By default, None. + parameters are added. """ super().__init__( display_name=display_name, @@ -131,7 +131,7 @@ def calculate(self, energy: sc.Variable | None = None) -> np.ndarray: ---------- energy : sc.Variable | None, default=None Optional energy grid to use for calculation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -153,7 +153,7 @@ def _calculate(self, energy: sc.Variable | None = None) -> np.ndarray: ---------- energy : sc.Variable | None, default=None Optional energy grid to use for calculation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -218,7 +218,7 @@ def as_fit_function( Parameters ---------- _x : np.ndarray | sc.Variable | None, default=None - Ignored. The energy grid is taken from the experiment. By default, None. + Ignored. The energy grid is taken from the experiment. **kwargs : dict[str, Any] Ignored. Included for compatibility with the EasyScience fitter. @@ -272,13 +272,13 @@ def plot_data_and_model( Parameters ---------- plot_components : bool, default=True - Whether to plot the individual components of the model. By default, True. + Whether to plot the individual components of the model. add_background : bool, default=True Whether to add the background to the model prediction when plotting individual - components. By default, True. + components. energy : sc.Variable | None, default=None Optional energy grid to use for plotting. If None, the energy grid from the experiment - is used. By default, None. + is used. **kwargs : dict[str, Any] Keyword arguments to pass to the plotting function. @@ -470,12 +470,12 @@ def _evaluate_components( The components to evaluate. convolver : Convolution | None, default=None An optional Convolution object to use for convolution. If None, a new Convolution - object will be created if convolve is True. By default, None. + object will be created if convolve is True. convolve : bool, default=True - Whether to perform convolution with the resolution. By default, True. + Whether to perform convolution with the resolution. energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -538,7 +538,7 @@ def _evaluate_sample( ---------- energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -568,7 +568,7 @@ def _evaluate_sample_component( The sample component to evaluate. energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -590,7 +590,7 @@ def _evaluate_background(self, energy: sc.Variable | None = None) -> np.ndarray: ---------- energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -622,7 +622,7 @@ def _evaluate_background_component( The background component to evaluate. energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -649,7 +649,7 @@ def _create_convolver( ---------- energy : sc.Variable | None, default=None Optional energy grid to use for convolution. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -700,10 +700,10 @@ def _create_component_scipp_array( component : ModelComponent The component to evaluate. background : np.ndarray | None, default=None - Optional background to add to the component. By default, None. + Optional background to add to the component. energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -730,7 +730,7 @@ def _create_background_component_scipp_array( The component to evaluate. energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -752,7 +752,7 @@ def _create_sample_scipp_array(self, energy: sc.Variable | None = None) -> sc.Da ---------- energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -773,10 +773,10 @@ def _create_components_dataset_single_Q( Parameters ---------- add_background : bool, default=True - Whether to add background components. By default, True. + Whether to add background components. energy : sc.Variable | None, default=None Optional energy grid to use for evaluation. If None, the energy grid from the - experiment is used. By default, None. + experiment is used. Returns ------- @@ -822,7 +822,7 @@ def _to_scipp_array( The values to convert. energy : sc.Variable | None, default=None Optional energy grid to use for the energy coordinate. If None, the energy grid from - the experiment is used. By default, None. + the experiment is used. Returns ------- diff --git a/src/easydynamics/analysis/analysis_base.py b/src/easydynamics/analysis/analysis_base.py index 6c606373..d249a052 100644 --- a/src/easydynamics/analysis/analysis_base.py +++ b/src/easydynamics/analysis/analysis_base.py @@ -37,22 +37,22 @@ def __init__( Parameters ---------- display_name : str | None, default='MyAnalysis' - Display name of the analysis. By default, 'MyAnalysis'. + Display name of the analysis. unique_name : str | None, default=None Unique name of the analysis. If None, a unique name is automatically generated. By default, None. experiment : Experiment | None, default=None The Experiment associated with this Analysis. If None, a default Experiment is created. - By default, None. + sample_model : SampleModel | None, default=None The SampleModel associated with this Analysis. If None, a default SampleModel is - created. By default, None. + created. instrument_model : InstrumentModel | None, default=None The InstrumentModel associated with this Analysis. If None, a default InstrumentModel - is created. By default, None. + is created. extra_parameters : Parameter | list[Parameter] | None, default=None Extra parameters to be included in the analysis for advanced users. If None, no extra - parameters are added. By default, None. + parameters are added. Raises ------ diff --git a/src/easydynamics/convolution/analytical_convolution.py b/src/easydynamics/convolution/analytical_convolution.py index d94e4ad7..a835f215 100644 --- a/src/easydynamics/convolution/analytical_convolution.py +++ b/src/easydynamics/convolution/analytical_convolution.py @@ -51,13 +51,13 @@ def __init__( energy : np.ndarray | sc.Variable 1D array of energy values where the convolution is evaluated. energy_unit : str | sc.Unit, default='meV' - The unit of the energy. By default, 'meV'. + The unit of the energy. sample_components : ComponentCollection | ModelComponent | None, default=None - The sample model to be convolved. By default, None. + The sample model to be convolved. resolution_components : ComponentCollection | ModelComponent | None, default=None - The resolution model to convolve with. By default, None. + The resolution model to convolve with. energy_offset : Numeric | Parameter, default=0.0 - An offset to shift the energy values by. By default, 0.0. + An offset to shift the energy values by. """ super().__init__( energy=energy, diff --git a/src/easydynamics/convolution/convolution.py b/src/easydynamics/convolution/convolution.py index 36d88bd6..32d3fb96 100644 --- a/src/easydynamics/convolution/convolution.py +++ b/src/easydynamics/convolution/convolution.py @@ -71,22 +71,19 @@ def __init__( resolution_components : ComponentCollection | ModelComponent The resolution components to convolve with. energy_offset : Numeric | Parameter, default=0.0 - An energy offset to apply to the energy values before convolution. By default, 0.0. + An energy offset to apply to the energy values before convolution. upsample_factor : Numeric | None, default=5 - The factor by which to upsample the input data before convolution. Default is - 5. By default, 5. + The factor by which to upsample the input data before convolution. Default is 5. extension_factor : Numeric | None, default=0.2 The factor by which to extend the input data range before convolution. Default is 0.2. - By default, 0.2. temperature : Parameter | Numeric | None, default=None - The temperature to use for detailed balance correction. By default, None. + The temperature to use for detailed balance correction. temperature_unit : str | sc.Unit, default='K' - The unit of the temperature parameter. By default, 'K'. + The unit of the temperature parameter. energy_unit : str | sc.Unit, default='meV' - The unit of the energy. By default, 'meV'. + The unit of the energy. normalize_detailed_balance : bool, default=True - Whether to normalize the detailed balance correction. Default is True. By default, - True. + Whether to normalize the detailed balance correction. Default is True. """ self._convolution_plan_is_valid = False diff --git a/src/easydynamics/convolution/convolution_base.py b/src/easydynamics/convolution/convolution_base.py index 784f5e84..d328dbed 100644 --- a/src/easydynamics/convolution/convolution_base.py +++ b/src/easydynamics/convolution/convolution_base.py @@ -33,13 +33,13 @@ def __init__( energy : np.ndarray | sc.Variable 1D array of energy values where the convolution is evaluated. sample_components : ComponentCollection | ModelComponent | None, default=None - The sample model to be convolved. By default, None. + The sample model to be convolved. resolution_components : ComponentCollection | ModelComponent | None, default=None - The resolution model to convolve with. By default, None. + The resolution model to convolve with. energy_unit : str | sc.Unit, default='meV' - The unit of the energy. By default, 'meV'. + The unit of the energy. energy_offset : Numeric | Parameter, default=0.0 - The energy offset applied to the convolution. By default, 0.0. + The energy offset applied to the convolution. Raises ------ diff --git a/src/easydynamics/convolution/numerical_convolution.py b/src/easydynamics/convolution/numerical_convolution.py index 00c26640..87e6b49e 100644 --- a/src/easydynamics/convolution/numerical_convolution.py +++ b/src/easydynamics/convolution/numerical_convolution.py @@ -47,20 +47,19 @@ def __init__( resolution_components : ComponentCollection | ModelComponent The resolution model to convolve with. energy_offset : Numeric | Parameter, default=0.0 - An energy offset to apply to the energy values before convolution. By default, 0.0. + An energy offset to apply to the energy values before convolution. upsample_factor : Numeric | None, default=5 - The factor by which to upsample the input data before convolution. By default, 5. + The factor by which to upsample the input data before convolution. extension_factor : Numeric | None, default=0.2 - The factor by which to extend the input data range before convolution. By default, 0.2. + The factor by which to extend the input data range before convolution. temperature : Parameter | Numeric | None, default=None - The temperature to use for detailed balance correction. By default, None. + The temperature to use for detailed balance correction. temperature_unit : str | sc.Unit, default='K' - The unit of the temperature parameter. By default, 'K'. + The unit of the temperature parameter. energy_unit : str | sc.Unit, default='meV' - The unit of the energy. By default, 'meV'. + The unit of the energy. normalize_detailed_balance : bool, default=True - Whether to normalize the detailed balance correction. Default is True. By default, - True. + Whether to normalize the detailed balance correction. Default is True. """ super().__init__( energy=energy, diff --git a/src/easydynamics/convolution/numerical_convolution_base.py b/src/easydynamics/convolution/numerical_convolution_base.py index 5d324c85..e2d6f5b6 100644 --- a/src/easydynamics/convolution/numerical_convolution_base.py +++ b/src/easydynamics/convolution/numerical_convolution_base.py @@ -57,19 +57,19 @@ def __init__( resolution_components : ComponentCollection | ModelComponent The resolution components to convolve with. energy_offset : Numeric | Parameter, default=0.0 - An energy offset to apply to the energy values before convolution. By default, 0.0. + An energy offset to apply to the energy values before convolution. upsample_factor : Numeric | None, default=5 - The factor by which to upsample the input data before convolution. By default, 5. + The factor by which to upsample the input data before convolution. extension_factor : Numeric | None, default=0.2 - The factor by which to extend the input data range before convolution. By default, 0.2. + The factor by which to extend the input data range before convolution. temperature : Parameter | Numeric | None, default=None - The temperature to use for detailed balance correction. By default, None. + The temperature to use for detailed balance correction. temperature_unit : str | sc.Unit, default='K' - The unit of the temperature parameter. By default, 'K'. + The unit of the temperature parameter. energy_unit : str | sc.Unit, default='meV' - The unit of the energy. By default, 'meV'. + The unit of the energy. normalize_detailed_balance : bool, default=True - Whether to normalize the detailed balance correction. By default, True. + Whether to normalize the detailed balance correction. Raises ------ diff --git a/src/easydynamics/experiment/experiment.py b/src/easydynamics/experiment/experiment.py index 3ba98185..383f6c06 100644 --- a/src/easydynamics/experiment/experiment.py +++ b/src/easydynamics/experiment/experiment.py @@ -33,13 +33,12 @@ def __init__( Parameters ---------- display_name : str | None, default='MyExperiment' - Display name of the experiment. By default, 'MyExperiment'. + Display name of the experiment. unique_name : str | None, default=None - Unique name of the experiment. If None, a unique name will be generated. By default, - None. + Unique name of the experiment. If None, a unique name will be generated. None. data : sc.DataArray | str | None, default=None Dataset associated with the experiment. Can be a sc.DataArray or a filename string to - load from. If None, no data is loaded. By default, None. + load from. If None, no data is loaded. Raises ------ @@ -252,7 +251,7 @@ def load_hdf5(self, filename: str, display_name: str | None = None) -> None: filename : str Path to the HDF5 file. display_name : str | None, default=None - Optional display name for the experiment. By default, None. + Optional display name for the experiment. Raises ------ @@ -286,7 +285,7 @@ def save_hdf5(self, filename: str | None = None) -> None: ---------- filename : str | None, default=None Path to the output HDF5 file. If None, the file will be named after the unique_name of - the experiment with a .h5 extension. By default, None. + the experiment with a .h5 extension. Raises ------ @@ -380,7 +379,7 @@ def plot_data(self, slicer: bool = False, **kwargs: dict) -> None: Parameters ---------- slicer : bool, default=False - If True, use plopp's slicer instead of plot. By default, False. + If True, use plopp's slicer instead of plot. **kwargs : dict Additional keyword arguments to pass to plopp. diff --git a/src/easydynamics/sample_model/background_model.py b/src/easydynamics/sample_model/background_model.py index bd538a6b..81f29b81 100644 --- a/src/easydynamics/sample_model/background_model.py +++ b/src/easydynamics/sample_model/background_model.py @@ -29,16 +29,16 @@ def __init__( Parameters ---------- display_name : str | None, default='MyBackgroundModel' - Display name of the model. By default, 'MyBackgroundModel'. + Display name of the model. unique_name : str | None, default=None - Unique name of the model. If None, a unique name will be generated. By default, None. + Unique name of the model. If None, a unique name will be generated. unit : str | sc.Unit, default='meV' - Unit of the model. By default, 'meV'. + Unit of the model. components : ModelComponent | ComponentCollection | None, default=None Template components of the model. If None, no components are added. These components - are copied into ComponentCollections for each Q value. By default, None. + are copied into ComponentCollections for each Q value. Q : Q_type | None, default=None - Q values for the model. If None, Q is not set. By default, None. + Q values for the model. If None, Q is not set. """ super().__init__( display_name=display_name, diff --git a/src/easydynamics/sample_model/component_collection.py b/src/easydynamics/sample_model/component_collection.py index 4b65a68d..a805f58f 100644 --- a/src/easydynamics/sample_model/component_collection.py +++ b/src/easydynamics/sample_model/component_collection.py @@ -34,13 +34,13 @@ def __init__( Parameters ---------- unit : str | sc.Unit, default='meV' - Unit of the collection. By default, 'meV'. + Unit of the collection. display_name : str | None, default='MyComponentCollection' - Display name of the collection. By default, 'MyComponentCollection'. + Display name of the collection. unique_name : str | None, default=None - Unique name of the collection. By default, None. + Unique name of the collection. components : list[ModelComponent] | None, default=None - Initial model components to add to the ComponentCollection. By default, None. + Initial model components to add to the ComponentCollection. Raises ------ diff --git a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py index 99515270..3bb71a72 100644 --- a/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py +++ b/src/easydynamics/sample_model/components/damped_harmonic_oscillator.py @@ -36,16 +36,16 @@ def __init__( Parameters ---------- area : Numeric | Parameter, default=1.0 - Area under the curve. By default, 1.0. + Area under the curve. center : Numeric | Parameter, default=1.0 - Resonance frequency, approximately the peak position. By default, 1.0. + Resonance frequency, approximately the peak position. width : Numeric | Parameter, default=1.0 Damping constant, approximately the half width at half max (HWHM) of the peaks. By default, 1.0. unit : str | sc.Unit, default='meV' - Unit of the parameters. By default, 'meV'. + Unit of the parameters. display_name : str | None, default='DampedHarmonicOscillator' - Display name of the component. By default, 'DampedHarmonicOscillator'. + Display name of the component. unique_name : str | None, default=None Unique name of the component. If None, a unique_name is automatically generated. By default, None. diff --git a/src/easydynamics/sample_model/components/delta_function.py b/src/easydynamics/sample_model/components/delta_function.py index 256c8733..178b4489 100644 --- a/src/easydynamics/sample_model/components/delta_function.py +++ b/src/easydynamics/sample_model/components/delta_function.py @@ -38,13 +38,13 @@ def __init__( Parameters ---------- center : Numeric | Parameter | None, default=None - Center of the delta function. If None. By default, None. + Center of the delta function. If None. area : Numeric | Parameter, default=1.0 - Total area under the curve. By default, 1.0. + Total area under the curve. unit : str | sc.Unit, default='meV' - Unit of the parameters. By default, 'meV'. + Unit of the parameters. display_name : str | None, default='DeltaFunction' - Name of the component. By default, 'DeltaFunction'. + Name of the component. unique_name : str | None, default=None Unique name of the component. If None, a unique_name is automatically generated. By default, None. @@ -119,7 +119,7 @@ def center(self, value: Numeric | None) -> None: Parameters ---------- value : Numeric | None - The new value for the center parameter. If None. By default, 0 and is fixed. + The new value for the center parameter. If None, defaults to 0 and is fixed. Raises ------ diff --git a/src/easydynamics/sample_model/components/exponential.py b/src/easydynamics/sample_model/components/exponential.py index c30553c9..7c5e36cb 100644 --- a/src/easydynamics/sample_model/components/exponential.py +++ b/src/easydynamics/sample_model/components/exponential.py @@ -39,16 +39,15 @@ def __init__( Parameters ---------- amplitude : Numeric | Parameter, default=1.0 - Amplitude of the Exponential. By default, 1.0. + Amplitude of the Exponential. center : Numeric | Parameter | None, default=None - Center of the Exponential. If None, the center is fixed at - 0. By default, None. + Center of the Exponential. If None, the center is fixed at 0. rate : Numeric | Parameter, default=1.0 - Decay or growth constant of the Exponential. By default, 1.0. + Decay or growth constant of the Exponential. unit : str | sc.Unit, default='meV' - Unit of the parameters. By default, 'meV'. + Unit of the parameters. display_name : str | None, default='Exponential' - Name of the component. By default, 'Exponential'. + Name of the component. unique_name : str | None, default=None Unique name of the component. if None, a unique_name is automatically generated. By default, None. diff --git a/src/easydynamics/sample_model/components/expression_component.py b/src/easydynamics/sample_model/components/expression_component.py index 16246b82..176b4dc5 100644 --- a/src/easydynamics/sample_model/components/expression_component.py +++ b/src/easydynamics/sample_model/components/expression_component.py @@ -82,13 +82,13 @@ def __init__( expression : str The symbolic expression as a string. Must contain 'x' as the independent variable. parameters : dict[str, Numeric] | None, default=None - Dictionary of parameter names and their initial values. By default, None. + Dictionary of parameter names and their initial values. unit : str | sc.Unit, default='meV' - Unit of the output. By default, 'meV'. + Unit of the output. display_name : str | None, default='Expression' - Display name for the component. By default, 'Expression'. + Display name for the component. unique_name : str | None, default=None - Unique name for the component. By default, None. + Unique name for the component. Raises ------ diff --git a/src/easydynamics/sample_model/components/gaussian.py b/src/easydynamics/sample_model/components/gaussian.py index 073b4195..9c185b2f 100644 --- a/src/easydynamics/sample_model/components/gaussian.py +++ b/src/easydynamics/sample_model/components/gaussian.py @@ -43,15 +43,15 @@ def __init__( Parameters ---------- area : Numeric | Parameter, default=1.0 - Area of the Gaussian. By default, 1.0. + Area of the Gaussian. center : Numeric | Parameter | None, default=None - Center of the Gaussian. If None. By default, None. + Center of the Gaussian. If None. width : Numeric | Parameter, default=1.0 - Standard deviation. By default, 1.0. + Standard deviation. unit : str | sc.Unit, default='meV' - Unit of the parameters. By default, 'meV'. + Unit of the parameters. display_name : str | None, default='Gaussian' - Name of the component. By default, 'Gaussian'. + Name of the component. unique_name : str | None, default=None Unique name of the component. if None, a unique_name is automatically generated. By default, None. @@ -128,7 +128,7 @@ def center(self, value: Numeric | None) -> None: Parameters ---------- value : Numeric | None - The new value for the center parameter. If None. By default, 0 and is fixed. + The new value for the center parameter. If None, defaults to 0 and is fixed. Raises ------ diff --git a/src/easydynamics/sample_model/components/lorentzian.py b/src/easydynamics/sample_model/components/lorentzian.py index 41629210..ca3d1a21 100644 --- a/src/easydynamics/sample_model/components/lorentzian.py +++ b/src/easydynamics/sample_model/components/lorentzian.py @@ -40,15 +40,15 @@ def __init__( Parameters ---------- area : Numeric | Parameter, default=1.0 - Area of the Lorentzian. By default, 1.0. + Area of the Lorentzian. center : Numeric | Parameter | None, default=None - Center of the Lorentzian. If None. By default, None. + Center of the Lorentzian. If None. width : Numeric | Parameter, default=1.0 - Half width at half maximum (HWHM). By default, 1.0. + Half width at half maximum (HWHM). unit : str | sc.Unit, default='meV' - Unit of the parameters. By default, 'meV'. + Unit of the parameters. display_name : str | None, default='Lorentzian' - Name of the component. By default, 'Lorentzian'. + Name of the component. unique_name : str | None, default=None Unique name of the component. If None, a unique_name is automatically generated. By default, None. @@ -122,7 +122,7 @@ def center(self, value: Numeric | None) -> None: Parameters ---------- value : Numeric | None - The new value for the center parameter. If None. By default, 0 and is fixed. + The new value for the center parameter. If None, defaults to 0 and is fixed. Raises ------ diff --git a/src/easydynamics/sample_model/components/mixins.py b/src/easydynamics/sample_model/components/mixins.py index 64db6bc0..a80a7200 100644 --- a/src/easydynamics/sample_model/components/mixins.py +++ b/src/easydynamics/sample_model/components/mixins.py @@ -42,9 +42,9 @@ def _create_area_parameter( name : str The name of the model component. unit : str | sc.Unit, default='meV' - The unit of the area Parameter. By default, 'meV'. + The unit of the area Parameter. minimum_area : float, default=MINIMUM_AREA - The minimum allowed area. By default, MINIMUM_AREA. + The minimum allowed area. Raises ------ @@ -98,10 +98,9 @@ def _create_center_parameter( fix_if_none : bool Whether to fix the center Parameter if center is None. unit : str | sc.Unit, default='meV' - The unit of the center Parameter. By default, 'meV'. + The unit of the center Parameter. enforce_minimum_center : bool, default=False - Whether to enforce a minimum center value to avoid zero center in DHO. By default, - False. + Whether to enforce a minimum center value to avoid zero center in DHO. Raises ------ @@ -153,11 +152,11 @@ def _create_width_parameter( name : str The name of the model component. param_name : str, default='width' - The name of the width parameter. By default, 'width'. + The name of the width parameter. unit : str | sc.Unit, default='meV' - The unit of the width Parameter. By default, 'meV'. + The unit of the width Parameter. minimum_width : float, default=MINIMUM_WIDTH - The minimum allowed width. By default, MINIMUM_WIDTH. + The minimum allowed width. Raises ------ diff --git a/src/easydynamics/sample_model/components/model_component.py b/src/easydynamics/sample_model/components/model_component.py index ab21a4bc..f4d0c15e 100644 --- a/src/easydynamics/sample_model/components/model_component.py +++ b/src/easydynamics/sample_model/components/model_component.py @@ -29,11 +29,11 @@ def __init__( Parameters ---------- unit : str | sc.Unit, default='meV' - The unit of the model component. By default, 'meV'. + The unit of the model component. display_name : str | None, default=None - A human-readable name for the component. By default, None. + A human-readable name for the component. unique_name : str | None, default=None - A unique identifier for the component. By default, None. + A unique identifier for the component. """ self.validate_unit(unit) super().__init__(display_name=display_name, unique_name=unique_name) diff --git a/src/easydynamics/sample_model/components/polynomial.py b/src/easydynamics/sample_model/components/polynomial.py index 9bd5b712..0263d81b 100644 --- a/src/easydynamics/sample_model/components/polynomial.py +++ b/src/easydynamics/sample_model/components/polynomial.py @@ -38,11 +38,11 @@ def __init__( Parameters ---------- coefficients : Sequence[Numeric | Parameter], default=(0.0,) - Coefficients c0, c1, ..., cN. By default, (0.0,). + Coefficients c0, c1, ..., cN. unit : str | sc.Unit, default='meV' - Unit of the Polynomial component. By default, 'meV'. + Unit of the Polynomial component. display_name : str | None, default='Polynomial' - Display name of the Polynomial component. By default, 'Polynomial'. + Display name of the Polynomial component. unique_name : str | None, default=None Unique name of the component. If None, a unique_name is automatically generated. By default, None. diff --git a/src/easydynamics/sample_model/components/voigt.py b/src/easydynamics/sample_model/components/voigt.py index 153bbee3..c261b3f2 100644 --- a/src/easydynamics/sample_model/components/voigt.py +++ b/src/easydynamics/sample_model/components/voigt.py @@ -40,17 +40,17 @@ def __init__( Parameters ---------- area : Numeric | Parameter, default=1.0 - Total area under the curve. By default, 1.0. + Total area under the curve. center : Numeric | Parameter | None, default=None - Center of the Voigt profile. By default, None. + Center of the Voigt profile. gaussian_width : Numeric | Parameter, default=1.0 - Standard deviation of the Gaussian part. By default, 1.0. + Standard deviation of the Gaussian part. lorentzian_width : Numeric | Parameter, default=1.0 - Half width at half max (HWHM) of the Lorentzian part. By default, 1.0. + Half width at half max (HWHM) of the Lorentzian part. unit : str | sc.Unit, default='meV' - Unit of the parameters. By default, 'meV'. + Unit of the parameters. display_name : str | None, default='Voigt' - Display name of the component. By default, 'Voigt'. + Display name of the component. unique_name : str | None, default=None Unique name of the component. If None, a unique_name is automatically generated. By default, None. @@ -136,7 +136,7 @@ def center(self, value: Numeric | None) -> None: Parameters ---------- value : Numeric | None - The new value for the center parameter. If None. By default, 0 and is fixed. + The new value for the center parameter. If None, defaults to 0 and is fixed. Raises ------ diff --git a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py index b8dbb6be..b3872d9a 100644 --- a/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/brownian_translational_diffusion.py @@ -48,16 +48,16 @@ def __init__( Parameters ---------- display_name : str | None, default='BrownianTranslationalDiffusion' - Display name of the diffusion model. By default, 'BrownianTranslationalDiffusion'. + Display name of the diffusion model. unique_name : str | None, default=None Unique name of the diffusion model. If None, a unique name will be generated. By default, None. unit : str | sc.Unit, default='meV' - Unit of the diffusion model. Must be convertible to meV. By default, 'meV'. + Unit of the diffusion model. Must be convertible to meV. scale : Numeric, default=1.0 - Scale factor for the diffusion model. Must be a non-negative number. By default, 1.0. + Scale factor for the diffusion model. Must be a non-negative number. diffusion_coefficient : Numeric, default=1.0 - Diffusion coefficient D in m^2/s. By default, 1.0. + Diffusion coefficient D in m^2/s. Raises ------ @@ -202,7 +202,7 @@ def create_component_collections( Q : Q_type Scattering vector values. component_display_name : str, default='Brownian diffusion' - Name of the Lorentzian component. By default, 'Brownian diffusion'. + Name of the Lorentzian component. Raises ------ diff --git a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py index 3ecd5b05..177d5e79 100644 --- a/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py +++ b/src/easydynamics/sample_model/diffusion_model/diffusion_model_base.py @@ -26,14 +26,14 @@ def __init__( Parameters ---------- display_name : str | None, default='MyDiffusionModel' - Display name of the diffusion model. By default, 'MyDiffusionModel'. + Display name of the diffusion model. unique_name : str | None, default=None Unique name of the diffusion model. If None, a unique name will be generated. By default, None. scale : Numeric, default=1.0 - Scale factor for the diffusion model. Must be a non-negative number. By default, 1.0. + Scale factor for the diffusion model. Must be a non-negative number. unit : str | sc.Unit, default='meV' - Unit of the diffusion model. Must be convertible to meV. By default, 'meV'. + Unit of the diffusion model. Must be convertible to meV. Raises ------ diff --git a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py index 846a682d..346ce152 100644 --- a/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py +++ b/src/easydynamics/sample_model/diffusion_model/jump_translational_diffusion.py @@ -51,18 +51,18 @@ def __init__( Parameters ---------- display_name : str | None, default='JumpTranslationalDiffusion' - Display name of the diffusion model. By default, 'JumpTranslationalDiffusion'. + Display name of the diffusion model. unique_name : str | None, default=None Unique name of the diffusion model. If None, a unique name will be generated. By default, None. unit : str | sc.Unit, default='meV' - Unit of the diffusion model. Must be convertible to meV. By default, 'meV'. + Unit of the diffusion model. Must be convertible to meV. scale : Numeric, default=1.0 - Scale factor for the diffusion model. Must be a non-negative number. By default, 1.0. + Scale factor for the diffusion model. Must be a non-negative number. diffusion_coefficient : Numeric, default=1.0 - Diffusion coefficient D in m^2/s. By default, 1.0. + Diffusion coefficient D in m^2/s. relaxation_time : Numeric, default=1.0 - Relaxation time t in ps. By default, 1.0. + Relaxation time t in ps. Raises ------ @@ -261,8 +261,7 @@ def create_component_collections( Q : Q_type Scattering vector in 1/angstrom. Can be a single value or an array of values. component_display_name : str, default='Jump translational diffusion' - Name of the Jump Diffusion Lorentzian component. By default, 'Jump translational - diffusion'. + Name of the Jump Diffusion Lorentzian component. Raises ------ diff --git a/src/easydynamics/sample_model/instrument_model.py b/src/easydynamics/sample_model/instrument_model.py index b734015b..00cf2544 100644 --- a/src/easydynamics/sample_model/instrument_model.py +++ b/src/easydynamics/sample_model/instrument_model.py @@ -40,23 +40,22 @@ def __init__( Parameters ---------- display_name : str, default='MyInstrumentModel' - The display name of the InstrumentModel. By default, 'MyInstrumentModel'. + The display name of the InstrumentModel. unique_name : str | None, default=None - The unique name of the InstrumentModel. By default, None. + The unique name of the InstrumentModel. Q : Q_type | None, default=None - The Q values where the instrument is modelled. By default, None. + The Q values where the instrument is modelled. resolution_model : ResolutionModel | None, default=None The resolution model of the instrument. If None, an empty resolution model is created - and no resolution convolution is carried out. By default, None. + and no resolution convolution is carried out. background_model : BackgroundModel | None, default=None The background model of the instrument. If None, an empty background model is created, - and the background evaluates to - 0. By default, None. + and the background evaluates to 0. energy_offset : Numeric | None, default=None Template energy offset of the instrument. Will be copied to each Q value. If None, the - energy offset will be 0. By default, None. + energy offset will be 0. unit : str | sc.Unit, default='meV' - The unit of the energy axis. By default, 'meV'. + The unit of the energy axis. Raises ------ @@ -307,7 +306,7 @@ def clear_Q(self, confirm: bool = False) -> None: Parameters ---------- confirm : bool, default=False - Confirmation to clear Q values. By default, False. + Confirmation to clear Q values. Raises ------ @@ -357,7 +356,7 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: ---------- Q_index : int | None, default=None The index of the Q value to get variables for. If None, get variables for all Q values. - By default, None. + Raises ------ @@ -415,7 +414,7 @@ def get_energy_offset( ---------- Q_index : int | None, default=None The index of the Q value to get the energy offset for. If None, get the energy offset - for all Q values. By default, None. + for all Q values. Raises ------ @@ -457,7 +456,7 @@ def fix_energy_offset(self, Q_index: int | None = None) -> None: ---------- Q_index : int | None, default=None The index of the Q value to fix the energy offset for. If None, fix energy offsets for - all Q values. By default, None. + all Q values. """ self._fix_or_free_energy_offset(Q_index, fixed=True) @@ -472,7 +471,7 @@ def free_energy_offset(self, Q_index: int | None = None) -> None: ---------- Q_index : int | None, default=None The index of the Q value to free the energy offset for. If None, free energy offsets - for all Q values. By default, None. + for all Q values. """ self._fix_or_free_energy_offset(Q_index, fixed=False) @@ -490,9 +489,9 @@ def _fix_or_free_energy_offset(self, Q_index: int | None = None, fixed: bool = T ---------- Q_index : int | None, default=None The index of the Q value to fix or free the energy offset for. If None, fix or free - energy offsets for all Q values. By default, None. + energy offsets for all Q values. fixed : bool, default=True - Whether to fix (True) or free (False) the energy offset. By default, True. + Whether to fix (True) or free (False) the energy offset. Raises ------ diff --git a/src/easydynamics/sample_model/model_base.py b/src/easydynamics/sample_model/model_base.py index 53fc74ba..1b5d9363 100644 --- a/src/easydynamics/sample_model/model_base.py +++ b/src/easydynamics/sample_model/model_base.py @@ -37,16 +37,16 @@ def __init__( Parameters ---------- display_name : str, default='MyModelBase' - Display name of the model. By default, 'MyModelBase'. + Display name of the model. unique_name : str | None, default=None - Unique name of the model. If None, a unique name will be generated. By default, None. + Unique name of the model. If None, a unique name will be generated. unit : str | sc.Unit | None, default='meV' - Unit of the model. By default, 'meV'. + Unit of the model. components : ModelComponent | ComponentCollection | None, default=None Template components of the model. If None, no components are added. These components - are copied into ComponentCollections for each Q value. By default, None. + are copied into ComponentCollections for each Q value. Q : Q_type | None, default=None - Q values for the model. If None, Q is not set. By default, None. + Q values for the model. If None, Q is not set. Raises ------ @@ -298,7 +298,7 @@ def clear_Q(self, confirm: bool = False) -> None: Parameters ---------- confirm : bool, default=False - Confirmation to clear Q values. By default, False. + Confirmation to clear Q values. Raises ------ @@ -335,7 +335,7 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: ---------- Q_index : int | None, default=None If None, get variables for all ComponentCollections. If int, get variables for the - ComponentCollection at this index. By default, None. + ComponentCollection at this index. Raises ------ diff --git a/src/easydynamics/sample_model/resolution_model.py b/src/easydynamics/sample_model/resolution_model.py index 5a140863..50fae8d0 100644 --- a/src/easydynamics/sample_model/resolution_model.py +++ b/src/easydynamics/sample_model/resolution_model.py @@ -31,16 +31,16 @@ def __init__( Parameters ---------- display_name : str, default='MyResolutionModel' - Display name of the model. By default, 'MyResolutionModel'. + Display name of the model. unique_name : str | None, default=None - Unique name of the model. If None, a unique name will be generated. By default, None. + Unique name of the model. If None, a unique name will be generated. unit : str | sc.Unit, default='meV' - Unit of the model. By default, 'meV'. + Unit of the model. components : ModelComponent | ComponentCollection | None, default=None Template components of the model. If None, no components are added. These components - are copied into ComponentCollections for each Q value. By default, None. + are copied into ComponentCollections for each Q value. Q : Q_type | None, default=None - Q values for the model. If None, Q is not set. By default, None. + Q values for the model. If None, Q is not set. """ super().__init__( diff --git a/src/easydynamics/sample_model/sample_model.py b/src/easydynamics/sample_model/sample_model.py index 39b66271..26fad08c 100644 --- a/src/easydynamics/sample_model/sample_model.py +++ b/src/easydynamics/sample_model/sample_model.py @@ -44,26 +44,25 @@ def __init__( Parameters ---------- display_name : str, default='MySampleModel' - Display name of the model. By default, 'MySampleModel'. + Display name of the model. unique_name : str | None, default=None - Unique name of the model. If None, a unique name will be generated. By default, None. + Unique name of the model. If None, a unique name will be generated. unit : str | sc.Unit, default='meV' - Unit of the model. If None,. By default, 'meV'. + Unit of the model. If None,. components : ModelComponent | ComponentCollection | None, default=None Template components of the model. If None, no components are added. These components - are copied into ComponentCollections for each Q value. By default, None. + are copied into ComponentCollections for each Q value. Q : Q_type | None, default=None - Q values for the model. If None, Q is not set. By default, None. + Q values for the model. If None, Q is not set. diffusion_models : DiffusionModelBase | list[DiffusionModelBase] | None, default=None Diffusion models to include in the SampleModel. If None, no diffusion models are added. - By default, None. temperature : float | None, default=None Temperature for detailed balancing. If None, no detailed balancing is applied. By default, None. temperature_unit : str | sc.Unit, default='K' - Unit of the temperature. By default, 'K'. + Unit of the temperature. divide_by_temperature : bool, default=True - Whether to divide the detailed balance factor by temperature. By default, True. + Whether to divide the detailed balance factor by temperature. Raises ------ @@ -414,7 +413,7 @@ def get_all_variables(self, Q_index: int | None = None) -> list[Parameter]: ---------- Q_index : int | None, default=None If specified, only get variables from the ComponentCollection at the given Q index. If - None, get variables from all ComponentCollections. By default, None. + None, get variables from all ComponentCollections. Returns ------- diff --git a/src/easydynamics/utils/detailed_balance.py b/src/easydynamics/utils/detailed_balance.py index 866e4788..796afaff 100644 --- a/src/easydynamics/utils/detailed_balance.py +++ b/src/easydynamics/utils/detailed_balance.py @@ -42,9 +42,9 @@ def detailed_balance_factor( temperature : int | float | sc.Variable | Parameter The temperature. If number, assumed to be in K unless temperature_unit is set. energy_unit : str | sc.Unit, default='meV' - Unit for energy if energy is given as a number or list. By default, 'meV'. + Unit for energy if energy is given as a number or list. temperature_unit : str | sc.Unit, default='K' - Unit for temperature if temperature is given as a number. By default, 'K'. + Unit for temperature if temperature is given as a number. divide_by_temperature : bool, default=True If True, divide the result by $k_B*T$ to make it dimensionless and have value 1 at E=0. By default, True.