Organize downloaded FEMA eBFE/BLE model files into standardized 4-folder structure. Use when working with eBFE downloads that need organization into: - HMS Model/ (HEC-HMS hydrologic models) - RAS Model/ (HEC-RAS hydraulic models) - Spatial Data/ (GIS, terrain, geodatabases) - Documentation/ (reports, PDFs, metadata) Handles variable archive structures, nested zips, and mixed content through intelligent file analysis and recursive extraction.
Scanned 2/12/2026
Install via CLI
openskills install majiayu000/claude-skill-registry---
name: ebfe_organize_models
model: sonnet
description: |
Organize downloaded FEMA eBFE/BLE model files into standardized 4-folder structure.
Use when working with eBFE downloads that need organization into:
- HMS Model/ (HEC-HMS hydrologic models)
- RAS Model/ (HEC-RAS hydraulic models)
- Spatial Data/ (GIS, terrain, geodatabases)
- Documentation/ (reports, PDFs, metadata)
Handles variable archive structures, nested zips, and mixed content through
intelligent file analysis and recursive extraction.
---
# Organizing eBFE Models
## Purpose
Organize downloaded FEMA eBFE/BLE study area files into a standardized 4-folder structure, regardless of the original archive organization patterns.
## Standardized Output Structure
Every organized eBFE study area should have this structure:
```
{StudyAreaName}_{HUC8}/
├── HMS Model/ # HEC-HMS hydrologic models
│ ├── {ProjectName}.hms
│ ├── {ProjectName}.basin
│ ├── *.dss
│ └── ... (all HMS-related files)
├── RAS Model/ # HEC-RAS hydraulic models
│ ├── {Model1}/
│ │ ├── {Model1}.prj
│ │ ├── {Model1}.g##
│ │ ├── {Model1}.p##
│ │ └── ... (all RAS project files)
│ └── {Model2}/...
├── Spatial Data/ # GIS, terrain, geodatabases
│ ├── Terrain/
│ ├── *.tif, *.hdf
│ ├── *.gdb/
│ └── ... (all spatial data)
└── Documentation/ # Reports, metadata, inventories
├── *.pdf
├── *.xlsx (inventories)
├── *_metadata.xml
└── ... (all documentation)
```
## Input Patterns
The skill must handle these downloaded archive patterns:
**Pattern 1**: Multiple 1D models in variable wrapper folders (80-200 MB)
**Pattern 2**: ModelURLs.txt links file (1 KB)
**Pattern 3**: Single 2D model in nested zip (5-15 GB)
**Pattern 4**: Compound HMS + RAS in nested zips (8+ GB)
See `feature_dev_notes/eBFE_Integration/RESEARCH_FINDINGS.md` for complete pattern documentation.
## File Classification Rules
### HMS Model/ Folder
Include files with these extensions or patterns:
- `.hms` - HEC-HMS project
- `.basin` - Basin model file
- `.met` - Meteorology file
- `.control` - Control specifications
- `.run` - Run configuration
- `.results` - HMS results
- `.dss` in `Hydrology/` path
- `.log`, `.out` in HMS folders
**Path indicators**: `Hydrology/`, `HMS/`
### RAS Model/ Folder
Include files with these extensions or patterns:
- `.prj` - HEC-RAS project (validate: contains "Proj Title=", "Geom File=")
- `.g##` - Geometry file
- `.p##` - Plan file
- `.f##` - Flow file
- `.u##` - Unsteady flow file
- `.c##` - Sediment file
- `.b##` - Bridge/culvert file
- `.bco##` - Boundary condition override
- `.IC.O##` - Initial conditions override
- `.x##` - Cross section index
- `.rasmap` - RAS Mapper project
- `.dsc` - DSS catalog (if in RAS folder)
- `.dss` (if in RAS folder, not HMS folder)
**Exclude**: `.prj` files in `Features/`, `Shp/`, `gis/` (shapefiles, not HEC-RAS)
**Organization within RAS Model/**:
- If single model: Place files directly in RAS Model/
- If multiple models: Create subfolder per model (use .prj stem as folder name)
### Spatial Data/ Folder
Include files with these extensions or patterns:
- `.tif` - GeoTIFF raster
- `.hdf` - Terrain HDF (if NOT .g##.hdf or .p##.hdf)
- `.vrt` - Virtual raster
- `.gdb/` - File geodatabase
- `.shp`, `.shx`, `.dbf`, `.prj` - Shapefiles (in Features/, Shp/, gis/ folders)
- Folder named `Terrain/` (entire folder)
- Folder named `Spatial/`, `GIS/`, `Shp/`, `Features/`
**Exception**: `.g##.hdf` (geometry preprocessor) and `.p##.hdf` (results) stay with RAS Model/
### Documentation/ Folder
Include files with these extensions or patterns:
- `.pdf` - Reports, guides
- `.xlsx`, `.xls` - Inventories, metadata spreadsheets
- `.xml` - Metadata
- Files with "Inventory" in name
- Files with "metadata" in name
- Files with "Report" in name
- `README*` files
## Agent Deliverables
**REQUIRED for Every Organization**:
1. ✅ Organized model in 4-folder structure
2. ✅ `agent/model_log.md` - Agent work log
3. ✅ `MANIFEST.md` - Organization manifest
4. ✅ **NEW**: Generated `organize_{modelname}()` function in `feature_dev_notes/eBFE_Integration/generated_functions/`
5. ✅ **NEW**: DSS validation results (if DSS files present)
6. ✅ **NEW**: Suggested compute test command for user
7. ✅ **NEW**: Haiku subagent results check (if compute test run)
## Workflow
### Step 1: Analyze Archive Structure
```python
# Inspect the downloaded archive
# - List all files
# - Identify nested zips
# - Detect pattern (1-4)
# - Count .prj files (RAS) and .hms files (HMS)
```
### Step 2: Extract Recursively
```python
# Extract Models.zip
# Find nested .zip files (_Final.zip, RAS_Submittal.zip, etc.)
# Extract nested zips in place
# Preserve directory structure during extraction
```
### Step 3: Classify and Organize
```python
# Recursively walk extracted content
# For each file:
# - Determine classification (HMS/RAS/Spatial/Docs)
# - Move to appropriate standardized folder
# - For RAS models with multiple projects:
# - Group files by .prj stem
# - Create subfolder per model
# CRITICAL INTEGRATIONS (to create runnable HEC-RAS models):
# 1. Move Output/ folder INTO HEC-RAS project folder
# eBFE separates Output/ (pre-run HDF files) from Input/ (project)
# HEC-RAS expects HDF files in project folder
for model_folder in ras_model.glob('**/Input'):
output_folder = model_folder.parent / 'Output'
if output_folder.exists():
# Move all Output/*.hdf and other files INTO Input/
for output_file in output_folder.rglob('*'):
if output_file.is_file():
shutil.copy2(output_file, model_folder / output_file.name)
# 2. Move Terrain/ INTO HEC-RAS project folder
# eBFE places Terrain/ as sibling to Input/ (breaks .rasmap references)
# HEC-RAS expects Terrain/ in project folder
for model_folder in ras_model.glob('**/Input'):
terrain_folder = model_folder.parent / 'Terrain'
if terrain_folder.exists():
# Move Terrain/ INTO Input/Terrain/
shutil.copytree(terrain_folder, model_folder / 'Terrain', dirs_exist_ok=True)
```
### Step 4: Validate Organization
```python
# Verify each folder:
# - HMS Model/: Check for .hms files
# - RAS Model/: Verify .prj files are valid HEC-RAS projects
# - Spatial Data/: Check for terrain files
# - Documentation/: Ensure reports are present
#
# Report summary:
# - X HMS projects found
# - Y RAS projects found
# - Z terrain files found
# - N documents organized
```
### Step 4: Correct DSS File Paths (CRITICAL - VALIDATE EXISTENCE)
```python
# CRITICAL: Fix DSS file path references in HEC-RAS files AND verify files exist
# eBFE models have:
# - Absolute paths from original system: C:\eBFE\... (doesn't exist on user system)
# - Wrong relative paths: DSS\Input\file.dss (file is actually in same folder)
# These cause "DSS path needs correction" GUI popups that break automation
import re
# Step 1: Find all DSS files that ACTUALLY EXIST in organized structure
dss_files = list(ras_model_folder.glob('**/*.dss'))
dss_lookup = {dss.name: dss for dss in dss_files} # Lookup by filename
print(f"Found {len(dss_files)} DSS file(s):")
for dss in dss_files:
print(f" - {dss.relative_to(ras_model_folder)}")
# Step 2: Find HEC-RAS files that reference DSS (.u##, .prj, .p##)
hecras_files = []
hecras_files.extend(ras_model_folder.glob('**/*.u[0-9]*')) # Unsteady flow files
hecras_files.extend(ras_model_folder.glob('**/*.p[0-9][0-9]')) # Plan files
hecras_files.extend(ras_model_folder.glob('**/*.prj')) # Project files
# Step 3: For each HEC-RAS file, validate and correct DSS references
for hecras_file in hecras_files:
content = hecras_file.read_text(encoding='utf-8', errors='ignore')
modified = False
# Find all "DSS File=" lines
dss_file_pattern = re.compile(r'DSS File=(.+?)(?:\n|$)', re.IGNORECASE)
for match in dss_file_pattern.finditer(content):
old_path = match.group(1).strip()
dss_filename = Path(old_path).name # Extract just the filename
# Check if this DSS file exists in our organized structure
if dss_filename in dss_lookup:
actual_dss_path = dss_lookup[dss_filename]
# CRITICAL: Verify the DSS file actually exists
if actual_dss_path.exists():
# Calculate correct relative path from HEC-RAS file to actual DSS location
rel_path = actual_dss_path.relative_to(hecras_file.parent)
rel_path_str = str(rel_path).replace('\\', '/')
# Only replace if current path is wrong
if old_path != rel_path_str:
old_full = f"DSS File={old_path}"
new_full = f"DSS File={rel_path_str}"
content = content.replace(old_full, new_full)
modified = True
print(f" Corrected in {hecras_file.name}:")
print(f" Old: {old_path}")
print(f" New: {rel_path_str} (✓ verified exists)")
else:
print(f" ⚠️ WARNING: DSS not found: {dss_filename}")
else:
print(f" ⚠️ WARNING: DSS not in organized structure: {dss_filename}")
if modified:
hecras_file.write_text(content, encoding='utf-8')
# Result: Model opens without GUI popups, all DSS paths verified
# Handles cases like:
# DSS\Input\UPG_precip.dss → UPG_precip.dss (if file is in same folder)
# C:\eBFE\...\file.dss → ../DSS/file.dss (if file is in subdirectory)
```
### Step 5: Validate DSS Files (If Present)
```python
# Validate DSS pathname contents (not just file paths)
from ras_commander.dss import RasDss
# Find all .dss files in RAS Model/
dss_files = list(ras_model_folder.glob('**/*.dss'))
for dss_file in dss_files:
# Get catalog
catalog = RasDss.get_catalog(dss_file)
# Check each pathname
for pathname in catalog['pathname']:
result = RasDss.check_pathname(dss_file, pathname)
if not result.is_valid:
# Document invalid pathnames in model_log.md
pass
```
### Step 6: Suggest Compute Test (If RAS Model Present)
```python
# If RAS model organized, suggest optional compute test to user
# This validates terrain, land use, and DSS files are correct
print("=" * 80)
print("OPTIONAL VALIDATION: Compute Test")
print("=" * 80)
print("To verify terrain, land use, and DSS files are correct,")
print("run at least one plan:")
print()
print(" from ras_commander import init_ras_project, RasCmdr")
print(f" init_ras_project(r'{ras_model_folder}', '{version}')")
print(" RasCmdr.compute_plan('01', num_cores=2)")
print()
print("If the plan executes successfully, terrain/DSS files are valid.")
print("=" * 80)
```
### Step 7: Check Results with Haiku Subagent (If Compute Test Run)
```python
# After compute test completes (if user runs it), check results for errors
from ras_commander.hdf import HdfResultsPlan
# Launch haiku subagent to check results
Task(
subagent_type="notebook-output-auditor",
model="haiku",
description="Check HEC-RAS results for errors",
prompt=f"""
Check HEC-RAS results for errors in: {hdf_file}
Extract compute messages and check for:
- Error messages
- Warning messages
- Convergence issues
- Numerical instabilities
- Missing data
Write findings to: {agent_folder}/compute_test_results.md
"""
)
```
### Step 8: Generate Deterministic Function
**REQUIRED**: After organizing each model, generate a Python function for future use.
```python
# Generate organize_{modelname}() function
# Write to: feature_dev_notes/eBFE_Integration/generated_functions/{studyarea}_{huc8}.py
def organize_{clean_name}(
downloaded_folder: Path,
output_folder: Optional[Path] = None
) -> Path:
"""
Organize {StudyArea} ({HUC8}) eBFE model.
Pattern {X}: {Pattern description}
Generated by ebfe_organize_models agent on {date}.
"""
# Specific organization steps discovered by agent
# Include pattern detection, extraction, classification
# Use lessons learned from this organization
pass
```
**Deliverable**: Write generated function to `feature_dev_notes/eBFE_Integration/generated_functions/organize_{studyarea}_{huc8}.py`
### Step 9: Generate Manifest and Model Log
```python
# Create organization manifest: MANIFEST.md (in project root)
# Document:
# - Original archive pattern detected
# - Files organized by category
# - RAS project inventory (model names, types, sizes)
# - HMS project inventory (if any)
# - Terrain files inventory
# - Document inventory
# - DSS validation results
# - Suggested compute test command
# Create agent work log: agent/model_log.md (in project root)
# **REQUIRED**: Every organized model MUST have agent/model_log.md
# Document:
# - Agent actions taken
# - Files classified and moved
# - Decisions made during organization
# - Issues encountered and resolutions
# - DSS validation results
# - Generated function location
# - Timestamps for all operations
```
## Output Format
### REQUIRED: agent/model_log.md
**CRITICAL**: Every organized eBFE model MUST have `agent/model_log.md` documenting agent work.
**Location**: `{StudyAreaName}_{HUC8}/agent/model_log.md`
**Template**:
```markdown
# Agent Work Log - {StudyAreaName}
**Agent**: ebfe_organize_models
**Date**: {YYYY-MM-DD HH:MM:SS}
**Study Area**: {Name} ({HUC8})
**Pattern**: {Pattern 1/2/3/4}
## Actions Taken
### Archive Extraction
- Extracted: {source_archive}
- Nested zips: {list any nested zips extracted}
- Total files extracted: {count}
### File Classification
{For each file category, list files moved}
#### HMS Model (X files, Y MB)
- {list key files}
#### RAS Model (X files, Y GB)
- {list models and key files}
#### Spatial Data (X files, Y MB)
- {list terrain, shapefiles, etc.}
#### Documentation (X files, Y MB)
- {list reports, inventories}
### Decisions Made
- {Document any classification decisions}
- {Document handling of ambiguous files}
- {Document terrain handling approach}
### Issues Encountered
- {List any problems}
- {Document resolutions}
### Validation Checks
- [x] All files classified
- [x] RAS .prj files validated (not shapefiles)
- [x] Terrain location documented
- [x] Manifest created
## Next Steps for User
{Provide clear next steps, e.g., testing with ras-commander}
```
### MANIFEST.md Template
```markdown
# eBFE Model Organization Manifest
**Study Area**: {Name}
**HUC8**: {HUC8}
**Original Pattern**: {Pattern 1/2/3/4}
**Organized Date**: {YYYY-MM-DD}
## HMS Model
{X} HEC-HMS projects found:
- {ProjectName}.hms - {StormFrequencies}
## RAS Model
{Y} HEC-RAS projects found:
### {ModelName1}
- Type: {1D/2D}
- Plans: {#}
- Size: {MB/GB}
- Terrain: {Self-contained/External/Not needed}
### {ModelName2}
...
## Spatial Data
{Z} terrain/spatial files:
- {TerrainFile1} - {Size}
- Geodatabase: {.gdb folders}
- Shapefiles: {count}
## Documentation
{N} documents:
- {Report1}.pdf - {Size}
- {Inventory}.xlsx
- {Metadata}.xml
## Notes
{Any special observations or issues encountered}
```
## Example Usage
```python
# Organize a downloaded study area
from pathlib import Path
# Input: Raw downloaded and extracted files
source = Path("D:/eBFE/raw_downloads/12040102_Spring_Models_extracted/")
# Output: Organized into 4 folders
target = Path("D:/eBFE/organized/SpringCreek_12040102/")
# Agent organizes the files
# Result: target/ now has HMS Model/, RAS Model/, Spatial Data/, Documentation/
```
## Special Handling Notes
### Nested Zips
- Recursively extract _Final.zip, RAS_Submittal.zip, etc.
- Delete intermediate zips after extraction (optional)
- Preserve meaningful folder names
### Shapefile .prj vs HEC-RAS .prj
- Shapefiles: `.prj` in Features/, Shp/, gis/ → Spatial Data/
- HEC-RAS: `.prj` with "Proj Title=" content → RAS Model/
### Self-Contained vs External Terrain
- If Terrain/ folder in model directory → stays with RAS Model/, copy to Spatial Data/
- If .rasmap references external terrain → document in manifest
### Multiple RAS Projects
- Create subfolder per .prj file using stem name
- Group related files (.g##, .p##, .f##) with matching basename
- Keep directory hierarchy for watershed organization if meaningful
## Generated Function Template
Every organization must generate an `organize_{modelname}()` function:
**File Location**: `feature_dev_notes/eBFE_Integration/generated_functions/organize_{studyarea}_{huc8}.py`
**Template**:
```python
"""
Generated organization function for {StudyArea} ({HUC8})
Generated by: ebfe_organize_models agent
Date: {YYYY-MM-DD}
Pattern: {Pattern X}
"""
from pathlib import Path
from typing import Optional
import shutil
import zipfile
from ras_commander.dss import RasDss
def organize_{clean_name}(
downloaded_folder: Path,
output_folder: Optional[Path] = None,
validate_dss: bool = True
) -> Path:
"""
Organize {StudyArea} ({HUC8}) eBFE model.
Pattern {X}: {Pattern description discovered by agent}
Args:
downloaded_folder: Path to extracted {HUC8}_Models folder
output_folder: Output location (default: ./ebfe_organized/{StudyArea}_{HUC8}/)
validate_dss: Run DSS validation checks
Returns:
Path to organized model with 4-folder structure + agent/model_log.md
Generated: {date} by ebfe_organize_models agent
"""
# [Agent-discovered organization steps]
# 1. Extract nested zips (if pattern requires)
# 2. Find .prj files recursively
# 3. Classify files to HMS/RAS/Spatial/Docs
# 4. Create 4-folder structure
# 5. Move files to organized locations
# 6. Validate DSS files if present
# 7. Create agent/model_log.md
# 8. Generate MANIFEST.md
if validate_dss:
# DSS validation code
pass
return output_folder
# Example usage in notebook
if __name__ == '__main__':
"""
Example usage for {StudyArea}:
>>> from pathlib import Path
>>> organized = organize_{clean_name}(
... Path(r"D:/downloads/{HUC8}_Models_extracted")
... )
>>> from ras_commander import init_ras_project
>>> init_ras_project(organized / "RAS Model", "{version}")
"""
```
## DSS Validation Example
```python
# After organizing RAS Model, validate DSS files
from ras_commander.dss import RasDss
from pathlib import Path
ras_model_folder = Path(r"D:/Organized/Model/RAS Model")
dss_files = list(ras_model_folder.glob('**/*.dss'))
dss_validation_results = []
for dss_file in dss_files:
print(f"\nValidating: {dss_file.name}")
# Get catalog
try:
catalog = RasDss.get_catalog(dss_file)
print(f" Found {len(catalog)} pathnames")
# Validate each pathname
for pathname in catalog['pathname']:
result = RasDss.check_pathname(dss_file, pathname)
if not result.is_valid:
dss_validation_results.append({
'file': dss_file.name,
'pathname': pathname,
'issues': result.message
})
print(f" ✗ INVALID: {pathname}")
print(f" Issue: {result.message}")
else:
print(f" ✓ Valid: {pathname}")
except Exception as e:
print(f" ✗ Error reading DSS: {e}")
dss_validation_results.append({
'file': dss_file.name,
'pathname': 'N/A',
'issues': f"Failed to read: {e}"
})
# Document results in agent/model_log.md
if dss_validation_results:
print(f"\n⚠️ Found {len(dss_validation_results)} DSS validation issues")
print(" See agent/model_log.md for details")
else:
print(f"\n✓ All DSS files valid")
```
## Compute Test Validation Workflow
```python
# After organization, suggest optional compute test
print("\n" + "=" * 80)
print("OPTIONAL: Compute Test Validation")
print("=" * 80)
print("\nTo verify terrain, land use, and DSS files are correct:")
print()
print("```python")
print(f"from ras_commander import init_ras_project, RasCmdr")
print(f"from pathlib import Path")
print()
print(f"project = Path(r'{organized_folder / 'RAS Model'}')")
print(f"init_ras_project(project, '{version}')")
print(f"RasCmdr.compute_plan('01', num_cores=2)")
print("```")
print()
print("If plan executes successfully → terrain/DSS files are valid")
print("If plan fails → check compute messages for specific errors")
print("=" * 80)
# After user runs compute test, check results with haiku
# (See Step 7 in workflow above)
```
## See Also
- **Research**: `feature_dev_notes/eBFE_Integration/RESEARCH_FINDINGS.md` - 5 patterns documented
- **Implementation**: `feature_dev_notes/eBFE_Integration/IMPLEMENTATION_SUMMARY.md` - Design guidance
- **Discovery API**: `feature_dev_notes/eBFE_Integration/prototype_discovery.py` - Download helpers
- **Generated Functions**: `feature_dev_notes/eBFE_Integration/generated_functions/` - Agent-generated deterministic functions
- **DSS Validation**: `.claude/rules/hec-ras/dss-files.md` - DSS validation patterns
- **Results Checking**: `.claude/agents/notebook-output-auditor.md` - Haiku results checker
No comments yet. Be the first to comment!