Legacy COM Interface¶
The RasControl class provides access to HEC-RAS 3.x-6.x via the HECRASController COM interface.
Overview¶
For older HEC-RAS versions that don't support command-line execution or HDF output, RasControl provides:
- Plan execution via COM automation
- Steady state profile extraction
- Unsteady time series extraction
- Version migration validation
Supported Versions¶
| Version | Controller capability contract | Result family |
|---|---|---|
| 3.x alias | Resolves to the 4.1 Controller contract below | legacy .O## |
| 4.0 | RAS400; inherently blocking two-argument compute; exact owned-process cleanup (no QuitRas) |
legacy .O## |
| 4.1 | RAS41; inherently blocking two-argument compute; exact owned-process cleanup (no QuitRas) |
legacy .O## |
| 5.0.x (501-507) | Modern three-argument compute, Compute_Complete, and QuitRas |
plan HDF |
| 6.0 | Modern Controller contract | plan HDF |
| 6.3 family alias | Modern contract; selects RAS630 |
plan HDF |
| 6.3.0.2 exact | Modern RAS630.HECRASController |
plan HDF |
| 6.3.1 exact | Modern RAS631.HECRASController |
plan HDF |
| 6.6 | Modern Controller contract | plan HDF |
| 7.0 | Modern Controller contract | plan HDF |
Initialization¶
from ras_commander import init_ras_project, RasControl
# Initialize with version number
init_ras_project("/path/to/project", "4.1")
# Or with specific version code
init_ras_project("/path/to/project", "506") # HEC-RAS 5.0.6
Running Plans¶
# Run a plan (uses plan number, not file path)
success, messages = RasControl.run_plan("02")
if success:
print("Plan completed successfully")
else:
print(f"Plan failed: {messages}")
The COM interface: 1. Opens HEC-RAS in the background 2. Loads the project 3. Sets the current plan 4. Executes the plan 5. Closes HEC-RAS
Exact HEC-RAS 6.3.0.2 batch execution¶
HEC-RAS 6.3.0.2 and 6.3.1 register different Controller ProgIDs. The 6.3
family alias selects RAS630; use the exact 6.3.0.2 identity when a batch
receipt must retain the complete product version:
from ras_commander import RasControl, RasPrj, init_ras_project
project = RasPrj()
init_ras_project("/path/to/project", "6.3", ras_object=project)
result = RasControl.run_plan(
"01",
ras_object=project,
force_recompute=True,
blocking=True,
controller_version="6.3.0.2",
use_watchdog=False,
strict_close=True,
refresh_results=False,
)
assert result.execution_details["controller_progid"] == (
"RAS630.HECRASController"
)
assert result.execution_details["watchdog_started"] is False
blocking=True uses Compute_CurrentPlan(None, None, True) and does not poll
Compute_Complete(). use_watchdog=False is intended only when an outer batch
supervisor already owns the process tree and hard timeout. strict_close=True
makes a QuitRas() failure or a verified surviving owned ras.exe process
fail the operation instead of logging only a warning. If the internal watchdog
is requested but its actual worker identity cannot be proved, execution fails
before computation. The worker publishes its own PID, creation time, executable,
and launch arguments; this also handles Windows virtual-environment launchers
whose PID differs from the interpreter doing the monitoring.
HEC-RAS 4.0/4.1 always use the inherently blocking two-argument
Compute_CurrentPlan(None, None) call, including when the caller leaves
blocking=False. The API records the requested flag separately from the
effective blocking mode. It does not poll on the same thread after that call
returns. Its runtime bound requires the independent watchdog or an external
supervisor. An outer supervisor is also necessary to bound project opening,
which occurs before the internal compute watchdog starts.
execution_details contains JSON-safe provenance. Its stable common keys are
requested_controller_version, resolved_controller_version,
controller_progid, compute_mode, completion_method,
controller_quit_supported, controller_close_method, message_count,
controller_message_count, watchdog_requested, watchdog_started, and
duration_seconds. Polled modern Controllers report Compute_Complete,
True, and quit_ras for the three capability fields; blocking modern
Controllers report Compute_CurrentPlan_blocking_return, True, and
quit_ras. HEC-RAS 4.0/4.1 report Compute_CurrentPlan_blocking_return, False, and
owned_process_cleanup. The common result-family fields include
selected_result_format, artifact_preparation_cleanup,
artifact_finalization_cleanup, and result_artifacts_finalized. A cleanup
record's result_format names the opposing family targeted for deletion;
removed_paths and missing_paths partition its complete exact target set.
Both cleanup records are None for a current-result skip. A skip is explicitly
non-calculation evidence: calculation_attempted is False and
solver_quiescence_confirmed is None. current_check_performed,
current_check_close_safe, and current_check_close_method describe the
separate currency-check session. completion_method and
controller_close_method remain unset because no calculation ran. Blocking results
also include blocking_result; polled results include poll_count.
Use observe_dialogs=True for exact Controller-scoped diagnostic observation
before project opening. The observer verifies process and window ownership and
records its lifecycle in execution_details["dialog_observation"]. Unknown
dialogs remain untouched. This option provides evidence for diagnosing a
blocking GUI gate; it does not make an inherently blocking COM call asynchronous
or replace the external deadline.
HEC-RAS 4.0/4.1 expose neither Compute_Complete nor QuitRas. RasControl
fails closed unless exact PID/create-time exit is positively proved. An
access-denied or other identity-query error preserves the session lock as
evidence; it is never interpreted as exit or PID reuse.
Steady State Results¶
# Extract steady state profiles
results = RasControl.get_steady_results("02")
print(results)
# DataFrame columns:
# - river
# - reach
# - station
# - profile (PF 1, PF 2, etc.)
# - wse (water surface elevation)
# - velocity
# - flow
# - area
# - top_width
Plot Steady Profiles¶
import matplotlib.pyplot as plt
results = RasControl.get_steady_results("02")
# Plot water surface for each profile
fig, ax = plt.subplots(figsize=(12, 6))
for profile in results['profile'].unique():
profile_data = results[results['profile'] == profile]
ax.plot(
profile_data['station'],
profile_data['wse'],
label=profile
)
ax.set_xlabel('River Station')
ax.set_ylabel('Water Surface Elevation (ft)')
ax.set_title('Steady Flow Profiles')
ax.legend()
ax.invert_xaxis() # Upstream on left
plt.show()
Unsteady Results¶
# Get available output times
times = RasControl.get_output_times("01")
print(f"Available times: {times}")
# Includes special "Max WS" timestep
# Extract unsteady results
results = RasControl.get_unsteady_results("01", max_times=20)
print(results)
# DataFrame columns:
# - river
# - reach
# - station
# - time (datetime or "Max WS")
# - wse
# - velocity
# - flow
Plot Time Series at Cross Section¶
import matplotlib.pyplot as plt
results = RasControl.get_unsteady_results("01", max_times=50)
# Filter to single cross section (exclude Max WS)
station = 1000.0
xs_data = results[
(results['station'] == station) &
(results['time'] != "Max WS")
]
fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
axes[0].plot(xs_data['time'], xs_data['wse'])
axes[0].set_ylabel('Water Surface (ft)')
axes[0].set_title(f'Station {station}')
axes[1].plot(xs_data['time'], xs_data['flow'])
axes[1].set_ylabel('Flow (cfs)')
axes[1].set_xlabel('Time')
plt.tight_layout()
plt.show()
Setting Current Plan¶
# Set by plan title
RasControl.set_current_plan("Steady Flow Run")
# Then perform operations
results = RasControl.get_steady_results() # Uses current plan
Version Comparison Workflow¶
Compare results between HEC-RAS versions for migration validation:
from ras_commander import init_ras_project, RasControl, RasPrj
import pandas as pd
versions = ["4.1", "5.0.6", "6.6"]
all_results = {}
for version in versions:
project = RasPrj()
init_ras_project("/path/to/project", version, ras_object=project)
# Run plan
success, _ = RasControl.run_plan("02", ras_object=project)
if success:
results = RasControl.get_steady_results("02", ras_object=project)
all_results[version] = results
# Compare WSE at key stations
compare_df = pd.DataFrame()
for version, results in all_results.items():
wse_col = results.groupby('station')['wse'].mean()
compare_df[version] = wse_col
print("WSE Comparison by Version:")
print(compare_df)
# Calculate differences
compare_df['diff_4.1_to_6.6'] = compare_df['6.6'] - compare_df['4.1']
print(f"\nMax difference: {compare_df['diff_4.1_to_6.6'].abs().max():.2f} ft")
Open-Operate-Close Pattern¶
RasControl uses an open-operate-close pattern to prevent conflicts:
# Each operation is self-contained
success1, _ = RasControl.run_plan("01") # Opens, runs, closes
success2, _ = RasControl.run_plan("02") # Opens, runs, closes
# No lingering HEC-RAS windows
Integration with Modern Workflow¶
Combine RasControl (legacy) with modern RAS Commander features:
from ras_commander import (
init_ras_project, RasControl, RasCmdr, ras
)
# For legacy extraction
init_ras_project("/path/to/old_project", "4.1")
legacy_results = RasControl.get_steady_results("01")
# For modern execution
init_ras_project("/path/to/new_project", "7.0")
RasCmdr.compute_plan("01")
# Use HDF extraction for modern results
from ras_commander import HdfResultsPlan
modern_wse = HdfResultsPlan.get_steady_wse(ras.plan_df['hdf_path'].iloc[0])
Error Handling¶
from ras_commander import RasControl
try:
success, messages = RasControl.run_plan("99") # Non-existent
except ValueError as e:
print(f"Plan not found: {e}")
except RuntimeError as e:
if "COM" in str(e):
print("COM interface error - check HEC-RAS installation")
else:
raise
Requirements¶
- Windows operating system
- HEC-RAS installed (version you want to use)
- pywin32 package:
pip install pywin32
Limitations¶
- Windows only (COM interface)
- One HEC-RAS instance at a time per version
- No direct HDF access (use file-based output)
- Slower than command-line execution
See Also¶
examples/17_legacy_1d_automation_with_hecrascontroller_and_rascontrol.ipynb- Plan Execution - Modern execution methods
- Steady Flow Analysis - HDF-based steady results