Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .copier-answers.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# WARNING: Do not edit this file manually.
# Any changes will be overwritten by Copier.
_commit: v0.11.3-3-ga67ebc3
_commit: v0.13.1
_src_path: gh:easyscience/templates
lib_docs_url: https://easyscience.github.io/core
lib_doi: 10.5281/zenodo.18163581
Expand Down
26 changes: 1 addition & 25 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,32 +63,8 @@ jobs:
files: ./coverage-unit.xml
token: ${{ secrets.CODECOV_TOKEN }}

# Job 2: Run integration tests with coverage and upload to Codecov
integration-tests-coverage:
runs-on: ubuntu-latest

steps:
- name: Check-out repository
uses: actions/checkout@v6

- name: Set up pixi
uses: ./.github/actions/setup-pixi

- name: Run integration tests with coverage
run:
pixi run integration-tests-coverage --cov-report=xml:coverage-integration.xml

- name: Upload integration tests coverage to Codecov
if: ${{ !cancelled() }}
uses: ./.github/actions/upload-codecov
with:
name: integration-tests-job
flags: integration
files: ./coverage-integration.xml
token: ${{ secrets.CODECOV_TOKEN }}

# Job 4: Build and publish dashboard (reusable workflow)
run-reusable-workflows:
needs: [docstring-coverage, unit-tests-coverage, integration-tests-coverage] # depend on the previous jobs
needs: [docstring-coverage, unit-tests-coverage] # depend on the previous jobs
uses: ./.github/workflows/dashboard.yml
secrets: inherit
9 changes: 6 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,14 @@ jobs:

# Build the static files for the documentation site for local inspection
# Input: docs/ directory containing the Markdown files
# Output: site/ directory containing the generated HTML files
# Output: docs/site/ directory containing the generated HTML files
# Also verifies that mkdocstrings generated docs/site/objects.inv.
- name: Build site for local check
run: pixi run docs-build-local
run: |
pixi run docs-build-local
pixi run docs-inventory-check

# Upload the static files from the site/ directory to be used for
# Upload the static files from the docs/site/ directory to be used for
# local check
- name: Upload built site as artifact
uses: ./.github/actions/upload-artifact
Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/pypi-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,15 @@ jobs:
frozen: false

- name: Init pixi project
run: pixi init easyscience
run:
pixi init --platform linux-64 --platform osx-arm64 --platform win-64
easyscience

- name: Set the minimum system requirements
- name: Configure pixi platforms
working-directory: easyscience
run: pixi project system-requirements add macos 14.0
run: |
pixi workspace platform edit linux-64 --glibc 2.35 --no-install
pixi workspace platform edit osx-arm64 --macos 14.0 --no-install

- name: Add Python 3.14 from Conda
working-directory: easyscience
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,16 @@ jobs:
echo "🔹🔸🔹🔸🔹 Python: $py_ver 🔹🔸🔹🔸🔹"

echo "Initializing pixi project"
pixi init easyscience_py$py_ver
pixi init --platform linux-64 --platform osx-arm64 --platform win-64 easyscience_py$py_ver
cd easyscience_py$py_ver

echo "Configure pixi platforms"
pixi workspace platform edit linux-64 --glibc 2.35 --no-install
pixi workspace platform edit osx-arm64 --macos 14.0 --no-install

echo "Adding Python $py_ver"
pixi add "python=$py_ver"

echo "Setting macOS 14.0 as minimum required"
pixi project system-requirements add macos 14.0

echo "Looking for wheel in ../dist/py$py_ver/"
ls -l "../dist/py$py_ver/"

Expand Down
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ docs/docs/assets/
# Node
node_modules

# Tox
.tox

# Misc
.benchmarks
.cache
Expand Down
3 changes: 1 addition & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ Please make sure you follow the EasyScience organization-wide
If you are not planning to contribute code, you may want to:

