Skip to content

Executing Plan Sets

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 RasCmdr, RasExamples, RasPlan, RasPrj, init_ras_project, ras

# Additional imports
import os
import numpy as np
import pandas as pd
from IPython import display
import matplotlib.pyplot as plt
import psutil  # For getting system CPU info
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
import subprocess
import shutil

# Verify which version loaded
import ras_commander
print(f"✓ Loaded: {ras_commander.__file__}")
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

Prerequisites

Before running this notebook, ensure you have:

  1. ras-commander installed: pip install ras-commander
  2. Python 3.10+: Check with python --version
  3. HEC-RAS 6.3+: REQUIRED for plan execution
  4. Disk Space: ~2 GB (example project + execution results)

What You'll Learn

This notebook demonstrates selective plan execution patterns:

  • Specific Plan Lists: Execute chosen plans, not all plans
  • Conditional Execution: Run only plans missing HDF results
  • Sequential Processing: Control execution order for dependent plans
  • 110_single_plan_execution.ipynb - Execute individual plans
  • 112_sequential_plan_execution.ipynb - Test mode debugging
  • 113_parallel_execution.ipynb - Parallel plan sets

Key Concept: Plan Selection Strategies

Strategy 1: Explicit List

Python
# Run specific plans by number
plans_to_run = ["01", "03", "05"]
for plan in plans_to_run:
    RasCmdr.compute_plan(plan)

Strategy 2: Conditional Selection

Python
# Run only plans without results
plans_without_hdf = ras.plan_df[~ras.plan_df['hdf_path'].apply(Path).map(lambda p: p.exists())]
missing_plans = plans_without_hdf['plan_number'].tolist()

Strategy 3: Filtered by Criteria

Python
# Run only unsteady plans
unsteady_plans = ras.plan_df[ras.plan_df['plan_title'].str.contains('Unsteady')]
plans_to_run = unsteady_plans['plan_number'].tolist()

Parameters

Configure these values to customize the notebook for your project.

Python
# =============================================================================
# PARAMETERS - Edit these to customize the notebook
# =============================================================================
from pathlib import Path

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

# Execution Settings
PLAN = "01"                       # Plan number to execute
NUM_CORES = 4                     # CPU cores for 2D computation
RUN_SUFFIX = "run"                # Suffix for run folder (e.g., Muncie_run)
Python
# Extract the Bald Eagle Creek example project
# The extract_project method downloads the project from GitHub if not already present,
# and extracts it to the example_projects folder
bald_eagle_path = RasExamples.extract_project("Balde Eagle Creek", suffix="111")
print(f"Extracted project to: {bald_eagle_path}")  


# Verify the path exists
print(f"Bald Eagle Creek project exists: {bald_eagle_path.exists()}")
Text Only
2026-01-11 22:11:01 - 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-11 22:11:01 - ras_commander.RasExamples - INFO - Loading project data from CSV...
2026-01-11 22:11:01 - ras_commander.RasExamples - INFO - Loaded 68 projects from CSV.
2026-01-11 22:11:01 - ras_commander.RasExamples - INFO - ----- RasExamples Extracting Project -----
2026-01-11 22:11:01 - ras_commander.RasExamples - INFO - Extracting project 'Balde Eagle Creek' as 'Balde Eagle Creek_111'
2026-01-11 22:11:01 - ras_commander.RasExamples - INFO - Folder 'Balde Eagle Creek_111' already exists. Deleting existing folder...
2026-01-11 22:11:01 - ras_commander.RasExamples - INFO - Existing folder 'Balde Eagle Creek_111' has been deleted.
2026-01-11 22:11:01 - ras_commander.RasExamples - INFO - Successfully extracted project 'Balde Eagle Creek' to C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111


Extracted project to: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111
Bald Eagle Creek project exists: True

Step 1: Project Initialization

Let's initialize the HEC-RAS project using the init_ras_project() function and explore the available plans.

Python
# Initialize the HEC-RAS project
init_ras_project(bald_eagle_path, RAS_VERSION)
print(f"Initialized HEC-RAS project: {ras.project_name}")

