Skip to content

Linux Execution of HEC-RAS with ras-commander

This notebook demonstrates how to execute HEC-RAS simulations on Linux servers using RasCmdr.compute_plan_linux(). This enables scalable, headless execution on cloud VMs, Proxmox containers, Docker, or any Linux host with the HEC-RAS Linux binaries installed.

Two-Phase Workflow

Linux HEC-RAS execution is a two-phase process:

Phase Platform What Happens
Phase 1: Preprocessing Windows Run RasPreprocess.preprocess_plan() to generate .tmp.hdf, .b##, .x## files
Phase 2: Execution Linux Run RasUnsteady binary with preprocessed files

Why two phases? The Linux HEC-RAS binaries (RasUnsteady, RasSteady, RasGeomPreprocess) are Fortran executables that run the compute engine only. They cannot do the full preprocessing or GUI operations needed to produce .tmp.hdf and .b## files. The Windows HEC-RAS application must preprocess the model first. Use RasPreprocess.preprocess_plan() to automate this step.

What You'll Learn

  • Setting up HEC-RAS Linux binaries on a server
  • Preprocessing a model on Windows using RasPreprocess.preprocess_plan()
  • Transferring files and running on Linux via SSH
  • macOS development workflow (for ras-agent users)
  • Verifying results match Windows execution

Prerequisites

1. Linux Server with SSH Access

You need a Linux machine accessible via SSH. Supported platforms: - Ubuntu 20.04+ / Debian 11+ - RHEL 8+ / Rocky Linux 8+ / AlmaLinux 8+ - Proxmox LXC containers - Docker containers - AWS EC2 / Azure VM / GCP instances

Minimum requirements: 4 GB RAM, 2 CPU cores, 10 GB disk space.

Set up passwordless SSH for automation:

Bash
# On your local machine (Windows PowerShell or macOS Terminal)
ssh-keygen -t ed25519 -C "ras-commander"  # Accept defaults
ssh-copy-id user@your-linux-server         # Copy public key

# Verify passwordless login
ssh user@your-linux-server "echo Connected"

3. HEC-RAS Linux Binaries

HEC-RAS Linux binaries are bundled with HEC-RAS 6.5+ Windows installers. They can also be downloaded from the USACE HEC-RAS website.

4. Python Environment

Bash
pip install ras-commander paramiko  # paramiko for SSH file transfer

Step 1: Install HEC-RAS Linux Binaries on the Server

HEC-RAS 6.5+ includes Linux binaries in the Windows installation directory:

Text Only
C:\Program Files (x86)\HEC\HEC-RAS\6.6\Linux\
    RasGeomPreprocess    # Geometry preprocessor
    RasSteady            # Steady flow solver
    RasUnsteady          # Unsteady flow solver
    run_helper.sh        # Official run script
    libs/                # Shared libraries
        libifcore.so.5
        libimf.so
        libiomp5.so
        ...
        mkl/             # Math Kernel Library
        rhel_8/          # RHEL 8 specific libs

Copy to the Linux server:

Bash
# From Windows (Git Bash or PowerShell with OpenSSH)
scp -r "C:/Program Files (x86)/HEC/HEC-RAS/6.6/Linux/"* \
    user@server:/opt/hecras/6.6/

# On the server: set executable permissions
ssh user@server "chmod +x /opt/hecras/6.6/RasUnsteady \
    /opt/hecras/6.6/RasSteady /opt/hecras/6.6/RasGeomPreprocess"

Option B: Extract from HEC-RAS Installer

For versions that bundle Linux binaries in the .exe installer but don't have a separate Linux/ folder, install HEC-RAS on a Windows machine first, then copy the Linux/ directory.

Directory Layout on Server

Recommended layout supporting multiple versions:

Text Only
/opt/hecras/
    6.5/
        RasUnsteady
        RasSteady
        RasGeomPreprocess
        run_helper.sh
        libs/
            mkl/
    6.6/
        RasUnsteady
        ...
        libs/
            mkl/
            rhel_8/
    6.7-beta5/
        ...

Verify Installation

