home / skills / a5c-ai / babysitter / stormwater-management

This skill enables integrated stormwater design and compliant analysis using SWMM, hydrologic methods, and green infrastructure sizing to optimize urban

npx playbooks add skill a5c-ai/babysitter --skill stormwater-management

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
15.1 KB
---
name: stormwater-management
description: Skill for integrated stormwater management and green infrastructure design with SWMM modeling, hydrologic analysis, BMP sizing, and MS4 permit compliance.
allowed-tools: Read, Grep, Write, Bash, Edit, Glob
category: Water and Wastewater Treatment
backlog-id: SK-004
metadata:
  author: babysitter-sdk
  version: "1.0.0"
---

# Stormwater Management Skill

Integrated stormwater management and green infrastructure design for sustainable urban drainage.

## Purpose

This skill provides comprehensive capabilities for stormwater management planning, including hydrologic analysis, green infrastructure design, BMP selection and sizing, SWMM modeling, and MS4 permit compliance analysis.

## Capabilities

### SWMM Modeling and Simulation
- EPA SWMM model setup and configuration
- Subcatchment delineation and parameterization
- Drainage network modeling
- Long-term continuous simulation
- Design storm analysis
- LID representation and modeling

### Hydrologic Analysis
- TR-55 methodology implementation
- Rational method calculations
- SCS Curve Number determination
- Time of concentration estimation
- Unit hydrograph development
- Rainfall-runoff modeling

### Green Infrastructure Sizing
- Bioretention facility design
- Permeable pavement sizing
- Rain garden design
- Green roof specifications
- Tree box filters
- Vegetated swales

### Detention/Retention Pond Design
- Storage volume calculations
- Stage-storage-discharge relationships
- Outlet structure design
- Emergency spillway sizing
- Sediment forebay design
- Maintenance access planning

### Water Quality BMP Selection
- Pollutant removal efficiency analysis
- BMP selection matrix
- Treatment train design
- Sizing for TSS removal
- Nutrient removal considerations
- Cost-effectiveness analysis

### Pollutant Load Modeling
- Event Mean Concentration (EMC) analysis
- Annual pollutant load estimation
- Source area contribution analysis
- Loading rate calculations
- Reduction target setting

### Low Impact Development Integration
- Site-level LID planning
- Watershed-scale LID analysis
- LID retrofit opportunities
- Performance monitoring design
- Adaptive management frameworks

### MS4 Permit Compliance Analysis
- NPDES requirements interpretation
- MCM implementation tracking
- TMDL compliance assessment
- Monitoring program design
- Annual report preparation

## Prerequisites

### Installation
```bash
pip install numpy scipy pandas matplotlib
```

### Optional Dependencies
```bash
# For SWMM integration
pip install swmm-api pyswmm

# For GIS analysis
pip install geopandas shapely

# For visualization
pip install plotly folium
```

## Usage Patterns

