Skip to main content

aihydro-lsh

Global large-sample hydrology — CAMELS-like catchment attributes for globally routed watersheds, with source-specific caveats.

A recipe layer over aihydro-data and aihydro-watershed that computes 101 static scalar attributes (8 families) plus daily meteorological forcing timeseries and temporal-tier extensions (trends, annual dynamics, drought/flood events) for basin geometries through region-aware product routing. The camels-attrs CONUS reference implementation is used to validate recipes against USGS gauge data; use aihydro_lsh.reliability.reliability_matrix() for the family/region caveats that qualify global interpretation.

Quick start

import geopandas as gpd
from shapely.geometry import box
import aihydro_lsh

# Any watershed polygon (EPSG:4326)
geom = gpd.GeoDataFrame(geometry=[box(-79.5, 38.5, -77.5, 39.5)], crs="EPSG:4326")
result = aihydro_lsh.attributes(geom, "1990-01-01", "2020-12-31")

print(result.attrs["p_mean"])          # mean daily precip (mm/day)
print(result.attrs["elev_mean"])       # mean elevation (m)
print(result.attrs["geol_porosity"])   # GLHYMPS porosity
df = result.to_dataframe()             # single-row DataFrame, 101 columns

# Full provenance report (agent-relay verbatim — package is the authority)
print(result.to_report())

# Fully JSON-serializable dict (NaN → null)
d = result.to_json()
print(d["meta"]["content_hash"])       # SHA-256 fingerprint of attrs

# USGS gauge — auto-delineate then extract (outlet coords wired automatically)
from aihydro_watershed.delineation.router import delineate_from_point
ws = delineate_from_point(39.27, -77.54)          # Potomac Point of Rocks
result = aihydro_lsh.attributes(ws, "1990-01-01", "2020-12-31",
                                 gauge_id="01638500")
# ws is a HydroResult — outlet_lat/outlet_lon extracted automatically for geomorphic attrs

# Daily forcing timeseries (for ML workflows — LSTM, HBV training)
df = aihydro_lsh.forcing(geom, "1990-01-01", "2020-12-31")
print(df.columns.tolist())
# ['prcp_mm', 'tmin_C', 'tmax_C', 'tavg_C', 'pet_mm', 'srad_Wm2', 'wind_ms', 'sph_kgkg']

# Combined: scalar attrs + daily forcing in one call
result = aihydro_lsh.attributes(geom, "1990-01-01", "2020-12-31", include_forcing=True)
print(result.forcing)          # pd.DataFrame with DatetimeIndex

# Temporal extensions: Mann-Kendall trend scalars (T2.5)
result = aihydro_lsh.attributes(geom, "1990-01-01", "2020-12-31", include_trends=True)
print(result.trends)           # pd.DataFrame — 16 slope/p-value scalars

# Temporal extensions: annual dynamic panels (T3)
result = aihydro_lsh.attributes(geom, "1990-01-01", "2020-12-31", include_dynamic=True)
print(result.dynamic)          # pd.DataFrame (year × 22 variables)

# Temporal extensions: drought and flood event inventory (T3)
result = aihydro_lsh.attributes(geom, "1990-01-01", "2020-12-31", include_events=True)
print(result.events["drought"])    # DataFrame of SPI-drought episodes
print(result.events["flood"])      # DataFrame of POT-flood exceedances

# Everything at once
result = aihydro_lsh.attributes(
    geom, "1990-01-01", "2020-12-31",
    include_forcing=True,
    include_trends=True,
    include_dynamic=True,
    include_events=True,
)

# Batch extraction (list of pour-points → single DataFrame)
df, errors = aihydro_lsh.batch_attributes(
    [{"id": "01638500", "lat": 39.27, "lon": -77.54},
     {"id": "02108000", "lat": 35.53, "lon": -79.09}],
    start="1990-01-01", end="2020-12-31",
)
df.to_csv("camels_global.csv", index=False)

Installation

pip install -e .                         # editable (ecosystem tree)
pip install -e .[validate]               # + camels-attrs CONUS reference
pip install -e .[mcp]                    # + MCP server tools

Attribute families (101 static scalars, 8 families + 1 timeseries family)

