AERMAP Troubleshooting¶
AERMAP is the terrain preprocessor for AERMOD. It reads DEM data,
snaps each source and receptor to the DEM grid, and writes elevation
(zelev) and hill-height (zhill) values AERMOD uses for terrain
effects.
This guide covers the common things that go wrong and how to use
pyaermod's terrain_utils helpers to diagnose them.
DEM data sources¶
| Source | Resolution | Coverage | Where |
|---|---|---|---|
| USGS 3DEP / NED 1/3" | ~10 m | CONUS + Alaska | pyaermod's DEMDownloader (see terrain.py) |
| SRTM v3.0 1" | ~30 m | global ±60° | srtm_tiles_for_bbox in terrain_utils |
| Copernicus GLO-30 | ~30 m | global | fetch manually; reproject via reproject_dem |
| NED 1/9" | ~3 m | CONUS, select | USGS, not fetched automatically |
Datum mismatches (the silent killer)¶
A surprisingly large fraction of "weird receptor elevation" bugs come from DEM and receptor coordinates being in different datums.
- NAD27 vs. NAD83 shifts are ~50–100 m in CONUS — enough to put receptors on the wrong side of a ridge.
- Older 7.5-minute quad DEMs are NAD27; modern 3DEP is NAD83.
- Use
pyaermod.terrain_utils.DatumTransformerto convert explicitly:
from pyaermod import DatumTransformer
tr = DatumTransformer.nad27_to_nad83()
lon83, lat83 = tr.transform(lon27, lat27)
UTM zone picking¶
AERMOD expects all inputs in a consistent projected coordinate system — typically the UTM zone covering the site. Pick with:
from pyaermod import utm_zone_for_lon, utm_epsg
zone = utm_zone_for_lon(-95.0) # -> 15
epsg = utm_epsg(-95.0, 40.0) # -> 32615 (WGS84 UTM 15N)
If the domain crosses a zone boundary, stick with one zone (the one containing the sources) rather than the nominal "center" — AERMAP / AERMOD computations are done in the input CRS, not lat/lon.
Multi-tile mosaics¶
NED tiles are 1x1 degree; a typical modeling domain spans several. To merge:
from pyaermod.terrain_utils import mosaic_dem_tiles, reproject_dem
mosaic = mosaic_dem_tiles(
["N34W106.tif", "N35W106.tif", "N34W105.tif", "N35W105.tif"],
output_path="mosaic.tif",
)
reproject_dem(mosaic, "mosaic_utm.tif", dst_epsg=32613) # UTM 13N
Requires rasterio. Cache the mosaic — reprojection is expensive.
Hill-height diagnostics¶
After running AERMAP, scan its RECEPTORS.DAT / SOURCES.DAT output
for anomalies:
from pyaermod import AERMAPOutputParser, hill_height_diagnostics
parsed = AERMAPOutputParser().parse_output("AERMAP.OUT")
flags = hill_height_diagnostics(parsed.receptors)
for f in flags:
print(f.reason, "at", (f.x, f.y))
What hill_height_diagnostics flags:
| Flag | Meaning | Typical cause |
|---|---|---|
zhill below zelev |
hill height less than ground elevation | DEM read failure / wrong datum |
elevation gradient > N m/m |
cliff-sharp change between adjacent receptors | hole in DEM, tile seam |
flat-elevation run |
25+ consecutive receptors at identical elevation | DEM "fill" / placeholder tile |
Common failure modes¶
| Symptom | Check |
|---|---|
| "receptor outside DEM bounds" | bbox of receptors vs. DEM extent — fetch more tiles |
All zhill values = 0 |
AERMAP didn't pick up terrain file — check CO pathway TERRHGTS path |
zhill < zelev on many receptors |
datum mismatch between receptors and DEM |
| Wildly high hill heights | receptor coordinates in feet but treated as meters |
SRTM fallback outside CONUS¶
USGS NED only covers the US. Outside that footprint, SRTM 1" is the workhorse fallback:
from pyaermod import srtm_tiles_for_bbox
tiles = srtm_tiles_for_bbox((-80.0, 25.0, -79.0, 26.0)) # bounds in lon/lat
for t in tiles:
print(t.tile_name, t.download_url)
SRTM downloads typically require NASA EarthData Login; OpenTopography is an unauthenticated alternative.