### Rational Method Calculations
```python
import numpy as np
from dataclasses import dataclass
from typing import Dict, List, Tuple

@dataclass
class CatchmentData:
    """Catchment characteristics"""
    area_acres: float
    runoff_coefficient: float
    time_of_concentration_min: float
    description: str = ""

class RationalMethod:
    """Rational method for peak runoff calculation"""

    def __init__(self):
        # IDF curve coefficients (example for generic location)
        # Q = C * I * A, where I from IDF: I = a / (Tc + b)^c
        self.idf_coefficients = {
            2: {'a': 100, 'b': 10, 'c': 0.8},
            5: {'a': 120, 'b': 10, 'c': 0.8},
            10: {'a': 140, 'b': 10, 'c': 0.8},
            25: {'a': 160, 'b': 10, 'c': 0.8},
            50: {'a': 180, 'b': 10, 'c': 0.8},
            100: {'a': 200, 'b': 10, 'c': 0.8}
        }

    def rainfall_intensity(self, tc_min: float, return_period: int) -> float:
        """Calculate rainfall intensity from IDF curve (in/hr)"""
        coef = self.idf_coefficients.get(return_period, self.idf_coefficients[10])
        intensity = coef['a'] / (tc_min + coef['b']) ** coef['c']
        return intensity

    def peak_runoff(self, catchment: CatchmentData, return_period: int) -> float:
        """Calculate peak runoff using Rational Method (cfs)"""
        C = catchment.runoff_coefficient
        I = self.rainfall_intensity(catchment.time_of_concentration_min, return_period)
        A = catchment.area_acres

        Q = C * I * A  # cfs
        return Q

    def composite_runoff_coefficient(self, subareas: List[Tuple[float, float]]) -> float:
        """Calculate composite C for mixed land uses
        subareas: list of (area, C) tuples
        """
        total_area = sum(a for a, c in subareas)
        weighted_c = sum(a * c for a, c in subareas) / total_area
        return weighted_c

    @staticmethod
    def time_of_concentration_kirpich(length_ft: float, slope_pct: float) -> float:
        """Kirpich equation for Tc (minutes)"""
        tc = 0.0078 * (length_ft ** 0.77) * (slope_pct ** -0.385)
        return tc

# Example runoff coefficients
RUNOFF_COEFFICIENTS = {
    'commercial': 0.85,
    'industrial': 0.75,
    'residential_high_density': 0.65,
    'residential_medium_density': 0.45,
    'residential_low_density': 0.35,
    'parks': 0.20,
    'forest': 0.15,
    'impervious': 0.95,
    'lawn_steep': 0.30,
    'lawn_flat': 0.20
}

# Example usage
rational = RationalMethod()

# Calculate composite C for mixed use area
subareas = [
    (5.0, RUNOFF_COEFFICIENTS['commercial']),
    (10.0, RUNOFF_COEFFICIENTS['residential_medium_density']),
    (3.0, RUNOFF_COEFFICIENTS['parks'])
]
composite_c = rational.composite_runoff_coefficient(subareas)

catchment = CatchmentData(
    area_acres=18.0,
    runoff_coefficient=composite_c,
    time_of_concentration_min=15.0,
    description="Mixed use development"
)

for rp in [2, 10, 25, 100]:
    Q = rational.peak_runoff(catchment, rp)
    print(f"{rp}-year storm: Q = {Q:.1f} cfs")
```

