Donelan and Variable Rougness MOST Fixes - #3952
Merged
Merged
Conversation
* Make ABL_MOST_SFC/SST perturbations decomposition-invariant * Add decomposition-invariant index-keyed perturbation RNG * Address code review findings on ABL perturbation work * Fix WPS map projection in TerrainNetCDF test fixture
)" This reverts commit 1737bc3.
pressel
reviewed
Sep 5, 2026
Collaborator
Author
|
CPU nightly regression test failures: |
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The PR is about the sea-surface roughness pathway. It fixes six correctness
defects, replaces the iteration scheme in two MOST solvers, removes a redundant
flux type, and consolidates five roughness laws into one place so the bounds and
the smooth-flow limit are written once instead of five times.
1. Correctness fixes
1.1 Wave-coupled roughness used turbulent, not molecular, viscosity
The aerodynamically-smooth term in the wave-coupled law read
EddyDiff::Mom_vis assigned asrho * nu_turb(
ERF_ComputeTurbulentViscosity.cpp:148) — dynamic turbulent viscosity,O(1) kg m⁻¹ s⁻¹. Smith (1988) calls for molecular kinematic viscosity,
ν ≈ 1.5 × 10⁻⁵ m² s⁻¹. The expression was five orders of magnitude too large and
dimensionally wrong (kg m⁻², not m): at u* = 0.3 m/s it evaluated to ≈ 0.37 m,
which pinned z₀ at the
z0_maxclamp and made the Taylor–Yelland wave-steepnessterm irrelevant. The wave-coupled option was, in effect, not doing wave coupling.
Now
air_viscosity(tm_arr(i,j,k))— the Andreas (1989) kinematic ν, 1.46 × 10⁻⁵m² s⁻¹ at 15 °C. Affected
adiabatic_wave_coupled,surface_flux_wave_coupled,and
surface_temp_wave_coupled.1.2 Charnock smooth-flow term was missing its coefficient
The 0.11 of z₀ = 0.11 ν/u* (Smith 1988; ECMWF IFS; WRF) had been dropped, making
the smooth-flow contribution ~9× too large. The u* floor also moves 0.05 → 0.01
to match the Donelan branch and WRF.
1.3 Moisture flux used a stale roughness
In
surface_flux_charnock,surface_flux_mod_charnock,surface_flux_donelanand
surface_flux_wave_coupled, momentum and heat used the freshly updated localz0while moisture used the storedz0_arr:z0_arris only written at the end ofiterate_flux, so the latent heat fluxlagged the sensible heat flux by a full surface-layer update.
1.4 Modified Charnock was unbounded
has an asymptote of e^2.7 = 14.9 m and previously had no clamp at all. In
shallow water at storm winds the inner z₀ fixed point fails outright — either
iter_zexceedsmax_itersand the device-sideAMREX_ALWAYS_ASSERTaborts, orz₀ climbs above the reference height,
ln(z_ref/z₀)goes negative, and u*, θ*and every derived flux are silently corrupted:
Now bounded to [1.27 × 10⁻⁷, 1.0 × 10⁻²] m. With that bound every case above
converges in ≤ 24 iterations against
max_iters = 100.1.5
bulk_coeffnever produced a roughness lengthThe bulk-coefficient flux type prescribes C_d/C_h/C_q and computes u*, θ*, q*
from the resulting fluxes, but never wrote
z_0. Downstream consumers — the YSUand YSU-New PBL schemes, 2D plotfiles, checkpoints — saw whatever
z0_constwasset at initialization.
Compute_roughnessnow back-solves the log law from thediagnosed u* and L:
so the reported roughness is consistent with the stress actually applied. It
carries a lower bound only (1 × 10⁻⁷ m) — no ocean cap, because the
bulk_coeffpath runs over land as well, and a floor to stop the exponential underflowing to
exactly zero when u* is small.
ERF_ComputeDiffusivityYSU.cpp:133divides by z₀without a guard, so a zero there would be fatal.
1.6 COARE 3.0 was not COARE 3.0
erf.most.charnock_viscositynow defaults totrue(wasfalse). COARE 3.0(Fairall et al. 2003) is defined with z₀ = α u*²/g + 0.11 ν/u*; the smooth-flow
term is part of the parameterization, not an option, and WRF's
module_sf_mynn.Fapplies it unconditionally. With the old default,
roughness_type_sea = coare3.0silently ran a variant that isn't COARE.
2. Rewritten iteration in
surface_temp_donelanandsurface_temp_wave_coupledThese two structs iterated directly on u* with Businger–Dyer stability functions
and an ad-hoc bisection guard for Obukhov-length sign flips:
That heuristic is fragile near neutral, where ⟨w'θ_v'⟩ → 0 drives L → ±∞ and the
iterate chatters. They now use the bulk-Richardson fixed point that
surface_temp,surface_temp_charnockandsurface_temp_mod_charnockalreadyused, so all five specified-temperature solvers share one scheme.
First call assumes near-neutral (L = 10³ m) rather than guessing u*.
Optional Beljaars (1995) gustiness, U²_eff = |U|² + (β w*)², β = 1.2, with the
buoyancy flux lagged one update as in WRF.
Bulk Richardson number over the reference height, moisture carried through θ_v,
clipped to [−4, 4].
Outer fixed point on ζ using the exact MOST identity
under-relaxed at α = 1/2, with
max(C−ψ, 1)guards.New inner fixed point on z₀, since every roughness law depends on u* which
itself depends on ln(z_ref/z₀). Previously z₀ lagged by one step.
Ri_b is built entirely from known quantities, so the outer iteration has a single
unknown and no singularity at neutral. Operational schemes (WRF
sf_sfclayrev,MYNN) invert Ri_b → ζ the same way, though through regression fits; solving the
relation directly keeps it exact for whatever ψ functions are supplied.
Both structs also switch from Businger–Dyer to the Jiménez et al. (2012) ψ
functions, matching the other
surface_temp_*variants. Stable branch followsCheng & Brutsaert (2005) with 6.1/2.5 and 5.3/1.1; unstable blends Kansas
(16 ζ) with the Grachev et al. (2000) convective forms (10 ζ, 34 ζ) through
ζ²/(1+ζ²). All coefficients match the published values.
3. Removal of the
donelanflux typeerf.surface_layer.flux_type = donelanand thedonelan_fluxfunctor are gone.The functor applied a wind-dependent drag coefficient directly:
The ramp is a Large & Pond (1981) style fit and the 0.0024 ceiling encodes the
Donelan et al. (2004) drag saturation, so the shape was defensible. Three
problems made it not worth keeping:
compute_q_fluxreturned zero unconditionally — moist runs on this path lostall surface latent heat.
bulk_coeff_fluxalready offers the samefunctional form through
erf.most.Cd/Ch/Cq.stability correction.
Donelan drag is now reached through MOST with
erf.most.roughness_type_sea = donelan, which recovers a wind-dependent C_dimplicitly through z₀(u*) and additionally gets stability corrections and a real
moisture flux. No inputs file in
Exec/orTests/used the removed flux type.The parser aborts on unknown strings, so a stale external deck fails loudly.
4. Roughness bounds
Every law now returns through an explicit clamp. What changed:
The 1.27 × 10⁻⁷ / 2.85 × 10⁻³ pair is WRF's open-ocean bound
(
ZNT = MIN(2.85e-3, MAX(ZNT, 1.27e-7))inmodule_sf_sfclayrev.F90), inheritedvia Davis et al. (2008). It is best read as a drag ceiling rather than a length:
Charnock, COARE 3.0 and Donelan keep the WRF value. The two laws whose purpose is
to be rougher than deep water — modified Charnock (shallow water,
Jiménez & Dudhia 2018) and wave-coupled (steep young seas, Taylor & Yelland 2001)
— get 1 × 10⁻² m instead. The deep-water cap would otherwise switch them off in
exactly the regime they exist for: modified Charnock in 5 m of water saturated at
U₁₀ ≈ 10 m/s, and Taylor–Yelland crossed 2.85 × 10⁻³ at a steepness of
H_s/L_p ≈ 0.05 (H_s = 4 m, L_p = 80 m gives 6.7 × 10⁻³ m).
The lower bound is nearly inert with the smooth-flow term active: z₀ ≥ 0.11ν/u*
only falls below 1.27 × 10⁻⁷ at u* > 12 m/s. It matters when
visc = falseinnear-calm, and it keeps ln(z_ref/z₀) finite.
5. Consolidation
ERF_MOSTRoughness.His deleted and its contents, plusmost_data,similarity_funsandair_viscosityfrom the top ofERF_MOSTStress.H, move tothe new
ERF_MOSTUtils.H. The five roughness laws become named functions —Charnock_roughness,Mod_Charnock_roughness,COARE3_roughness,Donelan_roughness,WaveCoupled_roughness— plusCompute_roughnessfor thelog-law inversion. Previously each law was written inline in three places
(adiabatic / specified-flux / specified-temperature), which is how 1.1, 1.2 and
1.3 came to differ between call sites.
ERF_MOSTStress.Hdrops from ~2450 to ~2130 lines and now holds only the MOSTfunctors.
Make.packageregisters the new header; CMake picks it up through therecursive glob at
CMakeLists.txt:724.6. Behavior changes reviewers should expect
These are intended, but they move results:
charnock_viscosityrenamed to a generalsmooth_flow_viscosityoption that changes defaultfalse→true. Affects all sea iterators.Charnock changes above U₁₀ ≈ 25 m/s; modified Charnock above the depth-dependent
threshold.
MOST_test_suitesea1 is modified Charnock.Exec/CanonicalTests/ABL/WW3_coupling.low-wind z₀ wherever
viscis on.it pegged at the clamp; it now tracks wave steepness as intended.
flux_type = donelanis a hard error. External decks using it must switchto
bulk_coeff, or to MOST withroughness_type_sea = donelan.At typical ABL forcing (u* ≈ 0.3–0.5 m/s) none of the new clamps bind, so the
canonical ABL cases are expected to be unaffected apart from the
charnock_viscositydefault — but that is worth confirming rather than assuming.7. Known remaining items
Not defects, but worth recording:
cnk_viscis plumbed only into the three*_charnockconstructors. Thedonelan, mod-charnock and wave-coupled structs fall through to
most_data::visc{true}, somost.charnock_viscosity = falseturns thesmooth-flow term off for Charnock/COARE but not for the others. Harmless while
both defaults are
true.Inputs.rstdescribescharnock_viscosityas "read only whenroughness_type_sea = charnock"; it also gatescoare3.0.SurfaceLayer.rst. A flat 2.85 mm z₀ fieldin a tropical-cyclone run will look like a bug to anyone who plots it.
adiabatic_donelanandadiabatic_wave_coupledstill iterate on u* ratherthan z₀, and compare that velocity residual against
tol_z, a lengthtolerance. Converges correctly; the other adiabatic variants were converted.
Ri_bdivides by θ while its numerator is a θ_v difference;t_staris definedfrom a dry-θ difference while ζ comes from a virtual-temperature Richardson
number.
ERF_MOSTUtils.H:282.Source/PBL/ERF_ComputeDiffusivityMRF.cppis whitespace-only in this diff andcould be dropped to keep the PR focused.
Verification
ERF_MOSTStress.HandERF_MOSTUtils.Hcompile clean underg++ -std=c++20 -fsyntax-only -Wall -Wextraagainst the AMReX submodule headersin both
AMREX_USE_DOUBLEandAMREX_USE_FLOAT, with no warnings. The inner z₀fixed point was checked numerically over z_ref ∈ {10, 20} m, depth ∈ {5, 10, 30,
100} m and U₁₀ ∈ {10 … 60} m/s: all cases converge, worst case 24 iterations.
This is a syntax and numerics check on the surface-layer headers, not a full
build, link, or regression run. The gold files in section 6 still need to be
exercised.
References