# Display the current plan files in the project
print("\nAvailable plans in the project:")
display.display(ras.plan_df)

# Check plan details to understand what each plan represents
plan_details = []
for index, row in ras.plan_df.iterrows():
    plan_number = row['plan_number']

    # Get plan description if available
    description = None
    if 'description' in row:
        description = row['description']
    else:
        try:
            description = RasPlan.read_plan_description(plan_number)
        except:
            pass

    # Get short identifier if available
    short_id = None
    if 'Short Identifier' in row:
        short_id = row['Short Identifier']

    # Get geometry file
    geom_file = None
    if 'Geom File' in row:
        geom_file = row['Geom File']

    # Check if the plan has results
    has_results = False
    if 'HDF_Results_Path' in row and row['HDF_Results_Path']:
        has_results = True

    plan_details.append({
        'Plan Number': plan_number,
        'Short ID': short_id,
        'Description': description[:50] + '...' if description and len(description) > 50 else description,
        'Geometry': geom_file,
        'Has Results': has_results
    })

# Create a DataFrame with the plan details
plan_details_df = pd.DataFrame(plan_details)
print("\nPlan details:")
display.display(plan_details_df)
Text Only
2026-01-11 22:11:01 - ras_commander.RasMap - INFO - Successfully parsed RASMapper file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.rasmap
2026-01-11 22:11:01 - ras_commander.RasPrj - INFO - Updated results_df with 2 plan(s)


Initialized HEC-RAS project: BaldEagle

Available plans in the project:
plan_number unsteady_number geometry_number Plan Title Program Version Short Identifier Simulation Date Computation Interval Mapping Interval Run HTab ... PS Cores DSS File Friction Slope Method HDF_Results_Path Geom File Geom Path Flow File Flow Path full_path flow_type
0 01 02 01 Unsteady with Bridges and Dam 5.00 UnsteadyFlow 18FEB1999,0000,24FEB1999,0500 2MIN 1HOUR 1 ... None dss 2 None 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 02 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... Unsteady
1 02 None 01 Steady Flow Run NaN SteadyRun 02/18/1999,0000,02/24/1999,0500 2MIN NaN 1 ... None dss 1 None 01 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... 02 C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... Steady

2 rows × 27 columns

Text Only
2026-01-11 22:11:01 - ras_commander.RasPlan - WARNING - No description found in plan file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p01
2026-01-11 22:11:01 - ras_commander.RasPlan - WARNING - No description found in plan file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p02



Plan details:
Plan Number Short ID Description Geometry Has Results
0 01 UnsteadyFlow 01 False
1 02 SteadyRun 01 False

Step 2: Sequential Execution of Specific Plans

Let's execute specific plans in sequence using RasCmdr.compute_test_mode() with a list of plan numbers. This approach allows us to run only the plans we need, in the order we specify.

Python
print("Executing specific plans sequentially...")
print("This may take several minutes...")

# Define the plans to execute
specific_plans = ["01", "03"]
print(f"Selected plans: {', '.join(specific_plans)}")

# Record start time for performance measurement
start_time = time.time()

# Execute specific plans sequentially
execution_results = RasCmdr.compute_test_mode(
    plan_number=specific_plans,
    dest_folder_suffix="[SpecificSequential]",
    num_cores=6, 
    overwrite_dest=True
)

# Record end time and calculate duration
end_time = time.time()
sequential_duration = end_time - start_time

print(f"Sequential execution of specific plans completed in {sequential_duration:.2f} seconds")

# Create a DataFrame from the execution results for better visualization
sequential_results_df = pd.DataFrame([
    {"Plan": plan, "Success": success, "Execution Type": "Sequential"}
    for plan, success in execution_results.items()
])

sequential_results_df 

# Ensure the 'Plan' column exists before sorting
if 'Plan' in sequential_results_df.columns:
    sequential_results_df = sequential_results_df.sort_values("Plan")
else:
    print("Warning: 'Plan' column not found in execution results.")

# Display the results
print("\nSequential Execution Results:")
display.display(sequential_results_df)

