Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
45c2af6
initial boiler plate for persistence model
nikeethr Feb 9, 2026
c5e740c
fix basic interface object creation tests. Add initial draft of forci…
nikeethr Feb 12, 2026
102f378
fix dask shinnenigans from tests
nikeethr Feb 16, 2026
190f73c
report.xml: remove accidental commit
nikeethr Feb 16, 2026
705bd19
ruff: minor formatting
nikeethr Feb 16, 2026
e7b24fe
ruff: format + fix missing imports on other test.
nikeethr Feb 16, 2026
b6c8120
add simple imputation logic for missing values so that median is easi…
nikeethr Feb 16, 2026
ab63c97
minor adjustment of docs
nikeethr Feb 16, 2026
104c56d
conversion between common data types as inputs
nikeethr Feb 17, 2026
fb74a25
[skip ci] WIP commit - persistence computation entrypoint in persiste…
nikeethr Feb 17, 2026
422bc88
[skip ci] wrong interface for return_raw_type
nikeethr Feb 18, 2026
fa3c056
[skip ci] WIP: ruff checks
nikeethr Feb 18, 2026
e075b28
[skip ci] wip add median of three method using numpy. Needs to be ref…
nikeethr Feb 23, 2026
17cf489
[skip ci] add remaining tests for median calc with numpy
nikeethr Feb 23, 2026
643bd1d
[skip ci] refactor private modules
nikeethr Feb 23, 2026
a7da4dc
[skip ci] refactor interface - midway
nikeethr Feb 26, 2026
5e9a029
[skip ci] work in progress implementation of chunker - partially tested
nikeethr Feb 27, 2026
5aaafce
[skip ci] wip test chunker works as expected for general scenarios
nikeethr Feb 27, 2026
3a76fc9
[skip ci] wip test chunker - minor bug fix
nikeethr Feb 28, 2026
0f6fb0b
[skip ci] wip abstract out computation pool and add some TODOs/docume…
nikeethr Feb 28, 2026
1b9d3f9
[skip ci] refactor chunker logic to chunk time based on required hist…
nikeethr Mar 1, 2026
e5534a1
[skip ci] basic tests for persistence compute base class
nikeethr Mar 1, 2026
2960569
[skip ci] wip process pool and some additional considerations require…
nikeethr Mar 2, 2026
eae9cb2
[skip ci] force compute context to fork server
nikeethr Mar 2, 2026
e496905
[skip ci] some documentation and some initial stubs to work on integr…
nikeethr Mar 4, 2026
4af0517
[skip ci] slight reorganisation of package structure; update persiste…
nikeethr Mar 5, 2026
015cb20
[skip ci] missed move of types.py
nikeethr Mar 5, 2026
16477b4
[skip ci] improved explanation of `with_return_raw_result`
nikeethr Mar 5, 2026
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: 2 additions & 0 deletions packages/bundled_models/persistence/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true -diff
4 changes: 4 additions & 0 deletions packages/bundled_models/persistence/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# pixi environments
.pixi/*
!.pixi/config.toml
report.xml
45 changes: 45 additions & 0 deletions packages/bundled_models/persistence/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Persistence Model for use with the PyEarthTools Package

**TODO: description**

## Installation

Clone the repository, then run
```shell
pip install -e .
```

## Training

No training is required for this model. It computes persistence on-the-fly using historical data loaded via the PET pipeline.

## Predictions / Inference

You can generate persistence values out of the box using the `pet predict` command line API, or by using a Jupyter Notebook as demonstrated in the tutorial gallery.

```shell
pet predict
```

and `Development/Persistence` should be visible.

If so, you can now run some inference.

```shell
pet predict --model Development/Persistence
```

When running the command, it will prompt for other required arguments.

**TODO: description of required arguments**


#### Example

```shell
pet predict --model Development/Persistence # TODO
```

## Acknowledgments

Not applicable. Heuristically developed.
3,369 changes: 3,369 additions & 0 deletions packages/bundled_models/persistence/pixi.lock

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions packages/bundled_models/persistence/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"

[project]
name = "pyearthtools-persistence"
version = "0.6.0"
description = "Persistence Bundled Model"
readme = "README.md"
requires-python = ">=3.11, <3.14"
keywords = ["persistence", "pyearthtools", "models"]
maintainers = [
{name = "Tennessee Leeuwenburg", email = "tennessee.leeuwenburg@bom.gov.au"},
{name = "Nikeeth Ramanathan", email = "nikeeth.ramanathan@gmail.com"},
]
classifiers = [
"License :: OSI Approved :: Apache Software License",
"Operating System :: OS Independent",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
]
dependencies = [
'pyearthtools.zoo>=0.5.0',
'pyearthtools.data>=0.5.0',
'pyearthtools.pipeline>=0.5.0',
'hydra-core',
]
[dependency-groups]
dev = [
"pytest>=8.4.2",
"ruff",
"pytest-cov",
"pytest-xdist",
]

[project.urls]
homepage = "https://pyearthtools.readthedocs.io/"
documentation = "https://pyearthtools.readthedocs.io/"
repository = "https://github.com/ACCESS-Community-Hub/PyEarthTools"

[project.entry-points."pyearthtools.zoo.model"]
Global_PERSIST = "persistence.registered_model:Persistence"

[tool.isort]
profile = "black"

[tool.black]
line-length = 120

[tool.mypy]
warn_return_any = true
warn_unused_configs = true

[[tool.mypy.overrides]]
ignore_missing_imports = true

[tool.hatch.version]
path = "src/persistence/__init__.py"

[tool.hatch.build.targets.wheel]
packages = ["src/pyearthtools/"]

[tool.pixi.workspace]
channels = ["conda-forge"]
platforms = ["linux-64"]

[tool.pixi.pypi-dependencies]
pyearthtools-persistence = { path = ".", editable = true }

[tool.pixi.tasks]

[tool.pixi.dependencies]
python = ">=3.11,<3.14"
xarray = ">=2026.1.0,<2027"

[tool.pixi.feature.testing.dependencies]
pytest = ">=9.0.2,<10"
pytest-cov = ">=7.0.0,<8"
pytest-xdist = ">=3.8.0,<4"
ruff = ">=0.15.0,<0.16"
ipython = ">=9.10.0,<10"

[tool.pixi.feature.dask.dependencies]
dask-core = "*"
distributed = "*"
pyarrow = ">=23.0.0,<24"

[tool.pixi.environments]
dask = ["dask"]
dev = ["dask", "testing"]
Empty file.
41 changes: 41 additions & 0 deletions packages/bundled_models/persistence/src/persistence/config/dask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from contextlib import contextmanager


# default scheduler string to set "single-threaded" mode.
_STR_DASK_SYNC_SCHEDULER = "synchronous"


@contextmanager
def _set_synchronous_dask():
"""
Wrapper to set `dask` to single-threaded mode. Note: "single-threaded" in `dask`-land
(specifically) is the same as "synchronous".

This handles the case where dask is _not_ installed. In which case it does a pass-through.

IMPORTANT: never nest this context manager or call dask.config.reset() or attempt to update any
configs inside this context. Doing so may invalidate the "synchronous" setting.

Example:
def do_stuff(...):
# I can now (optionally) fork other processes here - without confusing dask.
# IMPORTANT: I shouldn't try to reintroduce parallelism using dask here
...

with _set_synchronous_dask():
do_stuff(...)
"""
try:
# this import order is important for the "distributed" configs to be recognized
import dask
import dask.config

# NOTE: if you don't have dask.distributed, this setting may not work as intended.
# so you will have to manually deal with it in the compute level.
import dask.distributed

# set state to desired config
with dask.config.set(scheduler=_STR_DASK_SYNC_SCHEDULER):
yield
except ImportError:
yield
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
from enum import StrEnum, auto


class PersistenceBackendType(StrEnum):
"""
Enumeration of supported compute backends for persistence computations.

---

SUPPORTED BACKENDS (as of 2026-02-28):
- NUMPY (20260228)
- others are WIP

Note: "supported" implies that the backend is supported by the build system, it does not imply
that the particular persistence method itself is supported for that backend.

---

Backends are configured at the "build" level in pyproject.toml, e.g. for rust this may be
maturin/pyO3, which usually handles most of the heavy lifting.

numba might require certain system dependencies - e.g. llvm, to function since it requires
building on the fly.

For C/zig this would involve using:
a. ziglang/zig-pypi to build the zig packages into wheels and running them on the fly using
sys.execute to execute the wheel as a module, building/running zig on-the-fly. Avoids
having to distribute the pre-built dependencies, but may not work well with specific
interfaces like `numpy`.
b. using setuptools-zig to build them into a "integrated" library and packaging the build
into the wheel/distribution
c. using cffi or ctypes.

Methods a. and b. would require extending Python.h directly, and hence are preferrable, since
they don't involve foreign calls. Unlike numba, method a. exists for zig where jit compilation
can happen without dependency on additional system libraries.

All of the above methods generally avoid (or at least have the ability to avoid) the need for
conda environments and are pretty light weight.
"""

C = "c"
C_ZIG = "zig"
NUMBA = "numba"
NUMPY = "numpy"
RUST = "rust"
UNKNOWN = auto()

def check_support(self):
"""
As per the module documentation, this method only tells you if a particular backend is
supported by the *build system*, it doesn't imply that the backend is useable for any given
method.

Therefore, this check can and should be done as early as possible. Whereas method
compatiblilty will be checked later into the runtime but still early enough point in the
code, before attempting the computation. (see `PersistenceCompute` for more details)
"""
match self:
case PersistenceBackendType.NUMPY:
return
case _:
raise NotImplementedError(
f"PersistenceBackendType: {self} is not supported"
)
Loading