| name | ebfe-validator |
| model | sonnet |
| description | 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. |
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