# Check the test folder
test_folder = bald_eagle_path.parent / f"{ras.project_name} [SpecificSequential]"
if test_folder.exists():
    print(f"\nTest folder exists: {test_folder}")

    # Check for results
    hdf_files = list(test_folder.glob("*.p*.hdf"))
    if hdf_files:
        print(f"Found {len(hdf_files)} HDF result files:")
        for file in hdf_files:
            file_size = file.stat().st_size / (1024 * 1024)  # Size in MB
            print(f"  {file.name}: {file_size:.1f} MB")
    else:
        print("No HDF result files found in the test folder")
Text Only
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Starting the compute_test_mode...
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Creating the test folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]...
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Copied project folder to compute folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]
2026-01-11 22:11:01 - ras_commander.RasMap - INFO - Successfully parsed RASMapper file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.rasmap
2026-01-11 22:11:01 - ras_commander.RasPrj - INFO - Updated results_df with 2 plan(s)
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Initialized RAS project in compute folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.prj
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Getting plan entries...
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Retrieved plan entries successfully.
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Filtered plans to execute: ['01', '03']
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Running selected plans sequentially...
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Using ras_object with project folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]
2026-01-11 22:11:01 - ras_commander.RasUtils - INFO - Using provided plan file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01
2026-01-11 22:11:01 - ras_commander.RasUtils - INFO - Successfully updated file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Set number of cores to 6 for plan: 01
2026-01-11 22:11:01 - ras_commander.RasCmdr - INFO - Running HEC-RAS from the Command Line:


Executing specific plans sequentially...
This may take several minutes...
Selected plans: 01, 03


2026-01-11 22:11:01 - 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\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.prj" "C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01"
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - HEC-RAS execution completed for plan: 01
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Total run time for plan 01: 94.24 seconds
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Reading computation messages from HDF: BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Successfully extracted 1693 characters from HDF
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Extracting Plan Information from: BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Plan Name: Unsteady with Bridges and Dam
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Simulation Duration (hours): 149.0
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]\BaldEagle.p01.hdf
c:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\ras_commander\RasPrj.py:1513: 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-11 22:12:35 - ras_commander.RasPrj - INFO - Updated results_df with 1 plan(s)
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Successfully computed plan 01
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Total run time for plan 01: 94.29 seconds
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - All selected plans have been executed.
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Consolidating HDF results from C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential] back to original project folder...
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Consolidated 3 HDF file(s) to original project folder
2026-01-11 22:12:35 - ras_commander.RasCmdr - WARNING - Failed to remove test folder C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [SpecificSequential]: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Users\\billk_clb\\anaconda3\\envs\\rascmdr_piptest\\Lib\\site-packages\\examples\\example_projects\\Balde Eagle Creek_111 [SpecificSequential]'
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - compute_test_mode completed.
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - 
Execution Results:
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Plan 01: Successful
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Reading computation messages from HDF: BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Successfully extracted 1693 characters from HDF
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Extracting Plan Information from: BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Plan Name: Unsteady with Bridges and Dam
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Simulation Duration (hours): 149.0
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p01.hdf
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p01.hdf
c:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\ras_commander\RasPrj.py:1513: 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-11 22:12:35 - ras_commander.RasPrj - INFO - Updated results_df with 1 plan(s)


Sequential execution of specific plans completed in 94.37 seconds

Sequential Execution Results:
Plan Success Execution Type
0 01 True Sequential

Step 3: Running Only Plans Without HDF Results

An important use case is to identify and execute only those plans that have no existing HDF results. This approach can save time by avoiding redundant computations, especially useful when adding new plans to an existing project or after making limited changes.

Let's demonstrate how to:

  • Use the ras object to identify plans without results
  • Create a filtered list of these plans
  • Execute only the missing plans
Python
print("Identifying and executing plans without HDF results...")

# Use the ras object to determine which plans don't have results
plans_no_results = ras.plan_df[ras.plan_df['HDF_Results_Path'].isna()]['plan_number'].tolist()

if not plans_no_results:
    print("All plans already have HDF results. Creating a test scenario...")
    # For demonstration purposes, pretend some plans don't have results
    plans_no_results = ["04", "05"]
    print(f"Simulating no results for plans: {', '.join(plans_no_results)}")
