Real-Time Forecast Workflow with ras-commander¶
This notebook demonstrates how to build an operational real-time flood forecast workflow using ras-commander. It covers the equivalent functionality of the rtsPy pipeline used in NOAA/NWS operational systems, implemented with ras-commander's Python API.
The workflow downloads NOAA forecast products (HRRR precipitation, STOFS-3D coastal water levels), prepares boundary conditions, updates simulation dates, and executes HEC-RAS models automatically.
Note: This is a documentation/educational notebook. Actual download steps require internet access to NOAA NOMADS and STOFS servers. Code cells that require internet access will gracefully skip and continue.
# =============================================================================
# DEVELOPMENT MODE TOGGLE
# =============================================================================
USE_LOCAL_SOURCE = True
if USE_LOCAL_SOURCE:
import sys
from pathlib import Path
local_path = str(Path.cwd().parent)
if local_path not in sys.path:
sys.path.insert(0, local_path)
print(f"LOCAL SOURCE MODE: Loading from {local_path}/ras_commander")
else:
print("PIP PACKAGE MODE: Loading installed ras-commander")
from pathlib import Path
import pandas as pd
from datetime import datetime, timedelta
from ras_commander.precip import PrecipHrrr
from ras_commander.boundaries import CoastalBoundary
from ras_commander import init_ras_project, RasCmdr, RasPlan
The rtsPy Workflow (Context)¶
The NWS operational flood forecast pipeline (historically known as rtsPy) follows a 10-step process:
Step 1: Check forecast cycle availability (HRRR, GFS, etc.)
Step 2: Download precipitation forecast (HRRR GRIB2)
Step 3: Download coastal boundary (STOFS-3D NetCDF)
Step 4: Download upstream boundary (USGS real-time gauges)
Step 5: Process precipitation to DSS or spatially-varied format
Step 6: Generate stage/flow boundary conditions
Step 7: Update HEC-RAS plan simulation dates
Step 8: Execute HEC-RAS (single plan or ensemble)
Step 9: Extract water surface elevation results
Step 10: Post-process and publish to NWS web services
ras-commander handles steps 2-9 via clean Python APIs:
| Step | rtsPy Approach | ras-commander API |
|---|---|---|
| 2 - HRRR Download | Manual HTTP requests, hardcoded paths | PrecipHrrr.get_latest_forecast() |
| 3 - Coastal BC | Jython + DSSVue scripting | CoastalBoundary.download_stofs3d() |
| 4 - Upstream BC | Direct USGS API calls | RasUsgsBoundaryGeneration.generate_bc_from_gauge() |
| 5 - Precip processing | Custom GRIB2 parsers | PrecipHrrr.to_spatially_varied() |
| 6 - Stage BC | DSS Jython scripting | CoastalBoundary.generate_stage_bc() |
| 7 - Plan dates | Text search-and-replace | RasPlan.update_simulation_date() |
| 8 - Execute | subprocess / win32com | RasCmdr.compute_plan() with smart skip |
| 9 - Extract results | Manual HDF5 parsing | 18 HDF static classes |
Prerequisites¶
- HEC-RAS 6.6+ installed on Windows
- ras-commander installed (
pip install ras-commander) - Internet access for NOAA data downloads (NOMADS, STOFS servers)
- Optional: HEC-DSS installed for DSS-based boundary conditions
Estimated runtime (with internet): 5-15 minutes depending on download speed. Estimated runtime (demonstration mode, no internet): < 30 seconds.
Example 1: Inland Riverine Forecast (Muncie)¶
This example demonstrates a riverine flood forecast workflow using HRRR precipitation as the forcing data. The Muncie, Indiana area is used as a representative inland watershed.
Step 1: Check HRRR Forecast Availability¶
Before downloading, check what HRRR cycles are currently available on NOAA NOMADS. The HRRR is updated hourly with 18-hour forecasts (48-hour for the 00z and 12z cycles).
# Check what HRRR data is available
info = PrecipHrrr.get_info()
print("HRRR Forecast Information:")
for key, value in info.items():
print(f" {key}: {value}")
# Check latest available cycle
is_available = PrecipHrrr.check_availability()
print(f"\nLatest HRRR cycle available: {is_available}")
Step 2: Download HRRR Forecast¶
Download the latest available HRRR forecast GRIB2 files. Each file contains one forecast hour of gridded precipitation, wind, and thermodynamic data at 3 km resolution over CONUS.
# Download latest HRRR forecast (18 hours ahead)
# Note: Requires internet access to NOAA NOMADS
output_dir = Path("example_data/hrrr_forecast")
output_dir.mkdir(parents=True, exist_ok=True)
try:
grib_files = PrecipHrrr.get_latest_forecast(
output_dir=output_dir,
hours=18,
max_lookback_hours=6
)
print(f"Downloaded {len(grib_files)} HRRR GRIB2 files")
for f in grib_files[:3]:
print(f" {f.name}")
if len(grib_files) > 3:
print(f" ... and {len(grib_files) - 3} more")
except Exception as e:
print(f"HRRR download requires internet access: {e}")
print("Continuing with demonstration of remaining workflow steps...")
grib_files = []
Step 3: Update Plan Simulation Dates¶
Before executing, update the HEC-RAS plan's simulation start and end dates to match the forecast window. RasPlan.update_simulation_date() modifies the .p## file directly, preserving all other plan settings.
# In a real workflow, update the plan dates to match the forecast period
# RasPlan.update_simulation_date() modifies the .p## file directly
# Example: Set simulation to cover next 18 hours
forecast_start = datetime.now().replace(minute=0, second=0, microsecond=0)
forecast_end = forecast_start + timedelta(hours=18)
print(f"Forecast window: {forecast_start} to {forecast_end}")
print(f"\nTo update plan dates, use:")
print(f" RasPlan.update_simulation_date(")
print(f" plan_number='01',")
print(f" new_start_date='{forecast_start.strftime('%d%b%Y').upper()}',")
print(f" new_start_time='{forecast_start.strftime('%H%M')}',")
print(f" new_end_date='{forecast_end.strftime('%d%b%Y').upper()}',")
print(f" new_end_time='{forecast_end.strftime('%H%M')}'")
print(f" )")
Step 4: Execute HEC-RAS¶
Execute the forecast plan. The force_rerun=True parameter ensures HEC-RAS always runs even if existing results appear current, which is essential in operational forecasting where the forecast data changes each cycle.
# Execute the forecast plan
# init_ras_project("/path/to/project", "6.6")
# RasCmdr.compute_plan("01", force_rerun=True)
print("In a real workflow:")
print(" 1. init_ras_project('/path/to/flood_forecast', '6.6')")
print(" 2. RasCmdr.compute_plan('01', force_rerun=True)")
print(" 3. Results available via HdfResultsPlan/HdfResultsMesh")
Example 2: Coastal Watershed Forecast¶
This example extends the inland workflow by adding a downstream coastal stage boundary condition from STOFS-3D (formerly ADCIRC). Coastal watersheds like those draining into Galveston Bay require a downstream WSE boundary that accounts for storm surge and tides.
Step 1: Download STOFS-3D Coastal Boundary¶
STOFS-3D (Surge, Tide, and Overland Flow Surge - 3D) is NOAA's operational coastal storm surge model. It provides water surface elevation forecasts at 1-km resolution along the US coastline, updated 4 times daily.
# Check STOFS-3D availability
info = CoastalBoundary.get_info()
print("STOFS-3D Information:")
for key, value in info.items():
print(f" {key}: {value}")
# Download STOFS-3D forecast
stofs_dir = Path("example_data/stofs3d_forecast")
stofs_dir.mkdir(parents=True, exist_ok=True)
try:
stofs_files = CoastalBoundary.download_stofs3d(
output_dir=stofs_dir,
file_type="points"
)
print(f"\nDownloaded {len(stofs_files)} STOFS-3D files")
except Exception as e:
print(f"\nSTOFS-3D download requires internet access: {e}")
print("Continuing with demonstration...")
stofs_files = []
Step 2: Extract Coastal WSE at Point¶
Extract the water surface elevation time series at a specific coastal point. For the Houston Ship Channel example, we use the Galveston Bay entrance (lat=29.35, lon=-94.77). The WSE is extracted from the nearest STOFS-3D node and interpolated to the HEC-RAS simulation timestep.
# Extract water surface elevation at Galveston Bay entrance
# lat=29.35, lon=-94.77 (Houston Ship Channel)
try:
wse_df = CoastalBoundary.extract_wse_at_point(
stofs_dir=stofs_dir,
lat=29.35,
lon=-94.77,
units="feet"
)
print(f"Extracted {len(wse_df)} time steps of coastal WSE")
print(f"WSE range: {wse_df['wse_ft'].min():.2f} to {wse_df['wse_ft'].max():.2f} ft NAVD88")
print(wse_df.head())
except Exception as e:
print(f"WSE extraction requires downloaded STOFS-3D data: {e}")
print("\nExample output:")
print(" datetime wse_m wse_ft")
print(" 2025-01-01 00:00 0.305 1.00")
print(" 2025-01-01 01:00 0.335 1.10")
print(" ...")
Step 3: Generate Stage Boundary Condition¶
Write the coastal WSE time series as a downstream stage boundary condition in the HEC-RAS unsteady flow file (.u##). The method writes in HEC-RAS fixed-width format and automatically detects the appropriate time interval.
# Write coastal WSE as downstream stage boundary condition
# CoastalBoundary.generate_stage_bc() writes to HEC-RAS .u## file
print("To write coastal boundary condition:")
print(" CoastalBoundary.generate_stage_bc(")
print(" wse_timeseries=wse_df,")
print(" unsteady_file='project.u01',")
print(" bc_location='Downstream',")
print(" units='feet',")
print(" datum_adjustment_ft=0.0")
print(" )")
print()
print("This writes fixed-width format (8.2f, 10 values/line)")
print("directly into the Stage Hydrograph section of the .u## file")
Key Takeaways¶
Summary¶
This notebook demonstrated the real-time forecast workflow that ras-commander enables:
- HRRR Download (
PrecipHrrr) - Download NOAA HRRR forecast precipitation - STOFS-3D Download (
CoastalBoundary) - Download coastal storm surge forecasts - Plan Date Update (
RasPlan.update_simulation_date()) - Set forecast window - Execution (
RasCmdr.compute_plan()) - Run HEC-RAS with smart skip - Results (HDF classes) - Extract and analyze forecast results
rtsPy vs ras-commander Comparison¶
| Feature | rtsPy | ras-commander |
|---|---|---|
| HRRR Download | Manual HTTP, hardcoded paths | PrecipHrrr.get_latest_forecast() |
| Coastal BC | Jython + DSSVue scripting | CoastalBoundary.generate_stage_bc() |
| Plan Dates | Text replacement | RasPlan.update_simulation_date() |
| Execution | subprocess or win32com | RasCmdr.compute_plan() with smart skip |
| Results | Manual HDF parsing | 18 HDF static classes |
Adapting for Your Project¶
Replace the example parameters with your project-specific values:
- Project path and HEC-RAS version
- HRRR forecast hours and bounding box
- Coastal extraction point (lat/lon)
- Boundary condition location names in your .u## file
Common Pitfalls¶
- HRRR latency: NOMADS may not have the current cycle immediately. Use
max_lookback_hoursto fall back to a recent cycle. - Datum mismatch: STOFS-3D outputs in NAVD88. Verify your HEC-RAS model uses the same datum or apply
datum_adjustment_ft. - Simulation window: The plan's simulation end time must extend past the last forecast hour to avoid truncated results.
- force_rerun: Always use
force_rerun=Truein operational forecasting. Smart skip (default) may skip execution if the HDF appears current.
See Also¶
examples/900_aorc_precipitation.ipynb- AORC historic precipitation (calibration)examples/721_precipitation_hyetograph_comparison.ipynb- Atlas 14 design storm eventsras_commander/precip/CLAUDE.md- Complete precipitation module documentationras_commander/sources/federal/- NOAA/USGS data source modules