Bash
ssh user@server "export LD_LIBRARY_PATH=/opt/hecras/6.6/libs:/opt/hecras/6.6/libs/mkl:/opt/hecras/6.6/libs/rhel_8 && /opt/hecras/6.6/RasUnsteady --version 2>&1 || echo 'Binary runs (no --version flag, expected)'"

If the binary runs without "not found" errors, the libraries are correctly configured. The solver will fail with a usage error since no input was given — that's expected.

Step 2: Preprocess the Model on Windows (Phase 1)

The Linux solver needs preprocessed files that only the Windows HEC-RAS application can generate. There are two approaches:

The RasPreprocess.preprocess_plan() method automates preprocessing by:

  1. Enabling detailed logging (Write Detailed= 1) in the plan file
  2. Starting HEC-RAS and monitoring the .bco log file
  3. Detecting "Starting Unsteady Flow Computations" signal
  4. Killing HEC-RAS at that exact moment (preprocessing complete)
  5. Verifying .tmp.hdf, .b##, .x## files were generated
Python
from ras_commander import RasPreprocess, init_ras_project

init_ras_project("C:/Projects/MyModel", "6.6")
result = RasPreprocess.preprocess_plan("01")
if result:
    print(f"Preprocessing complete in {result.elapsed_seconds:.1f}s")
    print(f"  tmp.hdf: {result.tmp_hdf_path}")
    print(f"  .b file: {result.b_file_path}")
    print(f"  .x file: {result.x_file_path}")
else:
    print(f"Preprocessing failed: {result.error}")

You can also check if preprocessing has already been done:

Python
if RasPreprocess.verify_preprocessing("01"):
    print("Ready for Linux execution")
else:
    RasPreprocess.preprocess_plan("01")

Approach B: Manual Preprocessing

  1. Open the project in HEC-RAS GUI on Windows
  2. Run the plan (let it start computing)
  3. Once you see "Starting Unsteady Flow Computations" in the compute window, close HEC-RAS
  4. The .tmp.hdf file in the project folder contains all preprocessed data

Required Output Files

After preprocessing, your project folder should contain:

File Description Generated By
Project.p01.tmp.hdf Preprocessed plan HDF (geometry + setup) HEC-RAS preprocessing
Project.b01 Boundary conditions (Fortran format) HEC-RAS preprocessing
Project.x01 Cross-section preprocessor data HEC-RAS preprocessing
Project.g01.hdf Geometry HDF Existing (from project)
Project.p01 Plan file Existing (from project)

Step 3: Transfer Files to Linux Server

Python
import platform
import sys
from pathlib import Path
import subprocess

# IS_LINUX: flag used by all subsequent cells to guard Linux-only operations.
# When False every cell prints a skip message and exits cleanly.
IS_LINUX = sys.platform.startswith("linux")

if IS_LINUX:
    print("Running on Linux — notebook is active.")
else:
    print(
        "NOTE: This notebook targets Linux/WSL. "
        "All execution cells will be skipped on this platform "
        f"({sys.platform}). The code is shown for reference only."
    )

# Imports that are safe on any platform
try:
    from ras_commander import init_ras_project, RasCmdr, RasUtils, RasPreprocess
except ImportError:
    sys.path.append(str(Path(".").resolve().parent))
    from ras_commander import init_ras_project, RasCmdr, RasUtils, RasPreprocess
Python
import os
# ── Configuration ────────────────────────────────────────────
# Edit these values for your environment

if IS_LINUX:
    # Linux server connection
    LINUX_HOST = "192.168.3.2"           # Your Linux server IP or hostname
    LINUX_USER = "root"                   # SSH username
    LINUX_RAS_DIR = "/opt/hecras/6.7-beta5"  # HEC-RAS binary directory on server

    # Local Windows project (already preprocessed with Phase 1)
    LOCAL_RESULTS_DIR = os.environ.get("RAS_LINUX_RESULTS_DIR", "")
    LOCAL_PROJECT = Path(LOCAL_RESULTS_DIR) if LOCAL_RESULTS_DIR else Path("/tmp/MyModel")  # Your project folder
    PLAN_NUMBER = "01"                    # Plan to execute

    # Remote working directory
    REMOTE_PROJECT_DIR = "/tmp/ras_linux_run"
