Harvest a regional, time-windowed subset from eleven /spray observation archives — SWOT, RADS, AVISO L4, Argo, drifters, gliders, ICESat-2, in-situ wind, PACE, SNPP SST, and GOES ABI SST — into one HDF5 file (netCDF4 with nested groups; readable by both xarray(group=…) and h5py). Unlike the multi-altimeter OI driver — which flattens every source to scattered points — this tool preserves each source's native data structure.

Console script: odsl-super-subsetter (super_subsetter/subset.py).

Installation & dependencies

Ships with the odsl distribution. Core deps (numpy, pandas, xarray, netCDF4, scipy, pyproj, …) are always installed:

python -m pip install -e "."        # or ".[all]"

Layout

Module Purpose
subset.py CLI / main() for odsl-super-subsetter: orchestrates the run and writes the HDF5 + summary.
utils.py Native-structure subset core: AVISO L4 grid, SWOT swath slabs, RADS along-track profiles, and the subset_observations orchestrator.
sources.py Per-source native-structure subsetters for the non-altimetry archives (argo, drifter, glider, icesat2, wind, pace, snpp, geos).
vars_config.py Variable-selection catalogs, template writer, and +/- markdown parser.

Usage

odsl-super-subsetter \
    --start 2023-03-25 --end 2023-03-31 \
    --bbox -70 30 -50 45 \
    --sources rads aviso argo drifter glider \
    --out tmp/subset.h5

Output layout (one group per source, sub-group per platform/pass/granule):

subset.h5
├─ /swot/cycle###_pass###      native 2-D swath (num_lines × num_pixels)
├─ /rads/<mission>_c###_p####  along-track profile (obs)
├─ /aviso_l4                   gridded L4 map (time × latitude × longitude)
├─ /argo/<dac>_<wmo>           profile stack (N_PROF × N_LEVELS)
├─ /drifter/<id>               trajectory (obs)
├─ /glider/<deployment>        trajectory (row)
├─ /icesat2/<granule>          along-track segments (obs, all beams stacked)
├─ /wind/<family>_<station>    station time series (obs)
├─ /pace/<granule>             native 2-D swath (number_of_lines × pixels_per_line)
├─ /snpp/viirs_<stamp>         native 2-D L2P swath (nj × ni)
└─ /geos/goes_<stamp>          native 2-D GOES ABI L2P swath (nj × ni)

Variable selection — which variables each product contributes is controlled by an editable markdown config with +/- markers:

# 1. write the per-product variable lists (inspecting one sample file per archive)
odsl-super-subsetter --init-vars-config subset_variables.md
# 2. edit the +/- markers, then run with it
odsl-super-subsetter --vars-config subset_variables.md --start … --bbox … --sources …

Without a config, built-in essentials-with-uncertainties defaults apply (e.g. SWOT ssha_karin+ssha_karin_2 with _qual flags and ssh_karin_uncert; Argo PRES/TEMP/PSAL with _ADJUSTED/_ADJUSTED_ERROR/_QC; SNPP SST with sses_bias/sses_standard_deviation). Per-product --<product>-vars flags override both. Coordinates/time/positions are always kept.

Behavior notes

  • Swath sources (SWOT / PACE / SNPP / GOES) keep the full cross-track width; only the along-track extent is clipped to the bbox (SWOT by the monotonic nadir-latitude band; PACE/SNPP/GOES by the rows whose swath touches the bbox). Slabs therefore extend a little past the bbox on purpose — the original swath geometry is retained.
  • SWOT SSHA is stored corrected: ssha_karin and ssha_karin_2 each have height_cor_xover + internal_tide_hret added back (group attrs record it; disable with --no-swot-xover / --no-swot-internal-tide).
  • Search reuses the colocation indices (argo profile index, drifter/glider footprints, ICESat-2/PACE/SNPP/GOES granule footprints, RADS pass-index CSV, AVISO L4 daily-map parquet, wind station footprints — see odsl-colocate-refresh); PACE falls back to a date-tree scan when the footprint index doesn't cover the window. ICESat-2 reads the analysis-ready polar-segments parquet.
  • Sources with no data in the window are logged and skipped, never fatal (the archives don't fully overlap: AVISO L4 is early 2023, SWOT science data begins 2023-07-26, SNPP is May–Jul 2023, PACE begins 2024; NDBC wind rows carry no positions and are skipped with a warning).
  • --max-files N caps each source at N produced groups (not files inspected).
  • A markdown data summary is written next to the HDF5 file (<out>.summary.md): run parameters, the AVISO per-variable table, and one table per source (group, shape, time span, lon/lat coverage, NaN-safe stats of a representative variable). Override with --summary PATH, disable with --no-summary.

Useful flags: --sources {swot,rads,aviso,argo,drifter,glider,icesat2,wind,pace,snpp,geos,all}, --rads-missions j2 j3 3a, --icesat2-products ATL07 ATL10, --pace-products bgc iop, --allow-land, --max-sea-ice-conc, --no-swot-nadir-prefilter, per-source roots (--drifter-root, --snpp-root, --geos-root, …). Longitudes accept -180..180 or 0..360 and are preserved as -180..180 on output when the bbox is given that way. A single SWOT granule can set the window via --swot-file <name> --delta-t-days 2 instead of --start/--end.

Tests

pytest super_subsetter/tests
  • ../multi_altimeters — multi-altimeter OI mapping & point-vortex SSH; shares multi_altimeters/utils.py (BBox, longitude/bbox helpers, the SWOT/RADS search index used for broad-phase discovery).
  • ../swot — SWOT L2 LR SSH Expert loading (swot/utils.py).
  • ../rads — RADS nadir altimetry loading and indexing (rads/utils.py).
  • ../common/DATA_PATHS.md — per-dataset /spray layout (globs, var names, lon conventions, coverage).
  • ../README.md — repo-wide conventions (CLI structure, bbox/longitude, data roots, extras).