Family Attrs Data source Notes
watershed 5 GDF geometry area, perimeter, compactness, elongation, form_factor
topography 7 GLO30 / DEM3DEP / SRTM elev stats, slope stats, area
climate 14 GRIDMET / ERA5-Land / CHIRPS aridity, seasonality, snow frac, high/low precip stats
soil 9 POLARIS / SoilGrids texture, Ksat; porosity/AWC/FC from Saxton-Rawls PTF
geomorphic 28 3DEP/GLO30 + NLCD/ESA WorldCover shape, relief, stream network, CN, sinks, land cover %
vegetation 13 MODIS LAI/NDVI + ESA WorldCover LAI/GVF seasonal stats, LC fractions, root depth
geology 9 pygeoglim (GLiM + GLHYMPS) lithology classes, carbonate frac, permeability, porosity; global path is permission/tile-gated
hydrology 17 NWIS (CONUS) / GEOGLOWS (global) q_mean, BFI, FDC slope, half-flow date, …
forcing timeseries GRIDMET (CONUS) / ERA5-Land (global) Daily: prcp_mm, tmin_C, tmax_C, tavg_C, pet_mm [+ srad, wind, sph]

geomorphic runs after soil so clay_frac is available for NRCS Curve Number soil group estimation. forcing is opt-in (not in the default RECIPE_ORDER) — request via include_forcing=True or families=["forcing"].

Temporal-tier extensions