else:
    print("(skipped — not on Linux; config values not set)")
Python
# ── Verify prerequisite files exist locally ─────────────────────────────────────

if IS_LINUX:
    project_name = list(LOCAL_PROJECT.glob("*.prj"))[0].stem
    plan_num = PLAN_NUMBER.zfill(2)

    # Read geometry number from plan file
    import re
    plan_file = LOCAL_PROJECT / f"{project_name}.p{plan_num}"
    geom_num = "01"
    for line in plan_file.read_text(errors='replace').splitlines():
        if line.startswith("Geom File="):
            m = re.search(r'(\d+)', line.split('=', 1)[1])
            if m:
                geom_num = m.group(1)
            break

    required_files = {
        'tmp_hdf': LOCAL_PROJECT / f"{project_name}.p{plan_num}.tmp.hdf",
        'boundary': LOCAL_PROJECT / f"{project_name}.b{plan_num}",
        'xsec': LOCAL_PROJECT / f"{project_name}.x{geom_num}",
        'plan': plan_file,
        'geom_hdf': LOCAL_PROJECT / f"{project_name}.g{geom_num}.hdf",
    }

    print(f"Project: {project_name}")
    print(f"Plan: p{plan_num}, Geometry: g{geom_num}")
    print()
    all_ok = True
    for name, path in required_files.items():
        exists = path.exists()
        size = f"{path.stat().st_size / 1e6:.1f} MB" if exists else "MISSING"
        status = "OK" if exists else "MISSING"
        print(f"  [{status}] {path.name} ({size})")
        if not exists:
            all_ok = False

    if not all_ok:
        print("\nRun Phase 1 preprocessing on Windows first!")
    else:
        print("\nAll prerequisite files present. Ready for Linux transfer.")
else:
    print("(skipped — not on Linux)")
Python
# ── Transfer project to Linux server ───────────────────────────────────────────────
# Uses scp for simplicity. For large projects, consider rsync.

if IS_LINUX:
    def run_ssh(cmd, check=True):
        """Run a command on the Linux server via SSH."""
        result = subprocess.run(
            ["ssh", f"{LINUX_USER}@{LINUX_HOST}", cmd],
            capture_output=True, text=True, timeout=60
        )
        if check and result.returncode != 0:
            print(f"SSH error: {result.stderr}")
        return result

    # Create remote directory
    run_ssh(f"mkdir -p {REMOTE_PROJECT_DIR}")

    # Copy project files
    print(f"Transferring project to {LINUX_USER}@{LINUX_HOST}:{REMOTE_PROJECT_DIR}")
    scp_result = subprocess.run(
        ["scp", "-r", str(LOCAL_PROJECT) + "/.",
         f"{LINUX_USER}@{LINUX_HOST}:{REMOTE_PROJECT_DIR}/"],
        capture_output=True, text=True, timeout=600
    )

    if scp_result.returncode == 0:
        print("Transfer complete.")
        # Verify files arrived
        result = run_ssh(f"ls -la {REMOTE_PROJECT_DIR}/*.tmp.hdf {REMOTE_PROJECT_DIR}/*.b* {REMOTE_PROJECT_DIR}/*.x*")
        print(result.stdout)
    else:
        print(f"Transfer failed: {scp_result.stderr}")
else:
    print("(skipped — not on Linux)")

Step 4: Execute on Linux (Phase 2)

Python
# ── Execute RasUnsteady on the Linux server ─────────────────────────────────────────
# This runs the official run_helper.sh or invokes RasUnsteady directly.

if IS_LINUX:
    # Option A: Using run_helper.sh (simplest)
    cmd = (
        f"cd {REMOTE_PROJECT_DIR} && "
        f"{LINUX_RAS_DIR}/run_helper.sh RasUnsteady "
        f"{project_name}.p{plan_num}.tmp.hdf x{geom_num}"
    )

    print(f"Running: {cmd}")
    print("This may take several minutes...")
    print()

    result = subprocess.run(
        ["ssh", f"{LINUX_USER}@{LINUX_HOST}", cmd],
        capture_output=True, text=True,
        timeout=14400  # 4-hour timeout
    )

    # Print output
    if result.stdout:
        # Filter out FONT= lines (Fortran console formatting)
        for line in result.stdout.splitlines():
            if not line.startswith("FONT="):
                print(line)

    if result.returncode == 0:
        print("\nExecution completed successfully.")
    else:
        print(f"\nExecution failed (exit code {result.returncode})")
        if result.stderr:
            print(result.stderr[-500:])
