AERMOD Python Wrapper - Technical Architecture¶
Executive Summary¶
This document outlines the technical architecture for a Python wrapper around the AERMOD Fortran codebase. The wrapper aims to provide an accessible, API-driven interface for regulatory dispersion modeling without requiring expensive consulting services or direct Fortran expertise.
Architecture Overview¶
┌─────────────────────────────────────────────────────────────┐
│ User Interface Layer │
│ ┌────────────┐ ┌──────────────┐ ┌──────────────────────┐│
│ │ CLI Tool │ │ Python API │ │ Web Dashboard (opt.) ││
│ └────────────┘ └──────────────┘ └──────────────────────┘│
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ Core Python Wrapper (pyaermod) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Configuration & Parameter Management │ │
│ │ - Input validation │ │
│ │ - Parameter serialization │ │
│ │ - Project templates │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Input File Generation │ │
│ │ - AERMOD control file (.inp) │ │
│ │ - Source configuration │ │
│ │ - Receptor grid generation │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Process Management │ │
│ │ - AERMOD executable wrapper │ │
│ │ - AERMET integration │ │
│ │ - AERMAP integration │ │
│ │ - Error handling & logging │ │
│ └──────────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Output Parsing & Processing │ │
│ │ - Result file parsing │ │
│ │ - Data structure conversion (to DataFrame/NetCDF) │ │
│ │ - Statistical analysis │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ Data Integration Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Meteorology │ │ Terrain/Maps │ │ Emissions Data │ │
│ │ APIs │ │ APIs │ │ Sources │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ Visualization & Export Layer │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ Plotly/ │ │ Folium/ │ │ Report │ │
│ │ Matplotlib │ │ Leaflet │ │ Generation │ │
│ │ (Contours) │ │ (Interactive)│ │ (PDF/HTML) │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ AERMOD Fortran Core │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ AERMOD │ │ AERMET │ │ AERMAP │ │
│ │ (dispersion) │ │ (met prep) │ │ (terrain prep) │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Core Components¶
1. Configuration & Parameter Management¶
Purpose: Provide a Pythonic interface for AERMOD configuration
Key Features: - Object-oriented parameter definition using dataclasses or Pydantic models - JSON/YAML configuration file support - Input validation with clear error messages - Default parameter sets for common scenarios - Template system for regulatory compliance (EPA guidelines)
Example API:
from pyaermod import AERMODProject, PointSource, ReceptorGrid
project = AERMODProject(
name="facility_assessment",
pollutant="PM2.5",
averaging_periods=["1HR", "24HR", "ANNUAL"]
)
# Define emission source
stack = PointSource(
id="STACK1",
location=(latitude, longitude, elevation),
height=50.0, # meters
diameter=2.0,
temperature=400.0, # K
velocity=15.0, # m/s
emission_rate=1.5 # g/s
)
# Define receptor grid
grid = CartesianGrid.from_bounds(
bounds=(min_x, min_y, max_x, max_y),
spacing=100, # meters
coordinate_system="UTM"
)
2. Input File Generation¶
Purpose: Convert Python objects to AERMOD-compatible input files
Components: - Control File Generator: Creates .inp files from Python objects - Receptor Generator: Handles Cartesian/polar grids, discrete receptors, fence lines - Source Configuration: Supports point, area, volume, line sources - Keyword Parser: Validates AERMOD keywords and options
File Structure:
CO STARTING
TITLEONE Project generated by pyaermod
MODELOPT CONC FLAT
AVERTIME 1 24 ANNUAL
POLLUTID PM25
RUNORNOT RUN
CO FINISHED
SO STARTING
LOCATION STACK1 POINT <x> <y> <base_elev>
SRCPARAM STACK1 <emission> <height> <temp> <velocity> <diameter>
SO FINISHED
RE STARTING
... (receptor definitions)
RE FINISHED
3. Process Management & Execution¶
Purpose: Orchestrate AERMOD executable runs
Features: - Subprocess management with timeout controls - Platform-specific executable detection (Windows .exe, Linux binary) - Environment variable configuration - Progress monitoring and log capture - Parallel run support for sensitivity analysis - Resource management (temp directories, cleanup)
Implementation:
class AERMODRunner:
def __init__(self, executable_path=None):
self.executable = executable_path or self._find_aermod()
def run(self, input_file, working_dir=None, timeout=3600):
"""Execute AERMOD with error handling"""
# Validate inputs
# Set up working directory
# Execute subprocess
# Capture stdout/stderr
# Parse return codes
# Return results object
def run_batch(self, scenarios, n_workers=4):
"""Run multiple scenarios in parallel"""
# Use multiprocessing Pool or concurrent.futures
4. Data Integration Layer¶
Purpose: Connect to external data sources
API Integrations:
Meteorological Data¶
- NOAA ISD: Historical surface observations
- ERA5/MERRA-2: Reanalysis data via climate APIs
- Local weather stations: Custom data ingestion
- AERMINUTE: 1-minute ASOS data for AERMET processing
from pyaermod.data import MeteorologicalData
# Fetch and prepare meteorological data
met_data = MeteorologicalData.from_noaa(
station_id="KDEN",
start_date="2023-01-01",
end_date="2023-12-31"
)
# Automatically run AERMET preprocessing
surface_file, profile_file = met_data.prepare_for_aermod(
output_dir="./met_processed"
)
Terrain/Elevation Data¶
- USGS NED: National Elevation Dataset
- SRTM: Shuttle Radar Topography Mission
- OpenTopography: High-resolution DEM access
- Automatic AERMAP execution
from pyaermod.terrain import TerrainProcessor
terrain = TerrainProcessor.from_usgs(
bounds=(min_lon, min_lat, max_lon, max_lat),
resolution=10 # meters
)
# Generate AERMAP terrain file
terrain_file = terrain.process_for_aermod(
receptors=grid,
sources=[stack]
)
Base Maps for Visualization¶
- OpenStreetMap: Tile layers
- Mapbox: Custom styling
- ESRI: Satellite imagery
- Census TIGER: Boundaries and features
5. Output Parsing & Analysis¶
Purpose: Extract and structure AERMOD results
Features: - Parse .out files for concentration/deposition results - Convert to pandas DataFrame or xarray Dataset - Calculate statistical summaries (max, percentiles, exceedances) - Spatial interpolation for smooth contours - Time-series extraction at specific receptors - Regulatory compliance checking (NAAQS comparison)
Output Structure:
class AERMODResults:
def __init__(self, output_file):
self.metadata = self._parse_header()
self.concentrations = self._parse_concentrations()
def to_dataframe(self, averaging_period="24HR"):
"""Returns DataFrame with columns: x, y, concentration, rank, etc."""
def get_max_impact(self, averaging_period="24HR"):
"""Returns location and value of maximum impact"""
def check_compliance(self, standard, background=0.0):
"""Compare against regulatory standard"""
def to_netcdf(self, output_path):
"""Export as NetCDF for GIS integration"""
6. Visualization Layer¶
Purpose: Create publication-ready graphics and interactive maps
Visualization Types:
Static Plots (Matplotlib/Plotly)¶
- Concentration contour plots
- Isopleths with customizable levels
- Source/receptor overlays
- Time-series plots
- Exceedance probability plots
from pyaermod.viz import plot_contours
fig = plot_contours(
results,
averaging_period="ANNUAL",
levels=[5, 10, 15, 20, 25], # μg/m³
colormap="YlOrRd",
show_sources=True,
show_max_location=True
)
fig.save("output.png", dpi=300)
Interactive Maps (Folium/Plotly)¶
- Leaflet-based web maps
- Zoom/pan capabilities
- Popup information on click
- Multiple layer controls
- Export to standalone HTML
from pyaermod.viz import create_interactive_map
map_obj = create_interactive_map(
results,
basemap="OpenStreetMap",
opacity=0.6,
add_legend=True
)
map_obj.save("results_map.html")
Automated Reports¶
- PDF generation with charts and tables
- HTML dashboards with embedded visualizations
- Markdown reports for documentation
- Compliance summary sheets
7. Project Management¶
Purpose: Handle multi-scenario projects
Features: - Project directory structure - Version control for configurations - Scenario comparison tools - Sensitivity analysis automation - Parameter sweep utilities
from pyaermod import Project
proj = Project("facility_permit_renewal")
# Define base scenario
base = proj.create_scenario("baseline", ...)
# Create variations
for rate in [0.5, 1.0, 1.5, 2.0]:
scenario = base.copy()
scenario.sources["STACK1"].emission_rate = rate
proj.add_scenario(f"emission_{rate}", scenario)
# Run all scenarios
results = proj.run_all(parallel=True, n_workers=4)
# Compare results
comparison = proj.compare_scenarios(
metric="max_24hr_concentration"
)
Technology Stack¶
Core Dependencies¶
Essential:
- numpy: Numerical operations, array handling
- pandas: Tabular data manipulation
- pydantic or dataclasses: Configuration validation
- click or typer: CLI interface
- subprocess: AERMOD execution
- pathlib: Cross-platform path handling
Data Integration:
- requests: API calls
- xarray: Multi-dimensional arrays (meteorological data)
- rasterio: Geospatial raster data (terrain)
- geopandas: Vector geospatial data
- pyproj: Coordinate transformations
Visualization:
- matplotlib: Basic plotting
- plotly: Interactive charts
- folium: Interactive maps
- contextily: Basemap tiles
- reportlab or weasyprint: PDF generation
Optional:
- dask: Large-scale parallel computing
- netCDF4: NetCDF file I/O
- h5py: HDF5 for large datasets
- nicegui: Web dashboard + desktop bundle
- pytest: Testing framework
- sphinx: Documentation generation
Fortran Integration Strategy¶
Approach 1: Subprocess Wrapper (Recommended for MVP) - No Fortran recompilation needed - Use existing EPA-certified binaries - Communicate via input/output files - Pros: Simple, regulatory acceptance maintained - Cons: File I/O overhead, no in-memory access
Approach 2: F2PY Integration (Future Enhancement) - Wrap specific Fortran subroutines with f2py - Call Fortran directly from Python - Pros: Performance, memory efficiency - Cons: Compilation complexity, certification concerns
Approach 3: ISO C Binding (Advanced) - Create C interface to Fortran - Use ctypes/cffi from Python - Pros: Performance, cleaner interface - Cons: Significant refactoring required
MVP Recommendation: Start with subprocess wrapper, design API to abstract execution method for future upgrades.
Data Flow¶
Typical Workflow¶
1. User Input (Python API or CLI)
↓
2. Configuration Validation
↓
3. Fetch External Data (met, terrain, maps)
↓
4. Generate AERMOD Input Files (.inp)
↓
5. Execute AERMOD Fortran Binary
↓
6. Parse Output Files (.out)
↓
7. Post-process Results (statistics, interpolation)
↓
8. Generate Visualizations (plots, maps)
↓
9. Create Reports (PDF/HTML)
↓
10. Return Results to User
File Organization¶
pyaermod/
├── src/pyaermod/ # Main package (src layout)
│ ├── __init__.py # Public API, version, optional dep checks
│ ├── api.py # Stable public surface (from pyaermod.api import *)
│ ├── _optional.py # Shared optional-dependency helper
│ ├── input_generator.py # Facade: re-exports + AERMODProject class
│ ├── pathways.py # Enums, ControlPathway, MeteorologyPathway, OutputPathway, Events
│ ├── sources.py # 12 source types, deposition params, SourcePathway, background
│ ├── receptors.py # CartesianGrid, PolarGrid, DiscreteReceptor, ReceptorPathway
│ ├── input_reader.py # .inp file reader (bidirectional round-trip)
│ ├── validator.py # Per-field validation for all pathways
│ ├── validator_advanced.py # Cross-field AERMOD checks (integrated by default)
│ ├── regulatory.py # EPA Appendix W profile presets
│ ├── chemistry_presets.py # OLM/PVMRM/GRSM factories, deposition defaults
│ ├── runner.py # AERMODRunner, BatchRunner, run_aermod()
│ ├── runner_utils.py # Progress, failure diagnostics, resume, SLURM
│ ├── output_parser.py # .out file parsing to DataFrames
│ ├── aermod_outputs.py # PLOTFILE/MAXIFILE/RANKFILE/SEASONHR/deposition readers
│ ├── postfile.py # POSTFILE parser (text PLOT + binary UNFORM)
│ ├── visualization.py # Contour plots, Folium maps
│ ├── advanced_viz.py # 3D surfaces, wind roses, animations
│ ├── aermet.py # AERMET Stages 1-3 input generation + SFC/PFL parsers
│ ├── aermet_runner.py # AERMETRunner + three-stage pipeline
│ ├── met_ingest.py # ASOS 1-min, ISD, IGRA, MMIF data ingest
│ ├── met_qaqc.py # Meteorological data QA/QC checks
│ ├── aermap.py # AERMAP input generation
│ ├── terrain.py # DEM download, AERMAP runner, elevation pipeline
│ ├── terrain_utils.py # Datums, SRTM, mosaic, reproject, diagnostics
│ ├── geospatial.py # UTM/WGS84 transforms, GIS export
│ ├── bpip.py # Building downwash (BPIP) calculations
│ ├── prime.py # GEP stack height, cavity region, project-level BPIP
│ ├── cli.py # pyaermod command-line interface
│ └── gui.py # 7-page Streamlit web application
├── tests/ # 1590+ tests across 30+ files
├── docs/ # MkDocs documentation site
│ ├── quickstart.md
│ ├── gui-guide.md
│ ├── architecture.md
│ └── api/ # Auto-generated API reference (mkdocstrings)
├── examples/ # 6 example scripts + 5 Jupyter notebooks
├── benchmarks/ # Performance benchmarks
├── setup.py # Package metadata and dependencies
├── pyproject.toml # Build system + ruff config
├── mkdocs.yml # Documentation site configuration
└── CHANGELOG.md
API Design Principles¶
1. Pythonic Interface¶
- Follow PEP 8 naming conventions
- Use context managers for resource handling
- Provide sensible defaults
- Support both OOP and functional styles
2. Progressive Disclosure¶
- Simple tasks should be simple
- Advanced features available but not required
- Sane defaults based on EPA guidance
3. Type Safety¶
- Use type hints throughout
- Runtime validation with Pydantic
- Clear error messages
4. Flexibility¶
- Support multiple input formats (JSON, YAML, Python objects)
- Allow both high-level and low-level control
- Provide escape hatches for custom AERMOD keywords
Error Handling & Logging¶
Error Categories¶
- Configuration Errors: Invalid parameters, missing required fields
- Execution Errors: AERMOD runtime failures, missing executables
- Data Errors: API failures, invalid meteorological data
- I/O Errors: File access, disk space issues
Logging Strategy¶
import logging
# Structured logging with different levels
logger = logging.getLogger("pyaermod")
# User-friendly messages
logger.info("Starting AERMOD run for project: facility_assessment")
logger.warning("Meteorological data contains gaps, interpolating...")
logger.error("AERMOD execution failed: invalid source configuration")
# Debug mode for development
logger.debug(f"Generated input file:\n{input_content}")
User Feedback¶
- Progress bars for long operations (tqdm)
- Clear error messages with suggestions
- Validation errors before execution (fail fast)
- Summary statistics after completion
Testing Strategy¶
Unit Tests¶
- Configuration object creation and validation
- Input file generation (compare against known-good files)
- Output parsing (use EPA test cases)
- Coordinate transformations
- Data validation logic
Integration Tests¶
- Full AERMOD runs with EPA test datasets
- API data fetching (with mocking)
- End-to-end workflow tests
Regression Tests¶
- Compare results against previous versions
- Validate against EPA reference implementations
- Ensure regulatory compliance is maintained
Test Data¶
- Include EPA's test case suite
- Create minimal synthetic examples
- Document expected outputs
Documentation Requirements¶
User Documentation¶
- Quick Start Guide
- Installation instructions
- First model run in 5 minutes
-
Basic concepts
-
Tutorial Series
- Point source modeling
- Area source modeling
- Working with meteorological data
- Visualization options
-
Batch processing
-
API Reference
- Auto-generated from docstrings (Sphinx)
- Type annotations
-
Examples for each function
-
How-To Guides
- Regulatory compliance workflows
- Data integration recipes
- Custom visualization
-
Performance optimization
-
FAQ & Troubleshooting
- Common errors and solutions
- AERMOD-specific gotchas
- Platform-specific issues
Developer Documentation¶
- Architecture Overview (this document)
- Contributing Guide
- Code style
- Testing requirements
-
Pull request process
-
API Design Rationale
- Fortran Interface Details
- Release Process
Regulatory Documentation¶
- EPA Compliance Statement
- Which AERMOD version is wrapped
- Certification status
-
Limitations and disclaimers
-
Validation Report
- Comparison with EPA test cases
- Numerical precision analysis
- Known differences (if any)
Performance Considerations¶
Optimization Strategies¶
- Parallel Execution
- Multi-scenario runs via multiprocessing
-
Batch processing for sensitivity analysis
-
Caching
- Meteorological data caching
- Terrain data caching
-
Parsed output caching
-
Lazy Loading
- Only load data when needed
-
Stream large output files
-
Efficient Data Structures
- Use numpy arrays for receptor grids
- Consider HDF5 for large datasets
Scalability¶
- Support for large receptor grids (>10,000 points)
- Multiple years of meteorological data
- Batch processing 100+ scenarios
- Cloud deployment considerations (Docker containers)
Security & Validation¶
Input Validation¶
- Sanitize user inputs to prevent injection attacks
- Validate coordinate ranges
- Check file paths for directory traversal
API Key Management¶
- Support environment variables for API credentials
- Secure storage recommendations
- No hardcoded secrets
Output Validation¶
- Verify AERMOD execution success
- Check for numerical anomalies
- Validate against physical constraints
Deployment Options¶
Local Installation¶
Docker Container¶
FROM python:3.11
RUN apt-get update && apt-get install -y gfortran
COPY aermod-binaries/ /usr/local/bin/
RUN pip install pyaermod
Cloud Deployment¶
- AWS Lambda for API endpoints (if execution time permits)
- EC2/GCE for long-running jobs
- Kubernetes for scalable batch processing
Licensing & Compliance¶
Wrapper License¶
- MIT or Apache 2.0 (permissive for commercial use)
- Clear attribution requirements
AERMOD Binaries¶
- EPA public domain (no license restrictions)
- Include EPA's disclaimer
- Cite appropriate technical documentation
Dependencies¶
- Verify all dependencies have compatible licenses
- Document any GPL dependencies (if used)
Roadmap & Phasing¶
Phase 1: MVP (Months 1-3)¶
- Core subprocess wrapper
- Basic input file generation
- Simple output parsing
- CLI tool
- Point and area sources
- Static visualization
- Documentation
Phase 2: Data Integration (Months 4-6)¶
- NOAA meteorological data API
- USGS terrain data integration
- AERMET/AERMAP automation
- Interactive maps
- Basic web dashboard
Phase 3: Advanced Features (Months 7-9)¶
- Volume and line sources
- Building downwash (BPIP integration)
- Sensitivity analysis tools
- Advanced visualization (3D, time-lapse)
- Automated report generation
- Performance optimization
Phase 4: Enterprise Features (Months 10-12)¶
- Multi-user project management
- Version control integration
- Cloud deployment
- API authentication
- Database backend for results
- Advanced statistical analysis
Success Metrics¶
Technical Metrics¶
- 100% pass rate on EPA test cases
- <5% performance overhead vs. direct AERMOD execution
- Support for 95% of common use cases
- <100ms for input file generation
- <10s for result parsing (typical run)
User Metrics¶
- Reduce modeling time by 50% vs. manual workflow
- Enable non-experts to run compliant models
-
80% user satisfaction score
- <2 hours to first successful model run (new users)
Business Metrics¶
- Eliminate need for consulting fees for routine models
- Enable in-house regulatory compliance
- Reduce project turnaround time
- Lower barrier to entry for air quality modeling
Risk Mitigation¶
Regulatory Acceptance Risk¶
- Mitigation: Maintain exact AERMOD binary usage, provide validation documentation
- Fallback: Export inputs for verification in AERMOD View or other approved tools
Fortran Dependency Risk¶
- Mitigation: Abstract execution layer to support multiple AERMOD versions
- Fallback: Document manual AERMOD execution procedures
Data API Reliability Risk¶
- Mitigation: Implement caching, support offline mode with user-provided data
- Fallback: Detailed documentation for manual data preparation
Maintenance Burden Risk¶
- Mitigation: Comprehensive test suite, modular architecture
- Fallback: Community contribution model, commercial support option
Conclusion¶
This architecture provides a robust foundation for a Python wrapper around AERMOD that balances: - Accessibility: Pythonic API, clear documentation - Regulatory Compliance: Maintains EPA-certified calculations - Extensibility: Modular design for future enhancements - Performance: Efficient data handling and parallel execution - Practicality: Focused on real-world use cases
The phased approach allows for incremental development while delivering value at each stage. The MVP focuses on core functionality to eliminate consulting dependencies, while later phases add sophisticated features for power users.
References¶
- EPA AERMOD Implementation Guide
- AERMOD Model Formulation Document
- EPA SCRAM Website (Support Center for Regulatory Atmospheric Modeling)
- ISO 19115 (Geographic Information Metadata)
- CF Conventions (Climate and Forecast Metadata)