ebfe-validator
Validate organized eBFE/BLE model using ras-commander dataframes.Uses init_ras_project() then checks plan_df, boundary_df, rasmap_df to verify:- All plan files exist- All DSS files exist with relative paths- All terrain files exist with relative paths- All HDF results accessible- No absolute paths (would cause GUI popups)Use after organizing eBFE model to verify it's actually runnable.Generates validation report and script for user re-verification.
When & Why to Use This Skill
The ebfe-validator skill automates the structural and path validation of HEC-RAS eBFE/BLE models. By leveraging the ras-commander library, it ensures all plan, DSS, and terrain files are correctly referenced with relative paths, preventing GUI popups and ensuring the model is fully runnable for automated workflows. It provides a comprehensive validation report and a standalone script for re-verification.
Use Cases
- Post-organization verification: Ensuring a newly organized eBFE model is structurally sound and all internal file references (geometry, flow, plans) are intact.
- Automation readiness check: Identifying and flagging absolute file paths in DSS or terrain references that would trigger manual GUI popups and break headless simulation workflows.
- Data integrity auditing: Verifying the existence and accessibility of HDF results and terrain layers within the project structure to prevent runtime errors.
- Reproducibility assurance: Generating standalone validation scripts that allow team members to verify model validity across different local environments.
| name | ebfe-validator |
|---|---|
| model | sonnet |
| description | | |
eBFE Model Validator Skill
Purpose
Validate organized eBFE models using ras-commander's built-in dataframe validation capabilities.
Why This Matters: Not enough to just organize files - must verify the HEC-RAS project is actually runnable using ras-commander's own validation.
Validation Using ras-commander Dataframes
Step 1: Initialize Project
from ras_commander import init_ras_project
from pathlib import Path
# Initialize organized model
ras = init_ras_project(organized_ras_folder, version)
# If this succeeds, basic project structure is valid
# Now check dataframes for path validity
Step 2: Validate plan_df
Check all plan file references:
print("Validating Plans (plan_df)...")
for idx, row in ras.plan_df.iterrows():
plan_number = row['plan_number']
checks = {}
# Check plan file exists
plan_file = Path(row['plan_file'])
checks['plan_file_exists'] = plan_file.exists()
# Check geometry file exists
if 'geom_file' in row and pd.notna(row['geom_file']):
geom_file = Path(row['geom_file'])
checks['geom_file_exists'] = geom_file.exists()
# Check flow file exists
if 'flow_file' in row and pd.notna(row['flow_file']):
flow_file = Path(row['flow_file'])
checks['flow_file_exists'] = flow_file.exists()
# Check HDF file exists (pre-run results)
if 'hdf_path' in row and pd.notna(row['hdf_path']):
hdf_file = Path(row['hdf_path'])
checks['hdf_exists'] = hdf_file.exists()
if hdf_file.exists():
print(f" ✓ Plan {plan_number}: Pre-run results found")
# Check for absolute paths (CRITICAL)
checks['no_absolute_paths'] = not plan_file.is_absolute()
if all(v for k, v in checks.items() if v is not None):
print(f" ✓ Plan {plan_number}: All checks passed")
else:
failed = [k for k, v in checks.items() if v is False]
print(f" ✗ Plan {plan_number}: Failed checks: {failed}")
Step 3: Validate boundary_df (DSS Files)
Check all DSS boundary condition references:
print("\nValidating Boundary Conditions (boundary_df)...")
if hasattr(ras, 'boundary_df') and ras.boundary_df is not None:
for idx, row in ras.boundary_df.iterrows():
if 'dss_file' in row and pd.notna(row['dss_file']):
dss_path = Path(row['dss_file'])
# CRITICAL: Check if absolute (causes GUI popup)
if dss_path.is_absolute():
print(f" ✗ FAIL: Absolute DSS path: {dss_path}")
print(f" Will cause 'DSS path needs correction' GUI popup")
print(f" AUTOMATION BLOCKER - must fix")
continue
# Check if file exists
if dss_path.exists():
print(f" ✓ PASS: DSS found: {dss_path}")
else:
# Try relative to project
dss_resolved = ras.prj_file.parent / dss_path
if dss_resolved.exists():
print(f" ✓ PASS: DSS found (relative): {dss_path}")
# Validate DSS pathname contents
from ras_commander.dss import RasDss
catalog = RasDss.get_catalog(dss_resolved)
print(f" Contains {len(catalog)} pathname(s)")
# Validate pathnames
for pathname in catalog['pathname']:
result = RasDss.check_pathname(dss_resolved, pathname)
if not result.is_valid:
print(f" ⚠️ Invalid pathname: {pathname}")
else:
print(f" ✗ FAIL: DSS not found: {dss_path}")
print(f" Model will not run")
Step 4: Validate rasmap_df (Terrain Files)
Check terrain file references:
print("\nValidating Terrain (rasmap_df)...")
if hasattr(ras, 'rasmap_df') and ras.rasmap_df is not None:
for idx, row in ras.rasmap_df.iterrows():
if 'terrain_file' in row and pd.notna(row['terrain_file']):
terrain_path = Path(row['terrain_file'])
# CRITICAL: Check if absolute
if terrain_path.is_absolute():
print(f" ✗ FAIL: Absolute terrain path: {terrain_path}")
print(f" Will cause errors in RAS Mapper")
continue
# Check if file exists
if terrain_path.exists():
print(f" ✓ PASS: Terrain found: {terrain_path}")
# Validate using RasMap
from ras_commander import RasMap
is_valid = RasMap.is_valid_layer(terrain_path, layer_type='terrain')
if is_valid:
print(f" ✓ Terrain layer valid")
else:
print(f" ⚠️ Terrain layer validation failed")
else:
# Try relative to project
terrain_resolved = ras.prj_file.parent / terrain_path
if terrain_resolved.exists():
print(f" ✓ PASS: Terrain found (relative): {terrain_path}")
else:
print(f" ✗ FAIL: Terrain not found: {terrain_path}")
print(f" Model will not run")
# Search for terrain file
terrain_name = terrain_path.name
found = list(ras.prj_file.parent.glob(f'**/{terrain_name}'))
if found:
print(f" Found at: {found[0]}")
print(f" .rasmap needs correction to: {found[0].relative_to(ras.prj_file.parent)}")
Step 5: Validation Summary
print("\n" + "="*80)
print("Validation Summary")
print("="*80)
summary = {
'plans_checked': len(ras.plan_df),
'plans_valid': plans_valid_count,
'dss_checked': dss_count,
'dss_valid': dss_valid_count,
'terrain_checked': terrain_count,
'terrain_valid': terrain_valid_count,
'absolute_paths_found': absolute_path_count,
'all_checks_passed': all_checks_passed
}
print(f"\nPlans: {summary['plans_valid']}/{summary['plans_checked']} valid")
print(f"DSS Files: {summary['dss_valid']}/{summary['dss_checked']} valid")
print(f"Terrain Files: {summary['terrain_valid']}/{summary['terrain_checked']} valid")
print(f"Absolute paths: {summary['absolute_paths_found']}")
if summary['all_checks_passed']:
print("\n✓ MODEL IS FULLY VALIDATED AND RUNNABLE")
print(" - All paths are relative")
print(" - All files exist")
print(" - Ready for HEC-RAS")
print(" - Ready for automation (no GUI popups)")
else:
print("\n✗ MODEL HAS ISSUES")
print(" See validation details above")
print(" May need additional path corrections")
return summary
Output Format
Validation Report (agent/validation_report.md)
# eBFE Model Validation Report
**Model**: {StudyArea} ({HUC8})
**Pattern**: {Pattern}
**Validated**: {Date}
## Validation Using ras-commander Dataframes
### Plan Validation (plan_df)
- Plans checked: X
- Plans valid: X
- HDF files found: X (pre-run results)
- Issues: {list any issues}
### Boundary Condition Validation (boundary_df)
- DSS files checked: X
- DSS files valid: X
- Absolute paths: X (FAIL if > 0)
- DSS pathnames validated: X,XXX
- Issues: {list any issues}
### Terrain Validation (rasmap_df)
- Terrain files checked: X
- Terrain files valid: X
- Absolute paths: X (FAIL if > 0)
- Issues: {list any issues}
## Overall Status
{✓ PASS or ✗ FAIL}
{If PASS}: Model is fully validated and runnable
{If FAIL}: See issues above, additional path corrections needed
Validation Script (validate_{model}_{huc8}.py)
Agent generates standalone script for user to re-run validation
See Also
- eBFE Agent:
.claude/agents/ebfe-organizer/SUBAGENT.md- Complete agent - Path Validation:
.claude/rules/validation/validation-patterns.md - DSS Validation:
.claude/rules/hec-ras/dss-files.md - Critical Fixes:
feature_dev_notes/eBFE_Integration/CRITICAL_FIXES.md