The static families above are T1 (permanent) and T2 (window-mean over the caller's date range). Three optional tiers extend the attribute landscape:

Tier Flag Output Description
T2.5 — Trends include_trends=True result.trends — up to 16 slope/p-value scalars Mann–Kendall p-value and Sen slope for eight derived series: precipitation mean, temperature mean, PET mean, snow fraction, LAI maximum, GVF mean, discharge mean and runoff ratio. At least ten valid annual values are required. P-values do not yet adjust for serial dependence or multiple comparisons.
T3 — Dynamic include_dynamic=True result.dynamic — year × 22-column schema Annual climate, vegetation and streamflow summaries. Three annual land-cover columns are currently unavailable and filled with NaN. Other columns can also be missing by source/year; this is a schema, not 22 measured values in every year. Annual q5 is high flow (5% exceedance) and q95 is low flow.
T3 — Events include_events=True result.events["drought"] + result.events["flood"] SPI-based drought episodes (McKee et al. 1993) and peaks-over-threshold flood exceedances (Coles 2001). Each row is a discrete event with start/end date, duration, severity/magnitude.

The temporal extensions are opt-in so standard attributes() calls remain fast. All three can be combined with include_forcing=True in a single call.

Geometry input forms

attributes() accepts any of:

  • HydroResult from delineate_from_point() / delineate_watershed() — outlet coords auto-wired
  • GeoDataFrame (EPSG:4326, single or multi-row)
  • Shapely Polygon / MultiPolygon
  • (lat, lon) tuple — wrapped as 0.001° buffer (use full delineation for accurate basin-mean attrs)
  • (minx, miny, maxx, maxy) bbox tuple

Provenance + reproducibility

Every AttributeResult carries:

  • .provenance — per-family AttrProvenance (source, product, region, resolution_m, is_observed)
  • .meta — ResultMeta with package versions, bbox, timing, and a SHA-256 content hash
  • .to_report() — human-readable report; agents relay this verbatim (package is the authority)
  • .to_json() — fully JSON-serializable dict (NaN → null)

The is_observed flag distinguishes gauge data (NWIS, is_observed=True) from modelled or reanalysis products (GEOGLOWS, ERA5-Land, is_observed=False) — critical for uncertainty-aware interpretation by agents. For hydrology specifically, gauge-less/global streamflow signatures carry quality_flags including modelled_streamflow; AttributeResult.to_report() emits a mandatory MODELLED STREAMFLOW CAVEAT so BFI/FDC/flood-frequency/timing metrics are not mistaken for observed catchment properties.

Layering

aihydro-core  ←  aihydro-data  ←  aihydro-lsh
                  aihydro-watershed ↗

aihydro-lsh may depend DOWN on core/data/watershed, never UP on aihydro-tools. Enforced by the AST guard in tests/test_layering.py and import-linter.

MCP tools (C5)

When aihydro-lsh[mcp] is installed alongside aihydro-tools, ten tools are auto-registered on the shared server:

Tool Description
lsh_attributes All 101 static scalar attrs for a polygon or pour-point
lsh_forcing Daily basin-averaged meteorological timeseries (LSTM/HBV)
lsh_dynamic_attributes Annual dynamic panels (T3) — year × 22 variables
lsh_events Drought (SPI) and flood (POT) event inventories (T3)
lsh_families List families + attribute keys
lsh_attribute_info Unit, source, family, formula, CAMELS equivalent, and caveat for one attribute
lsh_batch Multi-basin extraction from JSON array
lsh_compare_to_ref lsh vs camels-attrs side-by-side (CONUS)
lsh_recipe_status Check which recipes can run (auth/deps)
lsh_reliability_matrix Family/region availability status and interpretation caveats

For comparative studies, keep product chains explicit. The helper aihydro_lsh.batch.summarize_product_homogeneity(results) reports whether each attribute family used one product across a result set or mixed products such as CHIRPS and ERA5-Land. Mixed products are valid but should be reported as a source of uncertainty rather than interpreted as purely hydrologic contrast.

Reliability matrix

aihydro_lsh.reliability.reliability_matrix() returns a code-readable status for each attribute family by region (reliable, available_with_caveats, or not_available). It is intentionally static and import-light: it does not prove live network/data availability, but it prevents binary “global” claims from dropping caveats such as modelled streamflow, product-switching uncertainty, and permission/tile availability for geology. Geology provenance includes global_tiles_status=... from pygeoglim.global_tiles_status() where available.

CONUS parity validation (C3)

# CI gate — offline, reads the pre-generated fixture, no network required
pytest tests/test_conus_parity.py -k Offline --tb=short

# Regenerate the fixture (network + GEE + pygeoglim HF token required;
# several minutes per gauge)
python scripts/gen_conus_parity_fixture.py

# Live spot-check against a fresh live run instead of the cached fixture
pytest tests/test_conus_parity.py -m live --tb=short

The parity suite is parameterized by tests/fixtures/conus_parity_panel.json — inspect that file for the current basin panel and how each gauge was selected (stratified by aridity x snow fraction x relief using pygeohydro.get_camels()'s real 671-station CAMELS metadata). It checks:

  • Topography: ±10 % of camels-attrs reference
  • Climate: ±10 %
  • Geomorphic: shape ratios within geodesic tolerance
  • Geology: ±5 % (same pygeoglim backend)
  • NaN guard: ≤5 NaN numeric attrs for a healthy extraction (geomorphic sinks/CN may NaN on global path)

What this does and does not establish: this validates that aihydro-lsh reproduces camels-attrs on CONUS — it does not validate the global attribute claim (no non-CONUS ground truth exists in this chain, and gauge-less hydrology signatures are computed from modelled streamflow with no observed reference to check against anywhere). See papers/DECISIONS.md PD-4 for the claim-scoping decision this follows, and scripts/gen_parity_tolerance_table.py for the per-attribute divergence table generated from the fixture.

Citations

Attribute-level citations are returned in AttributeResult.citations. Key references:

  • Saxton & Rawls (2006) — soil PTF
  • Hartmann & Moosdorf (2012) — GLiM lithology
  • Gleeson et al. (2014) — GLHYMPS permeability
  • Gutman & Ignatov (1998) — NDVI→GVF conversion
  • Jackson et al. (1996) — rooting-depth profiles
  • Addor et al. (2017) — CAMELS attribute definitions
  • Mann (1945); Kendall (1975) — Mann-Kendall trend test
  • Sen (1968) — Sen's slope estimator
  • McKee, Doesken & Kleist (1993) — Standardised Precipitation Index (SPI)
  • Coles (2001) — peaks-over-threshold extreme value analysis

Metadata

Release files for aihydro-lsh 0.2.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for aihydro-lsh 0.2.1
File Size Uploaded Provenance
aihydro_lsh-0.2.1.tar.gz 115.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for aihydro-lsh 0.2.1
File Interpreter ABI Platform
aihydro_lsh-0.2.1-py3-none-any.whl Python 3 none any Details

Total release size: 208.7 kB

Release files / aihydro_lsh-0.2.1.tar.gz

Download URL aihydro_lsh-0.2.1.tar.gz
Size 115.0 kB
Tags Source
SHA-256 checksum
How to use checksums
baff6f99e01538c45a2fa2d22bed3c09be5637fca4dfafffe14b0b908743aef1
BLAKE2b-256 checksum
How to use checksums
a5a236aca1942b963a1992933ad3fc43f775757820a6ab1a51b7a229998e003c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / aihydro_lsh-0.2.1-py3-none-any.whl

Download URL aihydro_lsh-0.2.1-py3-none-any.whl
Size 93.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
39e9002e107a2403f31a189ceddde3d15b9867547f4d4370f5d063a147d931f1
BLAKE2b-256 checksum
How to use checksums
2aea7b7447929bb10b5d376c395a78b99f7007e2d032e77b4cdf66a252a85588
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Security for aihydro-lsh 0.2.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page