### SCS Curve Number Method
```python
class SCSMethod:
    """SCS Curve Number method for runoff calculation"""

    def __init__(self, curve_number: float):
        self.cn = curve_number
        self.S = (1000 / curve_number) - 10  # Potential retention (inches)
        self.Ia = 0.2 * self.S  # Initial abstraction

    def runoff_depth(self, rainfall_inches: float) -> float:
        """Calculate runoff depth (inches)"""
        P = rainfall_inches
        if P <= self.Ia:
            return 0.0

        Q = (P - self.Ia) ** 2 / (P - self.Ia + self.S)
        return Q

    def runoff_volume(self, rainfall_inches: float, area_acres: float) -> float:
        """Calculate runoff volume (acre-feet)"""
        Q_inches = self.runoff_depth(rainfall_inches)
        volume_ac_ft = Q_inches / 12 * area_acres
        return volume_ac_ft

    @staticmethod
    def composite_cn(subareas: List[Tuple[float, float]]) -> float:
        """Calculate area-weighted composite CN
        subareas: list of (area, CN) tuples
        """
        total_area = sum(a for a, cn in subareas)
        weighted_cn = sum(a * cn for a, cn in subareas) / total_area
        return weighted_cn

    @staticmethod
    def adjust_cn_for_amc(cn_ii: float, condition: str) -> float:
        """Adjust CN for antecedent moisture condition
        condition: 'dry' (AMC-I), 'normal' (AMC-II), or 'wet' (AMC-III)
        """
        if condition == 'dry':
            cn = cn_ii / (2.281 - 0.01281 * cn_ii)
        elif condition == 'wet':
            cn = cn_ii / (0.427 + 0.00573 * cn_ii)
        else:
            cn = cn_ii
        return cn

# Standard curve numbers (AMC-II, Hydrologic Soil Group B)
CURVE_NUMBERS = {
    'impervious': 98,
    'commercial': 92,
    'industrial': 88,
    'residential_1_8_acre': 85,
    'residential_1_4_acre': 80,
    'residential_1_2_acre': 75,
    'residential_1_acre': 68,
    'open_space_good': 61,
    'open_space_fair': 69,
    'forest_good': 55,
    'pasture_good': 61
}

# Example usage
# Pre-development condition
pre_cn = SCSMethod.composite_cn([
    (20, CURVE_NUMBERS['forest_good']),
    (80, CURVE_NUMBERS['pasture_good'])
])
pre_scs = SCSMethod(pre_cn)

# Post-development condition
post_cn = SCSMethod.composite_cn([
    (30, CURVE_NUMBERS['impervious']),
    (40, CURVE_NUMBERS['residential_1_4_acre']),
    (30, CURVE_NUMBERS['open_space_good'])
])
post_scs = SCSMethod(post_cn)

rainfall = 3.5  # inches (design storm)
pre_runoff = pre_scs.runoff_volume(rainfall, area_acres=100)
post_runoff = post_scs.runoff_volume(rainfall, area_acres=100)

print(f"Pre-development CN: {pre_cn:.0f}")
print(f"Post-development CN: {post_cn:.0f}")
print(f"Pre-development runoff: {pre_runoff:.2f} acre-feet")
print(f"Post-development runoff: {post_runoff:.2f} acre-feet")
print(f"Required detention: {post_runoff - pre_runoff:.2f} acre-feet")
```

### Bioretention Sizing
```python
class BioretentionDesign:
    """Bioretention facility design"""

    def __init__(self, infiltration_rate_in_hr: float = 1.0):
        self.infiltration_rate = infiltration_rate_in_hr

    def size_for_water_quality(self, drainage_area_sf: float,
                                impervious_fraction: float,
                                design_rainfall_in: float = 1.0) -> Dict:
        """Size bioretention for water quality treatment"""
        # Calculate water quality volume (WQv)
        # Using simplified volumetric approach
        Rv = 0.05 + 0.009 * (impervious_fraction * 100)  # Runoff coefficient
        wqv_cf = Rv * design_rainfall_in / 12 * drainage_area_sf

        # Bioretention area sizing
        # Based on 6" ponding depth and filter media depth
        ponding_depth_ft = 0.5  # 6 inches
        drain_time_hr = 24  # Maximum drain time

        # Area based on infiltration during storm
        storm_duration_hr = 2  # Assume 2-hour storm
        infiltrated_depth = self.infiltration_rate * storm_duration_hr / 12  # feet

        # Minimum surface area
        min_area_sf = wqv_cf / (ponding_depth_ft + infiltrated_depth)

        # Typical sizing: 5-10% of impervious area
        recommended_area_sf = drainage_area_sf * impervious_fraction * 0.05

        return {
            'water_quality_volume_cf': wqv_cf,
            'minimum_surface_area_sf': min_area_sf,
            'recommended_area_sf': max(min_area_sf, recommended_area_sf),
            'ponding_depth_in': 6,
            'filter_media_depth_in': 24,
            'drain_time_hr': ponding_depth_ft * 12 / self.infiltration_rate
        }

    def design_details(self, surface_area_sf: float) -> Dict:
        """Generate design details for bioretention"""
        return {
            'surface_area_sf': surface_area_sf,
            'filter_media': {
                'depth_in': 24,
                'composition': '50% sand, 30% comite, 20% mulch (top)',
                'permeability_in_hr': self.infiltration_rate
            },
            'underdrain': {
                'diameter_in': 4,
                'material': 'Perforated PVC',
                'slope_pct': 0.5,
                'gravel_depth_in': 12
            },
            'overflow': {
                'type': 'Standpipe or weir',
                'elevation': '6 inches above media surface'
            },
            'plants': {
                'density': '1 per 3 sq ft',
                'recommended': ['Switchgrass', 'Black-eyed Susan', 'Sedges']
            },
            'maintenance': {
                'mulch_replacement': 'Annual',
                'vegetation_maintenance': 'Biannual',
                'sediment_removal': 'As needed, typically 5-year'
            }
        }

# Example usage
bio = BioretentionDesign(infiltration_rate_in_hr=1.5)

sizing = bio.size_for_water_quality(
    drainage_area_sf=43560,  # 1 acre
    impervious_fraction=0.6,
    design_rainfall_in=1.0
)

print(f"Water quality volume: {sizing['water_quality_volume_cf']:.0f} cf")
print(f"Recommended area: {sizing['recommended_area_sf']:.0f} sf")
print(f"Drain time: {sizing['drain_time_hr']:.1f} hours")

details = bio.design_details(sizing['recommended_area_sf'])
print(f"\nFilter media depth: {details['filter_media']['depth_in']} inches")
```

