Series position: This is a focused input-data drill-down for observed precipitation and validation workflows. Start with 915_realtime_forecast_workflow.ipynb for the full operational architecture, then use this notebook when you need MRMS QPE precipitation forcing or rain-on-grid validation detail.
Python
fromcontextlibimportcontextmanagerfromdatetimeimportdatetime,timedeltafrompathlibimportPathimportloggingimportshutilimportwarnings# tqdm.auto emits this during import when Jupyter widgets are unavailable.warnings.filterwarnings("ignore",message="IProgress not found.*",module="tqdm.auto")importgeopandasasgpdfromIPython.displayimportdisplayimportmatplotlib.pyplotaspltimportnumpyasnpimportpandasaspdfromrasterio.errorsimportNotGeoreferencedWarningfromshapely.geometryimportboxfromras_commanderimport(RasCmdr,RasExamples,RasPlan,RasProcess,RasUnsteady,init_ras_project,)fromras_commander.dssimportRasDssfromras_commander.hdfimportHdfMesh,HdfProject,HdfPump,HdfResultsMeshfromras_commander.precipimportPrecipMrmsREPO_ROOT=Path.cwd()ifREPO_ROOT.name.lower()=="examples":REPO_ROOT=REPO_ROOT.parentRUN_ROOT=REPO_ROOT/"working"/"CLB-642"/"examples_917_mrms_qpe_revisions"ARTIFACT_ROOT=RUN_ROOT/"videos"ARTIFACT_ROOT.mkdir(parents=True,exist_ok=True)OUTPUT_INTERVAL="5MIN"FPS=4VIDEO_DPI=110MIN_CONSOLIDATION_CELL_SIZE_FT=10.0ANIMATION_MAX_FRAMES=30# Keep handled subfunction and third-party diagnostics out of published output.# Exceptions still propagate; concise retry/gap-fill summaries are printed below.forlogger_name,levelin{"httpx":logging.WARNING,"pydsstools":logging.WARNING,"pyogrio":logging.WARNING,"rasterio":logging.ERROR,"matplotlib.animation":logging.WARNING,"ras_commander.RasPlan":logging.ERROR,"ras_commander.RasProcess":logging.WARNING,}.items():logging.getLogger(logger_name).setLevel(level)warnings.filterwarnings("ignore",message="You will likely lose important projection information.*",category=UserWarning,module="pyproj.crs.crs",)warnings.filterwarnings("ignore",category=NotGeoreferencedWarning)DAVIS_BOUNDS=(-121.78689244974507,38.523870898941006,-121.70713010751233,38.591248584093314,)CASES=[{"case_id":"davis_atmospheric_river","display_name":"Davis atmospheric river","project":"Davis","suffix":"mrms_qpe_917_davis_ar","ras_version":"7.0","plan_number":"02","precip_boundary":"area2","event_start":datetime(2022,12,31,0),"event_last_qpe":datetime(2023,1,1,12),"sim_end":datetime(2023,1,1,18),"animation_start":datetime(2022,12,31,0),"animation_end":datetime(2023,1,1,18),"mrms_bounds":DAVIS_BOUNDS,"dss_b":"DAVIS_AR","dss_f":"MRMS_AR_20221231","event_note":("29 Dec 2022 - 1 Jan 2023 Northern California atmospheric river; ""CLB-672 selected this Davis-local MRMS window."),},{"case_id":"neworleans_april2024_flash_flood","display_name":"NewOrleansMetro April 2024 flash flood","project":"NewOrleansMetro","suffix":"mrms_qpe_917_nola_apr2024","ras_version":"7.0","plan_number":"01","precip_boundary":"NewOrleans Metro","event_start":datetime(2024,4,10,0),"event_last_qpe":datetime(2024,4,10,23),"sim_end":datetime(2024,4,11,6),"animation_start":datetime(2024,4,10,0),"animation_end":datetime(2024,4,11,6),"mrms_bounds":None,"dss_b":"NOLA_APR10","dss_f":"MRMS_20240410","event_note":("NWS New Orleans/Baton Rouge documented the 10 Apr 2024 New Orleans ""Metro severe thunderstorm and flash-flood event as a non-hurricane ""rainfall case."),},]print(f"Run root: {RUN_ROOT}")print(f"Animation output root: {ARTIFACT_ROOT}")print(f"RAS output/mapping interval target: {OUTPUT_INTERVAL}")print(f"Consolidation policy: preserve dominant terrain cells >=10 ft; "f"otherwise use {MIN_CONSOLIDATION_CELL_SIZE_FT:g} ft; maximum frames: {ANIMATION_MAX_FRAMES}")
Text Only
Run root: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions
Animation output root: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\videos
RAS output/mapping interval target: 5MIN
Consolidation policy: preserve dominant terrain cells >=10 ft; otherwise use 10 ft; maximum frames: 30
For local source testing, run this notebook from the repository root using the repository .venv and an editable ras-commander install. Generated projects remain under the ignored working/ directory.
This notebook demonstrates MRMS QPE acquisition, HEC-Vortex DSS conversion, HEC-RAS rain-on-grid simulation, representative depth frames sampled across consecutive 5-minute results, and MP4 visualization for two real non-synthetic cases:
Davis, California: the CLB-672 atmospheric-river event from 2022-12-31 through 2023-01-01.
NewOrleansMetro: the April 10, 2024 New Orleans Metro severe thunderstorm and flash-flood event.
Each case first computes an otherwise identical zero-rain baseline, then computes the MRMS event and verifies the HEC-RAS precipitation-rate and cumulative-depth outputs against the incremental depths actually serialized into the unsteady file. Depth, WSE, and pump responses are compared at the same locations without presuming that precipitation creates a beneficial or adverse response everywhere.
The full consecutive 5-minute result window is verified before selecting at most 30 evenly distributed timestamps spanning the event. Multi-terrain source tiles are consolidated to one raster per timestamp using the active RasMapper terrain layers, with broad/coarse coverage written before finer local terrain. A Mapper frame is accepted only when the dominant terrain is present, the rasters are readable and georeferenced, and wetness agrees with the plan HDF; otherwise the entire timestamp is replaced from HDF results. The dominant active terrain's native resolution is preserved when it is at least 10 ft; finer terrain is conservatively consolidated at 10 ft. Every spatial map and animation frame includes the 2D mesh outline, pump station labels where the model contains pumps, and OpenStreetMap basemap context.
defcatalog_dss(dss_file:Path)->pd.DataFrame:catalog=RasDss.get_catalog(dss_file)ifcatalog.empty:raiseRuntimeError(f"DSS catalog is empty: {Path(dss_file).name}")returncatalogdefvalidate_dss_precipitation_grids(dss_file:Path,catalog:pd.DataFrame,case:dict,expected_count:int,)->pd.DataFrame:iflen(catalog)!=expected_count:raiseValueError(f"Expected {expected_count} DSS grids, found {len(catalog)}")rows=[]forpathnameincatalog["pathname"].astype(str):grid=RasDss.read_grid(dss_file,pathname)parts=grid["metadata"]["pathname_parts"]assertparts["A"]=="SHG"assertparts["B"]==case["dss_b"]assertparts["C"]=="PRECIPITATION"assertparts["F"]==case["dss_f"]assertgrid["units"].upper()=="MM"assertgrid["data_type"].upper()=="PER-CUM"assertgrid["grid_type"]=="albers"assert"North_American_1983"ingrid["crs"]assertnp.isclose(grid["cell_size"],2000.0)values=np.asarray(grid["data"],dtype=float)finite=values[np.isfinite(values)]ifnotlen(finite)ornp.any(finite<0):raiseValueError(f"Invalid DSS grid values for {pathname}")rows.append({"pathname":pathname,"start_time":grid["start_time"],"end_time":grid["end_time"],"rows":grid["shape"][0],"columns":grid["shape"][1],"minimum_mm":float(finite.min()),"maximum_mm":float(finite.max()),"mean_mm":float(finite.mean()),})audit=pd.DataFrame(rows).sort_values("start_time").reset_index(drop=True)expected_ends=pd.date_range(case["event_start"],periods=expected_count,freq="h")expected_starts=expected_ends-pd.Timedelta(hours=1)assertaudit["start_time"].tolist()==expected_starts.tolist()assertaudit["end_time"].tolist()==expected_ends.tolist()assertaudit["maximum_mm"].max()>0returnauditdefget_plan_row(ras,plan_number:str)->pd.Series:plan=ras.plan_df[ras.plan_df["plan_number"].astype(str).str.zfill(2)==plan_number.zfill(2)]ifplan.empty:raiseValueError(f"Plan {plan_number} not found. Available: {ras.plan_df['plan_number'].tolist()}")returnplan.iloc[0]defget_geometry_hdf(ras,plan_number:str)->Path:plan_row=get_plan_row(ras,plan_number)geom_number=str(plan_row["geometry_number"]).zfill(2)geom_hdf=ras.project_folder/f"{ras.project_name}.g{geom_number}.hdf"ifnotgeom_hdf.exists():raiseFileNotFoundError(f"Geometry HDF not found: {geom_hdf}")returngeom_hdfdefget_unsteady_number(ras,plan_number:str)->str:plan_row=get_plan_row(ras,plan_number)returnstr(plan_row["unsteady_number"]).zfill(2)defdisplay_preview(frame:pd.DataFrame,rows:int=3)->None:iflen(frame)<=rows*2:display(frame)returnprint(f"Showing first and last {rows} of {len(frame)} rows")display(pd.concat([frame.head(rows),frame.tail(rows)]))@contextmanagerdefcapture_logger_records(logger_name:str,level:int=logging.WARNING):logger=logging.getLogger(logger_name)records=[]classRecordHandler(logging.Handler):defemit(self,record):records.append(record)handler=RecordHandler(level=level)old_handlers=logger.handlers[:]old_level=logger.levelold_propagate=logger.propagatelogger.handlers=[handler]logger.setLevel(level)logger.propagate=Falsetry:yieldrecordsexceptException:print(f"{logger_name} failed; captured diagnostics:")forrecordinrecords:print(f"- {record.levelname}: {record.getMessage()}")raisefinally:logger.handlers=old_handlerslogger.setLevel(old_level)logger.propagate=old_propagatedefprepare_serialized_hyetograph(hyetograph:pd.DataFrame)->pd.DataFrame:serialized=hyetograph.copy()serialized["incremental_depth"]=serialized["incremental_depth"].round(2)serialized["cumulative_depth"]=serialized["incremental_depth"].cumsum()returnserializeddefzero_hyetograph_like(hyetograph:pd.DataFrame)->pd.DataFrame:baseline=hyetograph.copy()baseline["incremental_depth"]=0.0baseline["cumulative_depth"]=0.0returnbaselinedefvalidate_hdf_precipitation(plan_hdf:Path,mesh_name:str,expected_hyetograph:pd.DataFrame,label:str,)->pd.DataFrame:rate_da=HdfResultsMesh.get_mesh_timeseries(plan_hdf,mesh_name,"Cell Precipitation Rate",truncate=False)cumulative_da=HdfResultsMesh.get_mesh_timeseries(plan_hdf,mesh_name,"Cell Cumulative Precipitation Depth",truncate=False)ifrate_da.attrs.get("units")!="in/hr"orcumulative_da.attrs.get("units")!="in":raiseValueError(f"Unexpected HDF precipitation units: rate={rate_da.attrs.get('units')}, "f"cumulative={cumulative_da.attrs.get('units')}")interval_hours=float(expected_hyetograph["hour"].diff().dropna().median())expected_peak_rate=float((expected_hyetograph["incremental_depth"]/interval_hours).max())expected_total=float(expected_hyetograph["incremental_depth"].sum())rate_values=np.asarray(rate_da.values,dtype=float)cumulative_values=np.asarray(cumulative_da.values,dtype=float)hdf_peak_rate=float(np.nanmax(rate_values))hdf_final_total=float(np.nanmax(cumulative_values[-1]))positive_spreads=[]forrowinrate_values:applied=row[np.isfinite(row)&(row>1e-9)]iflen(applied):positive_spreads.append(float(applied.max()-applied.min()))max_applied_rate_spread=max(positive_spreads,default=0.0)peak_row=rate_values[int(np.nanargmax(np.nanmax(rate_values,axis=1)))]active_cell_fraction=float(np.count_nonzero(peak_row>1e-9)/peak_row.size)assertnp.isclose(hdf_peak_rate,expected_peak_rate,atol=0.011),(label,hdf_peak_rate,expected_peak_rate)assertnp.isclose(hdf_final_total,expected_total,atol=0.02),(label,hdf_final_total,expected_total)assertmax_applied_rate_spread<1e-6,(label,max_applied_rate_spread)returnpd.DataFrame([{"condition":label,"expected_peak_rate_in_hr":expected_peak_rate,"hdf_peak_rate_in_hr":hdf_peak_rate,"expected_total_in":expected_total,"hdf_final_total_in":hdf_final_total,"max_applied_rate_spread":max_applied_rate_spread,"active_cell_fraction_at_peak":active_cell_fraction,}])defhdf_depth_maxima(plan_hdf:Path,mesh_name:str)->pd.Series:depth_da=HdfResultsMesh.get_mesh_timeseries(plan_hdf,mesh_name,"Cell Hydraulic Depth",truncate=False)values=np.asarray(depth_da.values,dtype=float)maxima=np.nanmax(values,axis=1)returnpd.Series(maxima,index=pd.to_datetime(depth_da.coords["time"].values))defget_terrain_inventory(ras)->pd.DataFrame:importrasterioterrain_dir=ras.project_folder/"Terrain"ifnotterrain_dir.exists()or"terrain_hdf_path"notinras.rasmap_df.columns:returnpd.DataFrame()active_hdfs=[]forvalueinras.rasmap_df["terrain_hdf_path"].dropna():values=valueifisinstance(value,(list,tuple,set))else[value]active_hdfs.extend(Path(path)forpathinvaluesifpath)candidates:dict[Path,Path]={}forterrain_hdfinactive_hdfs:forterrain_pathinterrain_dir.glob(f"{terrain_hdf.stem}*.tif"):candidates[terrain_path.resolve()]=terrain_hdfrows=[]forterrain_path,terrain_hdfinsorted(candidates.items()):withrasterio.open(terrain_path)assrc:x_resolution=abs(float(src.res[0]))y_resolution=abs(float(src.res[1]))valid_cells=sum(int(np.count_nonzero(src.read_masks(1,window=window)))for_,windowinsrc.block_windows(1))rows.append({"terrain":terrain_path.name,"terrain_hdf":terrain_hdf.name,"path":terrain_path,"x_resolution":x_resolution,"y_resolution":y_resolution,"linear_units":src.crs.linear_unitsifsrc.crselseNone,"valid_cells":valid_cells,"valid_coverage_area":valid_cells*x_resolution*y_resolution,})inventory=pd.DataFrame(rows)ifinventory.empty:returninventoryinventory=inventory.sort_values("valid_coverage_area",ascending=False).reset_index(drop=True)inventory["nominal_resolution"]=inventory["x_resolution"].round(2)precedence=inventory.sort_values(["nominal_resolution","valid_coverage_area"],ascending=[False,False],).indexinventory["mosaic_order"]=0inventory.loc[precedence,"mosaic_order"]=np.arange(1,len(inventory)+1)returninventorydefget_pump_stations(geom_hdf:Path,mesh_areas:gpd.GeoDataFrame)->gpd.GeoDataFrame:try:pumps=HdfPump.get_pump_stations(geom_hdf)exceptException:returngpd.GeoDataFrame({"Name":[]},geometry=[],crs=mesh_areas.crs)ifpumps.emptyandmesh_areas.crsisnotNone:pumps=pumps.set_crs(mesh_areas.crs)returnpumpsdefmake_clip_shp(bounds:tuple[float,float,float,float],output_path:Path,label:str)->Path:output_path.parent.mkdir(parents=True,exist_ok=True)gdf=gpd.GeoDataFrame({"name":[label]},geometry=[box(*bounds)],crs="EPSG:4326")gdf.to_file(output_path)returnoutput_pathdefparse_ras_timestamp(timestamp:str)->datetime:returndatetime.strptime(timestamp,"%d%b%Y %H:%M:%S")defselect_animation_timestamps(timestamps:list[str],start:datetime,end:datetime,)->list[str]:selected=[timestampfortimestampintimestampsifstart<=parse_ras_timestamp(timestamp)<=end]iflen(selected)<2:raiseValueError(f"Animation window {start} to {end} selected {len(selected)} timestamp(s)")selected_start=parse_ras_timestamp(selected[0])selected_end=parse_ras_timestamp(selected[-1])ifselected_start!=startorselected_end!=end:raiseValueError(f"Result coverage {selected_start} to {selected_end} does not match "f"the requested event window {start} to {end}")deltas=[parse_ras_timestamp(selected[idx+1])-parse_ras_timestamp(selected[idx])foridxinrange(len(selected)-1)]ifany(delta!=timedelta(minutes=5)fordeltaindeltas):raiseValueError("Selected animation timestamps are not consecutive 5-minute frames")returnselecteddefget_depth_tiles(depth_results:dict[str,dict[str,list[Path]]],timestamp:str,terrain_inventory:pd.DataFrame|None=None,)->list[Path]:priority={}ifterrain_inventoryisnotNoneandnotterrain_inventory.empty:priority={str(row.terrain).casefold():int(row.mosaic_order)forrowinterrain_inventory.itertuples()}deftile_sort_key(path:Path)->tuple[int,str]:path_name=path.name.casefold()matches=[orderforterrain,orderinpriority.items()ifterraininpath_name]return(matches[0]ifmatcheselse0,path_name)tiles=sorted((Path(path)forpathindepth_results.get(timestamp,{}).get("depth",[])),key=tile_sort_key,)return[pathforpathintilesifpath.exists()]defaudit_mapper_depth_frames(depth_results:dict[str,dict[str,list[Path]]],timestamps:list[str],terrain_inventory:pd.DataFrame,hdf_depth_max:pd.Series,)->pd.DataFrame:importrasteriodominant_name=str(terrain_inventory.iloc[0]["terrain"]).casefold()rows=[]fortimestampintimestamps:tiles=get_depth_tiles(depth_results,timestamp,terrain_inventory)dominant_present=any(dominant_nameinpath.name.casefold()forpathintiles)readable=bool(tiles)georeferenced=bool(tiles)all_have_data=bool(tiles)mapper_max_depth=0.0forpathintiles:try:withrasterio.open(path)assrc:georeferenced=georeferencedandsrc.crsisnotNoneandnotsrc.transform.is_identitydata=src.read(1,masked=True)has_data=bool(data.count())all_have_data=all_have_dataandhas_dataifhas_data:mapper_max_depth=max(mapper_max_depth,float(data.max()))exceptException:readable=Falseresult_time=pd.Timestamp(parse_ras_timestamp(timestamp))hdf_max_depth=float(hdf_depth_max.get(result_time,np.nan))wetness_matches_hdf=not(hdf_max_depth>0.01andmapper_max_depth<=0.01)valid=(bool(tiles)anddominant_presentandreadableandgeoreferencedandall_have_dataandwetness_matches_hdf)reasons=[]ifnottiles:reasons.append("no depth raster")iftilesandnotdominant_present:reasons.append("dominant terrain missing")ifnotreadable:reasons.append("unreadable raster")iftilesandnotgeoreferenced:reasons.append("missing georeferencing")iftilesandnotall_have_data:reasons.append("all-nodata raster")ifnotwetness_matches_hdf:reasons.append("blank while HDF is wet")rows.append({"timestamp":timestamp,"terrain_tiles":len(tiles),"dominant_present":dominant_present,"mapper_max_depth_ft":mapper_max_depth,"hdf_max_depth_ft":hdf_max_depth,"valid":valid,"reason":"; ".join(reasons),})returnpd.DataFrame(rows)defcollect_depth_raster_frames(depth_results:dict[str,dict[str,list[Path]]],timestamps:list[str],terrain_inventory:pd.DataFrame,)->tuple[list[list[Path]],pd.DataFrame]:frames:list[list[Path]]=[]audit_rows:list[dict]=[]missing:list[str]=[]fortimestampintimestamps:tiles=get_depth_tiles(depth_results,timestamp,terrain_inventory)ifnottiles:missing.append(timestamp)continueframes.append(tiles)audit_rows.append({"timestamp":parse_ras_timestamp(timestamp),"terrain_tiles":len(tiles),"total_raster_mb":sum(path.stat().st_sizeforpathintiles)/1_000_000,"rasters":"; ".join(path.nameforpathintiles),})ifmissing:preview=", ".join(missing[:5])raiseRuntimeError(f"Stored-map depth rasters are missing for {len(missing)} timestep(s): {preview}")returnframes,pd.DataFrame(audit_rows)defsummarize_depth_stack(depth_stack)->pd.DataFrame:values=np.asarray(depth_stack.values,dtype=np.float32)x=np.asarray(depth_stack.coords["x"].values,dtype=float)y=np.asarray(depth_stack.coords["y"].values,dtype=float)dx=float(np.median(np.abs(np.diff(x))))iflen(x)>1elseMIN_CONSOLIDATION_CELL_SIZE_FTdy=float(np.median(np.abs(np.diff(y))))iflen(y)>1elseMIN_CONSOLIDATION_CELL_SIZE_FTcell_area_acres=dx*dy/43560.0rows=[]forframe_index,timestampinenumerate(pd.to_datetime(depth_stack.coords["time"].values)):data=values[frame_index]wet=np.isfinite(data)&(data>0)rows.append({"timestamp":timestamp,"wet_cells":int(np.count_nonzero(wet)),"wet_area_acres":float(np.count_nonzero(wet)*cell_area_acres),"max_depth_ft":float(np.nanmax(data))ifnp.isfinite(data).any()else0.0,"mean_wet_depth_ft":float(np.mean(data[wet]))ifwet.any()else0.0,})returnpd.DataFrame(rows)defmax_depth_grid_from_stack(depth_stack):values=np.asarray(depth_stack.values,dtype=np.float32)finite=np.isfinite(values)max_depth=np.max(np.where(finite,values,-np.inf),axis=0)max_depth[~finite.any(axis=0)]=np.nanmax_extent,_=PrecipMrms._data_extent(depth_stack)max_crs=depth_stack.attrs.get("crs")returnmax_depth,max_extent,max_crsdefplot_accumulation_map(case:dict,mrms_stack,hyetograph:pd.DataFrame,mesh_areas:gpd.GeoDataFrame,pump_stations:gpd.GeoDataFrame,):accum_in=(mrms_stack.sum(dim="time")/25.4).rename("MRMS accumulation")extent,origin=PrecipMrms._data_extent(mrms_stack)fig,axes=plt.subplots(1,2,figsize=(12,4.8),constrained_layout=True)axes[0].bar(hyetograph["time"],hyetograph["incremental_depth"],width=0.035,color="#2b8cbe")axes[0].plot(hyetograph["time"],hyetograph["cumulative_depth"],color="#08306b",marker="o")axes[0].set_ylabel("Depth (in)")axes[0].set_title(f"{case['display_name']} MRMS hyetograph")axes[0].tick_params(axis="x",rotation=30)im=axes[1].imshow(accum_in.values,extent=extent,origin=origin,cmap="turbo",vmin=0,alpha=0.78,zorder=2,)axes[1].set_title("MRMS accumulation with model context")axes[1].set_xlabel("Longitude")axes[1].set_ylabel("Latitude")PrecipMrms._plot_spatial_overlays(axes[1],data_crs="EPSG:4326",mesh_boundary=mesh_areas,pump_stations=pump_stations,add_basemap=True,)fig.colorbar(im,ax=axes[1],shrink=0.8,label="Accumulation (in)")plt.show()defplot_depth_response(case:dict,depth_summary:pd.DataFrame,depth_stack,mesh_areas:gpd.GeoDataFrame,pump_stations:gpd.GeoDataFrame,):max_depth,max_extent,max_crs=max_depth_grid_from_stack(depth_stack)fig,axes=plt.subplots(1,2,figsize=(12,4.8),constrained_layout=True)axes[0].plot(depth_summary["timestamp"],depth_summary["max_depth_ft"],color="#08519c",marker="o",)axes[0].set_title(f"{case['display_name']} selected-frame depth response")axes[0].set_ylabel("Max timestep depth (ft)")axes[0].tick_params(axis="x",rotation=30)vmax=max(float(np.nanpercentile(max_depth,98)),0.1)im=axes[1].imshow(max_depth,extent=max_extent,origin="upper",cmap="Blues",vmin=0,vmax=vmax,alpha=0.78,zorder=2,)axes[1].set_title("Maximum selected-frame depth with model context")axes[1].set_xlabel("Easting (ft)")axes[1].set_ylabel("Northing (ft)")axes[1].set_aspect("equal",adjustable="box")PrecipMrms._plot_spatial_overlays(axes[1],data_crs=max_crs,mesh_boundary=mesh_areas,pump_stations=pump_stations,add_basemap=True,)fig.colorbar(im,ax=axes[1],shrink=0.8,label="Depth (ft)")plt.show()deffresh_artifact_path(path:Path)->Path:path=Path(path)path.parent.mkdir(parents=True,exist_ok=True)path.unlink(missing_ok=True)returnpathdefwrite_consolidated_depth_rasters(depth_stack,output_dir:Path,)->tuple[list[Path],pd.DataFrame]:importrasteriofromrasterio.transformimportfrom_originoutput_dir=Path(output_dir)output_dir.mkdir(parents=True,exist_ok=True)x=np.asarray(depth_stack.coords["x"].values,dtype=float)y=np.asarray(depth_stack.coords["y"].values,dtype=float)iflen(x)<2orlen(y)<2ornotnp.all(np.diff(x)>0)ornotnp.all(np.diff(y)<0):raiseValueError("Consolidated raster coordinates must be x-ascending and y-descending")dx=float(np.median(np.diff(x)))dy=float(np.median(np.abs(np.diff(y))))transform=from_origin(x[0]-dx/2,y[0]+dy/2,dx,dy)nodata=np.float32(-9999.0)output_paths=[]audit_rows=[]expected_crs=rasterio.crs.CRS.from_user_input(depth_stack.attrs.get("crs"))forframe_index,time_valueinenumerate(depth_stack.coords["time"].values):timestamp=pd.Timestamp(time_value)output_path=output_dir/f"depth_{timestamp:%Y%m%d_%H%M%S}.tif"values=np.asarray(depth_stack.isel(time=frame_index).values,dtype=np.float32)write_values=np.where(np.isfinite(values),values,nodata).astype(np.float32)withrasterio.open(output_path,"w",driver="GTiff",height=write_values.shape[0],width=write_values.shape[1],count=1,dtype="float32",crs=depth_stack.attrs.get("crs"),transform=transform,nodata=float(nodata),compress="deflate",predictor=3,BIGTIFF="IF_SAFER",)asdst:dst.write(write_values,1)dst.update_tags(timestamp=timestamp.isoformat(),units=depth_stack.attrs.get("units",""))withrasterio.open(output_path)ascheck:assertcheck.crs==expected_crsassertcheck.transform.almost_equals(transform)assertnp.allclose(check.res,(dx,dy))assert(check.height,check.width)==write_values.shapeassertnp.isclose(check.nodata,float(nodata))assertcheck.tags().get("timestamp")==timestamp.isoformat()audit_rows.append({"timestamp":timestamp,"raster":output_path.name,"width":check.width,"height":check.height,"cell_size_ft":check.res[0],"size_mb":output_path.stat().st_size/1_000_000,})output_paths.append(output_path)returnoutput_paths,pd.DataFrame(audit_rows)defselect_reference_cell_by_depth_delta(event_plan_hdf:Path,baseline_plan_hdf:Path,mesh_name:str,)->tuple[int,pd.DataFrame]:"""Select the cell with the largest concurrent event-minus-baseline depth."""event_da=HdfResultsMesh.get_mesh_timeseries(event_plan_hdf,mesh_name,"Cell Hydraulic Depth",truncate=False)baseline_da=HdfResultsMesh.get_mesh_timeseries(baseline_plan_hdf,mesh_name,"Cell Hydraulic Depth",truncate=False)event_cells=np.asarray(event_da.coords["cell_id"].values,dtype=int)baseline_cells=np.asarray(baseline_da.coords["cell_id"].values,dtype=int)event_times=pd.to_datetime(event_da.coords["time"].values)baseline_times=pd.to_datetime(baseline_da.coords["time"].values)ifnotnp.array_equal(event_cells,baseline_cells):raiseValueError(f"Baseline and event cell IDs differ for mesh {mesh_name}")ifnotnp.array_equal(event_times,baseline_times):raiseValueError(f"Baseline and event output times differ for mesh {mesh_name}")event_depth=np.asarray(event_da.values,dtype=float)baseline_depth=np.asarray(baseline_da.values,dtype=float)depth_delta=event_depth-baseline_depthfinite=np.isfinite(depth_delta)peak_delta_by_cell=np.max(np.where(finite,depth_delta,-np.inf),axis=0)peak_delta_by_cell[~finite.any(axis=0)]=np.nanifnotnp.isfinite(peak_delta_by_cell).any():raiseRuntimeError(f"No finite event-minus-baseline depths found for mesh {mesh_name}")reference_idx=int(np.nanargmax(peak_delta_by_cell))peak_time_idx=int(np.nanargmax(depth_delta[:,reference_idx]))reference_cell_id=int(event_cells[reference_idx])selection=pd.DataFrame([{"mesh_name":mesh_name,"reference_cell_id":reference_cell_id,"selection_metric":"maximum concurrent event-minus-baseline depth","peak_response_time":event_times[peak_time_idx],"baseline_depth_ft":float(baseline_depth[peak_time_idx,reference_idx]),"event_depth_ft":float(event_depth[peak_time_idx,reference_idx]),"event_minus_baseline_depth_ft":float(depth_delta[peak_time_idx,reference_idx]),}])returnreference_cell_id,selectiondefbuild_reference_response(plan_hdf:Path,geom_hdf:Path,mesh_name:str,reference_cell_id:int|None=None,):depth_da=HdfResultsMesh.get_mesh_timeseries(plan_hdf,mesh_name,"Cell Hydraulic Depth",truncate=False)wse_da=HdfResultsMesh.get_mesh_timeseries(plan_hdf,mesh_name,"Water Surface",truncate=False)precip_da=HdfResultsMesh.get_mesh_timeseries(plan_hdf,mesh_name,"Cell Precipitation Rate",truncate=False)cumulative_precip_da=HdfResultsMesh.get_mesh_timeseries(plan_hdf,mesh_name,"Cell Cumulative Precipitation Depth",truncate=False)depth_values=np.asarray(depth_da.values,dtype=float)peak_by_cell=np.nanmax(depth_values,axis=0)ifnotnp.isfinite(peak_by_cell).any():raiseRuntimeError(f"No finite depth values found for mesh {mesh_name}")ifreference_cell_idisNone:reference_idx=int(np.nanargmax(peak_by_cell))reference_cell_id=int(depth_da.coords["cell_id"].values[reference_idx])else:cell_ids=np.asarray(depth_da.coords["cell_id"].values,dtype=int)matches=np.flatnonzero(cell_ids==int(reference_cell_id))ifnotlen(matches):raiseValueError(f"Cell {reference_cell_id} not found in mesh {mesh_name}")reference_idx=int(matches[0])reference_response=pd.DataFrame({"time":pd.to_datetime(depth_da.coords["time"].values),"depth_ft":depth_values[:,reference_idx],"wse_ft":np.asarray(wse_da.sel(cell_id=reference_cell_id).values,dtype=float),"precip_in_hr":np.asarray(precip_da.sel(cell_id=reference_cell_id).values,dtype=float),"cumulative_precip_in":np.asarray(cumulative_precip_da.sel(cell_id=reference_cell_id).values,dtype=float),})reference_response.attrs["mesh_name"]=mesh_namereference_response.attrs["cell_id"]=reference_cell_idcell_points=HdfMesh.get_mesh_cell_points(geom_hdf)reference_point=cell_points[(cell_points["mesh_name"]==mesh_name)&(cell_points["cell_id"]==reference_cell_id)].copy()returnreference_response,reference_point,reference_cell_iddefplot_reference_response(case:dict,hyetograph:pd.DataFrame,event_response:pd.DataFrame,baseline_response:pd.DataFrame,reference_point:gpd.GeoDataFrame,depth_stack,mesh_areas:gpd.GeoDataFrame,pump_stations:gpd.GeoDataFrame,):max_depth,max_extent,max_crs=max_depth_grid_from_stack(depth_stack)importmatplotlib.datesasmdatescell_id=event_response.attrs["cell_id"]mesh_name=event_response.attrs["mesh_name"]fig=plt.figure(figsize=(13,7),constrained_layout=True)grid=fig.add_gridspec(2,2,width_ratios=[1.25,1.0])ax_precip=fig.add_subplot(grid[0,0])ax_hydro=fig.add_subplot(grid[1,0],sharex=ax_precip)ax_map=fig.add_subplot(grid[:,1])ax_precip.bar(hyetograph["time"],hyetograph["incremental_depth"],width=0.035,color="#2b8cbe",label="Spatial mean MRMS",)ax_precip.set_ylabel("Incremental depth (in)")ax_precip.set_title(f"{case['display_name']} rainfall input")ax_precip.legend(loc="upper right")ax_hydro.plot(baseline_response["time"],baseline_response["depth_ft"],color="#636363",linestyle="--",label="No-rain depth")ax_hydro.plot(event_response["time"],event_response["depth_ft"],color="#08519c",label="MRMS-event depth")ax_hydro.set_ylabel("Depth (ft)")ax_hydro_wse=ax_hydro.twinx()ax_hydro_wse.plot(baseline_response["time"],baseline_response["wse_ft"],color="#969696",linestyle=":",label="No-rain WSE")ax_hydro_wse.plot(event_response["time"],event_response["wse_ft"],color="#238b45",label="MRMS-event WSE")ax_hydro_wse.set_ylabel("WSE (ft)")ax_hydro.set_title(f"Maximum rainfall-response cell {cell_id} hydrograph ({mesh_name})")ax_hydro.xaxis.set_major_locator(mdates.AutoDateLocator(minticks=4,maxticks=7))ax_hydro.xaxis.set_major_formatter(mdates.ConciseDateFormatter(ax_hydro.xaxis.get_major_locator()))lines=ax_hydro.get_lines()+ax_hydro_wse.get_lines()ax_hydro.legend(lines,[line.get_label()forlineinlines],loc="upper left",fontsize=8)vmax=max(float(np.nanpercentile(max_depth,98)),0.1)im=ax_map.imshow(max_depth,extent=max_extent,origin="upper",cmap="Blues",vmin=0,vmax=vmax,alpha=0.78,zorder=2,)ax_map.set_title("Maximum rainfall-response cell on event max-depth map")ax_map.set_xlabel("Easting (ft)")ax_map.set_ylabel("Northing (ft)")ax_map.set_aspect("equal",adjustable="box")PrecipMrms._plot_spatial_overlays(ax_map,data_crs=max_crs,mesh_boundary=mesh_areas,pump_stations=pump_stations,add_basemap=True,)ifnotreference_point.empty:plot_point=reference_point.to_crs(max_crs)ifmax_crsandreference_point.crselsereference_pointplot_point.plot(ax=ax_map,marker="*",color="#ffea00",edgecolor="black",markersize=160,zorder=8)fig.colorbar(im,ax=ax_map,shrink=0.8,label="Depth (ft)")plt.show()defget_pump_operation(plan_hdf:Path,pump_stations:gpd.GeoDataFrame)->dict[str,pd.DataFrame]:operations:dict[str,pd.DataFrame]={}ifpump_stations.emptyor"Name"notinpump_stations.columns:returnoperationsforstation_nameinpump_stations["Name"].dropna().astype(str):try:pump_da=HdfPump.get_pump_station_timeseries(plan_hdf,pump_station=station_name)exceptExceptionasexc:print(f"Pump operation unavailable for {station_name}: {exc}")continueframe=pd.DataFrame(np.asarray(pump_da.values,dtype=float),columns=[str(value)forvalueinpump_da.coords["variable"].values],)frame.insert(0,"time",pd.to_datetime(pump_da.coords["time"].values))frame.attrs["unit_by_variable"]=pump_da.attrs.get("unit_by_variable",{})operations[station_name]=framereturnoperationsdefplot_pump_operation(case:dict,event_operation:dict[str,pd.DataFrame],baseline_operation:dict[str,pd.DataFrame],)->pd.DataFrame:ifnotevent_operation:print(f"No pump operation time series available for {case['display_name']}")returnpd.DataFrame()importmatplotlib.datesasmdatesfig,axes=plt.subplots(len(event_operation),2,figsize=(13,3.5*len(event_operation)),squeeze=False,constrained_layout=True,)summary_rows=[]forrow_idx,(station_name,event_frame)inenumerate(event_operation.items()):baseline_frame=baseline_operation.get(station_name,pd.DataFrame())flow_col="Flow"if"Flow"inevent_frameelsenext((columnforcolumninevent_frame.columnsifcolumn.endswith(" Flow")),None)on_col="Pumps on"if"Pumps on"inevent_frameelsenext((columnforcolumninevent_frame.columnsifcolumn.endswith("Pumps on")),None)ax_flow=axes[row_idx,0]ifflow_colisnotNoneandnotbaseline_frame.emptyandflow_colinbaseline_frame:ax_flow.plot(baseline_frame["time"],baseline_frame[flow_col],color="#636363",linestyle="--",label="No-rain")ifflow_colisnotNone:ax_flow.plot(event_frame["time"],event_frame[flow_col],color="#08519c",label="MRMS event")ax_flow.set_title(f"{station_name} total pump flow")ax_flow.set_ylabel("Flow (cfs)")ax_flow.legend(loc="upper left",fontsize=8)ax_on=axes[row_idx,1]ifon_colisnotNoneandnotbaseline_frame.emptyandon_colinbaseline_frame:ax_on.step(baseline_frame["time"],baseline_frame[on_col],where="post",color="#636363",linestyle="--",label="No-rain")ifon_colisnotNone:ax_on.step(event_frame["time"],event_frame[on_col],where="post",color="#238b45",label="MRMS event")ax_on.set_title(f"{station_name} pump activation")ax_on.set_ylabel("Pumps on")ax_on.legend(loc="upper left",fontsize=8)foraxisin(ax_flow,ax_on):locator=mdates.AutoDateLocator(minticks=3,maxticks=5)axis.xaxis.set_major_locator(locator)axis.xaxis.set_major_formatter(mdates.ConciseDateFormatter(locator))event_peak_flow=float(event_frame[flow_col].max())ifflow_colelsenp.nanbaseline_peak_flow=(float(baseline_frame[flow_col].max())ifflow_colandnotbaseline_frame.emptyandflow_colinbaseline_frameelsenp.nan)event_on=event_frame[on_col]ifon_colelsepd.Series(0,index=event_frame.index)active=event_frame.loc[event_on>0,"time"]summary_rows.append({"station":station_name,"baseline_peak_flow_cfs":baseline_peak_flow,"event_peak_flow_cfs":event_peak_flow,"peak_flow_delta_cfs":event_peak_flow-baseline_peak_flow,"event_max_pumps_on":float(event_on.max())iflen(event_on)else0.0,"first_on":active.iloc[0]ifnotactive.emptyelsepd.NaT,"last_on":active.iloc[-1]ifnotactive.emptyelsepd.NaT,})fig.suptitle(f"No-rain baseline versus MRMS-event pump operation: {case['display_name']}")plt.show()returnpd.DataFrame(summary_rows)defdisplay_case_video_artifacts(case:dict,videos:list[tuple[str,Path]])->None:rows=[]forlabel,pathinvideos:path=Path(path)assertpath.exists()andpath.stat().st_size>0rows.append({"animation":label,"file":path.name,"size_mb":path.stat().st_size/1_000_000,})print(f"MP4 animations generated for {case['display_name']}:")display(pd.DataFrame(rows).round({"size_mb":2}))
2026-07-11 06:38:32 - ras_commander.RasUnsteady - INFO - Updated Precipitation Hydrograph in DavisStormSystem.u01: 37 time steps, interval=1HOUR, total depth=0.0000 inches
2026-07-11 06:38:32 - ras_commander.RasCmdr - INFO - Applied 'balanced' HDF settings profile to plan: DavisStormSystem.p02
Updated precipitation boundary: area2
Simulation window: 2022-12-31 00:00:00 to 2023-01-01 18:00:00
Output Interval: 5MIN
Instantaneous Interval: 5MIN
Mapping Interval: 5MIN
2026-07-11 06:39:40 - ras_commander.RasUnsteady - INFO - Updated Precipitation Hydrograph in DavisStormSystem.u01: 37 time steps, interval=1HOUR, total depth=1.7300 inches
2026-07-11 06:39:40 - ras_commander.RasCmdr - INFO - Applied 'balanced' HDF settings profile to plan: DavisStormSystem.p02
condition
expected_peak_rate_in_hr
hdf_peak_rate_in_hr
expected_total_in
hdf_final_total_in
max_applied_rate_spread
active_cell_fraction_at_peak
0
No-rain baseline
0.00
0.00
0.00
0.00
0.0
0.0000
1
MRMS event
0.22
0.22
1.73
1.73
0.0
0.9198
Text Only
Compute success: True
Plan HDF: G:\GH\ras-commander-wt-qpkit\working\CLB-642\examples_917_mrms_qpe_revisions\Davis_mrms_qpe_917_davis_ar\DavisStormSystem.p02.hdf
Total output timesteps: 505
Available consecutive 5-minute timesteps: 505
Selected map and animation frames: 30
Selected frame coverage: 31DEC2022 00:00:00 to 01JAN2023 18:00:00
Retrying 12 incomplete RAS Mapper timestamp(s) (attempt 1 of 2): {'all-nodata raster; blank while HDF is wet': 10, 'all-nodata raster': 1, 'no depth raster; unreadable raster; blank while HDF is wet': 1}
Retrying 5 incomplete RAS Mapper timestamp(s) (attempt 2 of 2): {'all-nodata raster; blank while HDF is wet': 4, 'all-nodata raster': 1}
2026-07-11 06:45:45 - ras_commander.hdf.HdfResultsMesh - INFO - Wrote 2 depth raster(s) for mesh 'area2'
RAS Mapper diagnostics handled by frame validation: errors=1, warnings=1
Replacing 2 incomplete timestamp(s) with plan-HDF depth rasters; no partial Mapper tile set is retained for those timestamps.
Showing first and last 3 of 30 rows
timestamp
terrain_tiles
dominant_present
mapper_max_depth_ft
hdf_max_depth_ft
valid
reason
0
31DEC2022 00:00:00
1
True
0.000000
0.000000
False
all-nodata raster
1
31DEC2022 01:25:00
1
True
0.000000
0.162791
False
all-nodata raster; blank while HDF is wet
2
31DEC2022 02:50:00
1
True
2.418030
0.329515
True
27
01JAN2023 15:05:00
1
True
3.542660
2.006750
True
28
01JAN2023 16:30:00
1
True
3.529881
2.001168
True
29
01JAN2023 18:00:00
1
True
3.530087
2.001368
True
Text Only
Showing first and last 3 of 30 rows
timestamp
terrain_tiles
total_raster_mb
rasters
source
0
2022-12-31 00:00:00
1
0.017832
Depth (31DEC2022 00 00 00).hdf.tif
HDF fallback
1
2022-12-31 01:25:00
1
0.127732
Depth (31DEC2022 01 25 00).hdf.tif
HDF fallback
2
2022-12-31 02:50:00
1
0.044542
Depth (31DEC2022 02 50 00).Terrain (1).Davis_t...
RAS Mapper
27
2023-01-01 15:05:00
1
0.053878
Depth (01JAN2023 15 05 00).Terrain (1).Davis_t...
RAS Mapper
28
2023-01-01 16:30:00
1
0.052488
Depth (01JAN2023 16 30 00).Terrain (1).Davis_t...
RAS Mapper
29
2023-01-01 18:00:00
1
0.051118
Depth (01JAN2023 18 00 00).Terrain (1).Davis_t...
RAS Mapper
Text Only
Showing first and last 3 of 30 rows
timestamp
raster
width
height
cell_size_ft
size_mb
0
2022-12-31 00:00:00
depth_20221231_000000.tif
682
569
28.845245
0.022989
1
2022-12-31 01:25:00
depth_20221231_012500.tif
682
569
28.845245
0.057809
2
2022-12-31 02:50:00
depth_20221231_025000.tif
682
569
28.845245
0.077873
27
2023-01-01 15:05:00
depth_20230101_150500.tif
682
569
28.845245
0.089363
28
2023-01-01 16:30:00
depth_20230101_163000.tif
682
569
28.845245
0.087853
29
2023-01-01 18:00:00
depth_20230101_180000.tif
682
569
28.845245
0.086547
Text Only
Showing first and last 3 of 30 rows
timestamp
wet_cells
wet_area_acres
max_depth_ft
mean_wet_depth_ft
hdf_max_depth_ft
wetness_matches_hdf
0
2022-12-31 00:00:00
0
0.000000
0.000000
0.000000
0.000000
True
1
2022-12-31 01:25:00
72459
1384.053652
0.502541
0.087701
0.162791
True
2
2022-12-31 02:50:00
9258
176.838884
2.418030
0.215997
0.329515
True
27
2023-01-01 15:05:00
11950
228.259307
3.542660
0.388752
2.006750
True
28
2023-01-01 16:30:00
11559
220.790739
3.529881
0.376261
2.001168
True
29
2023-01-01 18:00:00
11166
213.283969
3.530087
0.363610
2.001368
True
Text Only
RAS Mapper stored maps with 2 HDF gap fill(s): 30 source timesteps, 30 terrain tiles consolidated to 30 single 28.845-ft rasters
Consolidated raster folder: G:\GH\ras-commander-wt-qpkit\working\CLB-642\examples_917_mrms_qpe_revisions\Davis_mrms_qpe_917_davis_ar\ConsolidatedDepthFrames_30_28.845ft\davis_atmospheric_river
Terrain tiles per source timestep: min=1, median=1, max=1
Video: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\videos\mrms_precipitation_davis_atmospheric_river.mp4 (1,909,625 bytes)
Video: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\videos\flood_inundation_depth_davis_atmospheric_river_5min.mp4 (760,285 bytes)
Video: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\videos\combined_precip_flood_davis_atmospheric_river_5min.mp4 (1,084,085 bytes)
mesh_name
reference_cell_id
selection_metric
peak_response_time
baseline_depth_ft
event_depth_ft
event_minus_baseline_depth_ft
0
area2
600
maximum concurrent event-minus-baseline depth
2022-12-31 21:30:00
0.0
2.568577
2.568577
case
mesh_name
reference_cell_id
baseline_peak_depth_ft
event_peak_depth_ft
peak_depth_delta_ft
baseline_peak_wse_ft
event_peak_wse_ft
peak_wse_delta_ft
event_peak_precip_in_hr
0
davis_atmospheric_river
area2
600
0.0
2.568577
2.568577
37.542934
41.221306
3.678371
0.22
station
baseline_peak_flow_cfs
event_peak_flow_cfs
peak_flow_delta_cfs
event_max_pumps_on
first_on
last_on
0
Pump Station #1
0.0
67.364868
67.364868
1.0
2022-12-31 03:45:00
2023-01-01 18:00:00
Text Only
MP4 animations generated for Davis atmospheric river:
animation
file
size_mb
0
Precipitation only
mrms_precipitation_davis_atmospheric_river.mp4
1.91
1
Flood inundation only
flood_inundation_depth_davis_atmospheric_river...
0.76
2
Combined precipitation and flood
combined_precip_flood_davis_atmospheric_river_...
1.08
Python
results.append(run_mrms_case(CASES[1]))
Text Only
2026-07-11 06:47:05 - ras_commander.RasExamples - INFO - Downloading special project 'NewOrleansMetro'...
========================================================================================
NewOrleansMetro April 2024 flash flood
NWS New Orleans/Baton Rouge documented the 10 Apr 2024 New Orleans Metro severe thunderstorm and flash-flood event as a non-hurricane rainfall case.
2026-07-11 06:47:17 - ras_commander.RasExamples - INFO - Successfully extracted special project 'NewOrleansMetro' to NewOrleansMetro_mrms_qpe_917_nola_apr2024
Project folder: G:\GH\ras-commander-wt-qpkit\working\CLB-642\examples_917_mrms_qpe_revisions\NewOrleansMetro_mrms_qpe_917_nola_apr2024
Plan: 01; unsteady file: 01; geometry HDF: NewOrleansMetro.g02.hdf
Mesh areas: ['NewOrleans Metro']
HEC-RAS execution version: 7.0
mesh_name
mesh_cells
0
NewOrleans Metro
20486
Text Only
Pump stations: ['17th St Pumps', 'DPS 12']
Boundary conditions retained in both the no-rain baseline and MRMS event:
boundary_condition_number
area_2d
bc_line_name
bc_type
hydrograph_type
Interval
hydrograph_num_values
Use DSS
0
1
NewOrleans Metro
17th St Outflow
Stage Hydrograph
Stage Hydrograph
1DAY
41
False
1
2
NewOrleans Metro
Orleans Ouflow
Stage Hydrograph
Stage Hydrograph
1DAY
8
False
2
3
NewOrleans Metro
London Outflow
Stage Hydrograph
Stage Hydrograph
1DAY
8
False
3
4
NewOrleans Metro
Precipitation Hydrograph
Precipitation Hydrograph
1HOUR
100
False
4
5
Gate Opening
NaN
NaN
0
NaN
Text Only
Terrain mosaic order (1 is written first; later local detail takes precedence):
terrain
terrain_hdf
x_resolution
y_resolution
linear_units
valid_cells
nominal_resolution
mosaic_order
valid_coverage_sq_mi
0
NGOMTopoBathy-PCCPSurveys.NGOMTopoBathy New_PC...
NGOMTopoBathy-PCCPSurveys.hdf
3.280
3.280
US survey foot
76939264
3.28
1
29.691
1
NGOMTopoBathy-PCCPSurveys.NGOMTopoBathy New_PC...
NGOMTopoBathy-PCCPSurveys.hdf
2.000
2.000
US survey foot
596879
2.00
4
0.086
2
NGOMTopoBathy-PCCPSurveys.NGOMTopoBathy New_PC...
NGOMTopoBathy-PCCPSurveys.hdf
3.281
3.281
US survey foot
137189
3.28
2
0.053
3
NGOMTopoBathy-PCCPSurveys.NGOMTopoBathy New_PC...
NGOMTopoBathy-PCCPSurveys.hdf
3.279
3.279
US survey foot
46934
3.28
3
0.018
Text Only
Dominant terrain: NGOMTopoBathy-PCCPSurveys.NGOMTopoBathy New_PCCPSurveys.gom2022_coned_J1090780_clip.tif; native cell: 3.280 ft; consolidated cell: 10.000 ft
Project WGS84 bounds: (-90.18290001411526, 29.900389160096417, -90.04639080882717, 30.04210617844562)
MRMS download bounds: (-90.18290001411526, 29.900389160096417, -90.04639080882717, 30.04210617844562)
Showing first and last 3 of 24 rows
valid_time
product
archive_product
filename
size_bytes
compressed
0
2024-04-10 00:00:00
GaugeCorr_QPE_01H
MultiSensor_QPE_01H_Pass2_00.00
MRMS_MultiSensor_QPE_01H_Pass2_00.00_20240410-...
482186
True
1
2024-04-10 01:00:00
GaugeCorr_QPE_01H
MultiSensor_QPE_01H_Pass2_00.00
MRMS_MultiSensor_QPE_01H_Pass2_00.00_20240410-...
459145
True
2
2024-04-10 02:00:00
GaugeCorr_QPE_01H
MultiSensor_QPE_01H_Pass2_00.00
MRMS_MultiSensor_QPE_01H_Pass2_00.00_20240410-...
437204
True
21
2024-04-10 21:00:00
GaugeCorr_QPE_01H
MultiSensor_QPE_01H_Pass2_00.00
MRMS_MultiSensor_QPE_01H_Pass2_00.00_20240410-...
701986
True
22
2024-04-10 22:00:00
GaugeCorr_QPE_01H
MultiSensor_QPE_01H_Pass2_00.00
MRMS_MultiSensor_QPE_01H_Pass2_00.00_20240410-...
689638
True
23
2024-04-10 23:00:00
GaugeCorr_QPE_01H
MultiSensor_QPE_01H_Pass2_00.00
MRMS_MultiSensor_QPE_01H_Pass2_00.00_20240410-...
664050
True
Text Only
2026-07-11 06:47:38 - ras_commander.precip.PrecipMrms - INFO - Converting 24 MRMS GRIB2 file(s) to DSS via HEC-Vortex: G:\GH\ras-commander-wt-qpkit\working\CLB-642\examples_917_mrms_qpe_revisions\NewOrleansMetro_mrms_qpe_917_nola_apr2024\Precipitation\neworleans_april2024_flash_flood\neworleans_april2024_flash_flood_mrms_qpe.dss
2026-07-11 06:47:38 - ras_commander.precip.VortexCli - INFO - Importing 24 file(s) to DSS via HEC-Vortex: neworleans_april2024_flash_flood_mrms_qpe.dss
Downloaded 24 MRMS GRIB2 files
2026-07-11 06:47:48 - ras_commander.precip.VortexCli - INFO - DSS file created: neworleans_april2024_flash_flood_mrms_qpe.dss (152.0 KB)
Showing first and last 3 of 24 rows
2026-07-11 06:48:05 - ras_commander.RasUnsteady - INFO - Updated Precipitation Hydrograph in NewOrleansMetro.u01: 24 time steps, interval=1HOUR, total depth=0.0000 inches
2026-07-11 06:48:05 - ras_commander.RasCmdr - INFO - Applied 'balanced' HDF settings profile to plan: NewOrleansMetro.p01
Updated precipitation boundary: NewOrleans Metro
Simulation window: 2024-04-10 00:00:00 to 2024-04-11 06:00:00
Output Interval: 5MIN
Instantaneous Interval: 5MIN
Mapping Interval: 5MIN
2026-07-11 06:59:57 - ras_commander.RasUnsteady - INFO - Updated Precipitation Hydrograph in NewOrleansMetro.u01: 24 time steps, interval=1HOUR, total depth=4.1000 inches
2026-07-11 06:59:57 - ras_commander.RasCmdr - INFO - Applied 'balanced' HDF settings profile to plan: NewOrleansMetro.p01
condition
expected_peak_rate_in_hr
hdf_peak_rate_in_hr
expected_total_in
hdf_final_total_in
max_applied_rate_spread
active_cell_fraction_at_peak
0
No-rain baseline
0.00
0.00
0.0
0.0
0.0
0.0000
1
MRMS event
0.95
0.95
4.1
4.1
0.0
0.9622
Text Only
Compute success: True
Plan HDF: G:\GH\ras-commander-wt-qpkit\working\CLB-642\examples_917_mrms_qpe_revisions\NewOrleansMetro_mrms_qpe_917_nola_apr2024\NewOrleansMetro.p01.hdf
Total output timesteps: 361
Available consecutive 5-minute timesteps: 361
Selected map and animation frames: 30
Selected frame coverage: 10APR2024 00:00:00 to 11APR2024 06:00:00
Retrying 4 incomplete RAS Mapper timestamp(s) (attempt 1 of 2): {'dominant terrain missing; all-nodata raster; blank while HDF is wet': 4}
Retrying 3 incomplete RAS Mapper timestamp(s) (attempt 2 of 2): {'all-nodata raster': 2, 'dominant terrain missing; all-nodata raster; blank while HDF is wet': 1}
Replacing 3 incomplete timestamp(s) with plan-HDF depth rasters; no partial Mapper tile set is retained for those timestamps.
2026-07-11 07:29:07 - ras_commander.hdf.HdfResultsMesh - INFO - Wrote 3 depth raster(s) for mesh 'NewOrleans Metro'
Showing first and last 3 of 30 rows
timestamp
terrain_tiles
dominant_present
mapper_max_depth_ft
hdf_max_depth_ft
valid
reason
0
10APR2024 00:00:00
2
True
44.564072
22.845560
True
1
10APR2024 01:00:00
2
True
44.563969
22.845457
True
2
10APR2024 02:00:00
2
True
44.562614
22.844105
True
27
11APR2024 03:55:00
3
True
45.518265
23.798901
True
28
11APR2024 04:55:00
3
True
45.349087
23.629763
True
29
11APR2024 06:00:00
3
True
45.211082
23.491747
True
Text Only
Showing first and last 3 of 30 rows
timestamp
terrain_tiles
total_raster_mb
rasters
source
0
2024-04-10 00:00:00
2
1.654368
Depth (10APR2024 00 00 00).NGOMTopoBathy-PCCPS...
RAS Mapper
1
2024-04-10 01:00:00
2
1.697900
Depth (10APR2024 01 00 00).NGOMTopoBathy-PCCPS...
RAS Mapper
2
2024-04-10 02:00:00
2
1.680486
Depth (10APR2024 02 00 00).NGOMTopoBathy-PCCPS...
RAS Mapper
27
2024-04-11 03:55:00
3
20.237104
Depth (11APR2024 03 55 00).NGOMTopoBathy-PCCPS...
RAS Mapper
28
2024-04-11 04:55:00
3
19.584098
Depth (11APR2024 04 55 00).NGOMTopoBathy-PCCPS...
RAS Mapper
29
2024-04-11 06:00:00
3
18.938082
Depth (11APR2024 06 00 00).NGOMTopoBathy-PCCPS...
RAS Mapper
Text Only
Showing first and last 3 of 30 rows
timestamp
raster
width
height
cell_size_ft
size_mb
0
2024-04-10 00:00:00
depth_20240410_000000.tif
3611
4199
10.0
0.427427
1
2024-04-10 01:00:00
depth_20240410_010000.tif
3611
4199
10.0
0.429827
2
2024-04-10 02:00:00
depth_20240410_020000.tif
3611
4199
10.0
0.420459
27
2024-04-11 03:55:00
depth_20240411_035500.tif
3611
4199
10.0
6.872789
28
2024-04-11 04:55:00
depth_20240411_045500.tif
3611
4199
10.0
6.682877
29
2024-04-11 06:00:00
depth_20240411_060000.tif
3611
4199
10.0
6.495269
Text Only
Showing first and last 3 of 30 rows
timestamp
wet_cells
wet_area_acres
max_depth_ft
mean_wet_depth_ft
hdf_max_depth_ft
wetness_matches_hdf
0
2024-04-10 00:00:00
44879
103.028007
42.220322
10.144142
22.845560
True
1
2024-04-10 01:00:00
44862
102.988981
42.220219
10.147393
22.845457
True
2
2024-04-10 02:00:00
44842
102.943067
42.218864
10.151178
22.844105
True
27
2024-04-11 03:55:00
1643002
3771.813590
43.174515
1.075722
23.798901
True
28
2024-04-11 04:55:00
1580036
3627.263545
43.005337
1.081364
23.629763
True
29
2024-04-11 06:00:00
1518531
3486.067493
42.867332
1.084677
23.491747
True
Text Only
RAS Mapper stored maps with 3 HDF gap fill(s): 30 source timesteps, 76 terrain tiles consolidated to 30 single 10.000-ft rasters
Consolidated raster folder: G:\GH\ras-commander-wt-qpkit\working\CLB-642\examples_917_mrms_qpe_revisions\NewOrleansMetro_mrms_qpe_917_nola_apr2024\ConsolidatedDepthFrames_30_10.000ft\neworleans_april2024_flash_flood
Terrain tiles per source timestep: min=1, median=3, max=3
Video: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\videos\mrms_precipitation_neworleans_april2024_flash_flood.mp4 (1,456,776 bytes)
Video: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\videos\flood_inundation_depth_neworleans_april2024_flash_flood_5min.mp4 (1,146,308 bytes)
Video: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\videos\combined_precip_flood_neworleans_april2024_flash_flood_5min.mp4 (1,331,126 bytes)
mesh_name
reference_cell_id
selection_metric
peak_response_time
baseline_depth_ft
event_depth_ft
event_minus_baseline_depth_ft
0
NewOrleans Metro
17519
maximum concurrent event-minus-baseline depth
2024-04-10 15:40:00
0.0
19.675402
19.675402
case
mesh_name
reference_cell_id
baseline_peak_depth_ft
event_peak_depth_ft
peak_depth_delta_ft
baseline_peak_wse_ft
event_peak_wse_ft
peak_wse_delta_ft
event_peak_precip_in_hr
0
neworleans_april2024_flash_flood
NewOrleans Metro
17519
0.0
19.675402
19.675402
-30.0
-9.534735
20.465265
0.95
station
baseline_peak_flow_cfs
event_peak_flow_cfs
peak_flow_delta_cfs
event_max_pumps_on
first_on
last_on
0
17th St Pumps
0.0
2594.963867
2594.963867
4.0
2024-04-10 15:40:00
2024-04-11 06:00:00
1
DPS 12
0.0
265.646820
265.646820
1.0
2024-04-10 14:30:00
2024-04-11 06:00:00
Text Only
MP4 animations generated for NewOrleansMetro April 2024 flash flood:
The main workflow above uses ras-commander's PrecipMrms acquisition and HEC-Vortex DSS conversion. This section independently writes the same Davis MRMS event with qpkit v0.1.0, verifies the complete catalog count, and reads the deterministic peak-hour spatial record through RasDss.read_grid(). It verifies an exact grid value and complete metadata without replacing the primary ras-commander workflow.
qpkit is an optional Apache-2.0 package by Gyan Basyal / WEST Consultants. Install the reviewed release in the terminal with uv pip install "git+https://github.com/gyanz/[email protected]". The execution below deletes its prior DSS output first, requires a complete write with no failed records, and prints a concise summary instead of qpkit's per-file INFO stream.
Python
importjsonfromdatetimeimporttimezonetry:importqpkitfrompydsstools.core.crsimportshgfromqpkitimportBoundingBox,QPERequest,QPKitfromqpkit.modelsimportQPEGridOptionsexceptImportErrorasexc:raiseImportError('This optional verification requires qpkit v0.1.0. Install it in the terminal with: ''uv pip install "git+https://github.com/gyanz/[email protected]"')fromexcassertqpkit.__version__.split('+',1)[0]=="0.1.0",qpkit.__version__davis=CASES[0]qpkit_dir=RUN_ROOT/"qpkit_v010_davis_mrms"qpkit_grib_dir=qpkit_dir/"grib2"qpkit_grib_dir.mkdir(parents=True,exist_ok=True)qpkit_dss=qpkit_dir/"davis_mrms_qpe_v010.dss"qpkit_dss.unlink(missing_ok=True)request=QPERequest(product="MultiSensor_Pass2",interval=1,start=davis["event_start"].replace(tzinfo=timezone.utc),end=davis["event_last_qpe"].replace(tzinfo=timezone.utc),source="aws",)options=QPEGridOptions(part_a="MRMS",part_b=davis["dss_b"],part_c="PRECIP",part_f=f"{davis['dss_f']}_QPKIT",crs=shg(),cell_size=None,extents=BoundingBox(left_lon=DAVIS_BOUNDS[0],bottom_lat=DAVIS_BOUNDS[1],right_lon=DAVIS_BOUNDS[2],top_lat=DAVIS_BOUNDS[3],),)qpkit_logger=logging.getLogger("qpkit")previous_qpkit_level=qpkit_logger.levelqpkit_logger.setLevel(logging.WARNING)try:withQPKit()askit:qpkit_result=kit.download_to_dss(request,qpkit_grib_dir,qpkit_dss,grid_options=options,dss_version=6,)finally:qpkit_logger.setLevel(previous_qpkit_level)expected_qpkit_records=int((davis["event_last_qpe"]-davis["event_start"]).total_seconds()//3600)+1assertnotqpkit_result.download.failed,qpkit_result.download.failedassertnotqpkit_result.dss.failed,qpkit_result.dss.failedassertlen(qpkit_result.dss.written)==expected_qpkit_recordsassertqpkit_dss.exists()andqpkit_dss.stat().st_size>0qpkit_catalog=RasDss.get_catalog(qpkit_dss)assertlen(qpkit_catalog)==expected_qpkit_recordsdavis_peak_end=results[0]["dss_grid_audit"].loc[results[0]["dss_grid_audit"]["mean_mm"].idxmax(),"end_time"]peak_end_part=pd.Timestamp(davis_peak_end).strftime("%d%b%Y:%H%M").upper()matching_pathnames=[pathnameforpathnameinqpkit_catalog["pathname"].astype(str)ifpathname.split("/")[5].upper()==peak_end_part]assertlen(matching_pathnames)==1,matching_pathnamesqpkit_grid=RasDss.read_grid(qpkit_dss,matching_pathnames[0])qpkit_values=np.asarray(qpkit_grid["data"],dtype=float)assertnp.isfinite(qpkit_values).any()qpkit_row,qpkit_col=np.unravel_index(np.nanargmax(qpkit_values),qpkit_values.shape)qpkit_value=float(qpkit_values[qpkit_row,qpkit_col])qpkit_metadata=qpkit_grid["metadata"]assertqpkit_value>0assertqpkit_grid["units"].upper()=="MM"assertqpkit_grid["data_type"].upper()=="PER-CUM"assertqpkit_grid["grid_type"]=="albers"print(f"Verified exact qpkit pathname: {matching_pathnames[0]}")qpkit_readback={"pathname":matching_pathnames[0],"indexed_value":{"row":int(qpkit_row),"column":int(qpkit_col),"value_mm":qpkit_value,},"units":qpkit_grid["units"],"data_type":qpkit_grid["data_type"],"grid_type":qpkit_grid["grid_type"],"crs":qpkit_grid["crs"],"cell_size":qpkit_grid["cell_size"],"shape":qpkit_grid["shape"],"origin":qpkit_metadata["origin"],"lower_left_cell":qpkit_metadata["lower_left_cell"],"missing_values":qpkit_metadata["number_missing"],"nodata_value":qpkit_metadata["nodata_value"],}print("Verified qpkit grid metadata (non-truncated):")print(json.dumps(qpkit_readback,indent=2))display(pd.DataFrame([{"row":int(qpkit_row),"column":int(qpkit_col),"value_mm":qpkit_value,"units":qpkit_grid["units"],"data_type":qpkit_grid["data_type"],"grid_type":qpkit_grid["grid_type"],"crs":qpkit_grid["crs"],"cell_size":qpkit_grid["cell_size"],"shape":qpkit_grid["shape"],"origin":qpkit_metadata["origin"],"lower_left_cell":qpkit_metadata["lower_left_cell"],"missing_values":qpkit_metadata["number_missing"],"nodata_value":qpkit_metadata["nodata_value"],}]))print(f"qpkit {qpkit.__version__}: "f"downloaded={len(qpkit_result.download.succeeded)}, "f"cached={len(qpkit_result.download.skipped)}, "f"DSS grids written={len(qpkit_result.dss.written)}, "f"catalog records={len(qpkit_catalog)}")print(f"Fresh DSS output: {qpkit_dss}")ifqpkit_result.download.skipped:print("qpkit reused cached source grids; the DSS file above was deleted and recreated in this run.")display_preview(qpkit_catalog)
qpkit 0.1.0: downloaded=0, cached=37, DSS grids written=37, catalog records=37
Fresh DSS output: C:\Users\bill\.config\superpowers\worktrees\ras-commander\codex-dss-qpkit-precip-replay\working\CLB-642\examples_917_mrms_qpe_revisions\qpkit_v010_davis_mrms\davis_mrms_qpe_v010.dss
qpkit reused cached source grids; the DSS file above was deleted and recreated in this run.
Showing first and last 3 of 37 rows