nisar-pytools 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. nisar_pytools-0.1.0/.github/workflows/ci.yml +35 -0
  2. nisar_pytools-0.1.0/.github/workflows/publish.yml +28 -0
  3. nisar_pytools-0.1.0/.gitignore +34 -0
  4. nisar_pytools-0.1.0/.pre-commit-config.yaml +11 -0
  5. nisar_pytools-0.1.0/CHANGELOG.md +41 -0
  6. nisar_pytools-0.1.0/CLAUDE.md +52 -0
  7. nisar_pytools-0.1.0/LICENSE.txt +20 -0
  8. nisar_pytools-0.1.0/MANIFEST.in +4 -0
  9. nisar_pytools-0.1.0/PKG-INFO +207 -0
  10. nisar_pytools-0.1.0/README.md +154 -0
  11. nisar_pytools-0.1.0/environment.yml +31 -0
  12. nisar_pytools-0.1.0/notebooks/.gitkeep +0 -0
  13. nisar_pytools-0.1.0/notebooks/example.ipynb +108 -0
  14. nisar_pytools-0.1.0/pyproject.toml +84 -0
  15. nisar_pytools-0.1.0/setup.cfg +4 -0
  16. nisar_pytools-0.1.0/src/nisar_pytools/__init__.py +3 -0
  17. nisar_pytools-0.1.0/src/nisar_pytools/io/__init__.py +15 -0
  18. nisar_pytools-0.1.0/src/nisar_pytools/io/_download.py +176 -0
  19. nisar_pytools-0.1.0/src/nisar_pytools/io/_export.py +153 -0
  20. nisar_pytools-0.1.0/src/nisar_pytools/io/_h5_to_datatree.py +303 -0
  21. nisar_pytools-0.1.0/src/nisar_pytools/io/_reader.py +64 -0
  22. nisar_pytools-0.1.0/src/nisar_pytools/io/_search.py +115 -0
  23. nisar_pytools-0.1.0/src/nisar_pytools/io/_stack.py +245 -0
  24. nisar_pytools-0.1.0/src/nisar_pytools/processing/__init__.py +41 -0
  25. nisar_pytools-0.1.0/src/nisar_pytools/processing/phase_linking.py +233 -0
  26. nisar_pytools-0.1.0/src/nisar_pytools/processing/polsar.py +376 -0
  27. nisar_pytools-0.1.0/src/nisar_pytools/processing/sar.py +288 -0
  28. nisar_pytools-0.1.0/src/nisar_pytools/utils/__init__.py +0 -0
  29. nisar_pytools-0.1.0/src/nisar_pytools/utils/_search_validation.py +219 -0
  30. nisar_pytools-0.1.0/src/nisar_pytools/utils/_validation.py +96 -0
  31. nisar_pytools-0.1.0/src/nisar_pytools/utils/conversion.py +55 -0
  32. nisar_pytools-0.1.0/src/nisar_pytools/utils/dem.py +173 -0
  33. nisar_pytools-0.1.0/src/nisar_pytools/utils/local_incidence_angle.py +170 -0
  34. nisar_pytools-0.1.0/src/nisar_pytools/utils/masking.py +60 -0
  35. nisar_pytools-0.1.0/src/nisar_pytools/utils/metadata.py +57 -0
  36. nisar_pytools-0.1.0/src/nisar_pytools/viz/__init__.py +13 -0
  37. nisar_pytools-0.1.0/src/nisar_pytools/viz/plotting.py +212 -0
  38. nisar_pytools-0.1.0/src/nisar_pytools.egg-info/PKG-INFO +207 -0
  39. nisar_pytools-0.1.0/src/nisar_pytools.egg-info/SOURCES.txt +59 -0
  40. nisar_pytools-0.1.0/src/nisar_pytools.egg-info/dependency_links.txt +1 -0
  41. nisar_pytools-0.1.0/src/nisar_pytools.egg-info/requires.txt +33 -0
  42. nisar_pytools-0.1.0/src/nisar_pytools.egg-info/top_level.txt +1 -0
  43. nisar_pytools-0.1.0/tests/__init__.py +0 -0
  44. nisar_pytools-0.1.0/tests/conftest.py +143 -0
  45. nisar_pytools-0.1.0/tests/test_conversion.py +57 -0
  46. nisar_pytools-0.1.0/tests/test_dem.py +73 -0
  47. nisar_pytools-0.1.0/tests/test_download.py +161 -0
  48. nisar_pytools-0.1.0/tests/test_export.py +85 -0
  49. nisar_pytools-0.1.0/tests/test_h5_to_datatree.py +188 -0
  50. nisar_pytools-0.1.0/tests/test_local_incidence_angle.py +140 -0
  51. nisar_pytools-0.1.0/tests/test_masking.py +49 -0
  52. nisar_pytools-0.1.0/tests/test_metadata.py +46 -0
  53. nisar_pytools-0.1.0/tests/test_phase_linking.py +172 -0
  54. nisar_pytools-0.1.0/tests/test_polsar.py +203 -0
  55. nisar_pytools-0.1.0/tests/test_reader.py +98 -0
  56. nisar_pytools-0.1.0/tests/test_sar.py +399 -0
  57. nisar_pytools-0.1.0/tests/test_search.py +90 -0
  58. nisar_pytools-0.1.0/tests/test_search_validation.py +158 -0
  59. nisar_pytools-0.1.0/tests/test_stack.py +185 -0
  60. nisar_pytools-0.1.0/tests/test_validation.py +100 -0
  61. nisar_pytools-0.1.0/tests/test_viz.py +103 -0