else:
    print("(skipped — not on Linux)")
Python
# ── Option B: Using compute_plan_linux() (programmatic, with ras-commander on Linux)
# This requires ras-commander installed on the Linux server.
#
# ssh user@server "pip install ras-commander"
#
# Then from a Python script on the server:
#
# from ras_commander import init_ras_project, RasCmdr
# init_ras_project("/tmp/ras_linux_run")
# result = RasCmdr.compute_plan_linux(
#     "01",
#     ras_exe_dir="/opt/hecras/6.6",
#     timeout_sec=7200
# )
# print(f"Success: {result.success}")

Step 5: Retrieve Results

Python
# ── Copy results back from Linux server ────────────────────────────────────────────

if IS_LINUX:
    local_results = LOCAL_PROJECT / "linux_results"
    local_results.mkdir(exist_ok=True)

    # Copy the results HDF back
    scp_result = subprocess.run(
        ["scp",
         f"{LINUX_USER}@{LINUX_HOST}:{REMOTE_PROJECT_DIR}/{project_name}.p{plan_num}.tmp.hdf",
         str(local_results / f"{project_name}.p{plan_num}.hdf")],
        capture_output=True, text=True, timeout=600
    )

    if scp_result.returncode == 0:
        hdf_path = local_results / f"{project_name}.p{plan_num}.hdf"
        print(f"Results downloaded: {hdf_path}")
        print(f"Size: {hdf_path.stat().st_size / 1e6:.1f} MB")
    else:
        print(f"Download failed: {scp_result.stderr}")
else:
    print("(skipped — not on Linux)")
Python
# ── Extract and verify results ─────────────────────────────────────────────────

if IS_LINUX:
    from ras_commander.hdf import HdfResultsMesh
    import h5py

    hdf_path = local_results / f"{project_name}.p{plan_num}.hdf"

    # Check HDF structure
    with h5py.File(hdf_path, 'r') as hf:
        has_results = 'Results' in hf
        print(f"Has Results group: {has_results}")
        if has_results:
            print(f"Top-level groups: {list(hf.keys())}")
            results = hf['Results']
            print(f"Results subgroups: {list(results.keys())}")
else:
    print("(skipped — not on Linux)")

macOS Development Workflow

For macOS users (e.g., developing with ras-agent), the workflow is the same conceptually but with macOS-specific SSH tooling:

SSH Setup on macOS

Bash
# Generate SSH key (if not done)
ssh-keygen -t ed25519 -C "ras-commander"

# Copy to Linux server
ssh-copy-id user@linux-server

# Verify
ssh user@linux-server "uname -a"

File Transfer from macOS

Bash
# scp works identically on macOS
scp -r ./my_project/ user@server:/tmp/ras_run/

# rsync for large projects (faster for incremental updates)
rsync -avz --progress ./my_project/ user@server:/tmp/ras_run/

macOS Limitations

  • No Windows preprocessing on macOS: Phase 1 requires Windows HEC-RAS. Options:
  • Use a Windows VM (Parallels, UTM, VMware Fusion)
  • Use a remote Windows machine via RDP
  • Pre-generate .tmp.hdf files on a Windows build server
  • Use Docker with Wine (experimental)
  • ras-commander works on macOS for all non-execution operations: project initialization, HDF reading, geometry parsing, results extraction.
  • ras-agent pipeline runs entirely on macOS in mock mode for development; real execution requires the Linux server.

Typical macOS + Linux Workflow

