Real-Time Execution Monitoring with Callbacks¶
This notebook demonstrates how to use execution callbacks for real-time monitoring of HEC-RAS plan execution.
What you'll learn: - ConsoleCallback for basic output - FileLoggerCallback for logging to file - ProgressBarCallback with tqdm - SynchronizedCallback for thread safety - Creating custom callbacks
from pathlib import Path
import sys
import os
# Flexible imports
try:
from ras_commander import init_ras_project, RasCmdr, RasExamples, ExecutionCallback
from ras_commander.callbacks import ConsoleCallback, FileLoggerCallback, ProgressBarCallback, SynchronizedCallback
except ImportError:
parent_directory = Path(os.getcwd()).parent
sys.path.append(str(parent_directory))
from ras_commander import init_ras_project, RasCmdr, RasExamples, ExecutionCallback
from ras_commander.callbacks import ConsoleCallback, FileLoggerCallback, ProgressBarCallback, SynchronizedCallback
project_path = RasExamples.extract_project("Muncie", suffix="115_callbacks")
init_ras_project(project_path, "6.6")
1. ConsoleCallback - Basic Console Output¶
ConsoleCallback prints HEC-RAS output directly to the console.
print("=== ConsoleCallback Demo ===")
callback = ConsoleCallback(verbose=True)
RasCmdr.compute_plan("01", stream_callback=callback, force_rerun=True)
2. FileLoggerCallback - Logging to File¶
FileLoggerCallback writes execution messages to a log file.
print("=== FileLoggerCallback Demo ===")
log_dir = project_path / "logs_115"
callback = FileLoggerCallback(output_dir=log_dir)
RasCmdr.compute_plan("01", stream_callback=callback, force_rerun=True)
# Show log contents
print(f"\nLog directory created: {log_dir}")
if log_dir.exists():
for log_file in log_dir.iterdir():
print(f"Log file: {log_file.name} ({log_file.stat().st_size} bytes)")
3. ProgressBarCallback - Progress Bars with tqdm¶
ProgressBarCallback displays a progress bar during execution (requires tqdm).
print("=== ProgressBarCallback Demo ===")
try:
callback = ProgressBarCallback()
RasCmdr.compute_plan("01", stream_callback=callback, force_rerun=True)
except ImportError:
print("⚠️ tqdm not installed - install with: pip install tqdm")
4. Custom Callback - Implementing Your Own¶
Create custom callbacks by subclassing ExecutionCallback.
class MyCustomCallback(ExecutionCallback):
"""Custom callback that counts messages by type."""
def __init__(self):
super().__init__()
self.message_counts = {"info": 0, "warning": 0, "error": 0}
def on_exec_message(self, plan_number: str, message: str):
"""Called when HEC-RAS outputs a message."""
# Count message types
msg_lower = message.lower()
if "error" in msg_lower:
self.message_counts["error"] += 1
elif "warning" in msg_lower:
self.message_counts["warning"] += 1
else:
self.message_counts["info"] += 1
def on_exec_complete(self, plan_number: str, success: bool, duration: float):
"""Called when execution completes."""
print(f"\n=== Execution Summary (Plan {plan_number}) ===")
print(f"Success: {success}, Duration: {duration:.1f}s")
print(f"Info messages: {self.message_counts['info']}")
print(f"Warnings: {self.message_counts['warning']}")
print(f"Errors: {self.message_counts['error']}")
# Use custom callback
print("=== Custom Callback Demo ===")
callback = MyCustomCallback()
RasCmdr.compute_plan("01", stream_callback=callback, force_rerun=True)
5. SynchronizedCallback - Thread-Safe for Parallel Execution¶
When running multiple plans in parallel, use SynchronizedCallback for thread safety.
print("=== SynchronizedCallback Demo (Parallel Execution) ===")
base_callback = ConsoleCallback(verbose=True)
callback = SynchronizedCallback(base_callback)
# Run multiple plans in parallel with thread-safe callback
results = RasCmdr.compute_parallel(
plan_number=["01", "02"],
max_workers=2,
force_rerun=True
)
Summary¶
You've learned how to use: - ConsoleCallback: Basic console output - FileLoggerCallback: Log to file - ProgressBarCallback: Progress bars (requires tqdm) - Custom callbacks: Implement ExecutionCallback - SynchronizedCallback: Thread-safe wrapper for parallel execution
See the ras-commander documentation for more details on the callback system.