TERRANOETIS

Hurricane landfall (Holland 1980 wind + SWE surge + waves + rainfall + runoff)

Platform v3.0.0 Docs v3.0.0 MEASURED LOCALLY

Full description: Read the full narrative

The landfall scenario combines a parametric vortex wind field (Holland 1980 with the Atkinson–Hollan B estimate and Coriolis term, advected along a track that passes the pinned landfall point at mid-duration) with a depth-averaged nonlinear shallow-water surge solver forced by wind stress and bottom pressure, empirical wave growth (JONSWAP/Stokes–Moum–Bretschneider capped at Pierson–Moskowitz with USACE breaking/setup rules), Lonfat-shaped parametric rainfall, and USDA TR-55 SCS-CN runoff.

Execution mode
Local CPU (python3) — no Kaggle token required server/kaggle/simRunner.ts:126-141
Verification
MEASURED — executed directly (3 parameter sets incl. Cat 5 and Cat 1 boundaries); internal physics gate PASS observed
Wire scenario type
hurricane_landfall — contract at src/services/kaggleSim.ts:28-240; job API at Simulation job API
Evidence legend

MEASURED marks values produced by executing the actual code on this machine (commands in Reproduction; raw logs summarised in Methodology → Evidence runs).

Governing equations and coefficients

Source attribution as stated in the kernel header (verbatim):

Wind: Holland (1980, MWR 108:1212) gradient-wind balance with Coriolis: V(r) = sqrt( V_c^2 + (f·r/2)^2 ) − f·r/2, V_c^2 = (B·Δp/ρ)·x·e^(−x), x = (R_max/r)^B B from the observed Vmax–Δp relation (Atkinson & Hollan 2012, BAMS): B = e·ρ·Vmax^2/Δp, clipped to [1.0, 2.5].
kaggle-kernels/hurricane-sim/main.py:10-14
V(r) = sqrt(V_c² + (f·r/2)²) − f·r/2, V_c² = (B·Δp/ρ)·x·e^(−x), x = (R_max/r)^B
Holland gradient wind; r floored at 0.1 km; f = 2Ω·sin(lat), Ω = 7.2921159e-5 rad/s. kaggle-kernels/hurricane-sim/main.py:160-170,138-143,156
p(r) = p_c + Δp·exp(−(R_max/r)^B)
Holland pressure field; the inverse-barometer ocean response is implicit in the momentum forcing and is not re-added to the output. kaggle-kernels/hurricane-sim/main.py:20,154-157,27-29
τ = ρ_a·C_d·|U|·U ÷ (ρ_w·h_stress), C_d = 1.5e-3
Wind stress on the surge; drag saturation per Powell et al. 2003 (BAMS); base value Large & Pond 1981 (JPO 11:324). h_stress floored at 1 m. kaggle-kernels/hurricane-sim/main.py:25-27,519-529,108-110
Manning n = 0.03 bottom friction, damping-limited to ±0.9|u|/dt; current cap 10 m/s
Shelf/channel roughness constant. kaggle-kernels/hurricane-sim/main.py:549-560,111
H_s = 1.6e−3 · U_A · √F, U_A = 0.71·U10, capped at H_s ≤ 0.0248·U_A²
Fetch-limited JONSWAP/SMB growth with Pierson–Moskowitz fully-developed cap; USACE CEM EM 1110-2-1100 Part II-1. kaggle-kernels/hurricane-sim/main.py:30-36,117-119,173-182
H_b = 0.78·d; setup η_s ≈ 0.19·H_b
Depth-limited breaking (γ = 0.78, USACE CEM Part II-1) and wave setup (USACE Eq. II-4-24 radiation-stress result). kaggle-kernels/hurricane-sim/main.py:35-38,112-116,501-502
rate(r) = 1.2·Vmax · (r/r_peak) · ((500−r)/(500−r_peak))^1.5 mm/h, r_peak = max(100 km, R_max), 0 beyond 500 km
Lonfat et al. 2007 (JGR 112, doi:10.1029/2006JD007557 — as cited in code: MWR 135:3086) PHRaM/R-CLIPER-shaped footprint; validation reference Tuleya et al. 2007, WAF 22:56. kaggle-kernels/hurricane-sim/main.py:39-48,124-126,185-199
Q = (P − 0.2S)² / (P + 0.8S), S = (1000/CN − 10)·25.4 mm; Q ≤ P
USDA TR-55 SCS Curve Number runoff, applied incrementally; CN land: 77 (suburban) on land, 99 on water — of five coded CN values only these two are used by the terrain classifier. kaggle-kernels/hurricane-sim/main.py:49-51,131-136,202-209,426-427

Coefficients and named constants

