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 (SPectral Inversion of REflectance from Snow), 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{bair2024spipy,
  title={SpiPy: Python implementation of SPIRES snow property inversion},
  author={Bair, Ned and Griessbaum, Niklas},
  year={2024},
  url={https://github.com/edwardbair/SpiPy},
  version={0.2.0},
  note={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.2.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.2-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.2-cp312-cp312-macosx_11_0_arm64.whl (307.5 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

spires-0.2.2-cp311-cp311-manylinux_2_28_x86_64.whl (965.6 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.28+ x86-64

spires-0.2.2-cp311-cp311-macosx_11_0_arm64.whl (307.2 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

spires-0.2.2-cp310-cp310-manylinux_2_28_x86_64.whl (957.0 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.28+ x86-64

spires-0.2.2-cp310-cp310-macosx_11_0_arm64.whl (307.2 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

spires-0.2.2-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.2-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.2.tar.gz.

File metadata

  • Download URL: spires-0.2.2.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.2.tar.gz
Algorithm Hash digest
SHA256 ee8e970c09b3ead44c0f90545b12334511757db86c49c1fe466e3d775fe23613
MD5 05cc4c0641e3b2c4ed2cbdcfc3f80c03
BLAKE2b-256 e525282c44354294f439ea6ff7a6582b5981ed917d1edb2cd8e095c679c883bc

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp312-cp312-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 38b46a13aa061e2b0e48f91160ab8e1251e8c151ad4b0b420d0b6480bff3dcd0
MD5 2e472afd0dcdbceca9cb6951fb2e3cf0
BLAKE2b-256 ee990bdbdcc8bf26f28bbfe212588f755e6f905631ce1868ae7e93c976add59f

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 bd461e87632f2b5402933c197d476043783f03ae6e98ada8e9db511dc3484cb0
MD5 174c4ab991f0e2395b55420feaba37d0
BLAKE2b-256 f3c0a1534998a9a141d8146fcc146a8b8b16fade660d116644c8c1e6f7e434eb

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp311-cp311-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 07f2aa05b8402d04ad43ec6e96f02213d7ab12a48ed7e392d269c5b71f5da5d8
MD5 e44b687f9dcd13376d7ce022d7a904bd
BLAKE2b-256 fbea6743cb144f76b1ffee39964fe8f62744cf3e5eb06cc1c369453bd338e7be

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0b97cd275fba5561d019832bf83580f4e2df2190ac78626f01bab9ff82cd0894
MD5 a39fc1a6a94ff5d572ddaaa0ff95d878
BLAKE2b-256 711c47e1d065fdeaf8f3fc56ab3c65de50c6f9dac2fcf897a983a44802e5e29c

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp310-cp310-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 2704b3c5ee64f8a943d3c8acb64bd0aeddbcbcbefa3c6875dacb63009125d5ee
MD5 ac8a13e2d25deddd34c9495be483ccfe
BLAKE2b-256 6d5fffdd22c72190b465f5db264208d25f99ce0d7f7f83b6320bc25ab3dbeeb5

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9350fd37d2b92988406f00c9c9c6d8ef23ee44b109d529684b69363731360be5
MD5 2cb0608d7b7b95323600f13b7f5f20c0
BLAKE2b-256 1a4fdcf18b04ec178df13a1dde27eac560d489a77c5f371fe24895f3e29c043e

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp39-cp39-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 50464c9919d7df7348cc4ffca2484876c5a2780152a83a7d8005ebb72f445037
MD5 647c2300da4ddf515a211be2b3180974
BLAKE2b-256 3d1e81aea6ccb31141d7a7e0eb3fcdade646d3ee898e149b3733be1fc77870a8

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for spires-0.2.2-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 875dd7532d05236dc402b39b233b6fa67d55a0205b54747b6694ec903a6866c8
MD5 c5e9c2fccc166fcba950ae0982d644a0
BLAKE2b-256 8ee96b498f7f3752b7209e12f989044a1474e8f85099b150e3d6c12f6bec5470

See more details on using hashes here.

Provenance

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