Cross-cutting helpers reused by the instrument/source subpackages (swot,
snpp, geos, pace, rads, drifter, glider, …). The goal is that each
source package stays thin: swath→grid regridding, NASA Earthdata/CMR plumbing,
GHRSST flag decoding, atomic downloads, and quick-look plotting all live here
once instead of being copy-pasted per package.
Layout
| Module | Purpose |
|---|---|
common.bbox |
Dateline-safe BBox / parse_bbox (west south east north); re-exported from swot/pace/rads/multi_altimeters |
common.footprints |
Shared SST/L4 footprint parquet schema, dateline-safe overlap, incremental SST scan, atomic parquet write |
common.swath_regrid |
Level-2 swath → regular grid resampling on pyresample (lat/lon or regional cartesian; nearest/bilinear/gaussian/kriging) |
common.earthdata |
NASA Earthdata / CMR query + granule-naming helpers (temporal normalization, antimeridian bbox split, filename/date parsing) |
common.flags |
GHRSST l2p_flags / flag_meanings decoding helpers |
common.dataset |
xarray dataset helpers (encoding cleanup) |
common.sync |
shared download/sync engine: download_to_path (streaming, resume, size/checksum verify, atomic replace), earthaccess_worker, run_sync (serial/--jobs parallel, tqdm, summary), with_retries |
common.download |
atomic, idempotent file writes for plain-HTTP downloaders |
common.field_ops |
small numpy field helpers (FFT multiplier, finite differences, NaN handling) for spectral processing |
common.plotting |
matplotlib quick-look map helpers (lazy cartopy) |
common.log |
timestamped stderr logger |
common.cli |
common_sync_parser (shared download flags) and argparse value helpers |
The folder also holds DATA_PATHS.md — the reference map
of every dataset root on /spray (directory layouts, file globs, sample paths,
SSHA/SST variable names, longitude conventions, coverage windows). Consult it
before touching a /spray path or writing a new reader.
Import convention
common is installed as a bare top-level package (and mirrored as
odsl_code.common). Import shared code with the bare path:
from common.log import log
from common.earthdata import normalize_cmr_time, split_antimeridian_bbox
Scripts that may be run directly (e.g. python snpp/snpp_viirs_sst.py)
rather than via an installed console entry point add a small bootstrap so the
repo root is importable before the common imports:
import sys
from pathlib import Path
SCRIPT_DIR = Path(__file__).resolve().parent
PROJECT_DIR = SCRIPT_DIR.parent
if str(PROJECT_DIR) not in sys.path:
sys.path.insert(0, str(PROJECT_DIR))
from common.log import log # noqa: E402
Note:
from common.log import logno longer importspyresample.from common import regrid_datasetstill works via a lazy__getattr__.
common.footprints
Lookup-table helpers for colocate and the super-subsetter. Builders write a parquet once; providers query it by time and dateline-safe bbox so a query never walks every granule.
| Name | Purpose |
|---|---|
FOOTPRINT_COLUMNS |
path, t0, t1, lon_min, lon_max, lat_min, lat_max |
lon_overlap / bbox_overlaps |
Dateline-safe overlap. A stored lon_min=-180, lon_max=180 is a 360° span (wrapping both ends to 180° would look like a zero-length arc). |
build_sst_footprint_index |
Incremental scan of processed SNPP/GOES granules (mtime sidecar; --rebuild forces a full scan). |
write_footprint_index |
Atomic parquet write. |
SST and AVISO builders (odsl-snpp-footprints, odsl-geos-footprints,
odsl-aviso-index) call this module. See ../colocate.
common.swath_regrid
Maps Level-2 swath variables onto regular grids using pyresample geometry and
resampling routines.
Supported target grids:
| Grid | Builder | Notes |
|---|---|---|
| Lat/lon | build_latlon_grid |
Regular degree grid over a bbox |
| Regional cartesian | build_cartesian_grid |
Uniform x/y spacing in meters, default local azimuthal equidistant projection |
Supported interpolation methods:
| Method | Backend | Main parameters |
|---|---|---|
linear / bilinear |
pyresample.bilinear.resample_bilinear |
radius_of_influence, neighbours, epsilon |
gaussian |
pyresample.kd_tree.resample_gauss |
radius_of_influence, gaussian_sigma or smoothing_radius, neighbours |
nearest |
pyresample.kd_tree.resample_nearest |
radius_of_influence, epsilon |
kriging |
optional pykrige.ok.OrdinaryKriging |
kriging_variogram_model, kriging_variogram_parameters, kriging_n_closest_points |
Public API (re-exported from common/__init__.py): RegridConfig,
TargetGrid, build_cartesian_grid, build_latlon_grid, load_target_grid,
regrid_dataarray, regrid_dataset, regrid_swath, save_target_grid,
target_grid_to_dataset.
Install optional dependencies:
pip install pyresample
pip install pykrige # only needed for method="kriging"
Examples
Regular lat/lon grid:
import xarray as xr
from common.swath_regrid import RegridConfig, build_latlon_grid, regrid_dataset
ds = xr.open_dataset("level2_swath.nc")
grid = build_latlon_grid(
bbox=(-98, 18, -80, 31),
resolution_deg=0.02,
)
mapped = regrid_dataset(
ds,
variables=["sst_celsius"],
target_grid=grid,
lon_name="lon",
lat_name="lat",
config=RegridConfig(
method="gaussian",
radius_of_influence=15_000,
smoothing_radius=7_500,
neighbours=8,
),
)
mapped.to_netcdf("sst_gulf_latlon.nc")
Regional cartesian grid with 2 km cells:
from common.swath_regrid import build_cartesian_grid, regrid_dataarray
grid = build_cartesian_grid(
bbox=(-98, 18, -80, 31),
resolution_m=2_000,
)
sst = regrid_dataarray(
ds["sst_celsius"],
target_grid=grid,
lon=ds["lon"],
lat=ds["lat"],
method="linear",
radius_of_influence=8_000,
neighbours=32,
)
sst.to_netcdf("sst_gulf_2km.nc")
Kriging:
mapped = regrid_dataarray(
ds["sst_celsius"],
target_grid=grid,
lon=ds["lon"],
lat=ds["lat"],
config=RegridConfig(
method="kriging",
radius_of_influence=25_000,
kriging_variogram_model="spherical",
kriging_variogram_parameters={"sill": 1.0, "range": 20_000, "nugget": 0.05},
kriging_n_closest_points=32,
kriging_max_points=10_000,
),
)
pyresample expects longitude inputs in the [-180, 180) range. The helper
wraps longitudes automatically before building source swath definitions.
common.earthdata
NASA Earthdata / CMR query and granule-naming helpers, free of instrument logic
so every earthaccess-based source package can reuse them.
| Function | Description |
|---|---|
normalize_cmr_time(value, *, is_end=False) |
Normalize a str/date/datetime into a CMR temporal-query string; is_end fills the day's end edge |
split_antimeridian_bbox(bbox) |
Split a west south east north bbox that crosses the antimeridian into two CMR-safe bboxes |
filename_from_url(url) |
Strip query string and path, returning the bare filename |
date_parts(date_token) |
"YYYYMMDD" → ("YYYY", "MM", "DD") (or "unknown" triples) |
safe_token(value) |
Sanitize a string for use in a filename/path |
existing_netcdf_files(root) |
Index existing *.nc files under a root by basename (for idempotent skips) |
from common.earthdata import normalize_cmr_time, split_antimeridian_bbox
start = normalize_cmr_time("2025-01-01") # 2025-01-01T00:00:00Z
end = normalize_cmr_time("2025-01-31", is_end=True) # 2025-01-31T23:59:59Z
boxes = split_antimeridian_bbox((170, 10, -170, 20)) # two [-180,180) bboxes
common.flags
Helpers for decoding GHRSST l2p_flags and related flag metadata (used by the
SST processors to derive day/night and quality fields).
| Function | Description |
|---|---|
_as_list(value) |
Coerce a CF flag_meanings/flag_values attribute (str, bytes, scalar, iterable) into a list |
_normalize_flag_name(value) |
Lowercase/strip a flag name and normalize -→_ |
common.dataset
| Function | Description |
|---|---|
clear_encodings(ds) |
Clear per-variable .encoding so decoded data can be re-written without stale scale_factor/_FillValue conflicts |
common.sync
The shared download/sync engine every provider downloader builds on. Discovery
stays provider-specific; the engine unifies transfer, idempotency, verification,
retry, parallelism and dry-run. Work items are RemoteFile(url, dest, size?,
checksum?).
| Function | Description |
|---|---|
download_to_path(remote, opener, *, overwrite, verify, resume, dry_run, …) |
Stream a URL to .<name>.part then atomically replace dest; skip/verify existing files by size or checksum; HTTP range resume; the prior file is never lost on failure. Returns a SyncResult. |
earthaccess_worker(remote, *, provider, overwrite, verify, dry_run, …) |
Same skip/verify/summary contract for granules fetched via earthaccess.download (transferred into a temp dir, verified, atomically moved). |
run_sync(items, worker, *, jobs, …) |
Run a worker over every item serially or across jobs threads with a tqdm bar; returns a SyncSummary (per-status counts, exit_code). |
with_retries(worker, *, attempts, …) |
Retry a worker with exponential backoff on FAILED. |
RequestsOpener / UrllibOpener |
Byte openers over requests / stdlib for the plain-HTTP and HEAD-verify paths. |
Shared CLI flags come from common.cli.common_sync_parser (--overwrite,
--dry-run, --jobs, --verify {none,size,checksum}, --retries, --limit,
…) as an argparse parent, with per-provider aliases (--out-root/--out,
--max-granules/--max-files, --overwrite-downloads, --verify-downloads).
common.download
Atomic, idempotent whole-file byte writes (not URL fetches) — used for the catalog/manifest side-files of the plain-HTTP downloaders.
| Function | Description |
|---|---|
write_bytes_safely(data, out_file, overwrite) |
Write bytes to a .part temp file then atomically rename; returns "exists" / "downloaded"; backs up any pre-existing file when overwrite=True |
common.field_ops
Small, data-source-agnostic numpy helpers for spectral field processing (used by the SWOT eddy/wave geometric-separation scripts).
| Function | Description |
|---|---|
k_from_lambda_km(dx_m, lambda_km) |
Nondimensional wavenumber for a wavelength given grid spacing |
apply_fft_multiplier(u, mult) |
Apply a spectral multiplier: ifft2(mult * fft2(u)).real |
grad_forward(u) |
Forward-difference gradient (gx, gy) |
finite_mask(x) |
1.0 where finite else 0.0 |
replace_nans(x, value) |
Copy of x with non-finite entries set to value |
common.plotting
| Function | Description |
|---|---|
add_map_context(ax, bbox_values) |
Add coastlines/land/borders/gridlines to an axis over a west south east north bbox; lazily imports cartopy and degrades to a plain lon/lat axis if it (the plot extra) is unavailable |
common.log / common.cli
| Function | Description |
|---|---|
log(message) |
Print "[<UTC ISO8601>] message" to stderr (flushed) |
parse_variables(value) |
Parse a comma-separated CLI string into a list, or None |
common_sync_parser(...) |
Argparse parent with --overwrite, --dry-run, --jobs, --verify, --retries, --limit |
Related
../README.md— repo-wide conventions (bounding boxes, Earthdata credentials, idempotent downloads, SST processing rules).- Consumers:
../snpp,../geos,../swot,../pace,../drifter,../glider,../icesat2,../colocate,../aviso.