Skip to main content

Python implementation of SPIRES (SPectral Inversion of REflectance from Snow) for retrieving snow properties from satellite imagery

Project description

SpiPy

PyPI version Documentation Status Build and Test Python 3.9-3.14 License: MIT

📦 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:

DOI

  • 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:

DOI

  • 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 rhobeg per 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

spires-0.2.8.tar.gz (62.5 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

spires-0.2.8-cp312-cp312-manylinux_2_28_x86_64.whl (1.0 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.28+ x86-64

spires-0.2.8-cp312-cp312-macosx_11_0_arm64.whl (307.6 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

spires-0.2.8-cp311-cp311-manylinux_2_28_x86_64.whl (965.7 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

spires-0.2.8-cp311-cp311-macosx_11_0_arm64.whl (307.3 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

spires-0.2.8-cp310-cp310-manylinux_2_28_x86_64.whl (957.1 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

spires-0.2.8-cp310-cp310-macosx_11_0_arm64.whl (307.3 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

spires-0.2.8-cp39-cp39-manylinux_2_28_x86_64.whl (953.9 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.28+ x86-64

spires-0.2.8-cp39-cp39-macosx_11_0_arm64.whl (305.2 kB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

File details

Details for the file spires-0.2.8.tar.gz.

File metadata

  • Download URL: spires-0.2.8.tar.gz
  • Upload date:
  • Size: 62.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for spires-0.2.8.tar.gz
Algorithm Hash digest
SHA256 a2ec014fc5bd3cf1eca2620cc9b6fea65334ed68d410483bd71227d0e00d256c
MD5 a16fb3f6f0bc65445fadf5a7affa3a65
BLAKE2b-256 f64d9f425b1073d18a8412da0c1bd5ea6424a39ff727da761fe736bd114cfc41

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8.tar.gz:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 c1b1397cf6886e52a32fad827ca93da8b75b606d489b2c265459bd50e2091e9d
MD5 9b414a44c9b39eaa6b6724b3c5ab68d3
BLAKE2b-256 2cc30c374bc1b78f41629b50c0705e4dd5eb003018a37473b0540ac5cb6b587a

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp312-cp312-manylinux_2_28_x86_64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 960869d7c60efb8d83ec4dec7e6d3086ccaef00ac0e285fe940a08234f62c1d8
MD5 3e249fd8d2530fc55af2a99a50e0889e
BLAKE2b-256 a45b13d0a01303773b3370db7d2d737f0b9c64f090ba05f1667ac281acc0a169

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp312-cp312-macosx_11_0_arm64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 e544a42128a429b52d06c2126fad596545dbe842f3913a1fb1ab49c7cc8f6d91
MD5 4fd564f4958cad6781ff4b1ba858a2b3
BLAKE2b-256 24d72a25c7457d1d9f02c676d1afe6e1781c61fc788f6d6f0e079bff6da6cfca

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp311-cp311-manylinux_2_28_x86_64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 7921d6b4a63abfee99016bd28eedec2358b8b987fa8f9eeffe55846b51a9cba6
MD5 5d7a375eb592e10126530a3bed9565d4
BLAKE2b-256 f82179bfbdc42f8f27919e915adc2946ee91e74936ea6feaf6459e9b1803880f

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp311-cp311-macosx_11_0_arm64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 d17c6ff24e6b1596745865e0782490632b3e1df26dcf4722d2aff042ef219bbc
MD5 4c247c76ce66239e74a13d9a8199ef92
BLAKE2b-256 f5d301a5113ef6851affd686a9478f48c65639dd36b17f3eabce73bebaf6a680

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp310-cp310-manylinux_2_28_x86_64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 ac43a0d6978823d8b90304bf168142f3c5acbfd53eee4056b649d348e0d495ea
MD5 3c2ca6c839fee6f8704169b3f8622dac
BLAKE2b-256 d01091ab894d376cd1d69d81252ee71fc533e88f3914a7853210e1ce2cbf0eb1

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp310-cp310-macosx_11_0_arm64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp39-cp39-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp39-cp39-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 997785fff71726a579733995530eb0f4be4a6e38935b4ba77c25ca677698d29c
MD5 87ff59cbca4417b5c936f28dc20f5d00
BLAKE2b-256 073620517d03bd0ef4e386a782bd24557579782753baff61c4956b51a75ec1eb

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp39-cp39-manylinux_2_28_x86_64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file spires-0.2.8-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.8-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 4008cdce60505890f5961ec2916a4ccbb90a2c4db99ab9deef912343c1bbd5ca
MD5 ccdc805c72498abb9915cf025ebad42d
BLAKE2b-256 fba16a47589ca0489486717a5792f9b753102c2b7c45a684ad1f7e08570577fd

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.8-cp39-cp39-macosx_11_0_arm64.whl:

Publisher: publish-pypi.yml on NiklasPhabian/SpiPy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page