Skip to content

Commit 9c7a869

Browse files
authored
Merge pull request #53 from mirzaees/stream_xarray
Stream xarray
2 parents e639749 + 0778e8a commit 9c7a869

15 files changed

Lines changed: 2208 additions & 98 deletions

conda-env.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ channels:
33
- conda-forge
44
- nodefaults
55
dependencies:
6-
- python>=3.9,<3.12
6+
- python>=3.9
77
- pip>=21.3 # https://pip.pypa.io/en/stable/reference/build-system/pyproject-toml/#editable-installation
88
- git # for pip install, due to setuptools_scm
99
- click>=7.0
@@ -20,6 +20,9 @@ dependencies:
2020
- pysolid # For solid earth tide corrections
2121
# - pyaps3
2222
- xarray
23+
- earthaccess # For streaming remote GSLC files
24+
- dask # For parallel processing with chunking
25+
- distributed # For dask multi-worker parallelism
2326
# Unwrappers:
2427
- snaphu>=0.4.1
2528
- isce3-cpu>=0.16.0 # For baseline

src/disp_nisar/_baselines.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import h5py
21
import isce3
32
import numpy as np
43
from dolphin import baseline
@@ -9,10 +8,12 @@
98
)
109
from pyproj import CRS, Transformer
1110

11+
from ._streaming import open_h5_file
12+
1213

1314
def _get_look_side(h5file: Filename) -> isce3.core.LookSide:
1415
"""Get the look side from a NISAR GSLC HDF5 file."""
15-
with h5py.File(h5file, "r") as hf:
16+
with open_h5_file(h5file, "r") as hf:
1617
# Try NISAR path first
1718
for path in [
1819
"/science/LSAR/identification/lookDirection",

src/disp_nisar/_gdal_remote.py

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
"""Utilities for GDAL to access remote files via virtual file system."""
2+
3+
from __future__ import annotations
4+
5+
import logging
6+
from pathlib import Path
7+
from urllib.parse import urlparse
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
def to_gdal_path(file_path: str | Path) -> str:
13+
"""Convert a file path to GDAL-compatible format, handling remote URLs.
14+
15+
GDAL can access remote files using virtual file systems:
16+
- /vsicurl/ for HTTP(S) URLs
17+
- /vsis3/ for S3 URLs (requires AWS credentials)
18+
19+
Parameters
20+
----------
21+
file_path : str | Path
22+
File path (local or remote URL).
23+
24+
Returns
25+
-------
26+
str
27+
GDAL-compatible path string.
28+
29+
Examples
30+
--------
31+
>>> to_gdal_path("/local/path/file.h5")
32+
'/local/path/file.h5'
33+
>>> to_gdal_path("https://example.com/file.h5")
34+
'/vsicurl/https://example.com/file.h5'
35+
>>> to_gdal_path("s3://bucket/path/file.h5")
36+
'/vsis3/bucket/path/file.h5'
37+
38+
"""
39+
path_str = str(file_path)
40+
parsed = urlparse(path_str)
41+
42+
if parsed.scheme == "":
43+
# Local file
44+
return path_str
45+
46+
elif parsed.scheme in ("http", "https"):
47+
# HTTP(S) URL - use /vsicurl/
48+
return f"/vsicurl/{path_str}"
49+
50+
elif parsed.scheme == "s3":
51+
# S3 URL - use /vsis3/
52+
# Convert s3://bucket/path to /vsis3/bucket/path
53+
s3_path = f"{parsed.netloc}{parsed.path}"
54+
return f"/vsis3/{s3_path}"
55+
56+
else:
57+
# Unknown scheme, return as-is
58+
logger.warning(f"Unknown URL scheme '{parsed.scheme}' for {path_str}")
59+
return path_str
60+
61+
62+
def to_gdal_netcdf_path(file_path: str | Path, dataset: str) -> str:
63+
"""Convert file path and dataset to GDAL NETCDF format.
64+
65+
Parameters
66+
----------
67+
file_path : str | Path
68+
HDF5/NetCDF file path (local or remote).
69+
dataset : str
70+
Dataset path within the file.
71+
72+
Returns
73+
-------
74+
str
75+
GDAL NETCDF path: "NETCDF:file:dataset"
76+
77+
Examples
78+
--------
79+
>>> to_gdal_netcdf_path("/local/file.h5", "/data/HH")
80+
'NETCDF:/local/file.h5:/data/HH'
81+
>>> to_gdal_netcdf_path("https://example.com/file.h5", "/data/HH")
82+
'NETCDF:/vsicurl/https://example.com/file.h5:/data/HH'
83+
>>> to_gdal_netcdf_path("s3://bucket/file.h5", "/data/HH")
84+
'NETCDF:/vsis3/bucket/file.h5:/data/HH'
85+
86+
"""
87+
gdal_path = to_gdal_path(file_path)
88+
return f"NETCDF:{gdal_path}:{dataset}"
89+
90+
91+
def configure_gdal_for_remote(
92+
max_retry: int = 3,
93+
timeout: int = 60,
94+
chunk_size: int = 4 * 1024 * 1024,
95+
) -> None:
96+
"""Configure GDAL for optimal remote file access.
97+
98+
Parameters
99+
----------
100+
max_retry : int, optional
101+
Maximum number of retries for failed requests, by default 3.
102+
timeout : int, optional
103+
Timeout in seconds for HTTP requests, by default 60.
104+
chunk_size : int, optional
105+
Chunk size for HTTP range requests in bytes, by default 4MB.
106+
107+
"""
108+
from osgeo import gdal
109+
110+
# Enable GDAL exceptions
111+
gdal.UseExceptions()
112+
113+
# Configure HTTP/HTTPS access
114+
gdal.SetConfigOption("GDAL_HTTP_MAX_RETRY", str(max_retry))
115+
gdal.SetConfigOption("GDAL_HTTP_RETRY_DELAY", "1")
116+
gdal.SetConfigOption("CPL_VSIL_CURL_ALLOWED_EXTENSIONS", ".h5,.hdf5,.nc,.tif")
117+
gdal.SetConfigOption("GDAL_HTTP_TIMEOUT", str(timeout))
118+
119+
# Enable caching
120+
gdal.SetConfigOption("VSI_CACHE", "YES")
121+
gdal.SetConfigOption("VSI_CACHE_SIZE", str(chunk_size))
122+
123+
# For S3 access (requires AWS credentials in environment)
124+
# Set these if you have AWS credentials:
125+
# gdal.SetConfigOption("AWS_NO_SIGN_REQUEST", "YES") # For public buckets
126+
# Or configure credentials via AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY
127+
128+
logger.info("GDAL configured for remote file access")
129+
logger.debug(f" Max retry: {max_retry}")
130+
logger.debug(f" Timeout: {timeout}s")
131+
logger.debug(f" Chunk size: {chunk_size / 1024 / 1024:.1f} MB")

0 commit comments

Comments
 (0)