Version: v4.8.0 (commit 06d4240) Compiler: GNU Fortran 15.2.1, -O3 -march=znver3 -ftree-vectorize -funroll-loops -fno-trapping-math File: phys/module_sf_urban.F Configuration: sf_urban_physics=1, sf_surface_physics=4 (Noah-MP), bl_pbl_physics=5, sf_sfclay_physics=5, use_wudapt_lcz=1, TS_SCHEME: 1, GROPTION: 0, 3 domains (9/3/1 km), ERA5 forcing
Summary
The Newton-Raphson solver for urban wall and road temperatures applies its correction without any limit on step size or on the resulting iterate. When the Jacobian approaches singularity the iterate runs away; once it reaches infinity the saturation-vapour-pressure expression evaluates inf/inf and injects a NaN into the surface fluxes.
The NaN then leaves SLUCM and, in our configuration, eventually reaches MYNN-SFC where it causes a segmentation fault (filed separately as an unguarded lookup index). The more serious consequence is that the solver writes physically impossible surface temperatures for some time before any crash occurs, so a run that completes is not necessarily correct.
Mechanism
module_sf_urban.F:1534 opens the wall/road iteration:
fortran IF (TS_SCHEME == 1) THEN ! TB, TG Solving Non-Linear Simultaneous Equation by Newton-Rapson DO ITERATION=1,20
and line 1640 computes the correction:
TB = TBP + DTB TG = TGP + DTG ```
(FX*GY-GX*FY) is the Jacobian determinant and can approach zero. Nothing bounds DTB/DTG, and nothing bounds TB/TG. The loop does have a convergence test at line 1665, so a converging cell exits cleanly — the gap is purely on the divergent path.
Once TGP is infinite, line 1541 evaluates
fortran ES=6.11*EXP( (2.5*10.**6./461.51)*(TGP-273.15)/(273.15*TGP) )
(inf - 273.15)/(273.15*inf) is inf/inf, i.e. an invalid operation producing NaN. A build with -ffpe-trap=invalid traps precisely here:
3 __module_sf_urban_MOD_urban
at phys/module_sf_urban.f90:1534
4 __noahmpurbandrivermainmod_MOD_noahmp_urban
at noahmp/drivers/wrf/NoahmpUrbanDriverMainMod.F90:541
5 __module_surface_driver_MOD_surface_driver._omp_fn.8
The roof solver at line 1296 (DTR = F/DFDT) and the green-roof loop at line 1349 (DO ITERATION=1,100) share the same unbounded structure.
Evidence that output is corrupted before the crash
Urban-cell skin temperature on the innermost domain, unmodified 4.8.0 versus the same run with a bounded step:
model time stock with damped step
00:00 290.09 – 295.12 K 290.09 – 295.12 K (bit-identical)
01:00 290.76 – 295.48 K 290.74 – 295.13 K
02:00 247.06 – 294.41 K 290.81 – 294.59 K
02:33:55 SIGSEGV run continues
247 K is −26 °C on an urban surface in subtropical Australia in late autumn. The solver had been producing that for at least half an hour of model time before the segfault, so the crash is a late and optional symptom. Configurations that survive may still contain the corruption.
Suggested fix
A damped Newton step with a physical bound on the iterate. Applied to both the wall/road solver and the roof solver:
```fortran IF (.not. (DTB == DTB)) DTB = 0.0 IF (.not. (DTG == DTG)) DTG = 0.0 DTB = MAX(-DT_MAX, MIN(DT_MAX, DTB)) DTG = MAX(-DT_MAX, MIN(DT_MAX, DTG))
TB = TBP + DTB TG = TGP + DTG
TB = MAX(T_MIN, MIN(T_MAX, TB)) TG = MAX(T_MIN, MIN(T_MAX, TG)) ```
We used DT_MAX = 5.0 K, T_MIN = 200 K, T_MAX = 350 K.
Two observations from testing this locally:
The first output frame was bit-identical across all 5184 cells to the unmodified build, and frame 1 differed by only 0.02–0.35 K. A converging cell takes steps far below 5 K, so the limit is inert on healthy cells.
Zero cells reached the 200 K or 350 K bounds. The hard clamp never fired; the step damping alone was sufficient. That suggests damping is the substantive part and the temperature bounds are only a backstop.
With the guard applied, the previously crashing case completed a 4-hour run and a 24-hour run with no NaN in any output field.
Caveat on reproducibility
This is a marginal instability and we want to be straightforward about that. Whether a given cell diverges on a given timestep was sensitive to optimization flags, OpenMP thread count, and even to adding a few lines of diagnostic printing — one instrumented build ran clean through the same period where the uninstrumented build crashed.
We therefore cannot offer a small portable reproducer, and we would not expect the exact failure time to reproduce on different hardware or compiler settings. What we can state confidently is the structural defect: the correction is unbounded, the iterate is unbounded, and there is a code path from that to inf/inf at line 1541. The fix is defensible on general numerical grounds regardless of whether any particular case triggers it.
Happy to supply the FPE-trap backtraces, the full run matrix, or the input configuration if useful.
Version: v4.8.0 (commit 06d4240) Compiler: GNU Fortran 15.2.1, -O3 -march=znver3 -ftree-vectorize -funroll-loops -fno-trapping-math File: phys/module_sf_urban.F Configuration: sf_urban_physics=1, sf_surface_physics=4 (Noah-MP), bl_pbl_physics=5, sf_sfclay_physics=5, use_wudapt_lcz=1, TS_SCHEME: 1, GROPTION: 0, 3 domains (9/3/1 km), ERA5 forcing
Summary
The Newton-Raphson solver for urban wall and road temperatures applies its correction without any limit on step size or on the resulting iterate. When the Jacobian approaches singularity the iterate runs away; once it reaches infinity the saturation-vapour-pressure expression evaluates inf/inf and injects a NaN into the surface fluxes.
The NaN then leaves SLUCM and, in our configuration, eventually reaches MYNN-SFC where it causes a segmentation fault (filed separately as an unguarded lookup index). The more serious consequence is that the solver writes physically impossible surface temperatures for some time before any crash occurs, so a run that completes is not necessarily correct.
Mechanism
module_sf_urban.F:1534 opens the wall/road iteration:
fortran IF (TS_SCHEME == 1) THEN ! TB, TG Solving Non-Linear Simultaneous Equation by Newton-Rapson DO ITERATION=1,20
and line 1640 computes the correction:
3 __module_sf_urban_MOD_urban
at phys/module_sf_urban.f90:1534
4 __noahmpurbandrivermainmod_MOD_noahmp_urban
at noahmp/drivers/wrf/NoahmpUrbanDriverMainMod.F90:541
5 __module_surface_driver_MOD_surface_driver._omp_fn.8