Catalog PyPI
PACKAGE EXPLORERView in registry

aihydro-lsh

PyPI

Global large-sample hydrology — CAMELS-like catchment attributes for any watershed (recipe layer over aihydro-data + aihydro-watershed)

agenticcamelscatchment-attributesgeospatialglobalhydrologylarge-samplewatershed
Versions collected1
Direct dependencies18From release 0.2.1
Last observed21 Oct, 10:56 UTC

README

Version 0.2.1 documentation

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)

FamilyAttrsData sourceNotes
watershed5GDF geometryarea, perimeter, compactness, elongation, form_factor
topography7GLO30 / DEM3DEP / SRTMelev stats, slope stats, area
climate14GRIDMET / ERA5-Land / CHIRPSaridity, seasonality, snow frac, high/low precip stats
soil9POLARIS / SoilGridstexture, Ksat; porosity/AWC/FC from Saxton-Rawls PTF
geomorphic283DEP/GLO30 + NLCD/ESA WorldCovershape, relief, stream network, CN, sinks, land cover %
vegetation13MODIS LAI/NDVI + ESA WorldCoverLAI/GVF seasonal stats, LC fractions, root depth
geology9pygeoglim (GLiM + GLHYMPS)lithology classes, carbonate frac, permeability, porosity; global path is permission/tile-gated
hydrology17NWIS (CONUS) / GEOGLOWS (global)q_mean, BFI, FDC slope, half-flow date, …
forcingtimeseriesGRIDMET (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:

TierFlagOutputDescription
T2.5 — Trendsinclude_trends=Trueresult.trends — up to 16 slope/p-value scalarsMann–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 — Dynamicinclude_dynamic=Trueresult.dynamic — year × 22-column schemaAnnual 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 — Eventsinclude_events=Trueresult.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:

ToolDescription
lsh_attributesAll 101 static scalar attrs for a polygon or pour-point
lsh_forcingDaily basin-averaged meteorological timeseries (LSTM/HBV)
lsh_dynamic_attributesAnnual dynamic panels (T3) — year × 22 variables
lsh_eventsDrought (SPI) and flood (POT) event inventories (T3)
lsh_familiesList families + attribute keys
lsh_attribute_infoUnit, source, family, formula, CAMELS equivalent, and caveat for one attribute
lsh_batchMulti-basin extraction from JSON array
lsh_compare_to_reflsh vs camels-attrs side-by-side (CONUS)
lsh_recipe_statusCheck which recipes can run (auth/deps)
lsh_reliability_matrixFamily/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

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Versions 1

Collected releases
VersionPublishedDirect dependenciesOpen version
0.2.120 Oct 202618

Package advisories

0
No matching advisories collected

This describes our collected data; it is not a security assessment.

Repository

PENDING
ai-hydro/aihydro-lsh

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 21 Oct, 10:56 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package:5916002dddab35ed17d77dc6db53ea2ada4bda5f60b3c1d293aa8a590189c4bf