|
ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
|
#include <AMReX_Algorithm.H>#include <AMReX_BLassert.H>#include <AMReX_Math.H>#include "ERF_Constants.H"

Go to the source code of this file.
Classes | |
| struct | most_data |
| struct | similarity_funs |
| struct | most_flux_scale |
| struct | most_aitken |
Functions | |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real | most_bracket_floor (amrex::Real C) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real | most_bracket (amrex::Real C, amrex::Real psi) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real | most_rib_resid (const similarity_funs &sfuns, amrex::Real C, amrex::Real Rib, amrex::Real zeta) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool | most_rib_zeta_is_root (const similarity_funs &sfuns, amrex::Real C, amrex::Real Rib, amrex::Real zeta, amrex::Real delta) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real | most_rib_zeta_bracketed (const similarity_funs &sfuns, amrex::Real C, amrex::Real Rib, amrex::Real zeta0, amrex::Real tol) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real | most_clamp_zeta (amrex::Real zeta, amrex::Real zeta_fold, bool &at_fold) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE most_flux_scale | most_fold_flux_scale (bool at_fold, amrex::Real zeta_fold, amrex::Real ustar, amrex::Real thv, amrex::Real tflux_s, amrex::Real tflux_q, bool spec_qflux, amrex::Real kappa, amrex::Real gravity, amrex::Real zref) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void | most_flux_outputs (const most_data &mdata, bool spec_qflux, bool at_fold, amrex::Real zeta_fold, amrex::Real C, amrex::Real psi_h, amrex::Real ustar, amrex::Real zref, amrex::Real tm, amrex::Real tvm, amrex::Real qvm, amrex::Real qflux, amrex::Real &olen, amrex::Real &t_surf, amrex::Real &t_star, amrex::Real &q_surf, amrex::Real &q_star) |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real | air_viscosity (amrex::Real T_degK) |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real | Charnock_roughness (amrex::Real ustar, amrex::Real Cnk_a, amrex::Real nu, bool visc) |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real | Mod_Charnock_roughness (amrex::Real ustar, amrex::Real Cnk_b) |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real | COARE3_roughness (amrex::Real zref, amrex::Real umm, amrex::Real ustar, amrex::Real nu, bool visc) |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real | Donelan_roughness (amrex::Real ustar, amrex::Real nu, bool visc) |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real | WaveCoupled_roughness (amrex::Real Hwave, amrex::Real Lwave, amrex::Real eps, amrex::Real ustar, amrex::Real nu, bool visc) |
| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real | bound_inverted_roughness (amrex::Real z0, amrex::Real zref) noexcept |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real | Compute_roughness (amrex::Real zref, amrex::Real Olen, amrex::Real umm, amrex::Real ustar) |
Variables | |
| constexpr amrex::Real | most_zeta_lim = amrex::Real(100.0) |
| constexpr amrex::Real | most_min_ustar = amrex::Real(0.001) |
| constexpr amrex::Real | inverted_roughness_lo = amrex::Real(1.0e-7) |
| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real air_viscosity | ( | amrex::Real | T_degK | ) |
Empirical kinematic viscosity [m2/s] formula from Andreas (1989) CRREL Rep. 89-11, valid between -173 and 277 deg C.
| [in] | T_degK | air temperature in Kelvin |
Referenced by adiabatic_charnock::iterate_flux(), adiabatic_donelan::iterate_flux(), adiabatic_wave_coupled::iterate_flux(), surface_flux_charnock::iterate_flux(), surface_flux_donelan::iterate_flux(), surface_temp_charnock::iterate_flux(), surface_temp_donelan::iterate_flux(), surface_flux_wave_coupled::iterate_flux(), and surface_temp_wave_coupled::iterate_flux().

|
noexcept |
Bounds on the roughness recovered by Compute_roughness. The inversion is unbounded above: in weak wind under strong stability (u* from an LSM or bulk flux large relative to kappa*U, psi_m << 0) it returns z0 >> zref. The upper bound is above every tabulated land-cover roughness in NoahmpTable.TBL (Z0MVT <= 1.10 m) and below the 2 m diagnostic height; z0 is also kept below half of zref so that ln(zref/z0) stays positive.
Referenced by Compute_roughness().

| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Charnock_roughness | ( | amrex::Real | ustar, |
| amrex::Real | Cnk_a, | ||
| amrex::Real | nu, | ||
| bool | visc | ||
| ) |
Charnock roughness with optional aerodynamically-smooth contribution
Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
| [in] | ustar | friction velocity |
| [in] | cnk_a | charnock constant |
| [in] | nu | intrinsic fluid viscosity |
| [in] | visc | flag to apply smooth flow limit |
Referenced by adiabatic_charnock::iterate_flux(), surface_flux_charnock::iterate_flux(), and surface_temp_charnock::iterate_flux().

| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real COARE3_roughness | ( | amrex::Real | zref, |
| amrex::Real | umm, | ||
| amrex::Real | ustar, | ||
| amrex::Real | nu, | ||
| bool | visc | ||
| ) |
COARE3.0, following WRF phys/module_sf_mynn.F
Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
| [in] | zref | reference height for the wind speed |
| [in] | umm | horizontal wind speed magnitude at zref |
| [in] | ustar | friction velocity |
| [in] | nu | intrinsic fluid viscosity |
| [in] | visc | flag to apply smooth flow limit |
Referenced by adiabatic_charnock::iterate_flux(), surface_flux_charnock::iterate_flux(), and surface_temp_charnock::iterate_flux().

| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Compute_roughness | ( | amrex::Real | zref, |
| amrex::Real | Olen, | ||
| amrex::Real | umm, | ||
| amrex::Real | ustar | ||
| ) |
Invert log-law to get roughness
| [in] | zref | reference height for the wind speed |
| [in] | Olen | Obukhov length |
| [in] | umm | horizontal wind speed magnitude at zref |
| [in] | ustar | friction velocity |
Referenced by SurfaceLayer::compute_sfc_params_from_lsm_fluxes(), and SurfaceLayer::compute_SurfaceLayer_bcs().


| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Donelan_roughness | ( | amrex::Real | ustar, |
| amrex::Real | nu, | ||
| bool | visc | ||
| ) |
Updated Donelan 2004 as found in AHW
Matches implementations in WRF phys/physics_mmm/sf_sfclayrev.F90 and phys/module_sf_mynn.F
Smooth flow limit is intrinsic in zn2.
| [in] | ustar | friction velocity |
| [in] | nu | intrinsic fluid viscosity |
| [in] | visc | flag to apply smooth flow limit |
Referenced by adiabatic_donelan::iterate_flux(), surface_flux_donelan::iterate_flux(), and surface_temp_donelan::iterate_flux().

| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real Mod_Charnock_roughness | ( | amrex::Real | ustar, |
| amrex::Real | Cnk_b | ||
| ) |
Modified Charnock roughness
Smooth-flow limit is intrinsic.
| [in] | ustar | friction velocity |
| [in] | cnk_b | modified charnock constant |
Referenced by adiabatic_mod_charnock::iterate_flux(), surface_flux_mod_charnock::iterate_flux(), and surface_temp_mod_charnock::iterate_flux().

| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_bracket | ( | amrex::Real | C, |
| amrex::Real | psi | ||
| ) |
Log-law bracket ln(zref/z0) - psi of the MOST flux kernels, held at or above most_bracket_floor(C).
In strongly unstable air psi exceeds C = ln(zref/z0) and the bracket changes sign, which turns u* negative and puts the diagnosed surface temperature on the wrong side of the air for a prescribed flux. With the floor the bracket is at least 1/2, so u* stays positive and finite for every C.
| [in] | C | ln(zref/z0) |
| [in] | psi | stability correction (momentum or heat) |
Referenced by adiabatic::iterate_flux(), adiabatic_eb::iterate_flux(), adiabatic_mod_charnock::iterate_flux(), adiabatic_charnock::iterate_flux(), adiabatic_donelan::iterate_flux(), adiabatic_wave_coupled::iterate_flux(), surface_flux_charnock::iterate_flux(), surface_flux_mod_charnock::iterate_flux(), surface_flux_donelan::iterate_flux(), surface_temp_charnock::iterate_flux(), surface_temp_mod_charnock::iterate_flux(), surface_temp_donelan::iterate_flux(), surface_flux_wave_coupled::iterate_flux(), surface_temp_wave_coupled::iterate_flux(), surface_flux::iterate_flux(), surface_temp::iterate_flux(), surface_temp_eb::iterate_flux(), surface_flux_eb::iterate_flux(), most_flux_outputs(), and most_rib_resid().


| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_bracket_floor | ( | amrex::Real | C | ) |
Lower bound of the log-law bracket ln(zref/z0) - psi of the MOST flux kernels: C/2 held between 1/2 and 1.
The bound is 1 for zref >= e^2 z0 and C/2 down to zref = e z0, so it does not exceed the neutral bracket C wherever zref >= e^(1/2) z0. The lower limit of 1/2 keeps the bracket, and so u*, positive and finite when z0 approaches or exceeds zref (C <= 0).
The bound is set by the under-relaxed u* iteration, not by the physics. At an unstable fixed point the relaxed map has slope (1 - alpha) - alpha s / bracket, with s = -3 (z/L) dpsi_m/d(z/L) between 1.3 (z/L = -0.5) and 2.4 (z/L = -50) for Businger-Dyer. With alpha = 0.5 the iteration converges only for bracket > s/3 (0.4 to 0.8), so a bound of 1 keeps the switch between the bounded and free branches inside the convergent range, while 0.1 C (0.3 at C = 3) does not and the iteration oscillates between two values. If alpha changes, the bound needs revisiting; see PR #4866.
| [in] | C | ln(zref/z0) |
Referenced by similarity_funs::calc_zeta_fold(), and most_bracket().

| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_clamp_zeta | ( | amrex::Real | zeta, |
| amrex::Real | zeta_fold, | ||
| bool & | at_fold | ||
| ) |
z/L of the prescribed-flux kernels, bounded below by -most_zeta_lim and above by the fold (see similarity_funs::calc_zeta_fold), where the prescribed stable flux stops having a solution.
| [in] | zeta | z/L from the current u* and flux |
| [in] | zeta_fold | z/L at the fold |
| [out] | at_fold | whether the fold bound was applied |
Referenced by surface_flux_charnock::iterate_flux(), surface_flux_mod_charnock::iterate_flux(), surface_flux_donelan::iterate_flux(), surface_flux_wave_coupled::iterate_flux(), surface_flux::iterate_flux(), and surface_flux_eb::iterate_flux().

| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void most_flux_outputs | ( | const most_data & | mdata, |
| bool | spec_qflux, | ||
| bool | at_fold, | ||
| amrex::Real | zeta_fold, | ||
| amrex::Real | C, | ||
| amrex::Real | psi_h, | ||
| amrex::Real | ustar, | ||
| amrex::Real | zref, | ||
| amrex::Real | tm, | ||
| amrex::Real | tvm, | ||
| amrex::Real | qvm, | ||
| amrex::Real | qflux, | ||
| amrex::Real & | olen, | ||
| amrex::Real & | t_surf, | ||
| amrex::Real & | t_star, | ||
| amrex::Real & | q_surf, | ||
| amrex::Real & | q_star | ||
| ) |
Surface state of a prescribed-flux kernel once its u* iteration has converged.
Sets t_surf, t_star and q_star (and q_surf when the moisture flux is prescribed). At the fold the prescribed fluxes are reduced by most_fold_flux_scale and the Obukhov length is set to the fold value. u* is floored at most_min_ustar here, so every kernel applies the same floor.
| [in] | mdata | MOST data (prescribed fluxes, kappa, gravity) |
| [in] | spec_qflux | whether the moisture flux is prescribed |
| [in] | at_fold | whether z/L was held at the fold on the last pass |
| [in] | zeta_fold | z/L at the fold |
| [in] | C | ln(zref/z0) |
| [in] | psi_h | heat stability correction of the last pass |
| [in] | ustar | friction velocity (floored at most_min_ustar) |
| [in] | zref | reference height |
| [in] | tm | potential temperature at zref |
| [in] | tvm | virtual potential temperature at zref |
| [in] | qvm | water vapor at zref |
| [in] | qflux | moisture flux of the last pass |
| [in,out] | olen | Obukhov length |
| [out] | t_surf | surface potential temperature |
| [out] | t_star | temperature scale |
| [in,out] | q_surf | surface water vapor (read when the moisture flux is diagnosed) |
| [out] | q_star | moisture scale |
Referenced by surface_flux_charnock::iterate_flux(), surface_flux_mod_charnock::iterate_flux(), surface_flux_donelan::iterate_flux(), surface_flux_wave_coupled::iterate_flux(), surface_flux::iterate_flux(), and surface_flux_eb::iterate_flux().


| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE most_flux_scale most_fold_flux_scale | ( | bool | at_fold, |
| amrex::Real | zeta_fold, | ||
| amrex::Real | ustar, | ||
| amrex::Real | thv, | ||
| amrex::Real | tflux_s, | ||
| amrex::Real | tflux_q, | ||
| bool | spec_qflux, | ||
| amrex::Real | kappa, | ||
| amrex::Real | gravity, | ||
| amrex::Real | zref | ||
| ) |
Part of a prescribed stable flux the wind can carry at the fold.
The virtual heat flux is tflux_s + tflux_q, with tflux_s = surf_temp_flux (1 + epsv qv) and tflux_q = qflux epsv theta. When z/L is held at the fold (see similarity_funs::calc_zeta_fold), the wind is below the minimum the prescribed flux needs and carries only -u*^3 thv zeta_fold / (kappa g zref). Only the prescribed components that are downward drive the fold, so only they are reduced, by a common factor, until the net virtual flux equals that value. An upward component, or a moisture flux diagnosed from q_surf, is left unchanged; if no prescribed component is downward, nothing is reduced. The factor is not taken below 0, so when a diagnosed condensation flux alone is stronger than the fold value, the downward prescribed components are removed and the net flux remains stronger than the fold value. Returns 1 for both factors away from the fold.
| [in] | at_fold | whether z/L was held at the fold |
| [in] | zeta_fold | z/L at the fold |
| [in] | ustar | friction velocity |
| [in] | thv | virtual potential temperature at zref |
| [in] | tflux_s | sensible part of the virtual heat flux |
| [in] | tflux_q | moisture part of the virtual heat flux |
| [in] | spec_qflux | whether the moisture flux is prescribed |
| [in] | kappa | von Karman constant |
| [in] | gravity | gravitational acceleration |
| [in] | zref | reference height |
Referenced by most_flux_outputs().

| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_rib_resid | ( | const similarity_funs & | sfuns, |
| amrex::Real | C, | ||
| amrex::Real | Rib, | ||
| amrex::Real | zeta | ||
| ) |
Residual zeta - Rib (C - psi_m)^2 / (C - psi_h) of the prescribed-temperature kernels' z/L equation, with the Jimenez functions and the brackets of most_bracket.
| [in] | sfuns | similarity functions |
| [in] | C | ln(zref/z0) |
| [in] | Rib | bulk Richardson number |
| [in] | zeta | z/L |
Referenced by most_rib_zeta_bracketed(), and most_rib_zeta_is_root().


| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most_rib_zeta_bracketed | ( | const similarity_funs & | sfuns, |
| amrex::Real | C, | ||
| amrex::Real | Rib, | ||
| amrex::Real | zeta0, | ||
| amrex::Real | tol | ||
| ) |
Solve zeta = Rib (C - psi_m)^2 / (C - psi_h) of the prescribed-temperature kernels by bracketing and bisection, with the Jimenez functions and the brackets of most_bracket.
The relaxed fixed-point iteration stalls where zeta - Rib F(zeta) nearly touches zero without crossing it, which the Jimenez stable functions produce when z0 is comparable to or above zref (C below about 1): each pass then moves zeta by about the tolerance. From zeta0 this steps, with doubling steps, in the direction the iteration moves until the residual changes sign, and bisects that interval, so it returns the root the iteration was heading to, or the next one past a near-touch. The first step is limited so that two nearby roots are not stepped over together. The search stays within +-most_zeta_lim, and returns that bound when no root lies inside it, as the prescribed-flux kernels bound zeta.
| [in] | sfuns | similarity functions |
| [in] | C | ln(zref/z0) |
| [in] | Rib | bulk Richardson number |
| [in] | zeta0 | z/L to start from |
| [in] | tol | width of the final interval |
Referenced by surface_temp::iterate_flux(), and surface_temp_eb::iterate_flux().


| AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool most_rib_zeta_is_root | ( | const similarity_funs & | sfuns, |
| amrex::Real | C, | ||
| amrex::Real | Rib, | ||
| amrex::Real | zeta, | ||
| amrex::Real | delta | ||
| ) |
Whether a root of most_rib_resid lies within delta of zeta.
The relaxed fixed-point iteration stops on a small step, which a near-touch of the residual also gives where no root is near; the residual must change sign across [zeta - delta, zeta + delta] for zeta to be taken as a solution.
| [in] | sfuns | similarity functions |
| [in] | C | ln(zref/z0) |
| [in] | Rib | bulk Richardson number |
| [in] | zeta | z/L the relaxed iteration stopped at |
| [in] | delta | half-width of the interval checked |
Referenced by surface_temp::iterate_flux(), and surface_temp_eb::iterate_flux().


| AMREX_GPU_DEVICE AMREX_FORCE_INLINE amrex::Real WaveCoupled_roughness | ( | amrex::Real | Hwave, |
| amrex::Real | Lwave, | ||
| amrex::Real | eps, | ||
| amrex::Real | ustar, | ||
| amrex::Real | nu, | ||
| bool | visc | ||
| ) |
Wave coupled roughness
Smooth-flow limit follows z0 = 0.11 nu / u* (Smith 1988; ECMWF; WRF)
| [in] | Hwave | wave height |
| [in] | Lwave | wave length |
| [in] | eps | avoid divide by zero |
| [in] | ustar | friction velocity |
| [in] | nu | intrinsic fluid viscosity |
| [in] | visc | flag to apply smooth flow limit |
Referenced by adiabatic_wave_coupled::iterate_flux(), surface_flux_wave_coupled::iterate_flux(), and surface_temp_wave_coupled::iterate_flux().

|
constexpr |
Lower bound of the roughness recovered by Compute_roughness; shared with the guard in Compute_roughness so the two cannot drift apart.
Referenced by bound_inverted_roughness(), and Compute_roughness().
|
inlineconstexpr |
Minimum friction velocity [m/s] of the prescribed-flux kernels' outputs (see most_flux_outputs).
Referenced by most_flux_outputs().
|
inlineconstexpr |
Bound on |z/L| of the MOST kernels (see most_rib_zeta_bracketed and most_clamp_zeta).
Referenced by most_clamp_zeta(), and most_rib_zeta_bracketed().