else:
    print(f"Found {len(plans_no_results)} plans without HDF results: {', '.join(plans_no_results)}")

# Record start time for performance measurement
start_time = time.time()

# Execute only the plans without results
if plans_no_results:
    print(f"\nExecuting {len(plans_no_results)} plans without results...")
    execution_results = RasCmdr.compute_test_mode(
        plan_number=plans_no_results,
        dest_folder_suffix="[MissingPlans]",
        num_cores=6, 
        overwrite_dest=True
    )

    # Record end time and calculate duration
    end_time = time.time()
    duration = end_time - start_time

    print(f"Execution completed in {duration:.2f} seconds")

    # Create a DataFrame from the execution results
    missing_results_df = pd.DataFrame([
        {"Plan": plan, "Success": success, "Execution Type": "Missing Plans"}
        for plan, success in execution_results.items()
    ])

    # Sort by plan number
    missing_results_df = missing_results_df.sort_values("Plan")

    # Display the results
    print("\nExecution Results for Plans Without HDF Results:")
    display.display(missing_results_df)

    # Check the test folder
    test_folder = bald_eagle_path.parent / f"{ras.project_name} [MissingPlans]"
    if test_folder.exists():
        print(f"\nTest folder exists: {test_folder}")

        # Check for results
        hdf_files = list(test_folder.glob("*.p*.hdf"))
        if hdf_files:
            print(f"Found {len(hdf_files)} HDF result files:")
            for file in hdf_files:
                file_size = file.stat().st_size / (1024 * 1024)  # Size in MB
                print(f"  {file.name}: {file_size:.1f} MB")
        else:
            print("No HDF result files found in the test folder")
else:
    print("No plans without results to execute.")
Text Only
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Starting the compute_test_mode...
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Creating the test folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]...
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Compute folder 'C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]' exists. Overwriting as per overwrite_dest=True.
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Copied project folder to compute folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]
2026-01-11 22:12:35 - ras_commander.RasMap - INFO - Successfully parsed RASMapper file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.rasmap
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Reading computation messages from HDF: BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Successfully extracted 1693 characters from HDF
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Extracting Plan Information from: BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Plan Name: Unsteady with Bridges and Dam
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Simulation Duration (hours): 149.0
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p01.hdf
2026-01-11 22:12:35 - ras_commander.RasPrj - INFO - Updated results_df with 2 plan(s)
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Initialized RAS project in compute folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.prj
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Getting plan entries...
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Retrieved plan entries successfully.
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Filtered plans to execute: ['02']
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Running selected plans sequentially...
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Using ras_object with project folder: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]
2026-01-11 22:12:35 - ras_commander.RasUtils - INFO - Using provided plan file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02
2026-01-11 22:12:35 - ras_commander.RasUtils - INFO - Successfully updated file: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Set number of cores to 6 for plan: 02
2026-01-11 22:12:35 - ras_commander.RasCmdr - INFO - Running HEC-RAS from the Command Line:
2026-01-11 22:12:35 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.prj" "C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02"


Identifying and executing plans without HDF results...
Found 1 plans without HDF results: 02

Executing 1 plans without results...