@@ -0,0 +1,35 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [master]
6
+ pull_request:
7
+ branches: [master]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ defaults:
13
+ run:
14
+ shell: bash -l {0}
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - uses: conda-incubator/setup-miniconda@v3
20
+ with:
21
+ environment-file: environment.yml
22
+ activate-environment: nisar_pytools
23
+ miniforge-version: latest
24
+
25
+ - name: Lint
26
+ run: ruff check src/ tests/
27
+
28
+ - name: Run tests
29
+ run: pytest tests/ -v -m "not integration"
30
+
31
+ - name: Build package
32
+ run: python -m build
33
+
34
+ - name: Check package
35
+ run: twine check dist/*
@@ -0,0 +1,28 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+
11
+ permissions:
12
+ id-token: write # Required for trusted publishing
13
+
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.12"
20
+
21
+ - name: Install build tools
22
+ run: pip install build
23
+
24
+ - name: Build package
25
+ run: python -m build
26
+
27
+ - name: Publish to PyPI
28
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,34 @@
1
+ # Local data
2
+ local/
3
+
4
+ # Python
5
+ __pycache__/
6
+ *.py[cod]
7
+ *.egg-info/
8
+ *.egg
9
+ dist/
10
+ build/
11
+ *.whl
12
+
13
+ # Environments
14
+ .env
15
+ .venv/
16
+
17
+ # IDE
18
+ .vscode/
19
+ .idea/
20
+
21
+ # OS
22
+ .DS_Store
23
+ Thumbs.db
24
+
25
+ # Jupyter
26
+ .ipynb_checkpoints/
27
+
28
+ # Testing
29
+ .pytest_cache/
30
+ .coverage
31
+ htmlcov/
32
+
33
+ # Ruff
34
+ .ruff_cache/
@@ -0,0 +1,11 @@
1
+ repos:
2
+ - repo: https://github.com/kynan/nbstripout
3
+ rev: 0.8.1
4
+ hooks:
5
+ - id: nbstripout
6
+
7
+ - repo: https://github.com/astral-sh/ruff-pre-commit
8
+ rev: v0.11.4
9
+ hooks:
10
+ - id: ruff
11
+ args: [--fix]
@@ -0,0 +1,41 @@
1
+ # Changelog
2
+
3
+ ## v0.1.0
4
+
5
+ ### IO
6
+ - `open_nisar()` — read NISAR HDF5 files into lazy xarray DataTree with CRS
7
+ - `stack_gslcs()` — stack multiple same-track GSLCs into a `(time, y, x)` DataArray
8
+ - `find_nisar()` — search ASF for NISAR product URLs by AOI, dates, track, direction
9
+ - `download_urls()` — parallel download with retry and post-download HDF5 validation
10
+ - `to_zarr()` / `to_netcdf()` / `read_netcdf()` — export and import with complex data support
11
+ - Generic h5py-to-DataTree walker with dask-backed lazy arrays
12
+ - Automatic coordinate assignment and CRS from `projection` dataset
13
+ - HDF5 dimension scale resolution via `DIMENSION_LIST` attributes
14
+
15
+ ### Processing
16
+ - `interferogram()` — complex interferogram with grid matching validation
17
+ - `coherence()` — sliding-window coherence estimation
18
+ - `multilook()` / `multilook_interferogram()` — spatial averaging and downsampling
19
+ - `unwrap()` — phase unwrapping via SNAPHU
20
+ - `calculate_phase()` — extract phase from complex data
21
+ - `phase_link()` — EMI phase linking with SHP selection on SLC stacks
22
+ - `h_a_alpha()` — Cloude-Pottier polarimetric decomposition (entropy, anisotropy, alpha)
23
+ - Individual `entropy()`, `anisotropy()`, `alpha()`, `mean_alpha()` functions
24
+
25
+ ### Utilities
26
+ - `fetch_dem()` — auto-download Copernicus GLO-30 DEM matching a NISAR file's extent
27
+ - `local_incidence_angle()` — compute LIA from LOS vectors and a DEM
28
+ - `get_acquisition_time()`, `get_orbit_info()`, `get_bounding_polygon()` — metadata extraction
29
+ - `apply_mask()` / `get_mask()` — apply NISAR mask datasets
30
+ - `to_db()` / `from_db()` — dB conversion
31
+ - Date, AOI, URL, and path validation utilities
32
+
33
+ ### Visualization
34
+ - `plot_amplitude()`, `plot_phase()`, `plot_interferogram()`, `plot_coherence()`
35
+
36
+ ### Infrastructure
37
+ - PyPI-ready packaging with `pyproject.toml`
38
+ - CI/CD via GitHub Actions (lint, test, build, publish)
39
+ - Pre-commit hooks (nbstripout, ruff)
40
+ - Conda environment file
41
+ - 243 tests with synthetic HDF5 fixtures
@@ -0,0 +1,52 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project
6
+
7
+ Python tools for reading NISAR (NASA-ISRO SAR) HDF5 data products into lazy xarray DataTree objects. Currently supports GSLC and GUNW product types.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Use the nisar_pytools conda env for all commands
13
+ # Install: mamba env create -f environment.yml
14
+ # Activate or prefix with: /Users/zmhoppinen/miniforge3/envs/nisar_pytools/bin/python
15
+
16
+ # Run all unit tests
17
+ /Users/zmhoppinen/miniforge3/envs/nisar_pytools/bin/python -m pytest tests/ -v -m "not integration"
18
+
19
+ # Run a single test file or test
20
+ /Users/zmhoppinen/miniforge3/envs/nisar_pytools/bin/python -m pytest tests/test_reader.py -v
21
+ /Users/zmhoppinen/miniforge3/envs/nisar_pytools/bin/python -m pytest tests/test_reader.py::TestOpenNisar::test_lazy_by_default -v
22
+
23
+ # Run integration tests (requires real NISAR files in local/)
24
+ NISAR_TEST_GSLC=local/gslcs/<file>.h5 NISAR_TEST_GUNW=local/gunws/<file>.h5 \
25
+ /Users/zmhoppinen/miniforge3/envs/nisar_pytools/bin/python -m pytest tests/ -v
26
+
27
+ # Lint
28
+ /Users/zmhoppinen/miniforge3/envs/nisar_pytools/bin/ruff check src/ tests/
29
+
30
+ # Install dependencies with mamba, not pip or conda
31
+ mamba install -n nisar_pytools -c conda-forge <package>
32
+ ```
33
+
34
+ ## Architecture
35
+
36
+ **Entry point**: `from nisar_pytools import open_nisar` — takes an HDF5 file path, validates it, detects product type, returns `xr.DataTree` with dask-backed lazy arrays.
37
+
38
+ **Flow**: `open_nisar()` → `validate_nisar_hdf5()` → `detect_product_type()` → `h5_to_datatree()`
39
+
40
+ **Key design decisions**:
41
+ - Uses custom h5py walker (not `xr.open_datatree` with h5netcdf) because NISAR files have named types at root and 100+ scalar datasets that belong in attrs, not as DataArrays.
42
+ - All 2D+ arrays are dask-backed via `dask.array.from_array()`. Coordinates (1D `xCoordinates`/`yCoordinates`) are loaded eagerly since they're small.
43
+ - Scalar datasets become `Dataset.attrs`. 1D non-coordinate arrays (e.g., `listOfPolarizations`) also go to attrs.
44
+ - Unnamed dimensions are prefixed with the variable name (e.g., `eulerAngles_dim_1`) to avoid conflicts when sibling datasets have different shapes.
45
+ - The `h5py.File` handle is kept alive on `tree.__dict__["_h5file"]` to prevent GC while dask arrays reference it.
46
+
47
+ **`src/nisar_pytools/` layout**:
48
+ - `io/_reader.py` — `open_nisar()` entry point
49
+ - `io/_h5_to_datatree.py` — generic HDF5 group walker that builds DataTree
50
+ - `utils/_validation.py` — file validation and product type detection
51
+
52
+ **Tests** use synthetic HDF5 fixtures (tiny 8x10 arrays) defined in `tests/conftest.py`. Integration tests against real files are gated behind `@pytest.mark.integration` and env vars.
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Zachary Hoppinen
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ include LICENSE.txt
2
+ include README.md
3
+ include CHANGELOG.md
4
+ recursive-include src/nisar_pytools *.py
@@ -0,0 +1,207 @@
1
+ Metadata-Version: 2.4
2
+ Name: nisar-pytools
3
+ Version: 0.1.0
4
+ Summary: Open source Python tools for working with NISAR datasets
5
+ Author-email: Zachary Hoppinen <zachary.hoppinen@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/zmhoppinen/nisar_pytools
8
+ Project-URL: Repository, https://github.com/zmhoppinen/nisar_pytools
9
+ Project-URL: Issues, https://github.com/zmhoppinen/nisar_pytools/issues
10
+ Keywords: nisar,sar,insar,radar,remote-sensing,hdf5,xarray
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Scientific/Engineering :: GIS
20
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE.txt
24
+ Requires-Dist: asf_search>=7.0
25
+ Requires-Dist: dask[array]>=2024.0
26
+ Requires-Dist: h5py>=3.10
27
+ Requires-Dist: numpy>=1.24
28
+ Requires-Dist: pyproj>=3.4
29
+ Requires-Dist: rasterio>=1.3
30
+ Requires-Dist: requests
31
+ Requires-Dist: rioxarray>=0.15
32
+ Requires-Dist: scipy>=1.10
33
+ Requires-Dist: shapely>=2.0
34
+ Requires-Dist: snaphu>=0.3
35
+ Requires-Dist: xarray>=2024.10
36
+ Provides-Extra: dem
37
+ Requires-Dist: dem_stitcher; extra == "dem"
38
+ Provides-Extra: dev
39
+ Requires-Dist: build; extra == "dev"
40
+ Requires-Dist: nbstripout; extra == "dev"
41
+ Requires-Dist: pre-commit; extra == "dev"
42
+ Requires-Dist: pytest; extra == "dev"
43
+ Requires-Dist: ruff; extra == "dev"
44
+ Requires-Dist: twine; extra == "dev"
45
+ Provides-Extra: notebooks
46
+ Requires-Dist: jupyter; extra == "notebooks"
47
+ Requires-Dist: matplotlib; extra == "notebooks"
48
+ Provides-Extra: viz
49
+ Requires-Dist: matplotlib; extra == "viz"
50
+ Provides-Extra: all
51
+ Requires-Dist: nisar-pytools[dem,notebooks,viz]; extra == "all"
52
+ Dynamic: license-file
53
+
54
+ # nisar_pytools
55
+
56
+ Open source Python tools for working with NISAR datasets.
57
+
58
+ ## About
59
+
60
+ `nisar_pytools` provides utilities for searching, downloading, reading, and processing data products from NASA's [NISAR](https://nisar.jpl.nasa.gov/) (NASA-ISRO Synthetic Aperture Radar) mission.
61
+
62
+ ### Supported Products
63
+
64
+ - **GSLC** - Geocoded Single Look Complex
65
+ - **GUNW** - Geocoded Unwrapped Interferogram
66
+
67
+ Additional NISAR product types will be added over time.
68
+
69
+ ## Getting Started
70
+
71
+ ### Prerequisites
72
+
73
+ - Python 3.10+
74
+ - [Miniforge](https://github.com/conda-forge/miniforge) (recommended)
75
+ - NASA Earthdata login (for downloading from ASF)
76
+
77
+ ### Installation
78
+
79
+ 1. Clone the repository
80
+ ```sh
81
+ git clone https://github.com/zmhoppinen/nisar_pytools.git
82
+ cd nisar_pytools
83
+ ```
84
+ 2. Create the conda environment
85
+ ```sh
86
+ mamba env create -f environment.yml
87
+ conda activate nisar_pytools
88
+ ```
89
+
90
+ ## Usage
91
+
92
+ ### Search and Download
93
+
94
+ ```python
95
+ from nisar_pytools import find_nisar, download_urls
96
+
97
+ # Search ASF for GSLC products over an area of interest
98
+ urls = find_nisar(
99
+ aoi=[-115, 43, -114, 44],
100
+ start_date="2025-06-01",
101
+ end_date="2025-12-01",
102
+ product_type="GSLC",
103
+ path_number=77,
104
+ direction="ASCENDING",
105
+ )
106
+
107
+ # Download in parallel with automatic validation
108
+ fps = download_urls(urls, "local/gslcs/")
109
+ ```
110
+
111
+ ### Read a Single File
112
+
113
+ ```python
114
+ from nisar_pytools import open_nisar
115
+
116
+ dt = open_nisar("NISAR_L2_PR_GSLC_...h5")
117
+
118
+ # Access a frequency/polarization group
119
+ freq_a = dt["science/LSAR/GSLC/grids/frequencyA"].dataset
120
+ hh = freq_a["HH"] # lazy dask-backed DataArray with CRS set
121
+
122
+ # Coordinates and CRS are assigned automatically
123
+ print(hh.rio.crs) # e.g. EPSG:32611
124
+ ```
125
+
126
+ ### Stack GSLCs into a Time Series
127
+
128
+ ```python
129
+ from nisar_pytools import stack_gslcs
130
+
131
+ # Stack multiple same-track GSLCs into a (time, y, x) DataArray
132
+ stack = stack_gslcs(
133
+ ["gslc_date1.h5", "gslc_date2.h5", "gslc_date3.h5"],
134
+ frequency="frequencyA",
135
+ polarization="HH",
136
+ )
137
+ # Sorted by time, grid-validated, dask-backed, CRS assigned
138
+ ```
139
+
140
+ ### SAR Processing
141
+
142
+ ```python
143
+ from nisar_pytools.processing import (
144
+ interferogram, coherence, multilook, unwrap, calculate_phase
145
+ )
146
+
147
+ # Interferogram (validates matching grids)
148
+ ifg = interferogram(slc1, slc2)
149
+
150
+ # Multilooked interferogram
151
+ ml_ifg = multilook(ifg, looks_y=4, looks_x=4)
152
+
153
+ # Coherence estimation
154
+ coh = coherence(slc1, slc2, window_size=11)
155
+
156
+ # Phase unwrapping with SNAPHU
157
+ unw, conncomp = unwrap(ifg, coh, nlooks=20.0)
158
+ ```
159
+
160
+ ### Phase Linking
161
+
162
+ ```python
163
+ from nisar_pytools.processing import phase_link
164
+
165
+ # EMI phase linking on a GSLC stack
166
+ linked, temporal_coh = phase_link(stack, window_size=11, confidence=0.95)
167
+ ```
168
+
169
+ ### Polarimetric Decomposition
170
+
171
+ ```python
172
+ from nisar_pytools.processing import h_a_alpha
173
+
174
+ # H-A-alpha decomposition from quad-pol SLC channels
175
+ ds = h_a_alpha(hh, hv, vv)
176
+ # Returns Dataset with: entropy, anisotropy, alpha, mean_alpha
177
+ ```
178
+
179
+ ### Local Incidence Angle
180
+
181
+ ```python
182
+ from nisar_pytools.utils.local_incidence_angle import local_incidence_angle
183
+
184
+ lia = local_incidence_angle(dem, los_x, los_y, los_z, heights, x_rg, y_rg, epsg=32611)
185
+ ```
186
+
187
+ ## Roadmap
188
+
189
+ - [x] Lazy HDF5 reader returning xarray DataTree with CRS
190
+ - [x] GSLC and GUNW support
191
+ - [x] ASF search and parallel download with validation
192
+ - [x] GSLC time-series stacking
193
+ - [x] Interferogram, coherence, multilooking, phase extraction
194
+ - [x] Phase unwrapping (SNAPHU)
195
+ - [x] Phase linking (EMI with SHP selection)
196
+ - [x] Polarimetric decomposition (H-A-alpha)
197
+ - [x] Local incidence angle computation
198
+ - [x] Visualization helpers (amplitude, phase, interferogram, coherence)
199
+ - [ ] Support for additional NISAR product types
200
+
201
+ ## Contributing
202
+
203
+ Contributions are welcome! Please fork the repo and open a pull request, or open an issue to suggest improvements.
204
+
205
+ ## License
206
+
207
+ Distributed under the MIT License. See `LICENSE.txt` for more information.
@@ -0,0 +1,154 @@
1
+ # nisar_pytools
2
+
3
+ Open source Python tools for working with NISAR datasets.
4
+
5
+ ## About
6
+
7
+ `nisar_pytools` provides utilities for searching, downloading, reading, and processing data products from NASA's [NISAR](https://nisar.jpl.nasa.gov/) (NASA-ISRO Synthetic Aperture Radar) mission.
8
+
9
+ ### Supported Products
10
+
11
+ - **GSLC** - Geocoded Single Look Complex
12
+ - **GUNW** - Geocoded Unwrapped Interferogram
13
+
14
+ Additional NISAR product types will be added over time.
15
+
16
+ ## Getting Started
17
+
18
+ ### Prerequisites
19
+
20
+ - Python 3.10+
21
+ - [Miniforge](https://github.com/conda-forge/miniforge) (recommended)
22
+ - NASA Earthdata login (for downloading from ASF)
23
+
24
+ ### Installation
25
+
26
+ 1. Clone the repository
27
+ ```sh
28
+ git clone https://github.com/zmhoppinen/nisar_pytools.git
29
+ cd nisar_pytools
30
+ ```
31
+ 2. Create the conda environment
32
+ ```sh
33
+ mamba env create -f environment.yml
34
+ conda activate nisar_pytools
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Search and Download
40
+
41
+ ```python
42
+ from nisar_pytools import find_nisar, download_urls
43
+
44
+ # Search ASF for GSLC products over an area of interest
45
+ urls = find_nisar(
46
+ aoi=[-115, 43, -114, 44],
47
+ start_date="2025-06-01",
48
+ end_date="2025-12-01",
49
+ product_type="GSLC",
50
+ path_number=77,
51
+ direction="ASCENDING",
52
+ )
53
+
54
+ # Download in parallel with automatic validation
55
+ fps = download_urls(urls, "local/gslcs/")
56
+ ```
57
+
58
+ ### Read a Single File
59
+
60
+ ```python
61
+ from nisar_pytools import open_nisar
62
+
63
+ dt = open_nisar("NISAR_L2_PR_GSLC_...h5")
64
+
65
+ # Access a frequency/polarization group
66
+ freq_a = dt["science/LSAR/GSLC/grids/frequencyA"].dataset
67
+ hh = freq_a["HH"] # lazy dask-backed DataArray with CRS set
68
+
69
+ # Coordinates and CRS are assigned automatically
70
+ print(hh.rio.crs) # e.g. EPSG:32611
71
+ ```
72
+
73
+ ### Stack GSLCs into a Time Series
74
+
75
+ ```python
76
+ from nisar_pytools import stack_gslcs
77
+
78
+ # Stack multiple same-track GSLCs into a (time, y, x) DataArray
79
+ stack = stack_gslcs(
80
+ ["gslc_date1.h5", "gslc_date2.h5", "gslc_date3.h5"],
81
+ frequency="frequencyA",
82
+ polarization="HH",
83
+ )
84
+ # Sorted by time, grid-validated, dask-backed, CRS assigned
85
+ ```
86
+
87
+ ### SAR Processing
88
+
89
+ ```python
90
+ from nisar_pytools.processing import (
91
+ interferogram, coherence, multilook, unwrap, calculate_phase
92
+ )
93
+
94
+ # Interferogram (validates matching grids)
95
+ ifg = interferogram(slc1, slc2)
96
+
97
+ # Multilooked interferogram
98
+ ml_ifg = multilook(ifg, looks_y=4, looks_x=4)
99
+
100
+ # Coherence estimation
101
+ coh = coherence(slc1, slc2, window_size=11)
102
+
103
+ # Phase unwrapping with SNAPHU
104
+ unw, conncomp = unwrap(ifg, coh, nlooks=20.0)
105
+ ```
106
+
107
+ ### Phase Linking
108
+
109
+ ```python
110
+ from nisar_pytools.processing import phase_link
111
+
112
+ # EMI phase linking on a GSLC stack
113
+ linked, temporal_coh = phase_link(stack, window_size=11, confidence=0.95)
114
+ ```
115
+
116
+ ### Polarimetric Decomposition
117
+
118
+ ```python
119
+ from nisar_pytools.processing import h_a_alpha
120
+
121
+ # H-A-alpha decomposition from quad-pol SLC channels
122
+ ds = h_a_alpha(hh, hv, vv)
123
+ # Returns Dataset with: entropy, anisotropy, alpha, mean_alpha
124
+ ```
125
+
126
+ ### Local Incidence Angle
127
+
128
+ ```python
129
+ from nisar_pytools.utils.local_incidence_angle import local_incidence_angle
130
+
131
+ lia = local_incidence_angle(dem, los_x, los_y, los_z, heights, x_rg, y_rg, epsg=32611)
132
+ ```
133
+
134
+ ## Roadmap
135
+
136
+ - [x] Lazy HDF5 reader returning xarray DataTree with CRS
137
+ - [x] GSLC and GUNW support
138
+ - [x] ASF search and parallel download with validation
139
+ - [x] GSLC time-series stacking
140
+ - [x] Interferogram, coherence, multilooking, phase extraction
141
+ - [x] Phase unwrapping (SNAPHU)
142
+ - [x] Phase linking (EMI with SHP selection)
143
+ - [x] Polarimetric decomposition (H-A-alpha)
144
+ - [x] Local incidence angle computation
145
+ - [x] Visualization helpers (amplitude, phase, interferogram, coherence)
146
+ - [ ] Support for additional NISAR product types
147
+
148
+ ## Contributing
149
+
150
+ Contributions are welcome! Please fork the repo and open a pull request, or open an issue to suggest improvements.
151
+
152
+ ## License
153
+
154
+ Distributed under the MIT License. See `LICENSE.txt` for more information.
@@ -0,0 +1,31 @@
1
+ name: nisar_pytools
2
+ channels:
3
+ - conda-forge
4
+ - defaults
5
+ dependencies:
6
+ - python>=3.10
7
+ - asf_search>=7.0
8
+ - dask>=2024.0
9
+ - h5py>=3.10
10
+ - numpy>=1.24
11
+ - rasterio>=1.3
12
+ - pyproj>=3.4
13
+ - requests
14
+ - rioxarray>=0.15
15
+ - shapely>=2.0
16
+ - scipy>=1.10
17
+ - snaphu>=0.3
18
+ - xarray>=2024.10
19
+ - zarr
20
+ - h5netcdf
21
+ - build
22
+ - nbstripout
23
+ - pre-commit
24
+ - pytest
25
+ - ruff
26
+ - twine
27
+ - jupyter
28
+ - matplotlib
29
+ - pip
30
+ - pip:
31
+ - -e .
File without changes