Named constants (value — meaning — source).
ConstantValueMeaning / provenanceSource
RHO_AIR1.15 kg/m³Air density for stress/IBkaggle-kernels/hurricane-sim/main.py:105
RHO_WATER1025.0 kg/m³Seawater densitykaggle-kernels/hurricane-sim/main.py:106
G9.81 m/s²Gravitykaggle-kernels/hurricane-sim/main.py:107
C_DRAG0.0015Saturated high-wind drag (Powell 2003; Large & Pond 1981)kaggle-kernels/hurricane-sim/main.py:108-110
N_MANING0.03Typical shelf/channel Manning nkaggle-kernels/hurricane-sim/main.py:111
GAMMA_BREAKER0.78USACE CEM "(H/d)max = 0.78 agrees best with observations"kaggle-kernels/hurricane-sim/main.py:112-113
K_SETUP0.19Wave setup coefficient (USACE Eq II-4-24)kaggle-kernels/hurricane-sim/main.py:114-116
JONSWAP_CH1.6e-3SMB/JONSWAP fetch-growth coefficientkaggle-kernels/hurricane-sim/main.py:117-118
PM_LIMIT0.0248Pierson–Moskowitz cap coefficientkaggle-kernels/hurricane-sim/main.py:119
cat_winds{1:43, 2:50, 3:58, 4:70, 5:90} m/sSaffir–Simpson threshold wind per categorykaggle-kernels/hurricane-sim/main.py:351-352
Ω (OMEGA_EARTH)7.2921159e-5 rad/sEarth rotation for Corioliskaggle-kernels/hurricane-sim/main.py:138-143

Parameter contract

Hurricane parameters. Category drives derived pressure/radius via derivePhysicsFormOverrides. Shared request envelope (validated at the client boundary before dispatch).

Hurricane parameters. Category drives derived pressure/radius via derivePhysicsFormOverrides.
UI controlWire fieldUnitValid range (UI · wire · kernel)DefaultPhysical meaningSource
Saffir–Simpson Category slidercategorycat (int)UI & wire 1–53Peak wind 43/50/58/70/90 m/s (kernel table)src/components/scenarios/ScenarioEditor.tsx:69-76 src/services/kaggleSim.ts:140,604-612 kaggle-kernels/hurricane-sim/main.py:351-352
Forward Speed sliderforward_speed_kmhkm/hUI 5–60; wire 2–80UI 15 · kernel 30Track translation speed (asymmetric wind + accumulation)src/components/scenarios/ScenarioEditor.tsx:69-76 src/services/kaggleSim.ts:141 kaggle-kernels/hurricane-sim/main.py:342
Central Pressure slidercentral_pressure_hpahPaUI 880–1010 (overwritten to 1010−20·cat); wire 860–1020UI 950 · kernel 960Sets Δp, hence B and the whole radial profilesrc/components/scenarios/ScenarioEditor.tsx:69-76 src/services/kaggleSim.ts:142,609 kaggle-kernels/hurricane-sim/main.py:343
Radius of Max Winds sliderradius_max_wind_kmkmUI 10–200 (overwritten to max(20, 30+15·cat)); wire 5–300UI 50 · kernel 50Eyewall radius; needs ≤ ~R_max/2 cell size to be resolvedsrc/components/scenarios/ScenarioEditor.tsx:69-76 src/services/kaggleSim.ts:143,611 kaggle-kernels/hurricane-sim/main.py:344
Track Heading slider + auto checkboxheading_deg (optional)°, clockwise from NUI 0–360 step 5; wire 0–360; omitted in auto mode270Auto mode: kernel auto-aims the storm from the water centroid toward the pinned pointsrc/components/scenarios/ScenarioEditor.tsx:71-76,770-781 src/services/kaggleSim.ts:146-151,493 kaggle-kernels/hurricane-sim/main.py:393-400
Hours to Landfall sliderduration_hours = 2 × landfallTimehUI 6–96 (wire ≤ 720)UI 24The eye crosses the pinned point at mid-duration, so the run spans equal approach + inland halvessrc/components/scenarios/ScenarioEditor.tsx:69-76 src/services/kaggleSim.ts:144,477-494 kaggle-kernels/hurricane-sim/main.py:376-381
Landfall point (globe click)track_frac_x/y (optional)fraction 0–1clamped0.5, 0.5Column = east, row = south; default box centresrc/services/kaggleSim.ts:152-159 kaggle-kernels/hurricane-sim/main.py:382-383
Terrain (auto-sampled)terrain + terrain_gsm (negative = below sea)≤ 65,536 cellsReal relief/bathymetry replaces the synthetic coastal profilesrc/services/kaggleSim.ts:160-167

Outputs

