Skip to content

Pipes and Pumps

Overview

This notebook demonstrates extracting results for hydraulic structures within 2D flow areas: pipes, culverts, and pump stations. These structures convey flow through or around 2D mesh areas.

Structure Types in 2D Areas: - SA/2D Connections: Connect storage areas to 2D areas - Lateral Structures: Weirs, gates, culverts between 2D areas - Pump Stations: Mechanical pumps (rating curve or multi-stage) - Culverts: Buried conduits (can pressure flow)

HDF5 Structure for Hydraulic Structures

Text Only
/Results/Unsteady/Output/
├── Output Blocks/
│   └── Base Output/
│       └── Unsteady Time Series/
│           ├── SA/2D Connections/
│           │   └── {Connection Name}/
│           │       ├── Flow/              # Flow through connection
│           │       ├── Velocity/          # Average velocity
│           │       └── Upstream Water Surface/
│           ├── Pump Stations/
│           │   └── {Pump Name}/
│           │       ├── Flow/
│           │       ├── Status/            # On/off status
│           │       └── Power/             # Power consumption
│           └── 2D Area Connections/
│               └── {Structure Name}/
│                   ├── Flow/
│                   ├── Headwater/         # Upstream WSE
│                   └── Tailwater/         # Downstream WSE

Key Structure Datasets: - Flow: Discharge through structure (cfs or cms) - Headwater/Tailwater: WSE upstream and downstream - Velocity: Average flow velocity - Pump Status: Operating state (on/off/cycling)

Reference Documentation

Common Use Cases

  • Stormwater Networks: Pipes/culverts in urban drainage
  • Flood Control: Pump stations for interior drainage
  • Highway Crossings: Road culverts through 2D floodplains
  • Levee Systems: Closures and pump-around structures
Python
# =============================================================================
# DEVELOPMENT MODE TOGGLE
# =============================================================================
USE_LOCAL_SOURCE = False  # <-- TOGGLE THIS

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")

# Import ras-commander
from ras_commander import HdfBase, HdfMesh, HdfPipe, HdfPump, HdfResultsPlan, HdfUtils, RasCmdr, RasExamples, init_ras_project, ras

# Verify which version loaded
import ras_commander
print(f"✓ Loaded: {ras_commander.__file__}")
Text Only
📦 PIP PACKAGE MODE: Loading installed ras-commander


2026-05-23 08:54:05 - numexpr.utils - INFO - NumExpr defaulting to 8 threads.


✓ Loaded: C:\GH\symphony-workspaces\ras-commander\CLB-852\ras_commander\__init__.py

Parameters

Configure these values to customize the notebook for your project.

Python
# =============================================================================
# PARAMETERS - Edit these to customize the notebook
# =============================================================================

# Project Configuration
PROJECT_NAME = "Davis"           # Example project to extract
RAS_VERSION = "7.0"               # HEC-RAS version (6.3, 6.5, 6.6, etc.)

# HDF Analysis Settings
PLAN = "02"                       # Plan number (for HDF file path)
TIME_INDEX = -1                   # Time step index (-1 = last)
PROFILE = "Max"                   # Profile name for steady analysis
Python
import os
import sys
from pathlib import Path
import h5py
import numpy as np
import pandas as pd
import requests
from tqdm import tqdm
import scipy
import xarray as xr
import geopandas as gpd
import matplotlib.pyplot as plt
from IPython import display
import psutil  # For getting system CPU info
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
import subprocess
import shutil
from datetime import datetime, timedelta
from pathlib import Path  # Ensure pathlib is imported for file operations
import pyproj
from shapely.geometry import Point, LineString, Polygon

Use Example Project or Load Your Own Project

Python
# Extract or reuse the Davis example project.
try:
    from _notebook_prereqs import ensure_plan_result_hdf, get_or_extract_example_project
except ModuleNotFoundError:
    import sys

    examples_dir = Path.cwd() if Path.cwd().name == "examples" else Path.cwd() / "examples"
    if examples_dir.exists() and str(examples_dir) not in sys.path:
        sys.path.insert(0, str(examples_dir))
    from _notebook_prereqs import ensure_plan_result_hdf, get_or_extract_example_project

pipes_ex_path = get_or_extract_example_project(PROJECT_NAME, suffix="12")
print(f"Extracted project path: {pipes_ex_path}")

# Verify the path exists
print(f"Davis project exists: {pipes_ex_path.exists()}")

# Initialize the RAS project (Pipe Networks are only supported in versions 6.6 and above)
import logging
init_ras_project(pipes_ex_path, RAS_VERSION)
logging.info(f"Davis project initialized with folder: {ras.project_folder}")

# Ensure the required results HDF is present before analysis cells run.
plan_number = PLAN
plan_hdf = ensure_plan_result_hdf(
    plan_number,
    ras_object=ras,
    num_cores=2,
    clear_geompre=False,
)
print(f"Plan HDF: {plan_hdf}")
Text Only
2026-05-23 08:54:07 - ras_commander.RasExamples - INFO - Successfully extracted project 'Davis' to c:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 7.0 at C:\Program Files (x86)\HEC\HEC-RAS\7.0\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.7 Beta 5 at C:\Program Files (x86)\HEC\HEC-RAS\6.7 Beta 5\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.7 Beta 4 at C:\Program Files (x86)\HEC\HEC-RAS\6.7 Beta 4\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.5 at C:\Program Files (x86)\HEC\HEC-RAS\6.5\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.4.1 at C:\Program Files (x86)\HEC\HEC-RAS\6.4.1\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.3.1 at C:\Program Files (x86)\HEC\HEC-RAS\6.3.1\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.3 at C:\Program Files (x86)\HEC\HEC-RAS\6.3\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.2 at C:\Program Files (x86)\HEC\HEC-RAS\6.2\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.1 at C:\Program Files (x86)\HEC\HEC-RAS\6.1\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.0 at C:\Program Files (x86)\HEC\HEC-RAS\6.0\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 5.0.7 at C:\Program Files (x86)\HEC\HEC-RAS\5.0.7\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 5.0.6 at C:\Program Files (x86)\HEC\HEC-RAS\5.0.6\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 5.0.5 at C:\Program Files (x86)\HEC\HEC-RAS\5.0.5\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 5.0.4 at C:\Program Files (x86)\HEC\HEC-RAS\5.0.4\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 5.0.3 at C:\Program Files (x86)\HEC\HEC-RAS\5.0.3\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 5.0.1 at C:\Program Files (x86)\HEC\HEC-RAS\5.0.1\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 5.0 at C:\Program Files (x86)\HEC\HEC-RAS\5.0\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 4.1.0 at C:\Program Files (x86)\HEC\HEC-RAS\4.1.0\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 4.0 at C:\Program Files (x86)\HEC\HEC-RAS\4.0\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered HEC-RAS 6.6 at C:\Program Files (x86)\HEC\HEC-RAS\6.6\Ras.exe via filesystem (x86)


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Discovered 20 installed HEC-RAS version(s)


2026-05-23 08:54:07 - ras_commander.RasPrj - INFO - HEC-RAS 7.0 found via version discovery: C:\Program Files (x86)\HEC\HEC-RAS\7.0\Ras.exe


2026-05-23 08:54:07 - ras_commander.RasMap - INFO - Successfully parsed RASMapper file: C:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12\DavisStormSystem.rasmap


Extracted project to: c:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12
Davis project exists: True


2026-05-23 08:54:07 - ras_commander.RasPrj - INFO - ras-commander v0.96.2 | An open-source project of CLB Engineering Corporation (https://clbengineering.com/) | Docs: https://ras-commander.readthedocs.io | GitHub: https://github.com/gpt-cmdr/ras-commander


2026-05-23 08:54:07 - ras_commander.RasPrj - INFO - Project initialized: DavisStormSystem | Folder: C:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12


2026-05-23 08:54:07 - ras_commander.RasPrj - INFO - Using HEC-RAS executable: C:\Program Files (x86)\HEC\HEC-RAS\7.0\Ras.exe


2026-05-23 08:54:07 - ras_commander.RasPrj - INFO - 
═══════════════════════════════════════════════════════════════════════
ras-commander | HEC-RAS Automation Library
Docs: https://gpt-cmdr.github.io/ras-commander/
Repo: https://github.com/gpt-cmdr/ras-commander
═══════════════════════════════════════════════════════════════════════

PROJECT DATAFRAMES (single source of truth — use these, not file globbing):
  ras.plan_df        Plans, HDF paths, geometry/flow associations
  ras.geom_df        Geometry files and HDF preprocessor paths
  ras.flow_df        Steady flow files
  ras.unsteady_df    Unsteady flow files and configurations
  ras.boundaries_df  Boundary conditions (type, name, location)
  ras.results_df     Lightweight HDF results summaries
  ras.rasmap_df      RASMapper layers, terrain, land cover paths

KEY APIS (static classes — call directly, never instantiate):
  Execution:    RasCmdr.compute_plan() / compute_parallel() / compute_test_mode()
  Plan Files:   RasPlan.clone_plan() / clone_geom() / set_geom()
  Unsteady:     RasUnsteady — IC/BC management, gate openings, precipitation
  Geometry:     GeomCrossSection, GeomBridge, GeomStorage, GeomLateral, GeomMesh
  HDF Results:  HdfResultsPlan.get_wse() / get_compute_messages()
                HdfResultsMesh.get_mesh_max_ws() / get_mesh_cells_timeseries()
                HdfMesh.get_mesh_cell_points()
  QA/QC:        RasCheck.run_check() / RasFixit (geometry repair)
  DSS:          RasDss.get_timeseries() / check_pathname()
  USGS:         UsgsGaugeSpatial, GaugeMatcher, RasUsgsBoundaryGeneration
  Precipitation: StormGenerator, Atlas14Storm, PrecipAorc, Atlas14Variance
  Terrain:      RasTerrain.create_terrain_hdf() / RasTerrainMod

MULTI-PROJECT: Pass ras_object= to all API calls when using local RasPrj instances.

EXAMPLES: 100+ notebooks in examples/ (100s=execution, 200s=geometry, 300s=unsteady,
  400s=HDF results, 500s=remote, 800s=QA/QC, 900s=data integration).
  Review relevant notebooks before assembling new workflows.

PLATFORM: Most HEC-RAS operations require Windows. Linux/Wine support for
  headless execution, data access, geometry modification, and preprocessing
  is available via RasProcess (HEC-RAS 6.6+). See ras_commander/RasProcess.py.
  Remote distributed execution: ras_commander/remote/ (PsExec, Docker, SSH, cloud).
═══════════════════════════════════════════════════════════════════════


2026-05-23 08:54:07 - root - INFO - Davis project initialized with folder: C:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12


2026-05-23 08:54:07 - ras_commander.RasCmdr - INFO - Using ras_object with project folder: C:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12


2026-05-23 08:54:07 - ras_commander.RasUtils - INFO - Successfully updated file: C:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12\DavisStormSystem.p02


2026-05-23 08:54:07 - ras_commander.RasCmdr - INFO - Set number of cores to 2 for plan: 02


2026-05-23 08:54:07 - ras_commander.RasCmdr - INFO - Running HEC-RAS from the Command Line:


2026-05-23 08:54:07 - ras_commander.RasCmdr - INFO - Running command: "C:\Program Files (x86)\HEC\HEC-RAS\7.0\Ras.exe" -c "C:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12\DavisStormSystem.prj" "C:\GH\symphony-workspaces\ras-commander\CLB-852\examples\example_projects\Davis_12\DavisStormSystem.p02"


2026-05-23 08:57:15 - ras_commander.RasCmdr - INFO - HEC-RAS execution completed for plan: 02


2026-05-23 08:57:15 - ras_commander.RasCmdr - INFO - Total run time for plan 02: 187.43 seconds





ComputeResult(SUCCESS, results_df_row=available)

OPTIONAL: Use your own project instead

your_project_path = Path(r"D:\yourprojectpath")

init_ras_project(your_project_path, "6.6") plan_number = "01" # Plan number to use for this notebook

If you use this code cell, don't run the previous cell or change to markdown

NOTE: Ensure the HDF Results file was generated by HEC-RAS Version 6.x or above

Python

Python

Explore Project Dataframes using 'ras' Object

Python
print("Plan DataFrame for the project:")
ras.plan_df
Text Only
Plan DataFrame for the project:
plan_number unsteady_number geometry_number Plan Title Program Version Short Identifier Simulation Date Computation Interval Mapping Interval Run HTab ... DSS File Friction Slope Method UNET D2 SolverType UNET D2 Name HDF_Results_Path Geom File Geom Path Flow File Flow Path full_path
0 02 01 02 Full System ROM with Pump 6.60 Full System ROM with Pump 10JAN2000,1200,11JAN2000,2400 12SEC 10MIN -1 ... dss 1 PARDISO (Direct) area2 C:\GH\symphony-workspaces\ras-commander\CLB-85... 02 C:\GH\symphony-workspaces\ras-commander\CLB-85... 01 C:\GH\symphony-workspaces\ras-commander\CLB-85... C:\GH\symphony-workspaces\ras-commander\CLB-85...

1 rows × 34 columns

Python
print("\nUnsteady DataFrame for the project:")
ras.unsteady_df
Text Only
Unsteady DataFrame for the project:
unsteady_number full_path Flow Title Program Version Use Restart Precipitation Mode Wind Mode Met BC=Precipitation|Mode Met BC=Evapotranspiration|Mode Met BC=Precipitation|Expanded View Met BC=Precipitation|Constant Units Met BC=Precipitation|Gridded Source description
0 01 C:\GH\symphony-workspaces\ras-commander\CLB-85... Full System Rain w/ Pump 6.60 0 Disable No Wind Forces Constant None -1 in/hr DSS
Python
print("\nBoundary Conditions DataFrame for the project:")
ras.boundaries_df 
Text Only
Boundary Conditions DataFrame for the project:
unsteady_number boundary_condition_number river_reach_name river_station storage_area_name pump_station_name area_2d bc_line_name bc_type hydrograph_type ... Program Version Use Restart Precipitation Mode Wind Mode Met BC=Precipitation|Mode Met BC=Evapotranspiration|Mode Met BC=Precipitation|Expanded View Met BC=Precipitation|Constant Units Met BC=Precipitation|Gridded Source description
0 01 1 DS Channel DS Normal Normal Depth NaN ... 6.60 0 Disable No Wind Forces Constant None -1 in/hr DSS
1 01 2 area2 Precipitation Hydrograph Precipitation Hydrograph ... 6.60 0 Disable No Wind Forces Constant None -1 in/hr DSS

2 rows × 34 columns

Python
# Get HDF Results Entries (only present when results are present)
ras.get_hdf_entries()
plan_number unsteady_number geometry_number Plan Title Program Version Short Identifier Simulation Date Computation Interval Mapping Interval Run HTab ... DSS File Friction Slope Method UNET D2 SolverType UNET D2 Name HDF_Results_Path Geom File Geom Path Flow File Flow Path full_path
0 02 01 02 Full System ROM with Pump 6.60 Full System ROM with Pump 10JAN2000,1200,11JAN2000,2400 12SEC 10MIN -1 ... dss 1 PARDISO (Direct) area2 C:\GH\symphony-workspaces\ras-commander\CLB-85... 02 C:\GH\symphony-workspaces\ras-commander\CLB-85... 01 C:\GH\symphony-workspaces\ras-commander\CLB-85... C:\GH\symphony-workspaces\ras-commander\CLB-85...

1 rows × 34 columns

Find Paths for Results and Geometry HDF's

Python
# Get the plan HDF path for the plan_number defined above
plan_hdf_path = ras.plan_df.loc[ras.plan_df['plan_number'] == plan_number, 'HDF_Results_Path'].values[0]
Python
plan_hdf_path
Text Only
'C:\\GH\\symphony-workspaces\\ras-commander\\CLB-852\\examples\\example_projects\\Davis_12\\DavisStormSystem.p02.hdf'
Python
# Alternate: Get the geometry HDF path if you are extracting geometry elements from the geometry HDF
geom_hdf_path = ras.plan_df.loc[ras.plan_df['plan_number'] == plan_number, 'Geom Path'].values[0] + '.hdf'
Python
geom_hdf_path
Text Only
'C:\\GH\\symphony-workspaces\\ras-commander\\CLB-852\\examples\\example_projects\\Davis_12\\DavisStormSystem.g02.hdf'
Python
# Extract runtime and compute time data
print("\nExtracting runtime and compute time data")
runtime_df = HdfResultsPlan.get_runtime_data(hdf_path=plan_number)
runtime_df
Text Only
Extracting runtime and compute time data
Plan Name File Name Simulation Start Time Simulation End Time Simulation Duration (s) Simulation Time (hr) Completing Geometry (hr) Preprocessing Geometry (hr) Completing Event Conditions (hr) Unsteady Flow Computations (hr) Complete Process (hr) Unsteady Flow Speed (hr/hr) Complete Process Speed (hr/hr)
0 Full System ROM with Pump DavisStormSystem.p02.hdf 2000-01-10 12:00:00 2000-01-12 129600.0 36.0 N/A 0.00003 N/A 0.050751 0.051632 709.347958 697.246522

2D Models with Pipe Networks: HDF Data Extraction Examples

Python
# Get pipe conduits
pipe_conduits_gdf = HdfPipe.get_pipe_conduits("02") # NOTE: Here we use the plan number instead of the path variable.  The library decorators ensure this maps correctly.  
print("\nPipe Conduits: pipe_conduits_gdf")
pipe_conduits_gdf
Text Only
Pipe Conduits: pipe_conduits_gdf
Name System Name US Node DS Node Modeling Approach Conduit Length Max Cell Length Shape Rise Span ... US Entrance Loss Coefficient DS Exit Loss Coefficient US Backflow Loss Coefficient DS Backflow Loss Coefficient DS Gate Type Major Group Minor Group DS Flap Gate Polyline Terrain_Profiles
0 134 Davis O13-DMH007 O13-DMH006 Hydraulic 443.740020 40.0 Circular 6.00 6.00 ... 0.2 0.4 0.2 0.4 None Major Group 2 0 LINESTRING (6635295.441 1965214.2465, 6635196.... [(0.0, 40.819695), (21.217846, 40.642994), (35...
1 133 Davis O13-DMH024 O13-DMH009 Hydraulic 800.000024 40.0 Circular 6.00 6.00 ... 0.2 0.4 0.2 0.4 None Major Group 2 0 LINESTRING (6635597.5485 1964008.2795, 6635403... [(0.0, 40.530186), (21.1467, 40.44057), (50.88...
2 132 Davis O13-DMH006 O13-SDS03 Hydraulic 443.740070 40.0 Circular 6.00 6.00 ... 0.2 0.4 0.2 0.4 None Major Group 2 0 LINESTRING (6635196.5532 1965646.8276, 6635131... [(0.0, 41.700996), (26.817467, 41.552666), (83...
3 131 Davis N13-DMH022 O13-SDS03 Hydraulic 982.809915 40.0 Circular 6.00 6.00 ... 0.2 0.4 0.2 0.4 None Major Group 0 LINESTRING (6634067.2602 1966167.7235, 6634761... [(0.0, 43.376995), (17.315952, 43.37471), (42....
4 130 Davis O13-DMH009 O13-DMH007 Hydraulic 443.231808 40.0 Circular 6.00 6.00 ... 0.2 0.4 0.2 0.4 None Major Group 2 0 LINESTRING (6635403.0525 1964784.2765, 6635295... [(0.0, 40.699738), (84.2007, 40.623585), (113....
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
127 5 Davis P13-DI019 P13-DMH014 Hydraulic 55.979169 40.0 Circular 1.25 1.25 ... 0.2 0.4 0.2 0.4 None 0 LINESTRING (6634655.8786 1962994.2229, 6634695... [(0.0, 42.047863), (35.334522, 42.0), (55.9791...
128 4 Davis O14-DI083 O14-DI081 Hydraulic 308.809005 40.0 Circular 1.25 1.25 ... 0.2 0.4 0.2 0.4 None 0 LINESTRING (6637776.3431 1963594.9664, 6637752... [(0.0, 44.843853), (33.0322, 44.765797), (94.1...
129 3 Davis P12-DI011 P12-DMH005 Hydraulic 131.688547 40.0 Circular 1.25 1.25 ... 0.2 0.4 0.2 0.4 None 0 LINESTRING (6631602.9099 1963059.1324, 6631558... [(0.0, 43.631783), (13.137807, 43.916145), (18...
130 2 Davis P12-DI012 P12-DI011 Hydraulic 97.998216 40.0 Circular 1.25 1.25 ... 0.2 0.4 0.2 0.4 None 0 LINESTRING (6631662.213 1962981.1145, 6631602.... [(0.0, 43.573406), (11.616912, 43.510483), (47...
131 1 Davis P12-DI041 P12-DI042 Hydraulic 106.331064 40.0 Circular 1.25 1.25 ... 0.2 0.4 0.2 0.4 None 0 LINESTRING (6631979.2535 1962977.423, 6632043.... [(0.0, 43.332245), (16.201994, 43.217068), (47...

132 rows × 26 columns

Python
# Plot the pipe conduit linestrings
import matplotlib.pyplot as plt

# Create a new figure with a specified size
plt.figure(figsize=(12, 9))

# Plot each linestring from the GeoDataFrame
for idx, row in pipe_conduits_gdf.iterrows():
    # Extract coordinates from the linestring
    x_coords, y_coords = row['Polyline'].xy

    # Plot the linestring
    plt.plot(x_coords, y_coords, 'b-', linewidth=1, alpha=0.7)

    # Add vertical line markers at endpoints
    plt.plot([x_coords[0]], [y_coords[0]], 'x', color='black', markersize=4)
    plt.plot([x_coords[-1]], [y_coords[-1]], 'x', color='black', markersize=4)

    # Calculate center point of the line
    center_x = (x_coords[0] + x_coords[-1]) / 2
    center_y = (y_coords[0] + y_coords[-1]) / 2

    # Add pipe name label at center, oriented top-right
    plt.text(center_x, center_y, f'{row["Name"]}', fontsize=8, 
             verticalalignment='bottom', horizontalalignment='left',
             rotation=45)  # 45 degree angle for top-right orientation

# Add title and labels
plt.title('Pipe Conduit Network Layout')
plt.xlabel('Easting')
plt.ylabel('Northing')

# Add grid
plt.grid(True, linestyle='--', alpha=0.6)

# Adjust layout to prevent label clipping
plt.tight_layout()

# Display the plot
plt.show()

png

Python
# Plot the first 2 terrain profiles
import matplotlib.pyplot as plt

# Extract terrain profiles from the GeoDataFrame
terrain_profiles = pipe_conduits_gdf['Terrain_Profiles'].tolist()

# Create separate plots for the first 2 terrain profiles
for i in range(2):
    profile = terrain_profiles[i]

    # Unzip the profile into x and y coordinates
    x_coords, y_coords = zip(*profile)

    # Create a new figure for each profile
    plt.figure(figsize=(12, 6))
    plt.plot(x_coords, y_coords, marker='o', linestyle='-', color='g', alpha=0.7)

    # Add title and labels
    plt.title(f'Terrain Profile {i + 1}')
    plt.xlabel('Distance along profile (m)')
    plt.ylabel('Elevation (m)')

    # Add grid
    plt.grid(True, linestyle='--', alpha=0.6)

    # Adjust layout to prevent label clipping
    plt.tight_layout()

    # Display the plot
    plt.show()

png

png

Python
# Use get_hdf5_dataset_info function to get Pipe Conduits data:
#HdfUtils.get_hdf5_dataset_info(plan_hdf_path, "/Geometry/Pipe Nodes/")
Python
# Get pipe nodes
pipe_nodes_gdf = HdfPipe.get_pipe_nodes(plan_hdf_path)
print("\nPipe Nodes:")
pipe_nodes_gdf
Text Only
Pipe Nodes:
Name System Name Node Type Node Status Condtui Connections (US:DS) Invert Elevation Base Area Terrain Elevation Terrain Elevation Override Depth Top Inlet Type Top Inlet Elevation Side Inlet Type Side Inlet Elevation Total Connection Count geometry
0 O14-di027 Davis Junction Junction -with top inlet 1:1 36.060001 36.0 39.860001 NaN 3.799999 Top Inlet 1 39.863369 NaN 2 POINT (6637926.8105 1964917.3197)
1 P11-DMH004 Davis Junction Junction -with top inlet 1:1 38.169998 36.0 48.720001 NaN 10.550003 Top Inlet 1 48.718811 NaN 2 POINT (6629444.6337 1963504.411)
2 O14-DMH005 Davis Junction Junction -with top inlet 1:1 31.559999 36.0 40.840000 NaN 9.280001 Top Inlet 1 40.843731 NaN 2 POINT (6637368.4974 1966084.5743)
3 P11-DMH011 Davis Junction Junction -with top inlet 1:1 37.400002 36.0 45.330002 NaN 7.930000 Top Inlet 1 45.332291 NaN 2 POINT (6630653.5194 1963548.271)
4 O15-DMH016 Davis Start US Junction -with top inlet 0:1 38.639999 36.0 41.700001 NaN 3.060001 Top Inlet 1 41.700871 NaN 1 POINT (6638669.1365 1964981.6636)
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
128 O11-DMH017 Davis Junction Junction -with top inlet 3:1 31.410000 36.0 46.750000 NaN 15.340000 Top Inlet 1 46.750332 NaN 4 POINT (6630676.6795 1966070.6225)
129 N12-DMH010 Davis Junction Junction -with top inlet 2:1 31.639999 36.0 46.570000 NaN 14.930000 Top Inlet 1 46.572021 NaN 3 POINT (6630802.8125 1966200.091)
130 N12-DMH009 Davis Junction Junction -with top inlet 1:1 31.740000 36.0 46.200001 NaN 14.460001 Top Inlet 1 46.197262 NaN 2 POINT (6631619.097 1966201.567)
131 N12-DMH027 Davis Junction Junction -with top inlet 2:1 29.709999 36.0 44.830002 NaN 15.120003 Top Inlet 1 44.833260 NaN 3 POINT (6632530.277 1966194.4425)
132 O13-SDS03 Davis Junction Junction -with top inlet 3:0 24.600000 1000.0 50.939999 NaN 26.339998 Top Inlet 1 50.940022 NaN 3 POINT (6635026.261 1966041.155)

133 rows × 16 columns

Python
# Use get_hdf5_dataset_info function to get Pipe Conduits data:
#HdfUtils.get_hdf5_dataset_info(plan_hdf_path, "/Geometry/Pipe Networks/")
Python
# Get pipe network data
pipe_network_gdf = HdfPipe.get_pipe_network(plan_hdf_path)
print("\nPipe Network Data:")
pipe_network_gdf
Text Only
2026-05-23 08:57:15 - root - INFO - Selected Pipe Network: Davis



Pipe Network Data:
Cell_ID Conduit_ID Node_ID Minimum_Elevation DS_Face_Indices Face_Indices US_Face_Indices Cell_Property_Info_Index US Face Elevation DS Face Elevation Min Elevation Area Info Index Cell_Polygon Face_Polylines Node_Point
0 0 0 -1 26.824432 [1] [0, 1] [0] 0 26.934290 26.824432 26.824432 242.040024 0 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
1 1 0 -1 26.714573 [2] [1, 2] [1] 0 26.934290 26.824432 26.824432 242.040024 0 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
2 2 0 -1 26.604715 [3] [2, 3] [2] 0 26.934290 26.824432 26.824432 242.040024 0 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
3 3 0 -1 26.494858 [4] [3, 4] [3] 0 26.934290 26.824432 26.824432 242.040024 0 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
4 4 0 -1 26.385000 [5] [4, 5] [4] 0 26.934290 26.824432 26.824432 242.040024 0 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1987 1987 -1 72 39.456257 [1976] [1976] [] 325 33.416916 33.301682 33.301682 141.037354 28 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
1988 1988 -1 79 42.074768 [1977] [1977] [] 326 33.301682 33.186447 33.186447 141.037354 28 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
1989 1989 -1 42 40.804863 [1984] [1988, 1984] [1988] 327 33.186447 33.071213 33.071213 141.037354 28 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
1990 1990 -1 46 41.998379 [1987] [1987] [] 328 33.071213 32.955978 32.955978 141.037354 28 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None
1991 1991 -1 45 37.606800 [1989] [1989] [] 329 32.955978 32.840744 32.840744 141.037354 28 POLYGON ((6635288.02154 1965233.24073, 6635279... [LINESTRING (6635288.021542038 1965233.2407260... None

1992 rows × 16 columns

Python
# Get pump stations
pump_stations_gdf = HdfPump.get_pump_stations(plan_hdf_path)
print("\nPump Stations:")
pump_stations_gdf
Text Only
Pump Stations:
geometry station_id Name Inlet River Inlet Reach Inlet RS Inlet RS Distance Inlet SA/2D Inlet Pipe Node Outlet River ... Outlet Pipe Node Reference River Reference Reach Reference RS Reference RS Distance Reference SA/2D Reference Point Reference Pipe Node Highest Pump Line Elevation Pump Groups
0 POINT (6635027.027 1966080.07) 0 Pump Station #1 NaN Davis [O13-SDS03] ... NaN NaN 1

1 rows × 24 columns

Python
# Get pump groups
pump_groups_df = HdfPump.get_pump_groups(plan_hdf_path)
print("\nPump Groups:")
pump_groups_df
Text Only
Pump Groups:
Pump Station ID Name Bias On Start Up Time Shut Down Time Width Pumps efficiency_curve_start efficiency_curve_count efficiency_curve
0 0 Pump Station #1 0 5.0 NaN 5.0 1 0 6 [[2.0, 70.0], [4.0, 60.0], [6.0, 55.0], [8.0, ...
Python
# Use HdfUtils for extracting projection
print("\nExtracting Projection from HDF")
projection = HdfBase.get_projection(hdf_path=geom_hdf_path)
print(f"Projection: {projection}")
Text Only
Extracting Projection from HDF
Projection: EPSG:2871
Python
# Set CRS for GeoDataFrames
if projection:
    pipe_conduits_gdf.set_crs(projection, inplace=True, allow_override=True)
    pipe_nodes_gdf.set_crs(projection, inplace=True, allow_override=True)

print("Pipe Conduits GeoDataFrame columns:")
print(pipe_conduits_gdf.columns)

print("\nPipe Nodes GeoDataFrame columns:")
print(pipe_nodes_gdf.columns)

perimeter_polygons = HdfMesh.get_mesh_areas(geom_hdf_path)
if projection:
    perimeter_polygons.set_crs(projection, inplace=True, allow_override=True)

print("\nPerimeter Polygons GeoDataFrame columns:")
print(perimeter_polygons.columns)
Text Only
Pipe Conduits GeoDataFrame columns:
Index(['Name', 'System Name', 'US Node', 'DS Node', 'Modeling Approach',
       'Conduit Length', 'Max Cell Length', 'Shape', 'Rise', 'Span',
       'Manning's n', 'US Offset', 'DS Offset', 'US Elevation', 'DS Elevation',
       'Slope', 'US Entrance Loss Coefficient', 'DS Exit Loss Coefficient',
       'US Backflow Loss Coefficient', 'DS Backflow Loss Coefficient',
       'DS Gate Type', 'Major Group', 'Minor Group', 'DS Flap Gate',
       'Polyline', 'Terrain_Profiles'],
      dtype='str')

Pipe Nodes GeoDataFrame columns:
Index(['Name', 'System Name', 'Node Type', 'Node Status',
       'Condtui Connections (US:DS)', 'Invert Elevation', 'Base Area',
       'Terrain Elevation', 'Terrain Elevation Override', 'Depth',
       'Top Inlet Type', 'Top Inlet Elevation', 'Side Inlet Type',
       'Side Inlet Elevation', 'Total Connection Count', 'geometry'],
      dtype='str')

Perimeter Polygons GeoDataFrame columns:
Index(['mesh_name', 'geometry'], dtype='str')
Python
import matplotlib.pyplot as plt
from shapely import wkt
import matplotlib.patches as mpatches
import matplotlib.lines as mlines
import numpy as np

fig, ax = plt.subplots(figsize=(28, 20))

# Plot cell polygons with 50% transparency behind the pipe network
cell_polygons_df = HdfMesh.get_mesh_cell_polygons(geom_hdf_path)
if not cell_polygons_df.empty:
    cell_polygons_df.plot(ax=ax, edgecolor='lightgray', facecolor='lightgray', alpha=0.5)

# Plot pipe conduits - the Polyline column already contains LineString geometries
pipe_conduits_gdf.set_geometry('Polyline', inplace=True)

# Plot each pipe conduit individually to ensure all are shown
for idx, row in pipe_conduits_gdf.iterrows():
    ax.plot(*row.Polyline.xy, color='blue', linewidth=1)

# Create a colormap for node elevations
norm = plt.Normalize(pipe_nodes_gdf['Invert Elevation'].min(), 
                    pipe_nodes_gdf['Invert Elevation'].max())
cmap = plt.cm.viridis

# Plot pipe nodes colored by invert elevation
scatter = ax.scatter(pipe_nodes_gdf.geometry.x, pipe_nodes_gdf.geometry.y,
                    c=pipe_nodes_gdf['Invert Elevation'], 
                    cmap=cmap, norm=norm,
                    s=100)

# Add colorbar
cbar = plt.colorbar(scatter)
cbar.set_label('Invert Elevation (ft)', rotation=270, labelpad=15)

# Add combined labels for invert and drop inlet elevations
for idx, row in pipe_nodes_gdf.iterrows():
    label_text = ""  # Initialize label_text for each node
    # Add drop inlet elevation label if it exists and is not NaN
    if 'Drop Inlet Elevation' in row and not np.isnan(row['Drop Inlet Elevation']):
        label_text += f"TOC: {row['Drop Inlet Elevation']:.2f}\n"
    label_text += f"INV: {row['Invert Elevation']:.2f}"

    ax.annotate(label_text,
                xy=(row.geometry.x, row.geometry.y),
                xytext=(-10, -10), textcoords='offset points',
                fontsize=8,
                bbox=dict(facecolor='white', edgecolor='black', boxstyle='round,pad=0.5'))

# Add perimeter polygons 
if not perimeter_polygons.empty:
    perimeter_polygons.plot(ax=ax, edgecolor='black', facecolor='none')

# Create proxy artists for legend
conduit_line = mlines.Line2D([], [], color='blue', label='Conduits')
node_point = mlines.Line2D([], [], color='blue', marker='o', linestyle='None',
                          markersize=10, label='Nodes')
perimeter = mpatches.Patch(facecolor='none', edgecolor='black',
                          label='Perimeter Polygons')

ax.set_title('Pipe Network with Node Elevations')

# Add legend with proxy artists
ax.legend(handles=[conduit_line, node_point, perimeter])

# Set aspect ratio to be equal and adjust limits
ax.set_aspect('equal', 'datalim')
ax.autoscale_view()

plt.show()

png

Python
# Visualize pump stations on a map
fig, ax = plt.subplots(figsize=(12, 8))
pump_stations_gdf.plot(ax=ax, color='green', markersize=50, label='Pump Station')

# Add perimeter polygons
if not perimeter_polygons.empty:
    perimeter_polygons.plot(ax=ax, edgecolor='black', facecolor='none', label='Perimeter Polygons')

ax.set_title('Pump Station Location')
ax.legend()
plt.show()
Text Only
C:\Users\billk_clb\AppData\Local\Temp\ipykernel_24548\1821049155.py:10: UserWarning: Legend does not support handles for PatchCollection instances.
See: https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html#implementing-a-custom-legend-handler
  ax.legend()

png

Python
# Example 3: Get pipe network timeseries
valid_variables = [
    "Cell Courant", "Cell Water Surface", "Face Flow", "Face Velocity",
    "Face Water Surface", "Pipes/Pipe Flow DS", "Pipes/Pipe Flow US",
    "Pipes/Vel DS", "Pipes/Vel US", "Nodes/Depth", "Nodes/Water Surface"
]

print("Valid variables for pipe network timeseries:")
for var in valid_variables:
    print(f"- {var}")

# Extract pipe network timeseries for each valid pipe-related variable
pipe_variables = [var for var in valid_variables if var.startswith("Pipes/") or var.startswith("Nodes/")]

for variable in pipe_variables:
    try:
        pipe_timeseries = HdfPipe.get_pipe_network_timeseries(plan_hdf_path, variable=variable)
        print(f"\nPipe Network Timeseries ({variable}):")
        print(pipe_timeseries.head())  # Print first few rows to avoid overwhelming output
    except Exception as e:
        print(f"Error extracting {variable}: {str(e)}")
Text Only
2026-05-23 08:57:17 - ras_commander.hdf.HdfPipe - ERROR - Required dataset not found in HDF file: "Unable to synchronously open object (object 'Drop Inlet Flow' doesn't exist)"


Valid variables for pipe network timeseries:
- Cell Courant
- Cell Water Surface
- Face Flow
- Face Velocity
- Face Water Surface
- Pipes/Pipe Flow DS
- Pipes/Pipe Flow US
- Pipes/Vel DS
- Pipes/Vel US
- Nodes/Depth
- Nodes/Drop Inlet Flow
- Nodes/Water Surface

Pipe Network Timeseries (Pipes/Pipe Flow DS):
<xarray.DataArray 'Pipes/Pipe Flow DS' (time: 5, location: 5)> Size: 100B
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [-0.        , -0.        , -0.        , -0.        , -0.        ],
       [-0.        , -0.        , -0.        , -0.        , -0.        ],
       [-0.        , -0.00299399, -0.        , -0.        , -0.        ],
       [-0.        , -0.01100602, -0.        , -0.        , -0.        ]],
      dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 40B 2000-01-10T12:00:00 ... 2000-01-10T12...
  * location  (location) int64 40B 0 1 2 3 4
Attributes:
    units:     ft^3/s
    variable:  Pipes/Pipe Flow DS

Pipe Network Timeseries (Pipes/Pipe Flow US):
<xarray.DataArray 'Pipes/Pipe Flow US' (time: 5, location: 5)> Size: 100B
array([[ 0.0000000e+00,  0.0000000e+00,  0.0000000e+00,  0.0000000e+00,
         0.0000000e+00],
       [-0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00,
        -0.0000000e+00],
       [-0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00,
        -0.0000000e+00],
       [-0.0000000e+00, -0.0000000e+00, -0.0000000e+00, -0.0000000e+00,
         3.9259396e-02],
       [-0.0000000e+00,  1.0572882e-05, -0.0000000e+00, -0.0000000e+00,
         8.2022630e-02]], dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 40B 2000-01-10T12:00:00 ... 2000-01-10T12...
  * location  (location) int64 40B 0 1 2 3 4
Attributes:
    units:     ft^3/s
    variable:  Pipes/Pipe Flow US

Pipe Network Timeseries (Pipes/Vel DS):
<xarray.DataArray 'Pipes/Vel DS' (time: 5, location: 5)> Size: 100B
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [-0.        , -0.        , -0.        , -0.        , -0.        ],
       [-0.        , -0.        , -0.        , -0.        , -0.        ],
       [-0.        , -0.16168177, -0.        , -0.        , -0.        ],
       [-0.        , -0.10933261, -0.        , -0.        , -0.        ]],
      dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 40B 2000-01-10T12:00:00 ... 2000-01-10T12...
  * location  (location) int64 40B 0 1 2 3 4
Attributes:
    units:     ft/s
    variable:  Pipes/Vel DS

Pipe Network Timeseries (Pipes/Vel US):
<xarray.DataArray 'Pipes/Vel US' (time: 5, location: 5)> Size: 100B
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [-0.        , -0.        , -0.        , -0.        , -0.        ],
       [-0.        , -0.        , -0.        , -0.        , -0.        ],
       [-0.        , -0.        , -0.        , -0.        ,  0.45621765],
       [-0.        ,  0.02145246, -0.        , -0.        ,  0.47108054]],
      dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 40B 2000-01-10T12:00:00 ... 2000-01-10T12...
  * location  (location) int64 40B 0 1 2 3 4
Attributes:
    units:     ft/s
    variable:  Pipes/Vel US

Pipe Network Timeseries (Nodes/Depth):
<xarray.DataArray 'Nodes/Depth' (time: 5, location: 5)> Size: 100B
array([[ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ],
       [-0.04570961, -0.04727364, -0.03162766, -0.01459312,  0.        ],
       [-0.04570961, -0.04727364, -0.03162766, -0.01459312,  0.        ],
       [-0.04570961, -0.04727364, -0.03162766,  0.06485876,  0.        ],
       [-0.04570961, -0.04727364, -0.03037816,  0.11818657,  0.        ]],
      dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 40B 2000-01-10T12:00:00 ... 2000-01-10T12...
  * location  (location) int64 40B 0 1 2 3 4
Attributes:
    units:     ft
    variable:  Nodes/Depth
Error extracting Nodes/Drop Inlet Flow: "Unable to synchronously open object (object 'Drop Inlet Flow' doesn't exist)"

Pipe Network Timeseries (Nodes/Water Surface):
<xarray.DataArray 'Nodes/Water Surface' (time: 5, location: 5)> Size: 100B
array([[26.98    , 25.79    , 28.87    , 27.36    , 24.6     ],
       [26.93429 , 25.742727, 28.838373, 27.345407, 24.6     ],
       [26.93429 , 25.742727, 28.838373, 27.345407, 24.6     ],
       [26.93429 , 25.742727, 28.838373, 27.42486 , 24.6     ],
       [26.93429 , 25.742727, 28.839622, 27.478188, 24.6     ]],
      dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 40B 2000-01-10T12:00:00 ... 2000-01-10T12...
  * location  (location) int64 40B 0 1 2 3 4
Attributes:
    units:     ft
    variable:  Nodes/Water Surface

Pipe Network Timeseries Data Description

The get_pipe_network_timeseries function returns an xarray DataArray for each variable. Here's a general description of the data structure:

  1. Pipes/Pipe Flow DS and Pipes/Pipe Flow US:
  2. Dimensions: time, location (pipe IDs)
  3. Units: ft^3/s (cubic feet per second)
  4. Description: Represents the flow rate at the downstream (DS) and upstream (US) ends of pipes over time.

  5. Pipes/Vel DS and Pipes/Vel US:

  6. Dimensions: time, location (pipe IDs)
  7. Units: ft/s (feet per second)
  8. Description: Shows the velocity at the downstream (DS) and upstream (US) ends of pipes over time.

  9. Nodes/Depth:

  10. Dimensions: time, location (node IDs)
  11. Units: ft (feet)
  12. Description: Indicates the depth of water at each node over time.

  13. Nodes/Water Surface:

  14. Dimensions: time, location (node IDs)
  15. Units: ft (feet)
  16. Description: Shows the water surface elevation at each node over time.

General notes: - The 'time' dimension represents the simulation timesteps. - The 'location' dimension represents either pipe IDs or node IDs, depending on the variable. - The number of timesteps and locations may vary depending on the specific dataset and simulation setup. - Negative values in flow variables may indicate reverse flow direction.

Python
import matplotlib.pyplot as plt
from matplotlib.dates import DateFormatter
import numpy as np
import random

# Define the variables we want to plot
variables = [
    "Pipes/Pipe Flow DS", "Pipes/Pipe Flow US", "Pipes/Vel DS", "Pipes/Vel US",
    "Nodes/Depth", "Nodes/Water Surface"
]

# Create a separate plot for each variable
for variable in variables:
    try:
        # Get the data for the current variable
        data = HdfPipe.get_pipe_network_timeseries(plan_hdf_path, variable=variable)

        # Create a new figure
        fig, ax = plt.subplots(figsize=(12, 6))

        # Pick one random location
        random_location = random.choice(data.location.values)

        # Determine if it's a pipe or node variable
        if variable.startswith("Pipes/"):
            location_type = "Conduit ID"
        else:
            location_type = "Node ID"

        # Plot the data for the randomly selected location
        ax.plot(data.time, data.sel(location=random_location), label=f'{location_type} {random_location}')

        # Set the title and labels
        ax.set_title(f'{variable} Over Time ({location_type} {random_location})')
        ax.set_xlabel('Time')  # Corrected from ax.xlabel to ax.set_xlabel
        ax.set_ylabel(f'{variable} ({data.attrs["units"]})')  # Corrected from ax.ylabel to ax.set_ylabel

        # Format the x-axis to show dates nicely
        ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d %H:%M'))
        plt.xticks(rotation=45)

        # Add a legend
        ax.legend(title=location_type, loc='upper left')

        # Adjust the layout
        plt.tight_layout()

        # Show the plot
        plt.show()

    except Exception as e:
        print(f"Error plotting {variable}: {str(e)}")

png

png

png

png

png

Text Only
2026-05-23 08:57:18 - ras_commander.hdf.HdfPipe - ERROR - Required dataset not found in HDF file: "Unable to synchronously open object (object 'Drop Inlet Flow' doesn't exist)"


Error plotting Nodes/Drop Inlet Flow: "Unable to synchronously open object (object 'Drop Inlet Flow' doesn't exist)"

png

Python
# Example 8: Get pump station timeseries
pump_station_name = pump_stations_gdf.iloc[0]['Name']  # Get the first pump station name
# Use the results_pump_station_timeseries method 
pump_timeseries = HdfPump.get_pump_station_timeseries(plan_hdf_path, pump_station=pump_station_name)
print(f"\nPump Station Timeseries ({pump_station_name}):")
print(pump_timeseries)
Text Only
Pump Station Timeseries (Pump Station #1):
<xarray.DataArray 'Pump Station #1' (time: 217, variable: 5)> Size: 4kB
array([[ 0.      , 24.6     , 38.888123,  0.      ,  0.      ],
       [ 0.      , 24.6     , 38.888123,  0.      ,  0.      ],
       [ 0.      , 24.6     , 38.888123,  0.      ,  0.      ],
       ...,
       [ 0.      , 25.579357, 40.7534  ,  0.      ,  0.      ],
       [ 0.      , 25.841583, 40.652042,  0.      ,  0.      ],
       [ 0.      , 26.042273, 40.59146 ,  0.      ,  0.      ]],
      shape=(217, 5), dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 2kB 2000-01-10T12:00:00 ... 2000-01-12
  * variable  (variable) <U12 240B 'Flow' 'Stage HW' ... 'Pumps on'
Attributes:
    units:             [[b'Flow' b'cfs']\n [b'Stage HW' b'ft']\n [b'Stage TW'...
    unit_by_variable:  {'Flow': 'cfs', 'Stage HW': 'ft', 'Stage TW': 'ft', 'P...
    pump_station:      Pump Station #1
Python
# Use get_hdf5_dataset_info function to get Pipe Conduits data:
HdfBase.get_dataset_info(plan_hdf_path, "/Geometry/Pump Stations/")
Text Only
Exploring group: /Geometry/Pump Stations/


    Dataset: /Geometry/Pump Stations//Attributes
        Shape: (1,)
        Dtype: [('Name', 'S16'), ('Inlet River', 'S16'), ('Inlet Reach', 'S16'), ('Inlet RS', 'S8'), ('Inlet RS Distance', '<f4'), ('Inlet SA/2D', 'S16'), ('Inlet Pipe Node', 'S32'), ('Outlet River', 'S16'), ('Outlet Reach', 'S16'), ('Outlet RS', 'S8'), ('Outlet RS Distance', '<f4'), ('Outlet SA/2D', 'S16'), ('Outlet Pipe Node', 'S32'), ('Reference River', 'S16'), ('Reference Reach', 'S16'), ('Reference RS', 'S8'), ('Reference RS Distance', '<f4'), ('Reference SA/2D', 'S16'), ('Reference Point', 'S32'), ('Reference Pipe Node', 'S32'), ('Highest Pump Line Elevation', '<f4'), ('Pump Groups', '<i4')]

    Dataset: /Geometry/Pump Stations//Points
        Shape: (1, 2)
        Dtype: float64
    Attributes for /Geometry/Pump Stations//Points:
        Column: b'X,Y'
        Row: b'Points'

    Group: /Geometry/Pump Stations//Pump Groups
        Dataset: /Geometry/Pump Stations//Pump Groups/Attributes
            Shape: (1,)
            Dtype: [('Pump Station ID', '<i4'), ('Name', 'S16'), ('Bias On', 'u1'), ('Start Up Time', '<f4'), ('Shut Down Time', '<f4'), ('Width', '<f4'), ('Pumps', '<i4')]
        Dataset: /Geometry/Pump Stations//Pump Groups/Efficiency Curves Info
            Shape: (1, 2)
            Dtype: int32
    Attributes for /Geometry/Pump Stations//Pump Groups/Efficiency Curves Info:
        Column: [b'Starting Index' b'Count']
        Row: b'Feature'
        Dataset: /Geometry/Pump Stations//Pump Groups/Efficiency Curves Values
            Shape: (6, 2)
            Dtype: float32
    Attributes for /Geometry/Pump Stations//Pump Groups/Efficiency Curves Values:
        Column: [b'Head' b'Flow']
        Row: b'Points'
        Group: /Geometry/Pump Stations//Pump Groups/Pumps
            Dataset: /Geometry/Pump Stations//Pump Groups/Pumps/Attributes
                Shape: (1,)
                Dtype: [('Pump Group ID', '<i4'), ('Name', 'S16'), ('WS On', '<f4'), ('WS Off', '<f4'), ('Default Centerline', 'u1')]
            Dataset: /Geometry/Pump Stations//Pump Groups/Pumps/Centerline Info
                Shape: (1, 4)
                Dtype: int32
    Attributes for /Geometry/Pump Stations//Pump Groups/Pumps/Centerline Info:
        Column: [b'Point Starting Index' b'Point Count' b'Part Starting Index'
 b'Part Count']
        Feature Type: b'Polyline'
        Row: b'Feature'
            Dataset: /Geometry/Pump Stations//Pump Groups/Pumps/Centerline Parts
                Shape: (1, 2)
                Dtype: int32
    Attributes for /Geometry/Pump Stations//Pump Groups/Pumps/Centerline Parts:
        Column: [b'Point Starting Index' b'Point Count']
        Row: b'Part'
            Dataset: /Geometry/Pump Stations//Pump Groups/Pumps/Centerline Points
                Shape: (2, 2)
                Dtype: float64
    Attributes for /Geometry/Pump Stations//Pump Groups/Pumps/Centerline Points:
        Column: [b'X' b'Y']
        Row: b'Points'
            Dataset: /Geometry/Pump Stations//Pump Groups/Pumps/Outlet Cells
                Shape: (1,)
                Dtype: [('Pump Station ID', '<i4'), ('Pump Group ID', '<i4'), ('Pump ID', '<i4'), ('Cell Index', '<i4'), ('Station Start', '<f4'), ('Station End', '<f4')]
Python
# Extract the pump station timeseries data
pump_station_name = pump_stations_gdf.iloc[0]['Name']  # Get the first pump station name
pump_timeseries = HdfPump.get_pump_station_timeseries(plan_hdf_path, pump_station=pump_station_name)

# Print the pump station timeseries
print(f"\nPump Station Timeseries ({pump_station_name}):")
print(pump_timeseries)

# Create a new figure for plotting
fig, ax = plt.subplots(figsize=(12, 12))

# Plot each variable in the timeseries
for variable in pump_timeseries.coords['variable'].values:
    data = pump_timeseries.sel(variable=variable)

    # Decode units to strings
    unit = pump_timeseries.attrs["units"][list(pump_timeseries.coords["variable"].values).index(variable)][1].decode('utf-8')

    # Check if the variable is 'Pumps on' to plot it differently
    if variable == 'Pumps on':
        # Plot with color based on the on/off status
        colors = ['green' if val > 0 else 'red' for val in data.values.flatten()]
        ax.scatter(pump_timeseries['time'], data, label=f'{variable} ({unit})', color=colors)
    else:
        ax.plot(pump_timeseries['time'], data, label=f'{variable} ({unit})')

        # Label the peak values
        peak_time = pump_timeseries['time'][data.argmax()]
        peak_value = data.max()
        ax.annotate(f'Peak: {peak_value:.2f}', xy=(peak_time, peak_value), 
                    xytext=(peak_time, peak_value + 0.1 * peak_value), 
                    arrowprops=dict(facecolor='black', arrowstyle='->'),
                    fontsize=10, color='black', ha='center')

# Set the title and labels
ax.set_title(f'Timeseries Data for Pump Station: {pump_station_name}')
ax.set_xlabel('Time')
ax.set_ylabel('Values')

# Format the x-axis to show dates nicely
ax.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d %H:%M'))
plt.xticks(rotation=45)

# Add a legend
ax.legend(title='Variables', loc='upper left')

# Adjust the layout
plt.tight_layout()

# Show the plot
plt.show()
Text Only
C:\Users\billk_clb\anaconda3\envs\symphony-dev\Lib\site-packages\xarray\core\dataarray.py:6439: FutureWarning: Behaviour of argmin/argmax with neither dim nor axis argument will change to return a dict of indices of each dimension. To get a single, flat index, please use np.argmin(da.data) or np.argmax(da.data) instead of da.argmin() or da.argmax().
  result = self.variable.argmax(dim, axis, keep_attrs, skipna)
C:\Users\billk_clb\anaconda3\envs\symphony-dev\Lib\site-packages\xarray\core\dataarray.py:6439: FutureWarning: Behaviour of argmin/argmax with neither dim nor axis argument will change to return a dict of indices of each dimension. To get a single, flat index, please use np.argmin(da.data) or np.argmax(da.data) instead of da.argmin() or da.argmax().
  result = self.variable.argmax(dim, axis, keep_attrs, skipna)
C:\Users\billk_clb\anaconda3\envs\symphony-dev\Lib\site-packages\xarray\core\dataarray.py:6439: FutureWarning: Behaviour of argmin/argmax with neither dim nor axis argument will change to return a dict of indices of each dimension. To get a single, flat index, please use np.argmin(da.data) or np.argmax(da.data) instead of da.argmin() or da.argmax().
  result = self.variable.argmax(dim, axis, keep_attrs, skipna)
C:\Users\billk_clb\anaconda3\envs\symphony-dev\Lib\site-packages\xarray\core\dataarray.py:6439: FutureWarning: Behaviour of argmin/argmax with neither dim nor axis argument will change to return a dict of indices of each dimension. To get a single, flat index, please use np.argmin(da.data) or np.argmax(da.data) instead of da.argmin() or da.argmax().
  result = self.variable.argmax(dim, axis, keep_attrs, skipna)



Pump Station Timeseries (Pump Station #1):
<xarray.DataArray 'Pump Station #1' (time: 217, variable: 5)> Size: 4kB
array([[ 0.      , 24.6     , 38.888123,  0.      ,  0.      ],
       [ 0.      , 24.6     , 38.888123,  0.      ,  0.      ],
       [ 0.      , 24.6     , 38.888123,  0.      ,  0.      ],
       ...,
       [ 0.      , 25.579357, 40.7534  ,  0.      ,  0.      ],
       [ 0.      , 25.841583, 40.652042,  0.      ,  0.      ],
       [ 0.      , 26.042273, 40.59146 ,  0.      ,  0.      ]],
      shape=(217, 5), dtype=float32)
Coordinates:
  * time      (time) datetime64[us] 2kB 2000-01-10T12:00:00 ... 2000-01-12
  * variable  (variable) <U12 240B 'Flow' 'Stage HW' ... 'Pumps on'
Attributes:
    units:             [[b'Flow' b'cfs']\n [b'Stage HW' b'ft']\n [b'Stage TW'...
    unit_by_variable:  {'Flow': 'cfs', 'Stage HW': 'ft', 'Stage TW': 'ft', 'P...
    pump_station:      Pump Station #1

png

Exploring HDF Datasets with HdfBase.get_dataset_info

This allows users to find HDF information that is not included in the ras-commander library. Find the path in HDFView and set the group_path below to explore the HDF datasets and attributes. Then, use the output to write your own function to extract the data.

Use get_hdf5_dataset_info function to get Pipe Conduits data:

HdfBase.get_dataset_info(plan_hdf_path, "/Geometry/Pipe Conduits/")

For HDF datasets that are not supported by the RAS-Commander library, provide the dataset path to HdfBase.get_dataset_info and provide the output to an LLM along with a relevent HDF* class(es) to generate new functions that extend the library's coverage.

RAS Mapper Pipe Profile-Line Renderers

The following cells sample a Davis pipe conduit with the pythonnet-backed RAS Mapper profile-line renderers exposed by HdfResultsQuery. The same polyline is used for pipe velocity, pipe flow, and the corresponding native pipe time-series renderers.

Python
from ras_commander import HdfResultsQuery

with h5py.File(plan_hdf_path, "r") as hdf:
    conduit_attrs = hdf["Geometry/Pipe Conduits/Attributes"][:]
    conduit_points = hdf["Geometry/Pipe Conduits/Polyline Points"][:]
    conduit_info = hdf["Geometry/Pipe Conduits/Polyline Info"][:]

conduit_index = 0
start_idx, point_count = conduit_info[conduit_index, 0], conduit_info[conduit_index, 1]
pipe_profile_line = LineString(conduit_points[start_idx:start_idx + point_count, :2])
pipe_name = conduit_attrs[conduit_index]["Name"].decode("utf-8", errors="ignore")
pipe_time_index = 7

pipe_velocity_profile = HdfResultsQuery.query_polyline_pipe_velocity_profile(
    plan_hdf_path,
    pipe_profile_line,
    time_index=pipe_time_index,
    sample_spacing=40.0,
    terrain_raster=plan_hdf_path,
)
pipe_flow_profile = HdfResultsQuery.query_polyline_pipe_flow_profile(
    plan_hdf_path,
    pipe_profile_line,
    time_index=pipe_time_index,
    sample_spacing=40.0,
    terrain_raster=plan_hdf_path,
)

print(f"Pipe conduit {pipe_name}: {len(pipe_velocity_profile)} profile samples")
display.display(pipe_velocity_profile.head())
Text Only
Pipe conduit 134: 29 profile samples
station x y mesh_name face_id velocity_mag depth terrain_elev
0 0.000000 6.635295e+06 1.965214e+06 area2 1763 NaN NaN NaN
1 20.170002 6.635291e+06 1.965234e+06 area2 1624 1.729614 NaN NaN
2 40.340004 6.635286e+06 1.965254e+06 area2 1624 1.748997 NaN NaN
3 60.510006 6.635282e+06 1.965273e+06 area2 1624 1.768380 NaN NaN
4 60.510006 6.635282e+06 1.965273e+06 area2 1624 1.768380 NaN NaN
Python
fig, axes = plt.subplots(1, 2, figsize=(12, 4), constrained_layout=True)

axes[0].plot(
    pipe_velocity_profile["station"],
    pipe_velocity_profile["velocity_mag"],
    color="#1f77b4",
    linewidth=2,
    label="Velocity",
)
axes[0].set_title(f"Davis Pipe {pipe_name} Velocity Profile")
axes[0].set_xlabel("Station along conduit (ft)")
axes[0].set_ylabel("Velocity (ft/s)")
axes[0].grid(True, alpha=0.3)
axes[0].legend()

axes[1].plot(
    pipe_flow_profile["station"],
    pipe_flow_profile["flow"],
    color="#2ca02c",
    linewidth=2,
    label="Flow",
)
axes[1].set_title(f"Davis Pipe {pipe_name} Flow Profile")
axes[1].set_xlabel("Station along conduit (ft)")
axes[1].set_ylabel("Flow (cfs)")
axes[1].grid(True, alpha=0.3)
axes[1].legend()

plt.show()

png

Python
pipe_velocity_timeseries = HdfResultsQuery.query_polyline_pipe_velocity_timeseries(
    plan_hdf_path,
    pipe_profile_line,
    time_range=(pipe_time_index, pipe_time_index + 2),
    sample_spacing=40.0,
    terrain_raster=plan_hdf_path,
)
pipe_flow_timeseries = HdfResultsQuery.query_polyline_pipe_flow_timeseries(
    plan_hdf_path,
    pipe_profile_line,
    time_range=(pipe_time_index, pipe_time_index + 2),
    sample_spacing=40.0,
    terrain_raster=plan_hdf_path,
)

summary = pd.DataFrame({
    "quantity": ["pipe velocity", "pipe flow"],
    "rows": [len(pipe_velocity_timeseries), len(pipe_flow_timeseries)],
    "finite_samples": [
        pipe_velocity_timeseries["velocity_mag"].notna().sum(),
        pipe_flow_timeseries["flow"].notna().sum(),
    ],
    "source": [
        pipe_velocity_timeseries.attrs.get("velocity_source"),
        pipe_flow_timeseries.attrs.get("flow_source"),
    ],
})
display.display(summary)
quantity rows finite_samples source
0 pipe velocity 58 54 [RasMapperLib.Render.VelocityPipeTimeSeries]
1 pipe flow 58 54 [RasMapperLib.Render.FlowPipeTimeSeries]
CLB Engineering Corporation  ·  LLM Forward Engineering
RAS Commander is a free and open-source project maintained by CLB Engineering Corporation. For agencies and firms seeking to modernize H&H workflows with LLM Forward approaches, contact CLB to partner with the engineers who wrote the automation.