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.5.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.5-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.5-cp312-cp312-macosx_11_0_arm64.whl (307.6 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

spires-0.2.5-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.5-cp311-cp311-macosx_11_0_arm64.whl (307.3 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

spires-0.2.5-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.5-cp310-cp310-macosx_11_0_arm64.whl (307.3 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

spires-0.2.5-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.5-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.5.tar.gz.

File metadata

  • Download URL: spires-0.2.5.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.5.tar.gz
Algorithm Hash digest
SHA256 900681ec6c1724a47fc8f77ca12795dccd962967a67ee3f42b5f7a24b7c33aab
MD5 b2723bbb41ccb82605937ada9b3d73ed
BLAKE2b-256 f03141de27bb412da39d23d7b3972cdc8bd97db93662d0d8ca82db48cd82795d

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5.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.5-cp312-cp312-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 7032c8d7543fc379229f44cedbdebc5d5fcca27206de329f4556331253ad80a3
MD5 95bcbed1aa2c801023ee85ebe229e02e
BLAKE2b-256 12b21b401393c020ac9325e6bb22b0a32fc4d475317f6ac1674e37bc0fabedb4

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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.5-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 73595e1d72a95a147070b8c7cf85d01585577e7a7087586b9ed543902350692a
MD5 dbc20816c4081a79c72ccca3966d2be3
BLAKE2b-256 e5318d8210509368c644e48470871f0f34ce5e0c40534f2f7aeb1e2f2f3be348

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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.5-cp311-cp311-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 17f1c4f889feb67db702724098f1cfae6be9f46aeefb6b79784a9e558f74ca3e
MD5 38a6a89d0fc3fa5ce3594e8ffa55380c
BLAKE2b-256 4fba7e9813225836aed2aa4269ded0ef6650b4c21f1b2244e378858dcdf10298

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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.5-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fcf64a9978efcf96e7362afe0d4cf40d961250a9fdafa6fe47cc6a305fc17162
MD5 89eed0a544e5f54a7ccb17c45bca104f
BLAKE2b-256 8d8cd5b8f3f7ed48e4dba4f5013827d1528e79ce51decaab01f990db5bf20b0f

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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.5-cp310-cp310-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 ae58d0b8de8699e48727a509a3b817da7565530f31c297dc653ffeecf0df8099
MD5 358749005cadff19ba8768afee6270b1
BLAKE2b-256 28d98569628c3c6d9475ca0182062a31c3d6faf7ead1d55160755da25da715a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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.5-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 375bad5c9fb78381feafe68af2098592b17c87411be4ae9355feebbbc2da46c5
MD5 e87c1027537ea1c4795d8c1e676a7490
BLAKE2b-256 edf6a6e0d55723a32c65e26dad5efde616198762ff10007867bbcaa29e9f6922

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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.5-cp39-cp39-manylinux_2_28_x86_64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp39-cp39-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2842c76ca15256b6f504e92176a5c2612fcf25619be3a7b50abe392d9ea65009
MD5 86b1d740c7bbef240403a5ef44cfb7a3
BLAKE2b-256 fd6473ce7ad34a17cff92e50a144162e8c813d3dcd22d2b6eb536ada0b488f27

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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.5-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for spires-0.2.5-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 676ff83ad199c5aeb4d4b7419e470a6252c3930c814adcb0be9f3edadcd73d20
MD5 ab155d688ed819b755f3e1e599876c3e
BLAKE2b-256 0af3c7a6049e3abafa4ec9fc03f13ef9d2de7e50409becfe2cfa84a50e5d6d2f

See more details on using hashes here.

Provenance

The following attestation bundles were made for spires-0.2.5-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