SpiPy#
📦 View Source on GitHub | 📖 Documentation | 🐛 Report Issues
SpiPy is a Python implementation of SPIRES (Snow Property Inversion From Remote Sensing), originally implemented in MATLAB (SPIRES GitHub repository).
Overview#
SPIRES retrieves snow properties (grain size, dust concentration, fractional snow-covered area) from satellite multispectral imagery by inverting reflectance spectra using lookup tables generated from Mie-scattering theory.
Key features:
Hybrid Python/C++ implementation for performance (3000x speedup over pure Python)
Support for MODIS, Sentinel-2, and Landsat data
SWIG bindings for optimized interpolation and optimization routines
NLopt-based nonlinear optimization
Installation#
Quick Install (PyPI)#
pip install spires
Note: Pre-built binary wheels are available for Linux and macOS (Python 3.9-3.14). For other platforms or to build from source, see below.
Install from Source#
Important: Use conda-forge for all dependencies. The apt version of nlopt does not include required C++ headers.
# Install build tools and nlopt (required)
conda install -c conda-forge swig gxx gcc nlopt
# Install all dependencies (recommended)
conda install -c conda-forge numpy h5py scipy xarray netCDF4 gdal geopandas matplotlib tox sphinx dask jupyterlab pyproj
Git LFS#
This repository uses Git LFS for test data. Install Git LFS before cloning:
# macOS
brew install git-lfs
# Linux
sudo apt install git-lfs
# Initialize
git lfs install
Build and Install#
# Build SWIG extensions
python3 setup.py build_ext --inplace
# Install package
pip install .
# Or install with optional dependencies
pip install ".[dev,test,docs]"
Usage#
See the examples/ folder for Jupyter notebooks with detailed use cases.
Basic usage:
import spires
# Load lookup table
interpolator = spires.LutInterpolator(
lut_file='tests/data/lut_sentinel2b_b2to12_3um_dust.mat'
)
# Process imagery to get fractional snow-covered area
fsca = spires.get_fsca(...)
Development#
Building Wheels#
Build a wheel for the active Python interpreter:
pip install build
python -m build --wheel
Build wheels for multiple Python versions using tox:
tox -e py39,py310,py311,py312
Note: When using pyenv, wheels for Python 3.9 may incorrectly build for x86 instead of arm64 on M1 Macs. Use a conda environment to build correctly.
Building C++ Extensions Manually#
The setuptools build process handles SWIG bindings automatically. To build manually:
cd spires
make
Or specify paths explicitly:
NUMPY_INCLUDE=$(python -c "import numpy; print(numpy.get_include())")
g++ -shared -o spires_module.so spires.cpp -I$NUMPY_INCLUDE
Testing#
Run doctests:
pytest --doctest-modules
Documentation#
Install documentation dependencies:
pip install ".[docs]"
Build documentation:
cd doc/
make html
Lookup Tables and Test Data#
Lookup Tables#
Simulated Mie-scattering snow reflectance lookup tables are available on Zenodo:
MODIS:
LUT_MODIS.mat(537 MB)Sentinel-2:
lut_sentinel2b_b2to12_3um_dust.mat(70 MB)
Download using the helper script:
python scripts/download_test_data.py --luts
Or download directly:
curl -L -o LUT_MODIS.mat https://zenodo.org/records/18701286/files/LUT_MODIS.mat
curl -L -o lut_sentinel2b_b2to12_3um_dust.mat https://zenodo.org/records/18701286/files/lut_sentinel2b_b2to12_3um_dust.mat
Note: The Sentinel-2 LUT is also included in the repository via Git LFS. Landsat lookup tables are planned.
Test Data#
Full-resolution test imagery for validation is available on Zenodo:
Sentinel-2 reflectance:
sentinel_r.nc(1.4 GB, 921×1347 pixels)Background reflectance:
sentinel_r0.nc(705 MB)
Small subsets suitable for CI/testing are included in the repository via Git LFS. See tests/data/README.md for details.
Performance#
The C++ optimizations provide significant speedups over pure Python:
Interpolation: 3000x faster (1.07 ms → 309 ns)
Pure Python RegularGridInterpolator: 1.07 ms
Vectorized Python: 143 μs
SWIG C++ (vectorized): 5.58 μs
SWIG C++ (index lookup): 309 ns
Spectrum Difference: 1000x faster (1.1 ms → 1 μs)
Pure Python: 1.1 ms
With optimized interpolator: 3.8 μs
C++ implementation: 1 μs
Full Optimization: 3000x faster (165 ms → 43 μs)
Scipy optimization: 165 ms
With optimized interpolator: 4.94 ms
With C++ spectrum difference: 3.5 ms
NLopt in C++: 43 μs
Known Issues#
SLSQP solver doesn’t work in the C++ implementation; using COBYLA instead
SWIG interpolator and scipy’s RegularGridInterpolator behave differently when coordinates aren’t linspace
COBYLA in scipy can’t set
rhobegper dimension individually, requiring problem scaling
Roadmap#
[ ] Optimize inversion for single location over multiple timesteps (keep R_0 constant)
[ ] Support xarray inputs for interpolator and spectra
[ ] Add Landsat lookup tables
[ ] Improve cloud masking workflows
License#
See LICENSE file for details.
Citation#
If you use this software, please cite the algorithm paper, software implementation, and any datasets you use:
Algorithm:
@article{bair2021spires,
title={Snow Property Inversion From Remote Sensing (SPIReS): A Generalized Multispectral Unmixing Approach With Examples From MODIS and Landsat 8 OLI},
author={Bair, E. H. and Stillinger, T. and Dozier, J.},
journal={IEEE Transactions on Geoscience and Remote Sensing},
volume={59},
number={9},
pages={7270--7284},
year={2021},
doi={10.1109/TGRS.2020.3040328}
}
Software:
@software{bair2026spipy,
title={SpiPy: Python implementation of SPIRES snow property inversion},
author={Bair, Edward H. and Griessbaum, Niklas},
year={2026},
url={https://github.com/NiklasPhabian/SpiPy},
version={0.2.2},
doi={10.5281/zenodo.XXXXXXX},
note={DOI will be updated after Zenodo release. See CITATION.cff for full metadata}
}
Lookup Tables (if used):
@dataset{bair2026spires_luts,
author = {Bair, Edward and Dozier, Jeff},
title = {{SPIRES} Snow Reflectance Lookup Tables},
year = 2026,
publisher = {Zenodo},
doi = {10.5281/zenodo.18701286},
url = {https://doi.org/10.5281/zenodo.18701286}
}
Test Data (if used):
@dataset{griessbaum2026sentinel2_testdata,
author = {Griessbaum, Niklas},
title = {Sentinel-2 reflectance data for testing the {SpiPy} implementation of the {SPIRES} algorithm},
year = 2026,
publisher = {Zenodo},
doi = {10.5281/zenodo.18704072},
url = {https://doi.org/10.5281/zenodo.18704072}
}
Alternatively, see CITATION.cff or use GitHub’s “Cite this repository” feature.
Funding#
Development of this software was supported by:
Contract: W913E523C0002 Program: “Climate and natural hazards, snow-covered and mountain environment sensing research” Sponsor: Broad Agency Announcement Program, Cold Regions Research and Engineering Laboratory Monitored by: U.S. Army Engineer Research and Development Center, Hanover, NH 03755
Distribution Statement: Approved for public release; distribution is unlimited.