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
git clone https://github.com/scottstanie/whirlwind-insar.git
cd whirlwind-insar
pip install .
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.
For noisy scenes, coarsen the solve with downsample (it unwraps a
coherently-averaged copy at the given factor to pick each block's 2π cycle, then
maps the cycles back onto the full-resolution phase). nlooks stays the effective looks of your
input corr — the down-look scaling is handled internally, so you do not raise
it yourself:
unw, conncomp = ww.unwrap(igram, corr, nlooks=10.0, mask=mask, downsample=8)
CLI
The whirlwind CLI is at feature parity with the Python unwrap: every knob the
Python API exposes (downsample, the bridge post-pass, persistent-scatterer
interpolate, Goldstein filtering, and the connected-component cost controls) is
available as a flag. Run whirlwind --help for the full list. There are no subcommands: unwrapping is
the whole CLI, so all flags go directly to whirlwind (earlier releases used a
whirlwind unwrap ... subcommand, which is still accepted with a deprecation
note).
Install
Pick whichever is simplest for you:
-
Prebuilt binary (no Python or toolchain). Download the archive for your platform from the latest release, 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 (the same Rust CLI, entered in-process):uvx --from whirlwind-insar whirlwind --help # zero-install try-out pip install whirlwind-insar # puts `whirlwind` on PATH
-
From source with Cargo (needs the Rust toolchain):
cargo install --path crates/whirlwind-cli --locked
-
Docker (see below).
Run
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)
Headerless flat-binary rasters from the classic pipelines work directly - no GDAL conversion needed:
# 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), preserving amplitude for flat classic pipelines.--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).
Connected components default to the SNAPHU-faithful ambiguity-wiggle grow
(--conncomp-algorithm snaphu) with --conncomp-min-coherence auto, which labels
0 any pixel below a coherence floor of 0.32/sqrt(nlooks) (0.08 at 16 looks).
Set --conncomp-min-coherence off to label every reliably unwrapped pixel, or
pass a number for a fixed cutoff. The legacy linear grow is available with
--conncomp-algorithm linear.
For noisy scenes, coarsen the solve with --downsample (as in the Python API);
the integration-component --no-bridge-able re-leveling pass runs by default:
whirlwind --phase wrapped_phase.tif --cor coherence.tif \
--mask valid_mask.tif --nlooks 10 --downsample 8 \
--out unwrapped_phase.tif
The CLI is pure Rust (no GDAL), so it also runs from a container. Pull the prebuilt image (published to the GitHub Container Registry by CI), or build it locally:
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
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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file whirlwind_insar-0.4.0.tar.gz.
File metadata
- Download URL: whirlwind_insar-0.4.0.tar.gz
- Upload date:
- Size: 249.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51114c43b14a2b5d3293c2ad7aa57d87192c72158973e2faf33cb6866adb1620
|
|
| MD5 |
80a55ab3e8a7f9e081ef82aa0726fc68
|
|
| BLAKE2b-256 |
22cd49b1a6cfd173bb58aae7da87818cf6048dd2f12f54ec6bb8a31a17b453d2
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0.tar.gz:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0.tar.gz -
Subject digest:
51114c43b14a2b5d3293c2ad7aa57d87192c72158973e2faf33cb6866adb1620 - Sigstore transparency entry: 1945592111
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file whirlwind_insar-0.4.0-cp311-abi3-win_amd64.whl.
File metadata
- Download URL: whirlwind_insar-0.4.0-cp311-abi3-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: CPython 3.11+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45f65389bab0f3ff3d2af4647cd3626f1bc84b9f689a07d1bc5ca4521be0e5ec
|
|
| MD5 |
a551bda8a99c5d69cab2a996cabc33ca
|
|
| BLAKE2b-256 |
c453838980f222072c03d62cdc4bb2ba7408f0dcffb6d9506937ca72fea31daa
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0-cp311-abi3-win_amd64.whl:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0-cp311-abi3-win_amd64.whl -
Subject digest:
45f65389bab0f3ff3d2af4647cd3626f1bc84b9f689a07d1bc5ca4521be0e5ec - Sigstore transparency entry: 1945592143
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.11+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e293c0a79b9b1f6cd916458d389ecfc0aac06ca62da79e25e50b4498ed8c7fc
|
|
| MD5 |
40d017bfaf146f86a2bb54b8cbca4882
|
|
| BLAKE2b-256 |
8f29bfcfae0c798a5bd21a2b048472f96f872c8625ed320a20dd10d05b730602
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_x86_64.whl:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_x86_64.whl -
Subject digest:
6e293c0a79b9b1f6cd916458d389ecfc0aac06ca62da79e25e50b4498ed8c7fc - Sigstore transparency entry: 1945592179
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 1.7 MB
- Tags: CPython 3.11+, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48b71d374027c658f055c45cf04d0a6d388d0ce9769dd1f188f1a300721946ac
|
|
| MD5 |
f933c0db685424a6abb22baccb6efb0d
|
|
| BLAKE2b-256 |
fe48a587104945b877d0dc5cc3b6b8e8e7bf056d7196714ef711ec56d80334ae
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_aarch64.whl:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0-cp311-abi3-musllinux_1_2_aarch64.whl -
Subject digest:
48b71d374027c658f055c45cf04d0a6d388d0ce9769dd1f188f1a300721946ac - Sigstore transparency entry: 1945592166
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5caaf341ef2ea69969624c0342083eff22b98ee93f9a3b48935c7ec1ed103c8b
|
|
| MD5 |
38da1d0b2ebc7aa0413dbb8f0beb4a91
|
|
| BLAKE2b-256 |
400023367c5c062350e91f7ffc4e26ac62cb262baa365713f9a49d5d5061d15f
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
5caaf341ef2ea69969624c0342083eff22b98ee93f9a3b48935c7ec1ed103c8b - Sigstore transparency entry: 1945592138
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 1.5 MB
- Tags: CPython 3.11+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a2102a541e1750d9321c4c400b5cf7fd33a8dd57f399876650e3de618581203
|
|
| MD5 |
3fdbd588c7b54dca60ac25eb14d7162c
|
|
| BLAKE2b-256 |
a4519c8286863e7e1dec1bb1e4b9ef40f6f29c790286b51d259699db6ce9d4c7
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
0a2102a541e1750d9321c4c400b5cf7fd33a8dd57f399876650e3de618581203 - Sigstore transparency entry: 1945592130
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file whirlwind_insar-0.4.0-cp311-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: whirlwind_insar-0.4.0-cp311-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.4 MB
- Tags: CPython 3.11+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98fc990a5c1a600aea950d51e4170a5029444f61e5b470118112e1d73cafbc4e
|
|
| MD5 |
0119372ef30c7954df84f65987e0076c
|
|
| BLAKE2b-256 |
1ef7348533ecb3a6582002c765d296a129244274ced78e23694fcb12899f3651
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0-cp311-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0-cp311-abi3-macosx_11_0_arm64.whl -
Subject digest:
98fc990a5c1a600aea950d51e4170a5029444f61e5b470118112e1d73cafbc4e - Sigstore transparency entry: 1945592153
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file whirlwind_insar-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: whirlwind_insar-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 1.7 MB
- Tags: CPython 3.11+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
174fd46387faf1954449fba9de458ce4a0ddc537729c4e0aafcbe092341db0b2
|
|
| MD5 |
c2970eae84eeb1fc7e6a43a5eed1a2dd
|
|
| BLAKE2b-256 |
a5a73fe48c77b3cd803abe5c87ff28d751c46f0b94630d0f53b76a7a273806d7
|
Provenance
The following attestation bundles were made for whirlwind_insar-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl:
Publisher:
release.yml on scottstanie/whirlwind-insar
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
whirlwind_insar-0.4.0-cp311-abi3-macosx_10_12_x86_64.whl -
Subject digest:
174fd46387faf1954449fba9de458ce4a0ddc537729c4e0aafcbe092341db0b2 - Sigstore transparency entry: 1945592115
- Sigstore integration time:
-
Permalink:
scottstanie/whirlwind-insar@4304b145e64cae92f4648d6634acb72bd9032754 -
Branch / Tag:
refs/tags/v0.4.0 - Owner: https://github.com/scottstanie
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4304b145e64cae92f4648d6634acb72bd9032754 -
Trigger Event:
workflow_dispatch
-
Statement type: