Skip to content

1D Geometry File Parsing

This notebook demonstrates parsing and manipulating 1D geometry elements from HEC-RAS plain text geometry files, including: - Cross Section operations - Hydraulic Property Tables (HTAB) - Lateral Structure operations - Batch processing and statistics

Overview

This notebook demonstrates extraction of 1D geometry elements from HEC-RAS plain text geometry files (.g## format).

What You'll Learn

  • Parse cross sections and extract station-elevation data
  • Read hydraulic property tables (HTAB)
  • Extract lateral structure information
  • Perform batch processing

LLM Forward Approach

  • Verification: Check extracted DataFrames against HEC-RAS GUI
  • Visual Outputs: Plot cross sections for review
  • Audit Trail: Save extracted data to CSV

Reference Documentation

Python
# =============================================================================
# DEVELOPMENT MODE TOGGLE
# =============================================================================
from pathlib import Path
import sys

USE_LOCAL_SOURCE = False  # <-- TOGGLE THIS

if USE_LOCAL_SOURCE:
    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 geometry modules
from ras_commander import (
    RasGeometry, GeomLateral,
    RasGeometryUtils,
    HdfHydraulicTables,
    RasExamples,
    init_ras_project,
    RasCmdr,
    ras
)

# Additional imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from IPython import display

# Verify which version loaded
import ras_commander
print(f"✓ Loaded: {ras_commander.__file__}")
print(f"Working directory: {Path.cwd()}")
Text Only
📦 PIP PACKAGE MODE: Loading installed ras-commander
✓ Loaded: c:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\ras_commander\__init__.py
Working directory: c:\GH\ras-commander\examples

Parameters

Configure these values to customize the notebook for your project.

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

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

# Geometry Settings
GEOM_NUMBER = "01"                # Geometry file number
RIVER = "White"                   # River name for cross section queries
REACH = "West Fork"               # Reach name
CROSS_SECTION = "10457.31"        # Cross section station (RS)

Package Setup and Imports

Python
# NOTE: This cell runs HEC-RAS and may take 1-2 minutes!
# Uncomment to generate preprocessed HDF

# Extract and initialize project
project_path = RasExamples.extract_project(PROJECT_NAME, suffix="201")
init_ras_project(project_path, RAS_VERSION)

# Compute plan to generate preprocessed geometry HDF
print("Computing plan 01 to generate preprocessed geometry HDF...")
print("(This may take 1-2 minutes)\n")
result = RasCmdr.compute_plan("01")

if result:
    geom_hdf = ras.geom_df.iloc[0]['full_path'] + '.hdf'
    print(f"\n✓ Preprocessed HDF created: {Path(geom_hdf).name}")
    print(f"  Location: {geom_hdf}")
else:
    print("ERROR: Plan computation failed")
Text Only
2026-01-12 00:04:49 - ras_commander.RasExamples - INFO - Found zip file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\Example_Projects_6_6.zip
2026-01-12 00:04:49 - ras_commander.RasExamples - INFO - Loading project data from CSV...
2026-01-12 00:04:49 - ras_commander.RasExamples - INFO - Loaded 68 projects from CSV.
2026-01-12 00:04:49 - ras_commander.RasExamples - INFO - ----- RasExamples Extracting Project -----
2026-01-12 00:04:49 - ras_commander.RasExamples - INFO - Extracting project 'Muncie' as 'Muncie_201'
2026-01-12 00:04:49 - ras_commander.RasExamples - INFO - Successfully extracted project 'Muncie' to C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201
2026-01-12 00:04:49 - ras_commander.RasMap - INFO - Successfully parsed RASMapper file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.rasmap
2026-01-12 00:04:49 - ras_commander.RasPrj - INFO - Updated results_df with 3 plan(s)
2026-01-12 00:04:49 - ras_commander.RasCmdr - INFO - Using ras_object with project folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201
2026-01-12 00:04:49 - ras_commander.RasCmdr - INFO - Running HEC-RAS from the Command Line:
2026-01-12 00:04:49 - ras_commander.RasCmdr - INFO - Running command: "C:\Program Files (x86)\HEC\HEC-RAS\6.6\Ras.exe" -c "C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.prj" "C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.p01"


Computing plan 01 to generate preprocessed geometry HDF...
(This may take 1-2 minutes)



2026-01-12 00:05:05 - ras_commander.RasCmdr - INFO - HEC-RAS execution completed for plan: 01
2026-01-12 00:05:05 - ras_commander.RasCmdr - INFO - Total run time for plan 01: 15.24 seconds
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Using existing Path object HDF file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.p01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.p01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Reading computation messages from HDF: Muncie.p01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Successfully extracted 2578 characters from HDF
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Using existing Path object HDF file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.p01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.p01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Extracting Plan Information from: Muncie.p01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Plan Name: Unsteady Multi  9-SA run
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Simulation Duration (hours): 24.0
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Using existing Path object HDF file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.p01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.p01.hdf
c:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\ras_commander\RasPrj.py:1514: FutureWarning: The behavior of DataFrame concatenation with empty or all-NA entries is deprecated. In a future version, this will no longer exclude empty or all-NA columns when determining the result dtypes. To retain the old behavior, exclude the relevant entries before the concat operation.
  self.results_df = pd.concat([self.results_df, new_results], ignore_index=True)
2026-01-12 00:05:05 - ras_commander.RasPrj - INFO - Updated results_df with 1 plan(s)



✓ Preprocessed HDF created: Muncie.g01.hdf
  Location: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.g01.hdf
Python
# Display results summary from results_df
# This shows execution status, timing, and any errors/warnings for each plan
ras.results_df[['plan_number', 'plan_title', 'completed', 'has_errors', 'has_warnings', 'runtime_complete_process_hours']]
plan_number plan_title completed has_errors has_warnings runtime_complete_process_hours
0 03 Unsteady Run with 2D 50ft Grid False False False NaN
1 04 Unsteady Run with 2D 50ft User n Value R False False False NaN
2 01 Unsteady Multi 9-SA run True False False 0.003685

Section 1: Cross Section Operations

Cross sections define the channel geometry in 1D models. We'll explore how to list cross sections, extract their station/elevation data, and modify them.

Verification: Cross Section Data Quality

After extracting cross sections, verify:

  1. Count Matches: Number matches HEC-RAS GUI
  2. Station Range: Values in expected range
  3. Data Completeness: No missing values
  4. Units: Stations and elevations in correct units

Common Issues

Issue: FileNotFoundError - Fix: Verify geometry file path

Issue: Empty DataFrame - Fix: Check river/reach names (case-sensitive)

Issue: Station-elevation gaps - Fix: Verify geometry in HEC-RAS GUI

Python
ras.plan_df
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 01 01 01 Unsteady Multi 9-SA run 5.00 9-SAs 02JAN1900,0000,02JAN1900,2400 15SEC 5MIN 1 ... dss 1 NaN NaN C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
1 03 01 02 Unsteady Run with 2D 50ft Grid 5.10 2D 50ft Grid 02JAN1900,0000,02JAN1900,2400 10SEC 5MIN -1 ... dss 1 Pardiso (Direct) 2D Interior Area None 02 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
2 04 01 04 Unsteady Run with 2D 50ft User n Value R 5.10 50ft User n Regions 02JAN1900,0000,02JAN1900,2400 10SEC 5MIN 1 ... dss 1 Pardiso (Direct) 2D Interior Area None 04 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...

3 rows × 29 columns

Python
ras.geom_df
geom_file geom_number full_path hdf_path
0 g01 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
1 g02 02 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
2 g04 04 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...

1.1 Setup: Define Geometry File Path

Python
# Lookup geometry file path and HDF path from ras.geom_df by geom_number
geom_number = "01"
geom_row = ras.geom_df.loc[ras.geom_df['geom_number'] == geom_number].iloc[0]

geom_file = Path(geom_row["full_path"])
geom_hdf = Path(geom_row["hdf_path"])

print(f"Geometry file: {geom_file}")
print(f"File exists: {geom_file.exists()}")
if geom_file.exists():
    print(f"File size: {geom_file.stat().st_size / 1024:.1f} KB")
else:
    print("Geometry file does not exist!")
print(f"HDF file: {geom_hdf}")
print(f"HDF exists: {geom_hdf.exists()}")
Text Only
Geometry file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.g01
File exists: True
File size: 186.4 KB
HDF file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.g01.hdf
HDF exists: True

1.2 List All Cross Sections

Python
# Extract all cross sections
xs_df = RasGeometry.get_cross_sections(geom_file)

print(f"Total cross sections: {len(xs_df)}")
print(f"Rivers: {xs_df['River'].unique().tolist()}")
print(f"Reaches: {xs_df['Reach'].unique().tolist()}")

print("\nFirst 10 cross sections:")
display.display(xs_df)
Text Only
2026-01-12 00:05:05 - ras_commander.geom.GeomCrossSection - INFO - Extracted 63 cross sections from Muncie.g01


Total cross sections: 63
Rivers: ['White']
Reaches: ['Muncie']

First 10 cross sections:
River Reach RS Type Length_Left Length_Channel Length_Right NodeName
0 White Muncie 15696.24 1 228.66 210.73 167.84
1 White Muncie 15485.51 1 121.23 115.09 103.79
2 White Muncie 15370.43 1 174.81 165.14 117.82
3 White Muncie 15205.29 1 216.56 192.09 159.11
4 White Muncie 15013.20 1 98.06 95.84 84.00
... ... ... ... ... ... ... ... ...
58 White Muncie 1469.294 1 326.76 295.08 293.53
59 White Muncie 1174.213 1 359.34 308.67 300.36
60 White Muncie 865.5413 1 323.21 295.42 289.85
61 White Muncie 570.1187 1 383.75 332.47 321.89
62 White Muncie 237.6455 1 67.07 237.65 257.89

63 rows × 8 columns

1.3 Extract Station/Elevation for a Cross Section

Python
# Select first cross section
first_xs = xs_df.iloc[0]
river = first_xs['River']
reach = first_xs['Reach']
rs = first_xs['RS']

print(f"Selected cross section: {river} / {reach} / RS {rs}")

# Extract station/elevation data
sta_elev = RasGeometry.get_station_elevation(geom_file, river, reach, rs)

print(f"\nStation/Elevation Data:")
print(f"  Points: {len(sta_elev)}")
print(f"  Station range: {sta_elev['Station'].min():.2f} to {sta_elev['Station'].max():.2f} ft")
print(f"  Elevation range: {sta_elev['Elevation'].min():.2f} to {sta_elev['Elevation'].max():.2f} ft")
print(f"  Channel width: {sta_elev['Station'].max() - sta_elev['Station'].min():.2f} ft")

print("\nFirst 10 points:")
display.display(sta_elev.head(10))
Text Only
2026-01-12 00:05:05 - ras_commander.geom.GeomCrossSection - INFO - Extracted 134 station/elevation pairs for White/Muncie/RS 15696.24


Selected cross section: White / Muncie / RS 15696.24

Station/Elevation Data:
  Points: 134
  Station range: 0.00 to 807.07 ft
  Elevation range: 936.99 to 963.04 ft
  Channel width: 807.07 ft

First 10 points:
Station Elevation
0 0.00 963.04
1 27.20 963.04
2 32.64 963.02
3 38.08 962.85
4 43.52 962.71
5 54.40 962.71
6 59.84 962.61
7 65.28 962.47
8 70.72 962.23
9 76.16 961.81

1.4 Visualize Cross Section Profile

Python
# Plot cross section profile
fig, ax = plt.subplots(figsize=(12, 6))

ax.plot(sta_elev['Station'], sta_elev['Elevation'], 'b-', linewidth=2, label='Cross Section')
ax.fill_between(sta_elev['Station'], sta_elev['Elevation'],
                 sta_elev['Elevation'].min() - 5,
                 alpha=0.3)

ax.grid(True, alpha=0.3)
ax.set_xlabel('Station (ft)', fontsize=12)
ax.set_ylabel('Elevation (ft)', fontsize=12)
ax.set_title(f'Cross Section Profile: {river} / {reach} / RS {rs}',
             fontsize=14, fontweight='bold')

# Add statistics annotation
stats_text = f'Points: {len(sta_elev)}\n'
stats_text += f'Width: {sta_elev["Station"].max() - sta_elev["Station"].min():.1f} ft\n'
stats_text += f'Elev Range: {sta_elev["Elevation"].min():.1f} - {sta_elev["Elevation"].max():.1f} ft'
ax.text(0.02, 0.98, stats_text,
        transform=ax.transAxes,
        verticalalignment='top',
        bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5),
        fontsize=10)

plt.tight_layout()
plt.show()

png

1.5 Modify Cross Section Geometry (Round-Trip Example)

Python
# NOTE: This cell modifies the geometry file!
# Uncomment to actually modify the file (backup is created automatically)

# # Read original data
# original_sta_elev = RasGeometry.get_station_elevation(geom_file, river, reach, rs)
# print(f"Original mean elevation: {original_sta_elev['Elevation'].mean():.3f} ft")

# # Modify elevations (raise by 1 foot)
# modified_sta_elev = original_sta_elev.copy()
# modified_sta_elev['Elevation'] += 1.0

# # Write back to file (creates .bak backup automatically)
# RasGeometry.set_station_elevation(geom_file, river, reach, rs, modified_sta_elev)
# print(f"\n✓ Modified geometry written to file")
# print(f"  Backup created: {geom_file}.bak")

# # Verify round-trip
# readback_sta_elev = RasGeometry.get_station_elevation(geom_file, river, reach, rs)
# print(f"\nReadback mean elevation: {readback_sta_elev['Elevation'].mean():.3f} ft")
# print(f"Difference: {abs(modified_sta_elev['Elevation'].mean() - readback_sta_elev['Elevation'].mean()):.6f} ft")

# # Restore original (using backup)
# import shutil
# shutil.copy2(str(geom_file) + '.bak', geom_file)
# print(f"\n✓ Original geometry restored from backup")

print("Modification example is commented out to protect geometry file.")
print("Uncomment the code above to test round-trip operations.")
Text Only
Modification example is commented out to protect geometry file.
Uncomment the code above to test round-trip operations.

Section 2: Hydraulic Property Tables (HTAB)

Property tables contain preprocessed hydraulic properties (area, conveyance, wetted perimeter, etc.) as functions of elevation. These enable hydraulic analysis without re-running HEC-RAS.

IMPORTANT: Property tables only exist in preprocessed geometry HDF files. Run RasCmdr.compute_plan() to generate them.

Understanding Hydraulic Property Tables

HEC-RAS pre-computes hydraulic properties at discrete elevations.

Why HTABs Matter: - Used during flow computations - Interpolation between table values - Insufficient range causes errors

Verification

  • Check elevation range covers expected WSE
  • Verify monotonic increase in area/conveyance

2.1 Generate Preprocessed Geometry HDF

2.2 Extract HTAB for a Cross Section

Python
# Extract hydraulic property table using first cross section from current project
# (Uses river/reach/rs from cell 16 that were dynamically extracted)
htab = HdfHydraulicTables.get_xs_htab(geom_hdf, river, reach, str(rs))

print(f"Hydraulic Property Table for {river} / {reach} / RS {rs}")
print(f"\nTable dimensions: {len(htab)} elevations × {len(htab.columns)} properties")
print(f"Elevation range: {htab['Elevation'].min():.2f} to {htab['Elevation'].max():.2f} ft")

print("\nAvailable properties:")
for col in htab.columns:
    print(f"  - {col}")

print("\nFirst 5 rows:")
display.display(htab.head())
Text Only
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Using existing Path object HDF file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.g01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.g01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted HTAB for White/Muncie/RS 15696.24: 102 elevations, 26 properties


Hydraulic Property Table for White / Muncie / RS 15696.24

Table dimensions: 102 elevations × 26 properties
Elevation range: 936.99 to 987.99 ft

Available properties:
  - Elevation
  - Area_LOB
  - Area_Chan
  - Area_ROB
  - Area_Ineff_LOB
  - Area_Ineff_Chan
  - Area_Ineff_ROB
  - Conv_LOB
  - Conv_Chan
  - Conv_ROB
  - WP_LOB
  - WP_Chan
  - WP_ROB
  - Mann_N_LOB
  - Mann_N_Chan
  - Mann_N_ROB
  - Top_Width
  - Top_Width_LOB
  - Top_Width_Chan
  - Top_Width_ROB
  - Alpha
  - Storage_Area
  - Beta
  - Area_Total
  - Conveyance_Total
  - Wetted_Perimeter_Total

First 5 rows:
Elevation Area_LOB Area_Chan Area_ROB Area_Ineff_LOB Area_Ineff_Chan Area_Ineff_ROB Conv_LOB Conv_Chan Conv_ROB ... Top_Width Top_Width_LOB Top_Width_Chan Top_Width_ROB Alpha Storage_Area Beta Area_Total Conveyance_Total Wetted_Perimeter_Total
0 936.98999 0.0 0.000000 0.0 0.0 0.000000 0.0 0.0 0.000000 0.0 ... 0.000000 0.0 0.000000 0.0 1.0 0.0 1.0 0.000000 0.000000 0.000000
1 937.98999 0.0 30.739735 0.0 0.0 30.739735 0.0 0.0 920.303528 0.0 ... 42.387573 0.0 42.387573 0.0 1.0 0.0 1.0 30.739735 920.303528 42.487072
2 938.48999 0.0 53.730839 0.0 0.0 53.730839 0.0 0.0 2119.378174 0.0 ... 48.922852 0.0 48.922852 0.0 1.0 0.0 1.0 53.730839 2119.378174 49.107693
3 938.98999 0.0 79.565048 0.0 0.0 79.565048 0.0 0.0 3805.888184 0.0 ... 54.168121 0.0 54.168121 0.0 1.0 0.0 1.0 79.565048 3805.888184 54.453392
4 939.48999 0.0 107.678528 0.0 0.0 107.678528 0.0 0.0 5996.459961 0.0 ... 58.259857 0.0 58.259857 0.0 1.0 0.0 1.0 107.678528 5996.459961 58.665604

5 rows × 26 columns

2.3 Generate Rating Curves

Python
# Calculate hydraulic radius
htab['Hydraulic_Radius'] = htab['Area_Total'] / htab['Wetted_Perimeter_Total']
htab['Hydraulic_Radius'] = htab['Hydraulic_Radius'].replace([np.inf, -np.inf], 0)

# Create 4-panel rating curve plot
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# Plot 1: Area vs Elevation
ax1 = axes[0, 0]
ax1.plot(htab['Area_Total'], htab['Elevation'], 'b-', linewidth=2)
ax1.fill_betweenx(htab['Elevation'], 0, htab['Area_Total'], alpha=0.3)
ax1.set_xlabel('Flow Area (sq ft)', fontsize=11)
ax1.set_ylabel('Elevation (ft)', fontsize=11)
ax1.set_title('Area-Elevation Curve', fontsize=12, fontweight='bold')
ax1.grid(True, alpha=0.3)

# Plot 2: Conveyance vs Elevation
ax2 = axes[0, 1]
ax2.plot(htab['Conveyance_Total'], htab['Elevation'], 'g-', linewidth=2)
ax2.fill_betweenx(htab['Elevation'], 0, htab['Conveyance_Total'], alpha=0.3, color='green')
ax2.set_xlabel('Conveyance (cfs)', fontsize=11)
ax2.set_ylabel('Elevation (ft)', fontsize=11)
ax2.set_title('Conveyance-Elevation Curve', fontsize=12, fontweight='bold')
ax2.grid(True, alpha=0.3)

# Plot 3: Top Width vs Elevation
ax3 = axes[1, 0]
ax3.plot(htab['Top_Width'], htab['Elevation'], 'r-', linewidth=2)
ax3.fill_betweenx(htab['Elevation'], 0, htab['Top_Width'], alpha=0.3, color='red')
ax3.set_xlabel('Top Width (ft)', fontsize=11)
ax3.set_ylabel('Elevation (ft)', fontsize=11)
ax3.set_title('Top Width-Elevation Curve', fontsize=12, fontweight='bold')
ax3.grid(True, alpha=0.3)

# Plot 4: Hydraulic Radius vs Elevation
ax4 = axes[1, 1]
ax4.plot(htab['Hydraulic_Radius'], htab['Elevation'], 'm-', linewidth=2)
ax4.fill_betweenx(htab['Elevation'], 0, htab['Hydraulic_Radius'], alpha=0.3, color='purple')
ax4.set_xlabel('Hydraulic Radius (ft)', fontsize=11)
ax4.set_ylabel('Elevation (ft)', fontsize=11)
ax4.set_title('Hydraulic Radius-Elevation Curve', fontsize=12, fontweight='bold')
ax4.grid(True, alpha=0.3)

fig.suptitle(f'Hydraulic Property Curves: {river} / {reach} / RS {rs}',
             fontsize=14, fontweight='bold', y=0.995)

plt.tight_layout()
plt.show()

print("\nMaximum Hydraulic Properties:")
print(f"  Max Area: {htab['Area_Total'].max():.1f} sq ft")
print(f"  Max Conveyance: {htab['Conveyance_Total'].max():.1f} cfs")
print(f"  Max Hydraulic Radius: {htab['Hydraulic_Radius'].max():.2f} ft")
print(f"  Max Top Width: {htab['Top_Width'].max():.1f} ft")

png

Text Only
Maximum Hydraulic Properties:
  Max Area: 31712.2 sq ft
  Max Conveyance: 8935712.0 cfs
  Max Hydraulic Radius: 36.62 ft
  Max Top Width: 807.1 ft

2.4 Find Hydraulic Properties at Specific Elevation

Python
# Find properties at specific water surface elevation
target_elev = 665.0

# Find closest elevation in table
idx = (htab['Elevation'] - target_elev).abs().idxmin()
actual_elev = htab.loc[idx, 'Elevation']

print(f"Target elevation: {target_elev:.2f} ft")
print(f"Closest table elevation: {actual_elev:.2f} ft\n")

print(f"Hydraulic properties at elevation {actual_elev:.2f} ft:")
print(f"  Flow Area: {htab.loc[idx, 'Area_Total']:.1f} sq ft")
print(f"  Conveyance: {htab.loc[idx, 'Conveyance_Total']:.1f} cfs")
print(f"  Wetted Perimeter: {htab.loc[idx, 'Wetted_Perimeter_Total']:.1f} ft")
print(f"  Top Width: {htab.loc[idx, 'Top_Width']:.1f} ft")
print(f"  Hydraulic Radius: {htab.loc[idx, 'Hydraulic_Radius']:.2f} ft")
print(f"  Velocity Coefficient (Alpha): {htab.loc[idx, 'Alpha']:.3f}")
Text Only
Target elevation: 665.00 ft
Closest table elevation: 936.99 ft

Hydraulic properties at elevation 936.99 ft:
  Flow Area: 0.0 sq ft
  Conveyance: 0.0 cfs
  Wetted Perimeter: 0.0 ft
  Top Width: 0.0 ft
  Hydraulic Radius: nan ft
  Velocity Coefficient (Alpha): 1.000

2.5 Batch Extract HTABs for Multiple Cross Sections

Python
# Extract HTABs for all cross sections
print("Extracting property tables for all cross sections...")
print("(This may take a few seconds)\n")

all_htabs = HdfHydraulicTables.get_all_xs_htabs(geom_hdf)

print(f"Total HTABs extracted: {len(all_htabs)}")

# Calculate statistics across all cross sections
stats_list = []
for (river, reach, rs), htab_df in list(all_htabs.items())[:10]:  # First 10 for demo
    htab_df['Hydraulic_Radius'] = htab_df['Area_Total'] / htab_df['Wetted_Perimeter_Total']
    htab_df['Hydraulic_Radius'] = htab_df['Hydraulic_Radius'].replace([np.inf, -np.inf], 0)

    stats_list.append({
        'RS': rs,
        'Max_Area': htab_df['Area_Total'].max(),
        'Max_Conveyance': htab_df['Conveyance_Total'].max(),
        'Max_Hydraulic_Radius': htab_df['Hydraulic_Radius'].max(),
        'Num_Elevations': len(htab_df)
    })

stats_df = pd.DataFrame(stats_list)

print("\nStatistics for first 10 cross sections:")
display.display(stats_df)
Text Only
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Using existing Path object HDF file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.g01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201\Muncie.g01.hdf
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:05 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties


Extracting property tables for all cross sections...
(This may take a few seconds)



2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted property table: 102 elevations × 26 properties
2026-01-12 00:05:06 - ras_commander.hdf.HdfHydraulicTables - INFO - Extracted 61 property tables from Muncie.g01.hdf


Total HTABs extracted: 61

Statistics for first 10 cross sections:
RS Max_Area Max_Conveyance Max_Hydraulic_Radius Num_Elevations
0 15696.24 31712.218750 8935712.0 36.619583 102
1 15485.51 30332.736328 8523312.0 35.891979 102
2 15370.43 29522.572266 9290292.0 40.605034 102
3 15205.29 22697.011719 7227066.0 40.012123 102
4 15013.20 18485.404297 6603500.0 39.060474 102
5 14917.36 13339.439453 5512384.0 36.439335 102
6 14856.24 12367.175781 4710736.0 35.435398 102
7 14787.40 11737.270508 4672036.0 34.744865 102
8 14697.22 12324.720703 4643845.5 35.183830 102
9 14535.60 13008.683594 5283074.5 35.928162 102

Section 3: Lateral Structure Operations

Lateral structures are overflow weirs or connections along a river reach. We'll demonstrate extracting and visualizing these structures.

Understanding Lateral Structures

Lateral structures represent flow entering/leaving channel.

Key Parameters: - Station location - Weir coefficient - Crest elevation

Verification

  • Count matches HEC-RAS GUI
  • Stations within cross section limits

Load Geometry XX in project XX

Python
muncie_path = RasExamples.extract_project(PROJECT_NAME, suffix="201_plaintext_geometry")
print(muncie_path)

init_ras_project(muncie_path)
Text Only
2026-01-12 00:05:06 - ras_commander.RasExamples - INFO - ----- RasExamples Extracting Project -----
2026-01-12 00:05:06 - ras_commander.RasExamples - INFO - Extracting project 'Muncie' as 'Muncie_201_plaintext_geometry'
2026-01-12 00:05:06 - ras_commander.RasExamples - INFO - Successfully extracted project 'Muncie' to C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201_plaintext_geometry
2026-01-12 00:05:06 - ras_commander.RasPrj - INFO - No HEC-RAS Version Specified.Attempting to detect HEC-RAS version from plan files.
2026-01-12 00:05:06 - ras_commander.RasPrj - INFO - Searching for plan files in C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201_plaintext_geometry
2026-01-12 00:05:06 - ras_commander.RasPrj - INFO - Found plan file: Muncie.p01
2026-01-12 00:05:06 - ras_commander.RasPrj - INFO - Successfully read plan file with utf-8 encoding
2026-01-12 00:05:06 - ras_commander.RasPrj - INFO - Found Program Version=5.00 in Muncie.p01
2026-01-12 00:05:06 - ras_commander.RasPrj - INFO - Checking RAS executable path: C:\Program Files (x86)\HEC\HEC-RAS\5.0\Ras.exe
2026-01-12 00:05:06 - ras_commander.RasMap - INFO - Successfully parsed RASMapper file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201_plaintext_geometry\Muncie.rasmap
2026-01-12 00:05:06 - ras_commander.RasPrj - INFO - Updated results_df with 3 plan(s)


C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201_plaintext_geometry





<ras_commander.RasPrj.RasPrj at 0x23dce8402f0>
Python
ras.plan_df
plan_number unsteady_number geometry_number Plan Title Program Version Short Identifier Simulation Date Computation Interval Mapping Interval Run HTab ... Friction Slope Method UNET D2 SolverType UNET D2 Name HDF_Results_Path Geom File Geom Path Flow File Flow Path full_path flow_type
0 01 01 01 Unsteady Multi 9-SA run 5.00 9-SAs 02JAN1900,0000,02JAN1900,2400 15SEC 5MIN 1 ... 1 NaN NaN None 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... Unsteady
1 03 01 02 Unsteady Run with 2D 50ft Grid 5.10 2D 50ft Grid 02JAN1900,0000,02JAN1900,2400 10SEC 5MIN -1 ... 1 Pardiso (Direct) 2D Interior Area None 02 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... Unsteady
2 04 01 04 Unsteady Run with 2D 50ft User n Value R 5.10 50ft User n Regions 02JAN1900,0000,02JAN1900,2400 10SEC 5MIN 1 ... 1 Pardiso (Direct) 2D Interior Area None 04 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... Unsteady

3 rows × 30 columns

Python
ras.geom_df
geom_file geom_number full_path hdf_path
0 g01 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
1 g02 02 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
2 g04 04 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
Python
geom_number = "01"
geom_row = ras.geom_df.loc[ras.geom_df['geom_number'] == geom_number].iloc[0]

geom_file = Path(geom_row["full_path"])
geom_hdf = Path(geom_row["hdf_path"])

3.1 List Lateral Structures

Python
# Path to geometry with lateral structures
lateral_geom_file = geom_file

print(f"Geometry file: {lateral_geom_file}")
Text Only
Geometry file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Muncie_201_plaintext_geometry\Muncie.g01
Python
# Extract lateral structures
lat_strucs = GeomLateral.get_lateral_structures(lateral_geom_file)

print(f"\nLateral structures found: {len(lat_strucs)}")

if len(lat_strucs) > 0:
    print("\nLateral structure inventory:")
    display.display(lat_strucs[['River', 'Reach', 'RS', 'Position', 'Width', 'Coefficient', 'Distance', 'Description']])
else:
    print("No lateral structures found in this geometry file")
Text Only
2026-01-12 00:05:06 - ras_commander.geom.GeomLateral - INFO - Found 0 lateral structures in Muncie.g01



Lateral structures found: 0
No lateral structures found in this geometry file

3.2 Extract and Visualize Lateral Weir Profile

Python
if len(lat_strucs) > 0:
    # Get profile for first lateral structure
    first_lat = lat_strucs.iloc[0]
    river = first_lat['River']
    reach = first_lat['Reach']
    rs = first_lat['RS']
    position = first_lat['Position']

    print(f"Extracting lateral weir profile:")
    print(f"  Location: {river} / {reach} / RS {rs}")
    print(f"  Position: {position}")
    print(f"  Description: {first_lat['Description']}")

    profile = GeomLateral.get_weir_profile(lateral_geom_file, river, reach, rs, position)

    print(f"\nWeir Profile:")
    print(f"  Points: {len(profile)}")
    print(f"  Station range: {profile['Station'].min():.1f} to {profile['Station'].max():.1f} ft")
    print(f"  Elevation range: {profile['Elevation'].min():.2f} to {profile['Elevation'].max():.2f} ft")

    # Plot weir profile
    fig, ax = plt.subplots(figsize=(10, 5))
    ax.plot(profile['Station'], profile['Elevation'], 'go-', linewidth=2, markersize=6)
    ax.fill_between(profile['Station'], profile['Elevation'],
                     profile['Elevation'].min() - 2, alpha=0.3, color='green')
    ax.set_xlabel('Station (ft)', fontsize=11)
    ax.set_ylabel('Weir Crest Elevation (ft)', fontsize=11)
    ax.set_title(f'Lateral Weir Crest Profile: RS {rs}, Position {position}',
                 fontsize=12, fontweight='bold')
    ax.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()
else:
    print("Skipping lateral weir visualization - no laterals found")
Text Only
Skipping lateral weir visualization - no laterals found

Section 4: Batch Processing Example

Demonstrate how to automate operations across multiple geometry elements for batch analysis.

4.1 Calculate Statistics for All Cross Sections

Python
# Get all cross sections
xs_df = RasGeometry.get_cross_sections(geom_file)

print(f"Processing {len(xs_df)} cross sections...")

# Calculate geometry statistics for first 10 XS (for speed)
xs_stats = []
for idx, xs in xs_df.head(10).iterrows():
    try:
        sta_elev = RasGeometry.get_station_elevation(geom_file, xs['River'], xs['Reach'], xs['RS'])

        stats = {
            'RS': xs['RS'],
            'Points': len(sta_elev),
            'Min_Elev': sta_elev['Elevation'].min(),
            'Max_Elev': sta_elev['Elevation'].max(),
            'Relief': sta_elev['Elevation'].max() - sta_elev['Elevation'].min(),
            'Width': sta_elev['Station'].max() - sta_elev['Station'].min(),
            'Channel_Length': xs['Length_Channel']
        }
        xs_stats.append(stats)

    except Exception as e:
        print(f"  Warning: Could not process RS {xs['RS']}: {e}")

xs_stats_df = pd.DataFrame(xs_stats)

print()
print("Statistics for first 10 cross sections:")
display.display(xs_stats_df)
Text Only
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 63 cross sections from Muncie.g01
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 134 station/elevation pairs for White/Muncie/RS 15696.24
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 93 station/elevation pairs for White/Muncie/RS 15485.51
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 88 station/elevation pairs for White/Muncie/RS 15370.43
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 63 station/elevation pairs for White/Muncie/RS 15205.29
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 43 station/elevation pairs for White/Muncie/RS 15013.20
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 39 station/elevation pairs for White/Muncie/RS 14917.36
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 39 station/elevation pairs for White/Muncie/RS 14856.24
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 40 station/elevation pairs for White/Muncie/RS 14787.40
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 40 station/elevation pairs for White/Muncie/RS 14697.22
2026-01-12 00:05:06 - ras_commander.geom.GeomCrossSection - INFO - Extracted 42 station/elevation pairs for White/Muncie/RS 14535.60


Processing 63 cross sections...

Statistics for first 10 cross sections:
RS Points Min_Elev Max_Elev Relief Width Channel_Length
0 15696.24 134 936.99 963.04 26.05 807.07 210.73
1 15485.51 93 937.78 959.76 21.98 780.63 115.09
2 15370.43 88 937.78 959.97 22.19 645.10 165.14
3 15205.29 63 941.39 948.81 7.42 476.82 192.09
4 15013.20 43 940.73 946.97 6.24 381.34 95.84
5 14917.36 39 941.06 947.62 6.56 274.72 61.12
6 14856.24 39 940.18 947.62 7.44 259.72 68.84
7 14787.40 40 937.78 947.95 10.17 251.89 90.18
8 14697.22 40 938.88 947.95 9.07 263.44 161.62
9 14535.60 42 938.77 949.61 10.84 276.76 91.89

4.2 Visualize Cross Section Statistics Along Reach

Python
# Plot cross section properties along the reach
fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# Convert RS to numeric for plotting
xs_stats_df['RS_num'] = pd.to_numeric(xs_stats_df['RS'], errors='coerce')

# Plot 1: Channel width along reach
ax1 = axes[0, 0]
ax1.plot(xs_stats_df['RS_num'], xs_stats_df['Width'], 'b-o', linewidth=2, markersize=5)
ax1.set_xlabel('River Station', fontsize=11)
ax1.set_ylabel('Channel Width (ft)', fontsize=11)
ax1.set_title('Channel Width Along Reach', fontsize=12, fontweight='bold')
ax1.grid(True, alpha=0.3)
ax1.invert_xaxis()  # Invert so upstream is on left

# Plot 2: Relief (elevation change across XS)
ax2 = axes[0, 1]
ax2.plot(xs_stats_df['RS_num'], xs_stats_df['Relief'], 'g-o', linewidth=2, markersize=5)
ax2.set_xlabel('River Station', fontsize=11)
ax2.set_ylabel('Relief (ft)', fontsize=11)
ax2.set_title('Cross Section Relief Along Reach', fontsize=12, fontweight='bold')
ax2.grid(True, alpha=0.3)
ax2.invert_xaxis()

# Plot 3: Minimum elevation (thalweg)
ax3 = axes[1, 0]
ax3.plot(xs_stats_df['RS_num'], xs_stats_df['Min_Elev'], 'r-o', linewidth=2, markersize=5)
ax3.set_xlabel('River Station', fontsize=11)
ax3.set_ylabel('Minimum Elevation (ft)', fontsize=11)
ax3.set_title('Thalweg Profile', fontsize=12, fontweight='bold')
ax3.grid(True, alpha=0.3)
ax3.invert_xaxis()

# Plot 4: Number of points per XS
ax4 = axes[1, 1]
ax4.bar(xs_stats_df['RS_num'], xs_stats_df['Points'], color='purple', alpha=0.6)
ax4.set_xlabel('River Station', fontsize=11)
ax4.set_ylabel('Number of Points', fontsize=11)
ax4.set_title('Cross Section Detail Level', fontsize=12, fontweight='bold')
ax4.grid(True, alpha=0.3, axis='y')
ax4.invert_xaxis()

fig.suptitle('Cross Section Statistics Along Reach', fontsize=14, fontweight='bold', y=0.995)
plt.tight_layout()
plt.show()

png

Section 5: Practical Application - Sensitivity Study

Real-world use case: Setting up geometry modifications for parameter sensitivity analysis.

Python
# Example: Prepare geometry for Manning's n sensitivity study
# (Conceptual - actual Manning's n methods not yet implemented)

print("Sensitivity Study Example:")
print("\nPreparing geometry for parameter sensitivity analysis...")

# Get cross sections for modification
xs_subset = xs_df.head(5)

print(f"\nSelected {len(xs_subset)} cross sections for study:")
for idx, xs in xs_subset.iterrows():
    print(f"  - RS {xs['RS']}")

print("\nFor each cross section, you could:")
print("  1. Extract current geometry with get_station_elevation()")
print("  2. Extract current Manning's n (future: get_mannings_n())")
print("  3. Modify Manning's n values (e.g., ±10%, ±20%)")
print("  4. Write modified values (future: set_mannings_n())")
print("  5. Run RasCmdr.compute_plan() for each scenario")
print("  6. Compare results to assess sensitivity")

print("\nThis workflow enables automated sensitivity studies!")
Text Only
Sensitivity Study Example:

Preparing geometry for parameter sensitivity analysis...

Selected 5 cross sections for study:
  - RS 15696.24
  - RS 15485.51
  - RS 15370.43
  - RS 15205.29
  - RS 15013.20

For each cross section, you could:
  1. Extract current geometry with get_station_elevation()
  2. Extract current Manning's n (future: get_mannings_n())
  3. Modify Manning's n values (e.g., ±10%, ±20%)
  4. Write modified values (future: set_mannings_n())
  5. Run RasCmdr.compute_plan() for each scenario
  6. Compare results to assess sensitivity

This workflow enables automated sensitivity studies!

Summary

Methods Demonstrated

Cross Section Operations (RasGeometry): - get_cross_sections() - List all cross sections with metadata - get_station_elevation() - Extract station/elevation pairs - set_station_elevation() - Modify geometry with automatic backup

Hydraulic Property Tables (HdfHydraulicTables): - get_htab() - Extract preprocessed hydraulic properties - Rating curve generation from property tables

Lateral Structures (GeomLateral): - get_lateral_structures() - List lateral structures - get_lateral_structure_profile() - Extract weir profiles

Key Capabilities

  1. Geometry Modification: Round-trip read/modify/write with automatic backups
  2. Hydraulic Analysis: Extract rating curves and property tables
  3. Batch Processing: Analyze statistics across all cross sections
  4. Visualization: Profile plots, rating curves, reach statistics

See Also

  • 202_2d_plaintext_geometry.ipynb - 2D geometry operations (storage areas, SA/2D connections)
  • 400_1d_hdf_data_extraction.ipynb - 1D HDF results extraction
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.