### Pollutant Load Analysis
```python
class PollutantLoading:
    """Stormwater pollutant load estimation"""

    # Event Mean Concentrations (mg/L) by land use
    EMC = {
        'residential': {'TSS': 101, 'TP': 0.38, 'TN': 2.5, 'Zn': 0.14},
        'commercial': {'TSS': 69, 'TP': 0.22, 'TN': 2.2, 'Zn': 0.22},
        'industrial': {'TSS': 85, 'TP': 0.26, 'TN': 2.0, 'Zn': 0.32},
        'highway': {'TSS': 142, 'TP': 0.34, 'TN': 3.2, 'Zn': 0.35},
        'open_space': {'TSS': 40, 'TP': 0.10, 'TN': 1.0, 'Zn': 0.05}
    }

    # BMP removal efficiencies (%)
    BMP_REMOVAL = {
        'bioretention': {'TSS': 85, 'TP': 60, 'TN': 50, 'Zn': 80},
        'wet_pond': {'TSS': 80, 'TP': 50, 'TN': 30, 'Zn': 60},
        'dry_pond': {'TSS': 60, 'TP': 20, 'TN': 15, 'Zn': 30},
        'grass_swale': {'TSS': 70, 'TP': 25, 'TN': 20, 'Zn': 40},
        'perm_pavement': {'TSS': 85, 'TP': 60, 'TN': 50, 'Zn': 70},
        'sand_filter': {'TSS': 85, 'TP': 50, 'TN': 35, 'Zn': 80}
    }

    def annual_load(self, area_acres: float, land_use: str,
                    annual_runoff_in: float, pollutant: str) -> float:
        """Calculate annual pollutant load (lbs/year)"""
        emc = self.EMC.get(land_use, self.EMC['residential']).get(pollutant, 0)

        # Load = EMC * Volume
        # Volume (L) = runoff (in) * area (acres) * 43560 sf/ac * 0.0254 m/in * 1000 L/m3
        volume_l = annual_runoff_in * 0.0254 * area_acres * 43560 * 0.0929 * 1000

        # Load in mg, convert to lbs
        load_mg = emc * volume_l
        load_lbs = load_mg / 453592

        return load_lbs

    def load_reduction(self, load_lbs: float, bmp_type: str,
                       pollutant: str) -> Dict:
        """Calculate load reduction from BMP"""
        efficiency = self.BMP_REMOVAL.get(bmp_type, {}).get(pollutant, 0) / 100
        removed = load_lbs * efficiency
        remaining = load_lbs - removed

        return {
            'initial_load_lbs': load_lbs,
            'removal_efficiency_pct': efficiency * 100,
            'load_removed_lbs': removed,
            'remaining_load_lbs': remaining
        }

# Example usage
loading = PollutantLoading()

# Calculate loads for a 50-acre commercial development
area = 50  # acres
annual_runoff = 30  # inches
land_use = 'commercial'

for pollutant in ['TSS', 'TP', 'TN']:
    load = loading.annual_load(area, land_use, annual_runoff, pollutant)
    reduction = loading.load_reduction(load, 'bioretention', pollutant)
    print(f"{pollutant}: {load:.1f} lbs/yr -> {reduction['remaining_load_lbs']:.1f} lbs/yr "
          f"({reduction['removal_efficiency_pct']:.0f}% removal)")
```