Files written per run (also served by GET /api/kaggle/simulate/:jobId/grid/:name and …/geotiff/:name)
FieldUnitMeaningSource
wind_speed.npym/sTotal 10 m wind (gradient + translation)kaggle-kernels/hurricane-sim/main.py:724-745
wind_direction.npyradatan2 of east/north wind componentskaggle-kernels/hurricane-sim/main.py:724-745
surge_height.npymComposite water level: η + setup over ocean, inundation depth over land (NHC/USGS composite convention)kaggle-kernels/hurricane-sim/main.py:612-615
wave_setup.npy / wave_height.npym / m (Hs)Setup and significant wave heightkaggle-kernels/hurricane-sim/main.py:724-745
rainfall.npy / runoff.npymm (cumulative)Rain accumulation and SCS-CN runoffkaggle-kernels/hurricane-sim/main.py:582-591,724-745
inundation.npym above groundOn-land flooding depthkaggle-kernels/hurricane-sim/main.py:724-745
terrain.npymEffective terrain usedkaggle-kernels/hurricane-sim/main.py:724-745
snapshots_wind/surge.npy + snapshot_times.npy—; h≈20-frame serieskaggle-kernels/hurricane-sim/main.py:724-745
metadata.jsonmodel "holland_1980_wind + nonlinear_2d_swe_surge", physics/sources strings, limitskaggle-kernels/hurricane-sim/main.py:654-674

Spatial-origin semantics

Square domain; row 0 = north, so northward storm motion decreases the row index (cy = cy0 − v_north·t/dx). The eye passes the pinned track point (x = east, y = south, fractions of the grid) at mid-duration; heading 0 = N clockwise; auto-aim computes the bearing from the water centroid. Without supplied terrain the synthetic profile is ocean west / land east with a ~1.5 m/km shelf. kaggle-kernels/hurricane-sim/main.py:476-482,376-383,431-440,393-400,240-256

Documented validity limits (verbatim from the code)

'point-vortex Holland field — no eyewall fine structure, constant Vmax (no intensification/decay)' · 'fetch = distance to nearest coast (upper-bound proxy)' · 'wave setup empirical (USACE Eq II-4-24, ≈0.19·H_b) — no wave propagation' · 'rainfall parametric surrogate of the Lonfat-2007 PHRaM radial structure (no shear/topography Fourier terms), not microphysical' · 'no tides, no river routing (backwater excluded)' · 'equirectangular grid — valid ≤ ~500 km domain'
kaggle-kernels/hurricane-sim/main.py:663-674

The kernel refuses to emit fields if its physics gate fails — "Hurricane physics gate failed — refusing to emit fields from mis-wired parametric relations." Checks: V(R_max) ≈ V_max ± 15 %, B ∈ [1, 2.5], inverse-barometer 0.9–1.1 cm/hPa, CN75 @ 100 mm in (30, 50) mm, SCS zero below 0.2 S, wave growth vs PM cap, rain peak 40–130 mm/h with zero eye/500 km. kaggle-kernels/hurricane-sim/main.py:285-335,717-720

Measured runs and timings

Executed on an Apple-Silicon laptop (Python 3.14.5, NumPy 2.4.2). These are observations of one environment, not performance guarantees.
Run / checkMeasured result
Physics gate (every run, observed stdout)"B=2.29 V(Rmax)=69.0 m/s (target 70) | IB=0.99 cm/hPa | CN75@100mm=41.1 mm | waves 18.0→31.3 cap 5.00 m | rain peak=84mm/h eye=0 edge=0 → PASS"
Representative Cat 4 (950 hPa, 40 km RMW, 6 h, 240 km box)max wind 77.0 m/s (right-front asymmetry above the 70 m/s threshold), coastal water 1.15 m, inundation 0.39 m, rainfall 482 mm, runoff 402 mm; wall 1.47 s
Boundary Cat 5 with 5 km RMW on 2.5 km cellsmax wind 32.2 m/s — eyewall under-resolved by the grid ("coarse-grid dilution"); a real Cat 5 wind requires RMW ≳ 2× cell size. Documented behaviour, not an error
Boundary Cat 1 with 1020 hPa central pressuremax wind 1.6 m/s — Holland Δp floor (5 hPa) dominates; demonstrates that pressure, not category label, drives the field

Reproduction

Commands

curl -s -X POST http://localhost:3001/api/kaggle/simulate \
  -H 'Content-Type: application/json' -d '{
    "type":"hurricane_landfall","lat":25.0,"lon":-80.0,"grid_size":96,
    "extent_km":240,"category":4,"forward_speed_kmh":30,
    "central_pressure_hpa":950,"radius_max_wind_km":40,"duration_hours":6 }'

# direct kernel:
cd /tmp && mkdir h && cp <repo>/kaggle-kernels/hurricane-sim/main.py h/ && cd h && \
  echo '{"grid_size":96,"category":4,"central_pressure_hpa":950,"radius_max_wind_km":40,"forward_speed_kmh":30,"duration_hours":6,"extent_km":240}' > params.json && \
  TERRANOETIS_OUT_DIR=$PWD python3 main.py | grep VERIFY