- 🐞 Report a bug — see [Reporting Issues](#11-reporting-issues)
- 🛡 Report a security issue — see
[Security Issues](#12-security-issues)
- 🛡 Report a security issue — see [Security Issues](#12-security-issues)
- 💬 Ask a question or start a discussion at
[Project Discussions](https://github.com/easyscience/core/discussions)

Expand Down
9 changes: 8 additions & 1 deletion docs/docs/assets/stylesheets/extra.css
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,14 @@ label.md-nav__title[for="__drawer"] {

/* Change the overall width of the page */
.md-grid {
max-width: 1280px;
max-width: 116em;
}

/* Keep prose line length stable when sidebars are hidden at narrower widths */
.md-main .md-content > .md-content__inner {
width: min(100%, 40.5em);
margin-left: auto !important;
margin-right: auto !important;
}

/* Needed for mkdocs-jupyter to show download and other buttons on top of the notebook */
Expand Down
20 changes: 19 additions & 1 deletion docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,25 @@ plugins:
show_root_heading: true
show_root_full_path: false
show_submodules: true
show_source: true
show_source: false
show_bases: false
# Uncomment when the project depends on `easyscience` and inherited
# EasyScience base-class members should be shown in the API docs.
# preload_modules:
# - easyscience
inherited_members: true
show_category_heading: true
merge_init_into_class: true
docstring_options:
ignore_init_summary: true
summary: true
relative_crossrefs: true
scoped_crossrefs: true
filters: ['!^_[^_]', '!__repr__', '!__dir__'] # This is the default filter minus __repr__ and __dir__
inventories:
- url: https://scipp.github.io/objects.inv
- url: https://numpy.org/doc/stable/objects.inv
- url: https://easyscience.github.io/core/latest/objects.inv
- search

# Determines additional directories to watch when running mkdocs serve
Expand Down
24 changes: 15 additions & 9 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,19 @@
[workspace]

# Supported platforms for the lock file (pixi.lock)
platforms = ['win-64', 'linux-64', 'osx-arm64']
platforms = [
'win-64',
# Set minimum supported version for glibc to be 2.35 to ensure packages
# like `crysfml` that only have wheels for glibc 2.35+
# (manylinux_2_35_x86_64) are used.
#libc = { family = 'glibc', version = '2.35' }
{ platform = 'linux-64', glibc = '2.35' },
# Set minimum supported version for macOS to be 14.0 to ensure packages
# like `scipp` that only have wheels for macOS 14.0+ (macosx_14_0_arm64)
# are used instead of building from source. This is a workaround for
# Pixi, see https://github.com/prefix-dev/pixi/issues/5667
{ platform = 'osx-arm64', macos = '14.0' },
]

# Channels for fetching packages
channels = ['nodefaults', 'conda-forge']
Expand All @@ -19,13 +31,6 @@ channels = ['nodefaults', 'conda-forge']
[activation.env]
PYTHONIOENCODING = 'utf-8'

[system-requirements]
# Set minimum supported version for macOS to be 14.0 to ensure packages
# like `scipp` that only have wheels for macOS 14.0+ (macosx_14_0_arm64)
# are used instead of building from source. This is a workaround for
# Pixi, see https://github.com/prefix-dev/pixi/issues/5667
macos = '14.0'

# Non-default features:

# Set specific Python versions to be used in CI testing.
Expand Down Expand Up @@ -182,8 +187,9 @@ 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-inventory-check = 'python -c "from pathlib import Path; p = Path(\"docs/site/objects.inv\"); raise SystemExit(0 if p.is_file() and p.stat().st_size > 0 else \"missing or empty docs/site/objects.inv\")"'

docs-deploy-pre = 'mike deploy -F docs/mkdocs.yml --push --branch gh-pages --update-aliases --alias-type redirect'
docs-deploy-pre = 'mike deploy -F docs/mkdocs.yml --push --branch gh-pages --update-aliases --alias-type copy'
docs-set-default-pre = 'mike set-default -F docs/mkdocs.yml --push --branch gh-pages'

docs-update-assets = 'python tools/update_docs_assets.py'
Expand Down
11 changes: 8 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,11 @@ testpaths = ['tests']
[tool.ruff]
exclude = ['tests', 'legacy', 'src/easyscience/legacy']
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
builtins = [
'display',
] # Clutch-fix/patch to https://github.com/nbQA-dev/nbQA/issues/882
# Formatting options for Ruff

[tool.ruff.format]
Expand Down Expand Up @@ -233,6 +235,9 @@ ignore = [
'INP001', # https://docs.astral.sh/ruff/rules/implicit-namespace-package/
'T201', # https://docs.astral.sh/ruff/rules/print/
]
'docs/docs/tutorials/**' = [
'E402', # https://docs.astral.sh/ruff/rules/module-import-not-at-top-of-file/
]

# Specific options for certain rules

Expand Down
33 changes: 20 additions & 13 deletions src/easyscience/fitting/fitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,20 +433,24 @@ def mcmc_sample(
progress_callback: Optional[Callable[[dict], Optional[bool]]] = None,
abort_test: Optional[Callable[[], bool]] = None,
) -> dict:
"""Run Bayesian MCMC sampling using the BUMPS DREAM sampler.
"""
Run Bayesian MCMC sampling using the BUMPS DREAM sampler.

Works with both a plain ``Fitter`` (single dataset) and a
``MultiFitter`` (multiple datasets) via polymorphic dispatch:
``_precompute_reshaping`` and ``_fit_function_wrapper`` are resolved
on the concrete subclass at call time, so multi-dataset flattening
is handled automatically when called on a ``MultiFitter`` instance.
``_precompute_reshaping`` and ``_fit_function_wrapper`` are
resolved on the concrete subclass at call time, so multi-dataset
flattening is handled automatically when called on a
``MultiFitter`` instance.

Parameters
----------
x : np.ndarray
Independent variable array (or list of arrays for ``MultiFitter``).
Independent variable array (or list of arrays for
``MultiFitter``).
y : np.ndarray
Dependent variable array (or list of arrays for ``MultiFitter``).
Dependent variable array (or list of arrays for
``MultiFitter``).
weights : np.ndarray
Weight array (or list of arrays for ``MultiFitter``).
samples : int, default=10000
Expand All @@ -459,16 +463,19 @@ def mcmc_sample(
population : Optional[int], default=None
BUMPS DREAM population count (number of parallel chains).
vectorized : bool, default=False
When ``True``, each x array may be multi-dimensional (e.g. an
``(N, M, 2)`` grid for a 2D model) and is left as-is. When
``False`` (default), each x array is expected to be 1-D.
When ``True``, each x array may be multi-dimensional (e.g.
an ``(N, M, 2)`` grid for a 2D model) and is left as-is.
When ``False`` (default), each x array is expected to be
1-D.
sampler_kwargs : Optional[dict], default=None
Additional keyword arguments forwarded to the BUMPS DREAM sampler.
Additional keyword arguments forwarded to the BUMPS DREAM
sampler.
progress_callback : Optional[Callable[[dict], Optional[bool]]], default=None
Optional callback invoked at each DREAM generation. The payload
dict includes ``iteration`` and ``sampling: True``.
Optional callback invoked at each DREAM generation. The
payload dict includes ``iteration`` and ``sampling: True``.
abort_test : Optional[Callable[[], bool]], default=None
Optional callable that returns ``True`` to abort sampling early.
Optional callable that returns ``True`` to abort sampling
early.

Returns
-------
Expand Down
44 changes: 25 additions & 19 deletions src/easyscience/fitting/minimizers/minimizer_bumps.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ def fit(
``iteration`` carries the BUMPS optimizer step index. By
default, None.
abort_test : Callable[[], bool] | None, default=None
Optional callback that returns ``True`` to signal that the fit
should be aborted. Called periodically during the
BUMPS optimizer iteration loop.
Optional callback that returns ``True`` to signal that the
fit should be aborted. Called periodically during the BUMPS
optimizer iteration loop.
minimizer_kwargs : dict | None, default=None
Additional keyword arguments passed to the BUMPS minimizer.
By default, None.
Expand Down Expand Up @@ -393,12 +393,14 @@ def mcmc_sample(
progress_callback: Callable[[dict], bool | None] | None = None,
abort_test: Callable[[], bool] | None = None,
) -> dict:
"""Run Bayesian MCMC sampling using the BUMPS DREAM sampler.
"""
Run Bayesian MCMC sampling using the BUMPS DREAM sampler.

Builds a BUMPS `FitProblem` from the current model and runs the DREAM
sampler. This is the public minimizer-level entry point for Bayesian
sampling; the higher-level `MultiFitter.mcmc_sample` delegates to this
method after flattening multi-dataset arrays.
Builds a BUMPS ``FitProblem`` from the current model and runs
the DREAM sampler. This is the public minimizer-level entry
point for Bayesian sampling; the higher-level
``MultiFitter.mcmc_sample`` delegates to this method after
flattening multi-dataset arrays.

Parameters
----------
Expand All @@ -417,15 +419,16 @@ def mcmc_sample(
population : int | None, default=None
BUMPS DREAM population count (number of parallel chains).
sampler_kwargs : dict | None, default=None
Additional keyword arguments forwarded to `bumps.fitters.fit`.
Additional keyword arguments forwarded to
``bumps.fitters.fit``.
progress_callback : Callable[[dict], bool | None] | None, default=None
Optional callback for progress updates during sampling. The
payload dict includes ``iteration`` (DREAM generation number) and
``sampling: True``.
payload dict includes ``iteration`` (DREAM generation
number) and ``sampling: True``.
abort_test : Callable[[], bool] | None, default=None
Optional callback that returns ``True`` to signal that sampling
should be aborted. Called periodically during the DREAM sampling
loop.
Optional callback that returns ``True`` to signal that
sampling should be aborted. Called periodically during the
DREAM sampling loop.

Returns
-------
Expand All @@ -439,7 +442,8 @@ def mcmc_sample(
If the input shapes or weights are invalid, or if
``progress_callback`` is not callable.
FitError
If DREAM sampling was aborted by the user (via ``abort_test``).
If DREAM sampling was aborted by the user (via
``abort_test``).
Exception
Re-raised from DREAM fitting if any unexpected error occurs
(parameter values are restored beforehand).
Expand Down Expand Up @@ -545,11 +549,13 @@ def mcmc_sample(
def _build_sample_progress_payload(
self, problem, iteration: int, point: np.ndarray, nllf: float
) -> dict:
"""Build a progress payload for Bayesian DREAM sampling steps.
"""
Build a progress payload for Bayesian DREAM sampling steps.

Called by :class:`BumpsProgressMonitor` at each DREAM generation.
The payload includes ``sampling: True`` so downstream consumers can
distinguish sampling progress from classical fitting progress.
Called by :class:`BumpsProgressMonitor` at each DREAM
generation. The payload includes ``sampling: True`` so
downstream consumers can distinguish sampling progress from
classical fitting progress.
"""
payload = self._build_progress_payload(problem, iteration, point, nllf)
payload['sampling'] = True
Expand Down
7 changes: 4 additions & 3 deletions src/easyscience/fitting/multi_fitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,10 @@ def _precompute_reshaping(
weights : list[np.ndarray] | None
Optional weights for each dataset.
vectorized : bool
When ``True``, each x array may be multi-dimensional (e.g. an
``(N, M, 2)`` grid for a 2D model) and is left as-is. When
``False`` (default), each x array is expected to be 1-D.
When ``True``, each x array may be multi-dimensional (e.g.
an ``(N, M, 2)`` grid for a 2D model) and is left as-is.
When ``False`` (default), each x array is expected to be
1-D.

Returns
-------
Expand Down
Loading