Text Only
macOS (development)          Windows VM              Linux Server
    |                            |                        |
    |-- Edit model files ------->|                        |
    |                            |-- Preprocess (Phase 1) |
    |                            |-- .tmp.hdf, .b, .x --->|
    |                            |                        |-- RasUnsteady (Phase 2)
    |<-- Results (.hdf) ---------|<-- Results (.hdf) -----|
    |-- Analyze with RC          |                        |

HEC-RAS Linux Version Compatibility

Version Linux Binaries Library Layout Notes
6.3.1 Separate download libs/, libs/mkl/ Oldest supported
6.4.1 Separate download libs/, libs/mkl/
6.5 Bundled in installer libs/, libs/mkl/ First version bundled with Windows
6.6 Bundled in installer libs/, libs/mkl/, libs/rhel_8/ Added RHEL 8 libs
6.7 Beta Bundled in installer libs/, libs/mkl/, libs/rhel_8/ Latest

compute_plan_linux() auto-detects the library layout by scanning all subdirectories under libs/ and adding them to LD_LIBRARY_PATH.

Version-Specific Considerations

  • 6.3.1-6.4.1: May require centos_7 libs instead of rhel_8 on older distributions.
  • 6.5-6.6: Most widely tested. Recommended for production.
  • 6.7 Beta: Newer Fortran I/O conventions. Requires geometry files preprocessed with the same version — a model preprocessed with 6.5 may not run on 6.7 due to HDF schema changes (e.g., IBCTYP dataset).

Rule of thumb: Always preprocess and execute with the same HEC-RAS version.

Fortran I/O Naming Convention

The Linux RasUnsteady binary is a Fortran executable that uses hardcoded unit numbers for file I/O. When invoked with a project-named file (e.g., Muncie.p04.tmp.hdf), it looks for supporting files with a base name of io — for example, io.b, io.X, io.g.

compute_plan_linux() handles this automatically by creating temporary symlinks:

Text Only
io.b    → Muncie.b04      (boundary conditions)
io.X    → Muncie.x04      (cross-section preprocessor)
io.x    → Muncie.x04      (lowercase variant)
io.g    → Muncie.g04      (geometry)
io.p    → Muncie.p04      (plan)
io.u    → Muncie.u01      (unsteady flow)
...

These symlinks are created before execution and cleaned up afterwards. If you're running manually (without compute_plan_linux()), you'll need to create these symlinks yourself or use the official run_helper.sh script.

Troubleshooting

"file not found: io.b"

The solver can't find the boundary conditions file. Ensure: - .b## file exists in the project directory - io.b symlink points to it (or use compute_plan_linux() which creates it)

"IBCTYP doesn't exist" / "TRY SAVING THE GEOMETRY AND RE-RUNNING THE PREPROCESSOR"

Version mismatch between preprocessing and execution. The .g##.hdf was preprocessed with a different HEC-RAS version than the Linux binary. Solution: Re-preprocess on Windows using the same version as the Linux binary.

"The output must not already exist"

The .tmp.hdf file already has a /Results group. Delete it or let compute_plan_linux() handle it.

"unable to open file" / HDF5 errors

Possible causes: - File permissions (run chmod 644 *.hdf) - File corruption during transfer (re-copy with scp or rsync -c) - Wrong HDF5 library version on server

Timeout after 4 hours

Large models may need more time. Increase timeout_sec:

Python
RasCmdr.compute_plan_linux("01", ras_exe_dir, timeout_sec=28800)  # 8 hours

CRLF line ending errors

If the .b## or .g## files have Windows line endings (CRLF), the Fortran parser may fail. compute_plan_linux() runs dos2unix automatically. For manual execution:

Bash
sed -i 's/\r$//' *.b* *.g*

Key Takeaways

  1. Two-phase workflow: Preprocess on Windows (Phase 1), execute on Linux (Phase 2)
  2. Version matching: Always use the same HEC-RAS version for both phases
  3. Prerequisite files: .tmp.hdf, .b##, .x## must exist before Linux execution
  4. Fortran I/O: The solver needs io.* symlinks — compute_plan_linux() handles this
  5. macOS users: Use a Windows VM for Phase 1, SSH to Linux for Phase 2
  6. Multiple versions: Install each version in /opt/hecras/{version}/
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.