whirlwind
Fast Rust-backed 2D InSAR phase unwrapping with Python bindings.
Whirlwind unwraps a complex interferogram and returns both unwrapped phase and connected-component labels. The NISAR comparison shows agreement with production SNAPHU on 2pi ambiguities, with lower runtime in the tested scenes.
The package is
whirlwind-insaron PyPI and GitHub; it imports aswhirlwind.
Quickstart
whirlwind can be installed from PyPI,
pip install whirlwind-insar
or on Conda Forge:
conda install -c conda-forge whirlwind-insar
Source installs require Python 3.11+ and Rust.
Usage
import whirlwind as ww
unw, conncomp = ww.unwrap(igram, corr, nlooks=10.0, mask=mask)
igram is a complex wrapped interferogram, corr is coherence/correlation in [0, 1], and mask is optional with True for valid pixels.
CLI
A CLI is provided that mirrors the Python API. Run whirlwind --help for the full list.
➜ whirlwind --help
InSAR phase unwrapper.
...
CLI installation
There are multiple ways to install whirlwind to use only the CLI:
- Prebuilt binary (no Python or toolchain). Download the archive for your platform from the [latest release][releases], unpack it, and run the
whirlwindexecutable. A single self-contained binary - handy for MATLAB users driving it viasystem('whirlwind ...'). - With the Python package. The wheel ships a
whirlwindconsole script which can be run usinguvxwith with the UV tool system:
uvx --from whirlwind-insar whirlwind --help # zero-install try-out
pip install whirlwind-insar # puts `whirlwind` on PATH
-
Docker via the Github Container Registry
-
From source with Cargo using a local Git clone:
cargo install --path crates/whirlwind-cli --locked
Running the CLI
whirlwind \
--phase wrapped_phase.tif \
--cor coherence.tif \
--mask valid_mask.tif \
--nlooks 10 \
--out unwrapped_phase.tif
--phase is the wrapped phase in radians: a float32 TIFF, or a flat binary float32 file (see below). If you start from a complex-valued GeoTIFF, extract GDAL's PHASE derived subdataset first and pass that as --phase; --ifg is for flat complex64 rasters. The phase path reconstructs a unit-magnitude interferogram, so it does not preserve amplitude. --mask is optional; nonzero means valid. When --mask is omitted the CLI uses coherence > 0 (and igram != 0 with --ifg) as the default valid mask, matching the Python API. The CLI writes a SNAPHU-faithful connected-component label map by default next to --out (foo.conncomp.tif for TIFF, foo.unw.conncomp for flat .unw); use --conncomp PATH to choose the path or --no-conncomp to skip it.
Flat-binary formats (snaphu / ROI_PAC / isce2 / GAMMA)
Whirlwind can also accept flat binary rasters:
# snaphu-style: complex64 .int + amp/cor .cc; width ("line length") on the CLI
whirlwind --ifg pair.int --cor pair.cc --cols 1024 --nlooks 10 --out pair.unw
# ROI_PAC / Stanford: geometry read from the <file>.rsc sidecar automatically
whirlwind --ifg 20150902_20150914.int --cor 20150902_20150914.cc \
--nlooks 10 --out 20150902_20150914.unw
# isce2 stripmapStack / topsStack: the <file>.xml sidecars provide everything
whirlwind --ifg filt_fine.int --cor filt_fine.cor --nlooks 10 \
--out filt_fine.unw
# GAMMA: big-endian; width from a .par/.off (or --cols + --big-endian)
whirlwind --ifg pair.diff --ifg-meta pair.off \
--cor pair.cc --cor-meta pair.off --nlooks 10 --out-format float --out pair.unw
--ifgis the raw flat complex64 interferogram (snaphuCOMPLEX_DATA, i.e.numpy.tofile()of a complex64 array).--phaseaccepts float32 wrapped phase as TIFF or flat binary (snaphuFLOAT_DATA) and reconstructs unit-magnitude complex values. Exactly one of the two is given.--cormay be single-band float32 (isce2.cor, GAMMA.cc) or the two-band line-interleaved amplitude+correlation "rmg" layout (snaphu's default, ROI_PAC.cc): the band count is detected from the file size and the correlation is read from the second channel, exactly as snaphu does.--cor-format alt-samplecovers snaphu's sample-interleaved variant.--cols(alias--width) is snaphu's "line length" / ROI_PACWIDTH; the row count always comes from the file size. A<file>.rscor<file>.xmlnext to each input supplies it automatically (and, for isce2, the dtype, band count, scheme, and byte order). Use--ifg-meta,--phase-meta, or--cor-metawhen the sidecar is not next to that input.- Output is chosen by extension (override with
--out-format):.tif→ TIFF;.unw→ two-band amp+phase rmg (snaphu's default output layout); anything else → flat float32 phase. Conncomp follows the output style by default: u16 TIFF for TIFF outputs, or one-byte-per-pixel flat for flat outputs (the snaphu/isce2 convention). Flat outputs keep the input's byte order. --maskalso accepts snaphu-style flat byte masks (nonzero = valid, zero = masked).
docker pull ghcr.io/scottstanie/whirlwind-insar:main # prebuilt, or:
docker build -t ghcr.io/scottstanie/whirlwind-insar . # build locally
docker run --rm -v "$PWD:/data" ghcr.io/scottstanie/whirlwind-insar \
--phase /data/wrapped.tif --cor /data/cor.tif --nlooks 10 \
--out /data/unw.tif
Dolphin
Dolphin can select Whirlwind as an unwrap method:
dolphin unwrap --unwrap-options.unwrap-method WHIRLWIND ...
See the Dolphin docs for the rest of the Dolphin workflow.
Development
git clone https://github.com/scottstanie/whirlwind-insar.git
cd whirlwind-insar
pip install .
uv sync
uv run maturin develop --release
uv run pytest python/tests
cargo test --workspace
More
- NISAR comparison
- Why SNAPHU/PHASS differ
- Memory and scaling notes
- Algorithm notes
- Environment variables
Repository Layout
python/whirlwind: Python API.crates/whirlwind-core: Rust algorithms.crates/whirlwind-py: PyO3 bindings.crates/whirlwind-cli: CLI binary.docs: reference docs.scripts: benchmarks and development utilities.
License
Licensed under either the BSD 3-Clause License or the Apache License, Version 2.0, at your option. See LICENSE.
Metadata
Release files for whirlwind-insar 0.10.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| whirlwind_insar-0.10.0.tar.gz | 334.7 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| whirlwind_insar-0.10.0-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| whirlwind_insar-0.10.0-cp311-abi3-musllinux_1_2_x86_64.whl | CPython 3.11 | abi3 | Linux musl 1.2+ x86-64 | Details |
| whirlwind_insar-0.10.0-cp311-abi3-musllinux_1_2_aarch64.whl | CPython 3.11 | abi3 | Linux musl 1.2+ ARM64 | Details |
| whirlwind_insar-0.10.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| whirlwind_insar-0.10.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| whirlwind_insar-0.10.0-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
| whirlwind_insar-0.10.0-cp311-abi3-macosx_10_12_x86_64.whl | CPython 3.11 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 12.4 MB
Release files / whirlwind_insar-0.10.0.tar.gz
| Download URL | whirlwind_insar-0.10.0.tar.gz |
|---|---|
| Size | 334.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
40c890a0235774b451abd82baf070947118314c754db9747bd842783f32b4e6b
|
|
BLAKE2b-256 checksum How to use checksums |
4a382e41c710c346740f966fee485efda4c457e5f461a240cad737539fb53447
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / whirlwind_insar-0.10.0-cp311-abi3-win_amd64.whl
| Download URL | whirlwind_insar-0.10.0-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 1.7 MB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
7e4b55bc922357dace7a05752ac1cfa6531d0f75995726dd274d8be4a2647b58
|
|
BLAKE2b-256 checksum How to use checksums |
28045bbf4b4c9624c481e47a2f4f647e58439d65e5b6605aa5b84c81df9e165a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / whirlwind_insar-0.10.0-cp311-abi3-musllinux_1_2_x86_64.whl
| Download URL | whirlwind_insar-0.10.0-cp311-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 2.1 MB |
| Tags | CPython 3.11 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
4c32ad1b25e99e98feddb40d0fb417b9b3d36ba64eb6546920627329c7fe7e1f
|
|
BLAKE2b-256 checksum How to use checksums |
4c44f57a34170972b96defb847438d900875274228193be5c9dcf450f4cdc598
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / whirlwind_insar-0.10.0-cp311-abi3-musllinux_1_2_aarch64.whl
| Download URL | whirlwind_insar-0.10.0-cp311-abi3-musllinux_1_2_aarch64.whl |
|---|---|
| Size | 1.7 MB |
| Tags | CPython 3.11 Linux musl 1.2+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
d0871efa2847417d446f6dbf38c3543d9e87762bd2655b451b5d83bfeb9cbb44
|
|
BLAKE2b-256 checksum How to use checksums |
472fd51c274e4baf1e1dfd9b5c49ad687195086f745a625111a8a275bab95cb6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / whirlwind_insar-0.10.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | whirlwind_insar-0.10.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 1.8 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
897452e4b0e1070ba5c3b6f44e1861ac4c201045befb2e56a6cf9a82d8b770b2
|
|
BLAKE2b-256 checksum How to use checksums |
ab13ba58309e792fe88f2ddbfc21bd657d4975a9a5490fd993d5d9a07b91e4bb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / whirlwind_insar-0.10.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | whirlwind_insar-0.10.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 1.6 MB |
| Tags | CPython 3.11 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
ed4018ae3e5ff4686800e40c00060e98c5d26d609c7091f6e5a115198da85abf
|
|
BLAKE2b-256 checksum How to use checksums |
8c9d0bec3dccaa5f085bfc7c6383fe93df13010b0397851b5867592d8b83e8f1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / whirlwind_insar-0.10.0-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | whirlwind_insar-0.10.0-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 1.5 MB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
eefae6d94cc84a7b80b9546f6b5e7522ef97df9f15abbce885a11b12b489748a
|
|
BLAKE2b-256 checksum How to use checksums |
1f05280a1ebc9149049f670569f83946b280e7036ccb752f1002b34b44e5e688
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency logRelease files / whirlwind_insar-0.10.0-cp311-abi3-macosx_10_12_x86_64.whl
| Download URL | whirlwind_insar-0.10.0-cp311-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 1.7 MB |
| Tags | CPython 3.11 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
23f21c0f769750c3713fc192bb251642d84aabc16c714d3a564131851f5b28ea
|
|
BLAKE2b-256 checksum How to use checksums |
c82aafe5a0479be2a82cdd2f501e6b063256e7bfacbef28ea8639a075c8e9ba7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.
Transparency log