CoolFace
Apppublic

mangrovedigital/tide-engine-api

sourceHugging Faceupdated 2mo agoView on Hugging Face
0likes
App README

Tides — Wind-Corrected Tide Engine (10,000 Islands / Everglades City, FL)

Outputs an accurate corrected water level (NAVD88, metres) for a point/time in the 10,000 Islands backcountry, accounting for wind and pressure rather than the astronomical tide alone. Pure-Python (stdlib + requests), no model files.

corrected(t) = astronomical_tide(t) + correction(t)

The product: wind-corrected tide forecast

Standard tide chart + a wind-corrected curve, carried 3 days on the wind forecast, anchored to the current observed level. Built for the case the chart fails: a multi-day N/NE/E blow after a winter front that turns a "mid incoming" into a dead low. Validated on held-out winter fronts: the plain chart is off ~1.2 ft; the product cuts that ~62% (0.46 ft), and beats persistence ~20% during fronts.

python
from engine.forecast import TideForecaster
from datetime import datetime, timezone
fc = TideForecaster.build("255327081275900", 25.89539, -81.4555)   # East River
out = fc.forecast(datetime.now(tz=timezone.utc).timestamp(), horizon_h=72)
for p in out["series"]:                 # each: tide_ft, corrected_ft, lead_h, confidence_ft
    print(p["t"], p["tide_ft"], p["corrected_ft"])

See it: python scripts/demo_forecast.py (live 3-day, two curves) · python scripts/demo_front_replay.py (chart vs actual vs corrected through a real front) · python scripts/validate_forecast.py (held-out accuracy numbers).

Quick start (corrected level / navigability engine)

python
from engine import core
from datetime import datetime, timezone

eng = core.build_engine(
    site="255327081275900", lat=25.89538889, lon=-81.4555,   # East River
    train=("2025-09-01", "2026-03-31"),
    neighbor_site="255432081303900",                          # Faka-Union (nearest)
    neighbor_train=("2025-09-01", "2026-03-31"),
    hp_win=120, lags=tuple(range(10)),
)
t = datetime(2026, 6, 12, 12, tzinfo=timezone.utc).timestamp()
print(eng.corrected_at(t))     # -> dict with corrected_m, layer, provenance, status

Every output carries provenance and a status of OK or HOLD: <reason> (it never emits a silent zero when data is missing).

How it works (layered, most-accurate-available)

  1. 1.PRIMARY (nowcast): astronomical + nearest independent neighbour gauge's full non-tidal residual (regionally coherent, corr ≈ 0.99). ~0.03 m RMSE.
  2. 2.FORECAST: astronomical + persisted regional slow offset + learned wind/pressure correction (uses forecast met). ~0.08 m RMSE.
  3. 3.MET-ONLY: astronomical + wind/pressure correction (no neighbour).
  4. 4.HOLD: no forcing and no neighbour.

The wind→water response is learned from data and direction-dependent; it independently reproduces the real bay geometry (drains on N/NE wind, fills on S/SW wind).

Data sources (official / managed APIs)

  • —USGS NWIS instantaneous values (NAVD88 water level) — ground truth + regional offset
  • —Open-Meteo ERA5 archive + forecast — wind speed/direction + surface pressure

Verify it yourself

python -m engine.harmonic          # math selftest (synthetic, known answer)
python -m engine.residual          # math selftest (synthetic, known answer)
python scripts/stage3_smoke.py     # corrected beats baseline on held-out data
python scripts/stage4_full.py      # optimization ladder + learned physics
python scripts/final_run.py        # full coverage gate; writes out/final_report.json

Accuracy (held-out test 2026-05-01…2026-06-15)

GaugeBaselinePrimaryForecast
East River0.186 m0.032 m (83%)0.086 m
Faka-Union0.163 m0.033 m (80%)0.076 m
Pumpkin River0.175 m0.033 m (81%)0.090 m

See out/FINAL_REPORT.md for the full write-up and out/*.json for raw results.

Scope

In: corrected water-level output + provenance + self-verification + accuracy maximization. Out: UI, hardware. The engine is ready for a UI to call core.build_engine(...) then engine.corrected_at(epoch).