2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - HEC-RAS execution completed for plan: 02
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - Total run time for plan 02: 3.92 seconds
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Reading computation messages from HDF: BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Successfully extracted 529 characters from HDF
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Extracting Plan Information from: BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - ERROR - Error parsing simulation times: time data 'Unknown' does not match format '%d%b%Y %H:%M:%S'
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]\BaldEagle.p02.hdf
c:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\ras_commander\RasPrj.py:1513: 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-11 22:12:39 - ras_commander.RasPrj - INFO - Updated results_df with 1 plan(s)
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - Successfully computed plan 02
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - Total run time for plan 02: 3.95 seconds
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - All selected plans have been executed.
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - Consolidating HDF results from C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans] back to original project folder...
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - Consolidated 4 HDF file(s) to original project folder
2026-01-11 22:12:39 - ras_commander.RasCmdr - WARNING - Failed to remove test folder C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111 [MissingPlans]: [WinError 32] The process cannot access the file because it is being used by another process: 'C:\\Users\\billk_clb\\anaconda3\\envs\\rascmdr_piptest\\Lib\\site-packages\\examples\\example_projects\\Balde Eagle Creek_111 [MissingPlans]'
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - compute_test_mode completed.
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - 
Execution Results:
2026-01-11 22:12:39 - ras_commander.RasCmdr - INFO - Plan 02: Successful
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Reading computation messages from HDF: BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Successfully extracted 529 characters from HDF
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Extracting Plan Information from: BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - ERROR - Error parsing simulation times: time data 'Unknown' does not match format '%d%b%Y %H:%M:%S'
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p02.hdf
2026-01-11 22:12:39 - 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\Balde Eagle Creek_111\BaldEagle.p02.hdf
2026-01-11 22:12:39 - ras_commander.hdf.HdfResultsPlan - INFO - Final validated file path: C:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\examples\example_projects\Balde Eagle Creek_111\BaldEagle.p02.hdf
c:\Users\billk_clb\anaconda3\envs\rascmdr_piptest\Lib\site-packages\ras_commander\RasPrj.py:1513: 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-11 22:12:39 - ras_commander.RasPrj - INFO - Updated results_df with 1 plan(s)


Execution completed in 4.04 seconds

Execution Results for Plans Without HDF Results:
Plan Success Execution Type
0 02 True Missing Plans

Verification of Results

After executing the plans that were missing HDF results, it's important to verify that the results were properly generated. Let's check if the execution actually created the expected output files.

Python
# Re-initialize the project with the test folder to see updated results
missing_plans_folder = bald_eagle_path.parent / f"{ras.project_name} [MissingPlans]"

if missing_plans_folder.exists():
    # Initialize the project from the test folder
    test_ras = RasPrj()
    init_ras_project(missing_plans_folder, RAS_VERSION, ras_object=test_ras)

    # Check which plans now have results
    plans_with_results = test_ras.plan_df[test_ras.plan_df['HDF_Results_Path'].notna()]['plan_number'].tolist()

    print(f"Plans with results after execution: {', '.join(plans_with_results)}")

    # Verify if all previously missing plans now have results
    all_generated = all(plan in plans_with_results for plan in plans_no_results)

    if all_generated:
        print("✅ Successfully generated results for all missing plans")
    else:
        print("⚠️ Some plans still don't have results after execution")
        missing_after = [plan for plan in plans_no_results if plan not in plans_with_results]
        print(f"Plans still missing results: {', '.join(missing_after)}")

Viewing Execution Summary with results_df

The results_df DataFrame provides execution status, timing, and error/warning information for all executed plans.

Python
# Display execution summary from results_df
print("Execution Summary:")
ras.results_df.T
Text Only
Execution Summary:
0 1
plan_number 01 02
plan_title Unsteady with Bridges and Dam Steady Flow Run
flow_type Unsteady Unsteady
hdf_path C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt... C:\Users\billk_clb\anaconda3\envs\rascmdr_pipt...
hdf_exists True True
hdf_mtime 2026-01-11 22:12:35.461179 2026-01-11 22:12:39.546552
completed True True
has_errors False False
has_warnings False False
error_count 0 0
warning_count 0 0
first_error_line None None
rt_simulation_start 1999-02-18 00:00:00 NaT
rt_simulation_end 1999-02-24 05:00:00 NaT
rt_simulation_hours 149.0 NaN
rt_complete_process_hours 0.025616 NaN
rt_unsteady_compute_hours 0.000886 NaN
rt_complete_process_speed 5816.588772 NaN
unsteady_time_of_maximum_stage None None
unsteady_time_of_maximum_velocity None None
unsteady_time_of_maximum_flow None None
unsteady_computation_interval None None
steady_solution NaN NaN
vol_Error -29.546846 NaN
vol_Error_Percent 0.014071 NaN
vol_Total_Boundary_Flux_of_Water_In 200682.453125 NaN
vol_Total_Boundary_Flux_of_Water_Out 112574.828125 NaN
vol_Vol_Accounting_in Acre Feet NaN
vol_Volume_Ending 97384.882812 NaN
vol_Volume_Starting 9306.797852 NaN

