Changelog
Version History and Updates
All notable changes to this project will be documented in this file.
This project adheres to Calendar Versioning (YYYY.M).
[2026.9] - September 2026
Added
dask_processor.py: concurrent global processing
compute_spi_dask()andcompute_spei_dask()run tiles in parallel on a local Dask cluster and keep the distribution fitting parameters, which the chunked path could not do for a global gridplan_layout()sizes tiles fromn_workersx per-tile peak, so a run is checked against available RAM before it starts- Resume: a run manifest records completed tiles, and an interrupted run picks up where it stopped instead of restarting
- Zarr region writes for lock-free concurrent output, with
zarr_to_netcdf()to stream the finished store out - Write retry with backoff, which absorbs the transient file locks that antivirus and search indexers cause on Windows
Utilities
utils.find_variable(): one variable detector shared byindices,chunkedanddask_processor, replacing four inline implementations. Matches exact name, then whole token, then prefix, then substring, so short patterns likeprno longer matchpressureimport srcnow works alongside the flat module imports
Fixed
- Rolling sum precision. The windowed sum differenced a float32 cumulative sum. With the SPEI offset of 1000 the running total reaches ~8e5, where float32 spacing is 0.0625, so results depended on how many years of record preceded a cell. Measured on TerraClimate SPEI-12, a 1950-start against a 1958-start record differed by mean 9.7e-05 and maximum 1.3e-02; with a float64 accumulator the difference is exactly zero. Output remains float32. The valid-value counter moved from
int16toint32, whichint16would have overflowed on daily records longer than about 89 years - Fitting threshold cliff.
MIN_VALUES_FOR_FITwas 30 while the default calibration window is exactly 30 years, so one missing year voided a cell entirely while Gamma kept returning values from the same data. Lowered to 20, now sourced fromconfig.pyrather than duplicated indistributions.py - Chunked writes. Each tile read the whole output variable back, modified it and wrote it out again. Tiles now write only their own slice
- Eager load at the end of a chunked run, which materialized the full result in memory after the tiles had already been written to disk
- Silent
except Exception: passblocks indistributions.pynow log
Changed
- Pearson III parameters are fitted with vectorized method of moments instead of one SciPy call per cell per calendar period, roughly 12x faster and bit-identical to the loop it replaced
ChunkedProcessor(n_workers=...)is deprecated and ignored: the class always processed tiles serially. Usedask_processorfor concurrency- New configuration constants:
MEMORY_MULTIPLIER_SPEI,MIN_VALUES_FOR_FIT,MIN_NONZERO_VALUES,MAX_ZERO_PROPORTION,DASK_TILE_MULTIPLIER_SPI,DASK_TILE_MULTIPLIER_SPEI,MAX_DASK_TILE - Removed dead code in
compute.pywhose per-cell branch assigned a placeholder value instead of transforming through the CDF
[2026.1] - January 2026
Initial Release
First public release of the precip-index package — a streamlined Python implementation for calculating SPI and SPEI climate indices with comprehensive event analysis capabilities.
Core Features
Climate Indices
- SPI (Standardized Precipitation Index) and SPEI (Standardized Precipitation Evapotranspiration Index)
- Multi-scale support: 1, 3, 6, 12, 24 months
- Five probability distributions: Gamma, Pearson III, Log-Logistic, GEV, Generalized Logistic
- Automatic PET calculation from temperature:
- Thornthwaite method (default) — requires only mean temperature
- Hargreaves-Samani method — requires Tmin/Tmax, better for arid regions
- Parameter save/load for operational workflows
- CF-compliant NetCDF output with customizable metadata
Run Theory Analysis
- Event identification for both dry (drought) and wet (flood) conditions
- Dual magnitude tracking: cumulative and instantaneous
- Gridded period statistics for decision support
- Event characteristics: duration, magnitude, intensity, peak, inter-arrival
Visualization
- WMO standard 11-category classification
- Time series plots with event highlighting
- Spatial statistics maps
- Cross-distribution comparison charts
Technical Highlights
- Modular architecture:
indices.py,runtheory.py,distributions.py,visualization.py - Centralized configuration via
config.py - Memory-efficient chunked processing for global-scale data
- NumPy vectorization with Numba JIT compilation
- Robust fitting with automatic fallback chains (L-moments → Method of Moments → MLE)
- Data diagnostics and goodness-of-fit testing
Documentation
- Comprehensive user guides for SPI, SPEI, run theory, and magnitude concepts
- Technical documentation: methodology, distributions, implementation, API reference
- Interactive Jupyter notebook tutorials
- Quick start guide and configuration reference
Future Releases
- Bug fixes and performance improvements
- Additional test coverage
- Enhanced documentation and examples
- Community-requested features
For detailed technical notes, see Implementation Details