## Usage Guidelines

### When to Use This Skill
- Stormwater management plan development
- Green infrastructure design
- BMP selection and sizing
- MS4 permit compliance analysis
- Watershed planning and TMDL implementation

### Best Practices
1. **Match design storm** to local requirements
2. **Consider treatment train approaches** for multiple benefits
3. **Plan for maintenance access** in design
4. **Verify infiltration rates** with field testing
5. **Include pre-treatment** for high pollutant areas
6. **Monitor performance** for adaptive management

### Process Integration
- WW-004: Stormwater Management Planning (all phases)

## Dependencies

- numpy, scipy: Numerical calculations
- pandas: Data analysis
- pyswmm: SWMM model interaction (optional)

## References

- EPA SWMM Reference Manual
- ASCE Manual of Practice No. 77
- State-specific stormwater design manuals
- NCHRP Report 565 BMP Selection

Overview

This skill delivers integrated stormwater management and green infrastructure design tools for planners and engineers. It combines hydrologic analysis, SWMM modeling, BMP sizing, pollutant load estimation, and MS4 permit compliance support to produce practical design outputs. The focus is on reproducible calculations, LID integration, and compliance-ready summaries.

How this skill works

The skill builds hydrologic inputs (Rational, TR-55, SCS Curve Number) and assembles SWMM model components: subcatchments, drainage networks, LID units, and long-term simulations. It runs peak and continuous runoff analyses, sizes bioretention, permeable pavement, ponds, and other BMPs, and computes pollutant loads using EMCs and BMP removal efficiencies. Outputs include design volumes, stage-storage relations, BMP performance metrics, and MS4 compliance summaries for reporting.

When to use it

  • Preliminary site design and watershed-scale screening
  • Sizing water quality and quantity BMPs (bioretention, ponds, swales)
  • Preparing SWMM models and running design-storm or continuous simulations
  • Estimating pollutant loads and evaluating BMP treatment trains
  • Documenting MS4/TMDL compliance and generating annual report inputs

Best practices

  • Start with accurate catchment delineation and land-use breakdowns before modeling
  • Use localized IDF and rainfall records for intensity and continuous simulations
  • Combine multiple methods (Rational for peaks, SCS for volumes) to cross-check results
  • Apply conservative BMP infiltration and detention assumptions for safety factors
  • Document assumptions, parameter sources, and maintenance plans for compliance and review

Example use cases

  • Design a bioretention area sized to treat the first-inch water quality volume for a redevelopment site
  • Develop a SWMM model for a new subdivision including LID controls and run a 25-year design storm analysis
  • Compare pollutant load reductions for alternative BMP treatment trains to meet TMDL targets
  • Calculate detention storage required to maintain pre-development peak discharge rates for a 100-year event
  • Prepare MS4 permit deliverables: MCM tracking, monitoring plan outlines, and annual load reduction summaries

FAQ

What inputs are required to size a bioretention facility?

You need drainage area, impervious fraction, soil infiltration rate, design water quality rainfall, and desired drain time. The skill converts those into water quality volume, minimum surface area, and recommended media and underdrain details.

Can this skill run EPA SWMM simulations?

Yes — it assembles SWMM-ready components (subcatchments, nodes, links, LID units) and supports design storm and long-term simulations when integrated with a SWMM runtime or API.

How are pollutant loads estimated?

The skill uses Event Mean Concentrations by land use with annual runoff volumes to compute loads, then applies BMP removal efficiencies to estimate reductions and remaining loads.