Plan Set Execution Best Practices

Common Patterns

Pattern 1: Baseline + Alternatives

Python
baseline_plan = "01"
alternatives = ["02", "03", "04", "05"]

# Run baseline first
print("Running baseline...")
RasCmdr.compute_plan(baseline_plan)

# Then run alternatives
print("Running alternatives...")
for plan in alternatives:
    RasCmdr.compute_plan(plan)

Pattern 2: Sensitivity Analysis Grid

Python
# Create plan matrix: different roughness values
roughness_values = [0.030, 0.035, 0.040, 0.045]
plan_map = {}

for i, roughness in enumerate(roughness_values, start=1):
    plan_num = f"{i:02d}"
    plan_map[plan_num] = roughness

# Execute all sensitivity plans
for plan_num in plan_map.keys():
    print(f"Running plan {plan_num} (n={plan_map[plan_num]})...")
    RasCmdr.compute_plan(plan_num)

Pattern 3: Phased Execution

Python
# Phase 1: Quick steady-state runs
steady_plans = ras.plan_df[ras.plan_df['plan_title'].str.contains('Steady')]
for plan in steady_plans['plan_number']:
    RasCmdr.compute_plan(plan)

# Phase 2: Longer unsteady runs
unsteady_plans = ras.plan_df[ras.plan_df['plan_title'].str.contains('Unsteady')]
for plan in unsteady_plans['plan_number']:
    RasCmdr.compute_plan(plan)

LLM Forward: Execution Audit Trail

Document which plans were executed and why:

Python
def log_plan_execution_set(plans_executed, selection_criteria, output_file):
    import json
    from datetime import datetime

    execution_log = {
        'timestamp': datetime.now().isoformat(),
        'selection_criteria': selection_criteria,
        'plans_executed': plans_executed,
        'plan_details': []
    }

    for plan in plans_executed:
        plan_info = ras.plan_df[ras.plan_df['plan_number'] == plan].iloc[0]
        execution_log['plan_details'].append({
            'plan_number': plan,
            'plan_title': plan_info['plan_title'],
            'geom_file': plan_info['geom_file'],
            'flow_file': plan_info.get('flow_file', 'N/A')
        })

    with open(output_file, 'w') as f:
        json.dump(execution_log, f, indent=2)

    print(f"Execution log saved: {output_file}")

# Usage
log_plan_execution_set(
    plans_executed=["01", "03", "05"],
    selection_criteria="Sensitivity analysis: Manning's n variations",
    output_file=Path('execution_log.json')
)

This provides: - Reproducibility: Know exactly which plans were run - Audit trail: Document selection rationale - Peer review: Non-programmers can verify correct plans executed

Summary of Plan Specification Techniques

In this notebook, we've explored different ways to specify and execute HEC-RAS plans using the RAS Commander library. Here's a summary of the key techniques we've covered:

  1. Basic Plan Specification
  2. Single plan by number: "01"
  3. List of specific plans: ["01", "03"]
  4. All plans: ras.plan_df['plan_number'].tolist()

  5. Advanced Selection

  6. Categorization: Grouping plans by purpose or type
  7. Dependencies: Ensuring prerequisite plans are run first
  8. Ordered execution: Running plans in a specific sequence

  9. Run Plans with Missing Results (HDF)

  10. Using ras object to determine which plans have results
  11. Creating a list of plans with no results
  12. Running those plans sequentially

  13. NOTE: run_parallel can also run a list of plans, but compute_plan is only made for single plan execution.

Best Practices for Plan Specification

  1. Consistent Formatting: Use two-digit strings for plan numbers ("01" instead of 1)
  2. Descriptive Naming: Use meaningful short identifiers that describe the plan's purpose
  3. Verify Availability: Check that specified plans exist before trying to execute them
  4. Document Dependencies: Keep track of which plans depend on others
  5. Use Appropriate Execution Method: Choose sequential or parallel based on dependencies and resources
  6. Monitor Performance: Track execution times to identify optimization opportunities

By applying these techniques, you can create efficient and organized workflows for executing HEC-RAS plans, from simple batch processing to complex dependency-based execution sequences.

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.