climate_indices
Python library of climate indices for drought, wildfire, and flood monitoring
climate_indices provides reference implementations of climate index algorithms that give a
geographical and temporal picture of the severity and duration of precipitation, temperature,
evaporative-demand, fire-weather, and wet-extreme anomalies for climate monitoring and research.
It began as a drought library; it now covers drought, wildfire, and flood potential, and an
energy family is in development.
Indices
Drought and moisture balance
- SPI,
Standardized Precipitation Index, utilizing gamma and Pearson Type III distributions, with
selectable placement of zero accumulations (
zero_handling) - SPEI, Standardized Precipitation Evapotranspiration Index, utilizing gamma, Pearson Type III, and generalized-logistic (log-logistic) distributions
- Standardized index (
indices.standardized_index()), the SPI fitting pipeline for any non-negative series, such as runoff or streamflow for SRI/SSI work - PNP, Percentage of Normal Precipitation
- PCI, Precipitation Concentration Index
- EDDI, Evaporative Demand Drought Index
- Palmer indices, including PDSI, PHDI, PMDI, Z-Index, and scPDSI
Evapotranspiration
- PET, Potential Evapotranspiration, utilizing the Thornthwaite, Hargreaves, or FAO-56 Penman-Monteith equations
Wildfire (climate_indices.fire)
- KBDI, the Keetch-Byram Drought Index
- CFFWIS, the Canadian Forest Fire Weather Index System: the FFMC, DMC, and DC moisture codes (with Drought Code overwintering) and the ISI, BUI, FWI, and DSR behavior indices
- Fosberg Fire Weather Index (FFWI)
- Hot-Dry-Windy Index (HDW)
- Haines Index
Flood potential (climate_indices.flood)
- Effective Precipitation (PE) and its derived Effective Drought Index (EDI, distinct from EDDI), the Flood Index (I_F), and the Antecedent Precipitation Index (API): daily accumulated-wetness measures that indicate flood potential, not flooding
flood_events(), which extracts events with onset, duration, peak, and severity from a daily flood index
Energy (in development, #1157)
Planned, none shipped yet in the package:
- Heating, cooling, and energy degree days (HDD / CDD / EDD)
- Hub-height wind-speed profile, and wind and temperature-derated PV capacity factors
- Standardized energy production and demand indices: SREPI and a standardized demand index, plus SRLI for signed residual-load series, following Allen and Otero (2023)
- Run-theory energy-drought events (onset, duration, severity), and a capacity-weighted precipitation proxy for hydropower
- These indices describe the climate-driven component of energy supply and demand, not actual generation or load
Supporting tools
- Run theory (
climate_indices.runs): runs above or below a threshold with duration, magnitude, intensity, and peak, per series or per grid cell - Distribution fit diagnostics (
fit_diagnostics()): the fitted parameters, probability of zero, and Kolmogorov-Smirnov statistic per calendar step and cell - Probability-scale output (
output_scale): standardized indices as normal scores, fitted cumulative probabilities, or a bounded[-1, 1]scale
Highlights
- Rust backend. An optional compiled extension (
climate_indices._native) runs Rust ports of the numerical kernels behind SPI, SPEI, the standardized index, EDDI, PET, PNP, PCI, the Palmer family, the KBDI and CFFWIS moisture-code recurrences, and the flood family. It preserves the public API; a cross-backend parity registry checks every ported kernel against the Python reference atrtol = atol = 1e-10with matching NaN positions, not bit-for-bit equality; see the parity contract. Speedups vary by kernel: the flood family measured 1.2x to 6.7x faster than its Python path and Thornthwaite PET 1.4x, while Hargreaves measured at parity and Penman-Monteith slightly slower (0.89x) at the benchmark size; see the measurements. - Vectorized gridded computation. SPI, SPEI, EDDI, PNP, PET, and PDSI fit or rank a
whole
(time, *cells)block in one call instead of looping over cells. On a 38x87-cell, 40-year reference grid that is 4.4x faster for SPI, 3.6x for SPEI, 53x for Thornthwaite PET, 342x for EDDI, and 111x for gridded PDSI. On fully populated monthly grids, gamma SPI/SPEI, EDDI, and PNP are bit-identical to per-cell computation; Thornthwaite PET and successful Pearson fits agree within1e-12. Pearson SPI's block-wide gamma fallback is not per-cell equivalent and can depend on chunk layout; daily and missing-data bounds are documented separately. - xarray, Dask, and Zarr. Supported xarray entry points accept
xarray.DataArrayinput, preserve coordinates, attach CF metadata, and stay lazy on Dask-backed arrays for chunk-by-chunk Zarr output. Temporal inference and core-dimension chunk requirements vary by function;indices.standardized_index()and scPDSI remain NumPy-only. See the compatibility matrix, writing NetCDF and Zarr outputs, the Zarr/Dask notebook, and chunking and scheduler guidance. - Validation. Documented evidence distinguishes external checks against NOAA, NRCan, SPEIbase, and literature reference data from regression-only coverage; see Validation.
- Command-line interface.
climate_indices --index {spi,spei,pnp,scaled,pet,palmers,kbdi,pe,edi,flood_index,api,all}computes indices from NetCDF inputs.
Project goals
This Python implementation of the above climate index algorithms is being developed with the following goals in mind:
- to provide an open source software package to compute a suite of climate indices commonly used for climate monitoring, with well documented code that is faithful to the relevant literature and which produces scientifically verifiable results
- to provide a central, open location for participation and collaboration for researchers, developers, and users of climate indices
- to facilitate standardization and consensus on best-of-breed climate index algorithms and corresponding compliant implementations in Python
- to provide transparency into the operational code used for climate monitoring activities at NCEI/NOAA, and consequent reproducibility of published datasets computed from this package
- to incorporate modern software engineering principles and scientific programming best practices
This is a developmental/forked version of code that was originally developed by NIDIS/NCEI/NOAA. See drought.gov.
- Documentation
- Climate Indices for Wildfire Applications
- Climate Indices for Flood and Wet-Extreme Applications
- Validation status
- Changelog
- License
- Disclaimer
Installation
This README describes 3.0.0, which is not yet published on PyPI. The released 2.x
package does not include the fire, flood, or runs modules or the Rust backend.
For 3.0.0 features, install from a development checkout.
Install the released 2.x package from PyPI:
pip install "climate-indices>=2.3"
uv users can run uv pip install "climate-indices>=2.3". The 2.3.0 floor matches the
quickstart,
which uses the xarray API added in 2.3.0; see
Supported Python Versions for interpreter support.
Starting with 3.0.0, wheels for Linux (x86-64 and aarch64, manylinux_2_28, so glibc 2.28 or newer), macOS (Apple silicon and Intel), and Windows (x86-64) include the optional Rust acceleration backend; every other platform, including a Linux system with older glibc, installs the pure-Python wheel. Both carry the same version and the same public API; results agree within the cross-backend parity tolerance, not necessarily bit for bit. Calling code need not depend on which one pip selected. To see which one you have:
python -c "import climate_indices._native" # succeeds when the extension is installed
A missing extension is not an error: climate_indices imports, and every computation
runs the Python implementation. Installing from source needs no Rust toolchain either —
pip install --no-binary climate_indices climate_indices installs from the sdist, which
builds the pure-Python wheel. Developers who
want the extension from a checkout build it with uv run maturin develop --release; see
the Rust backend section of the architecture notes.
Developer Workflow
This project uses trunk-based development. main is the trunk and should always
be releasable.
- Start from current trunk:
git switch main && git pull --ff-only origin main - Create a short-lived branch:
git switch -c feature/<short-topic> - Make focused changes with tests.
- Run validation:
uv run ruff check src/ tests/uv run ruff format --check src/ tests/uv run mypy src/ tests/test_type_checking.pyuv run pytest - Open a PR into
main. - The maintainer merges the PR after review and passing CI; agents never merge.
Use feature/<topic>, fix/<topic>, docs/<topic>, chore/<topic>,
perf/<topic>, refactor/<topic>, test/<topic>, ci/<topic>, or
hotfix/<topic> branch names. Release branches are avoided; use maintenance
branches only for approved older-version support.
The methodology behind this workflow — parallel agent sessions, worktree isolation, and the evidence each change must carry — is documented in AI-assisted development.
Release Recipe
Releases are tag-based. The Git tag, package version, GitHub Release, and PyPI version must match.
- Git tag:
v1.2.3 - Package version:
1.2.3 - GitHub Release:
v1.2.3 - PyPI release:
1.2.3
- Prepare a release PR that updates
pyproject.toml,CHANGELOG.md, and release notes/docs; the maintainer merges it after review and passing CI. - Confirm
mainis green. - Create an annotated tag from
main. - Push the tag. The release workflow builds, validates, publishes to PyPI, and creates the GitHub Release.
Tag creation and publishing require maintainer approval. See
docs/release-process.md for the full checklist.
Maintainer Quick Commands
Read-only preflight:
git status --short
git branch --show-current
git log --oneline --decorate -5
uv run pytest tests/test_release_integrity.py
Safe PR branch setup:
git switch main
git pull --ff-only origin main
git switch -c chore/issue-667-release-docs
Approval-required release tag commands:
git switch main
git pull --ff-only origin main
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git push origin vX.Y.Z
Supported Python Versions
Supports Python 3.10–3.14.
All supported versions are tested on Linux (ubuntu-latest) for every pull request and push
to main. Python 3.14 is additionally tested on macOS on every event, and 3.10 on macOS on
pushes to main, merge groups, the weekly schedule, and manual dispatch. Both latest and
minimum declared dependency versions are tested in CI.
Version Support Policy
This project provides 12 months notice before dropping support for a Python version. When a version approaches end-of-life, removal will be announced via the CHANGELOG and a GitHub issue, and implemented no sooner than 12 months after announcement with a version bump.
Python 3.9 support was dropped in v2.2.0 (August 2025) due to scipy>=1.15.3 requiring 3.10+.
API Stability
| API Surface | Status | Guarantee |
|---|---|---|
NumPy array functions (indices.spi, indices.spei, indices.pet, and the flood indices) |
Stable | No breaking changes in minor versions |
xarray DataArray entry points (any index function accepting xr.DataArray) |
Beta | No breaking changes in patch versions |
Stable API: The NumPy-based computation functions follow strict semantic versioning.
Beta API: The xarray adapter layer provides automatic parameter inference, coordinate
preservation, CF metadata, and Dask support. While beta, computation results follow the
stable NumPy API's documented numerical-equivalence bounds
— only the interface surface (parameter names, metadata attributes,
coordinate handling) may evolve. Beta features are marked in docstrings, with
BetaFeatureWarning as their public warning category. The adapter stays Beta in 3.0.0
and is promoted no earlier than 3.1.0, once the 3.0.0 calendar alignment has a release
of soak time (ADR-0012).
See docs/xarray_compatibility.md for the 3.0.0 compatibility matrix, including
Dask chunking constraints, metadata behavior, and the Palmer xarray adapter.
See docs/performance.md for a runnable parallel SPI/SPEI example and
the measured speedups behind the chunk and scheduler guidance.
Validation
VALIDATION.md classifies the evidence for the indices in its per-index
inventory, separating independent external validation from regression coverage and recording
their known gaps. Fosberg Fire Weather Index and Haines Index are not yet classified there.
uv run pytest -m validation runs the marked reference-fixture and specification checks.
FAO-56 worked-example checks run in the core suite via uv run pytest tests/test_pm_eto.py.
The evidence includes:
- EDDI: NOAA PSL monthly reference ET/EDDI for 1-, 3-, and 6-month timescales
(1979–2023); maximum observed error
2.43e-6. - SPI: characterized against NOAA NCEI's operational climate-divisional SPI for all 344
divisions and 7 timescales; zero placement compared with the R
SEIandSCIpackages. - SPEI: reproduces SPEIbase v2.11 from its own CRU TS inputs (correlation
0.9996–0.99999) and matches the R
SPEIpackage's log-logistic fit within1e-6. - Standard Palmer (PDSI, PHDI, PMDI, Z-Index): qualified external validation against NOAA NCEI nClimDiv for all 344 divisions, 1895–2022 (median absolute difference 0.0127).
- scPDSI: cross-validated against Wells-lineage reference fixtures (
atol=5e-5). - CFFWIS: all seven components match the NRCan
cffdrsreference within1e-9. - KBDI: reproduces the Keetch & Byram (1968) worked example.
- HDW: reproduces event timing and tracks the daily series in the Srock et al. (2018) Cedar Fire case; published magnitudes are characterization only, not numerical validation.
- PET: selected FAO-56 helper examples and the daily end-to-end Example 18, plus Thornthwaite and Hargreaves literature examples; monthly Example 17 is not encoded.
- Flood family: specification-level and regression coverage only; no external numeric oracle has been adopted yet.
The Rust backend has its own gate: the parity registry in tests/parity_registry.py runs
each ported entry point through the extension and through the Python implementation on
property-generated inputs, and fails if a kernel is added without an entry.
Upgrading to 3.0.0
3.0.0 changes some computed values and exception types without a deprecation period, most
notably corrected daily calendar alignment in the xarray adapter, the PCI February fix, and
the gamma probability of zero now taken from the Calibration Period. It also removes the spi
console script in favor of climate_indices --index spi. Each change, how to detect it, and
what to change is in docs/deprecations/api-changes.md;
the full list is in the CHANGELOG. Upgrading from 2.1.x or earlier also
crosses the 2.2.0 switch from None return tuples to exceptions.
Citation
You can cite climate_indices in your projects and research papers via the BibTeX
entry below.
@misc {climate_indices,
author = "James Adams",
title = "climate_indices, an open source Python library providing reference implementations of commonly used climate indices",
url = "https://github.com/monocongo/climate_indices",
month = "may",
year = "2017--"
}
Metadata
Release files for climate-indices 3.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| climate_indices-3.0.0.tar.gz | 2.8 MB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| climate_indices-3.0.0-py3-none-any.whl | Python 3 | none | any | Details |
| climate_indices-3.0.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| climate_indices-3.0.0-cp310-abi3-manylinux_2_28_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ x86-64 | Details |
| climate_indices-3.0.0-cp310-abi3-manylinux_2_28_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.28+ ARM64 | Details |
| climate_indices-3.0.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| climate_indices-3.0.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 7.1 MB
Release files / climate_indices-3.0.0.tar.gz
| Download URL | climate_indices-3.0.0.tar.gz |
|---|---|
| Size | 2.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4c8449a8f6a29a527673e15ba2d3a039bc2020921cd187a8efbe40846c17dc7b
|
|
BLAKE2b-256 checksum How to use checksums |
4c8f3224e6b6d24216ea04d625dcc7ef395d49df5270702e1fed3ac597e168f4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / climate_indices-3.0.0-py3-none-any.whl
| Download URL | climate_indices-3.0.0-py3-none-any.whl |
|---|---|
| Size | 368.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
77f06782fe93430762967047484ce5bac2583c236e47a7d3d536fe9e3993f762
|
|
BLAKE2b-256 checksum How to use checksums |
34ffdf6ba366f60dddfcf9ddb0151fb98184388abadde3be3e9d191d19ea9d58
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / climate_indices-3.0.0-cp310-abi3-win_amd64.whl
| Download URL | climate_indices-3.0.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 739.0 kB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
439d46e0ae729dce948d4d11c08ebc890da15fa971d0c77e1669842145e95f24
|
|
BLAKE2b-256 checksum How to use checksums |
e81f5dc949061882bdfd8637277b8cbd1084ab84b3c4dac34ef6bb87778d15bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / climate_indices-3.0.0-cp310-abi3-manylinux_2_28_x86_64.whl
| Download URL | climate_indices-3.0.0-cp310-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 838.2 kB |
| Tags | CPython 3.10 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
73af6262b40c5f32f88719458b4c27d9f6defc94eb820aa09be0c9e59ebee95c
|
|
BLAKE2b-256 checksum How to use checksums |
83bcff815954f9c54101d2cd7c2d25934260cca2d7b712245ba913fd3e0d5449
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / climate_indices-3.0.0-cp310-abi3-manylinux_2_28_aarch64.whl
| Download URL | climate_indices-3.0.0-cp310-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 818.8 kB |
| Tags | CPython 3.10 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
eeb6a5f64baf018180290b0a9446579c92cf2ff0f9f25623ba6103e8c7fe65b5
|
|
BLAKE2b-256 checksum How to use checksums |
a3b8e7037981159be8352ce8210ff74e58d51aade5255242c7c62314e5c73e0f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / climate_indices-3.0.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | climate_indices-3.0.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 792.4 kB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
099fb909f574bf4d7d86787e59f5021951e3cba0a72270e6a91fb60145ba87be
|
|
BLAKE2b-256 checksum How to use checksums |
6a6f4a5b38ad36cd92b2743be6bd93057d22a70340d124c3702c0429b7a77d38
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency logRelease files / climate_indices-3.0.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | climate_indices-3.0.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 809.7 kB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
9ca54ae224d44f39f51eb622200b91daa9f4cab55007863f5312f7a02efc0ec8
|
|
BLAKE2b-256 checksum How to use checksums |
dc2066f1f8d57063c4894d65a486f1d8fc60dc1ce6b912f3a70100d727b1e406
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 12, 2026.
Transparency log