rdb_ocean_epbl Module

Prognostic-energy surface boundary layer: each thermo step the wind supplies mechanical TKE (mstar·rho0·u*^3·dt) and surface buoyancy loss supplies convective PE (nstar-weighted); the scheme spends that energy interface by interface — the diffusivity at each interface is the largest value whose implicit-diffusion PE cost the remaining TKE can pay. Mixing stops where the energy runs out, which IS the mixed-layer depth. Energetically closed by construction; unconditionally stable (the sweep performs the forward elimination of the backward-Euler vertical-diffusion solve it feeds).

References: Reichl & Hallberg (2018), Ocean Modelling 132 (“ePBL”); the gravity-wave column-height correction follows the same paper’s available-PE bookkeeping. Knob table: docs/generated_nml_knobs.md.

Scope (PR 1): surface boundary layer only — no bottom-boundary ePBL, no mean-KE→TKE conversion (so the closed-form direct energy solve applies; no inner Newton loop), no Langmuir enhancement (PR 2). Boussinesq SI.

Interface convention (same as rdb_ocean_vmix): kd_int(:,:,k) lives at the bottom interface of layer k; kd_int(:,:,1) is the bed and kd_int(:,:,nz+1) the free surface, both forced to 0. Layers are bottom-up: k=1 bed, k=nz surface.

EPBL replaces the KPP overlay (mutually exclusive); the PP81 interior closure + background diffusivity continue to run underneath, and epbl_merge_into_kv_kt folds kd_int into vmix%kv / vmix%kt additively (MOM6 EPBL_IS_ADDITIVE) or by max, every stage; epbl_compute itself runs at thermo cadence.


Uses

  • module~~rdb_ocean_epbl~~UsesGraph module~rdb_ocean_epbl rdb_ocean_epbl iso_fortran_env iso_fortran_env module~rdb_ocean_epbl->iso_fortran_env module~rdb_constants rdb_constants module~rdb_ocean_epbl->module~rdb_constants module~rdb_eos rdb_eos module~rdb_ocean_epbl->module~rdb_eos module~rdb_grid rdb_grid module~rdb_ocean_epbl->module~rdb_grid module~rdb_mem_report rdb_mem_report module~rdb_ocean_epbl->module~rdb_mem_report module~rdb_multilayer_state rdb_multilayer_state module~rdb_ocean_epbl->module~rdb_multilayer_state module~rdb_ocean_surface_flux rdb_ocean_surface_flux module~rdb_ocean_epbl->module~rdb_ocean_surface_flux module~rdb_ocean_surface_stress rdb_ocean_surface_stress module~rdb_ocean_epbl->module~rdb_ocean_surface_stress module~rdb_scratch_3d rdb_scratch_3d module~rdb_ocean_epbl->module~rdb_scratch_3d pic_types pic_types module~rdb_constants->pic_types module~rdb_eos->module~rdb_constants module~rdb_eos->module~rdb_grid module~rdb_grid->module~rdb_constants module~rdb_mem_report->iso_fortran_env module~rdb_mem_report->module~rdb_constants pic_logger pic_logger module~rdb_mem_report->pic_logger pic_strings pic_strings module~rdb_mem_report->pic_strings module~rdb_multilayer_state->iso_fortran_env module~rdb_multilayer_state->module~rdb_constants module~rdb_multilayer_state->module~rdb_grid module~rdb_multilayer_state->module~rdb_mem_report module~rdb_efp rdb_efp module~rdb_multilayer_state->module~rdb_efp module~rdb_error_ring rdb_error_ring module~rdb_multilayer_state->module~rdb_error_ring module~rdb_tracer rdb_tracer module~rdb_multilayer_state->module~rdb_tracer module~rdb_multilayer_state->pic_logger module~rdb_ocean_surface_flux->iso_fortran_env module~rdb_ocean_surface_flux->module~rdb_constants module~rdb_ocean_surface_flux->module~rdb_grid module~rdb_ocean_surface_flux->module~rdb_mem_report module~rdb_ocean_surface_flux->module~rdb_multilayer_state module~rdb_ocean_surface_stress->iso_fortran_env module~rdb_ocean_surface_stress->module~rdb_constants module~rdb_ocean_surface_stress->module~rdb_grid module~rdb_ocean_surface_stress->module~rdb_mem_report module~rdb_ocean_surface_stress->module~rdb_multilayer_state module~rdb_ocean_surface_stress->module~rdb_scratch_3d module~rdb_scratch_3d->iso_fortran_env module~rdb_scratch_3d->module~rdb_constants module~rdb_scratch_3d->module~rdb_mem_report module~rdb_efp->iso_fortran_env ieee_arithmetic ieee_arithmetic module~rdb_efp->ieee_arithmetic module~rdb_error_ring->pic_logger module~rdb_tracer->iso_fortran_env module~rdb_tracer->module~rdb_constants module~rdb_tracer->module~rdb_grid module~rdb_tracer->module~rdb_mem_report

Used by

  • module~~rdb_ocean_epbl~~UsedByGraph module~rdb_ocean_epbl rdb_ocean_epbl module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_epbl module~rdb_ocean_mle rdb_ocean_mle module~rdb_ocean_dyn->module~rdb_ocean_mle module~rdb_continuity rdb_continuity module~rdb_ocean_dyn->module~rdb_continuity module~rdb_ocean_mle->module~rdb_ocean_epbl module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_setup->module~rdb_ocean_epbl module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_epbl module~rdb_ocean_state->module~rdb_ocean_dyn module~rdb_ocean_state->module~rdb_ocean_mle module~rdb_ocean_state->module~rdb_continuity module~rdb_continuity->module~rdb_ocean_mle module~rdb_driver rdb_driver module~rdb_driver->module~rdb_ocean_dyn module~rdb_driver->module~rdb_ocean_state module~rdb_ocean_engine rdb_ocean_engine module~rdb_driver->module~rdb_ocean_engine module~rdb_handle rdb_handle module~rdb_handle->module~rdb_ocean_state module~rdb_handle->module~rdb_ocean_engine module~rdb_ocean_api rdb_ocean_api module~rdb_ocean_api->module~rdb_ocean_dyn module~rdb_ocean_api->module~rdb_handle module~rdb_ocean_diag_derived rdb_ocean_diag_derived module~rdb_ocean_api->module~rdb_ocean_diag_derived module~rdb_ocean_diag_fills rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_ocean_diag_fills module~rdb_ocean_api->module~rdb_ocean_engine module~rdb_ocean_diag_derived->module~rdb_ocean_state module~rdb_ocean_diag_derived->module~rdb_ocean_diag_fills module~rdb_ocean_diag_fills->module~rdb_ocean_state module~rdb_ocean_engine->module~rdb_ocean_dyn module~rdb_ocean_engine->module~rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_state module~rdb_ocean_engine->module~rdb_ocean_diag_derived module~rdb_ocean_engine->module~rdb_ocean_diag_fills module~rdb_ice_transport rdb_ice_transport module~rdb_ocean_engine->module~rdb_ice_transport module~rdb_ice_transport->module~rdb_continuity

Variables

Type Visibility Attributes Name Initial
integer, public, parameter :: EPBL_COMBINE_ADD = 1

kt += kd ; kv += prandtl*kd (MOM6 EPBL_IS_ADDITIVE=.true.)

integer, public, parameter :: EPBL_COMBINE_MAX = 2

kt = max(kt, kd) ; kv = max(kv, prandtl*kd)

integer, public, parameter :: EPBL_LT_ADDITIVE = 2

mstar += coef * La^exp

integer, public, parameter :: EPBL_LT_NONE = 0
integer, public, parameter :: EPBL_LT_RESCALE = 1

mstar *= min(max_enh, 1 + coef * La^exp) (multiplicative)

integer, public, parameter :: EPBL_MSTAR_CONSTANT = 1

Fixed mstar (the simplest credible configuration).

integer, public, parameter :: EPBL_MSTAR_OM4 = 2

Ekman/Obukhov-balance form used by MOM6’s OM4 production config (Reichl & Hallberg 2018 Appendix).

integer, public, parameter :: EPBL_MSTAR_RH18 = 3

Reichl & Hallberg (2018) eq. fits (cN1..cS2 coefficients).

integer, public, parameter :: EPBL_VSTAR_CUBE_ROOT = 1

vstar = vstar_scale_fac * (TKE / (dt rho0))^(1/3).

integer, public, parameter :: EPBL_VSTAR_RH18 = 2

Separate mechanical (u*-proportional, surface-decaying) + convective cube-root contributions (RH18).

real(kind=wp), private, parameter :: H_NEGLECT = H_DIV_EPS
real(kind=wp), private, parameter :: LT_CHARNOCK_ICPT = -0.005_wp

Charnock intercept at U10 = 0.

real(kind=wp), private, parameter :: LT_CHARNOCK_MIN = 0.028_wp

Cap on the Charnock parameter.

real(kind=wp), private, parameter :: LT_CHARNOCK_SLOPE = 0.0017_wp

d(alpha_Charnock)/dU10 (s/m).

real(kind=wp), private, parameter :: LT_FM_INTO_FP = 1.296_wp

Mean / peak frequency ratio (Webb 2011).

real(kind=wp), private, parameter :: LT_NU_AIR = 1.0e-6_wp

Kinematic viscosity of air (m^2/s) for the smooth-flow z0.

real(kind=wp), private, parameter :: LT_PI = 4.0_wp*atan(1.0_wp)
real(kind=wp), private, parameter :: LT_RHO_AIR = 1.225_wp

Air density (kg/m^3) for the water->air u* conversion.

real(kind=wp), private, parameter :: LT_R_LOSS = 0.667_wp

Stokes-transport loss ratio.

real(kind=wp), private, parameter :: LT_SWH_FROM_U10SQ = 0.0246_wp

Significant wave height = c * U10^2 (s^2/m).

real(kind=wp), private, parameter :: LT_U19P5_TO_U10 = 1.075_wp

Pierson-Moskowitz U19.5/U10 ratio.

real(kind=wp), private, parameter :: LT_US_TO_U10 = 0.0162_wp

Surface Stokes drift / U10 (Webb 2011).

real(kind=wp), private, parameter :: LT_VONKAR_WAVES = 0.40_wp

von Karman constant used by the COARE u*->U10 inversion.


Derived Types

type, public ::  ocean_epbl_t

Components

Type Visibility Attributes Name Initial
real(kind=wp), public, allocatable :: b0(:,:)

Surface buoyancy flux (m^2/s^3, > 0 stabilizing) from the last solve — the same B0 = g·rho0·(dSV/dT·q_T + dSV/dS·q_S) the mstar scaling uses, persisted so the Bodner (2023) MLE restratification can form its convective velocity scale w*^3 = max(0,-b0)·mld. Zero until the first EPBL step.

real(kind=wp), public :: c_ek = 0.085_wp

OM4 Ekman-limit coefficient (MOM6 MSTAR2_COEF2).

integer, public :: combine_mode = EPBL_COMBINE_ADD
type(scratch_3d_buffer_t), public :: ctke_sw

(PR-21) Per-layer TKE cost (J/m^2, <= 0 for solar heating) of homogenising the penetrating shortwave absorbed IN that layer. Filled once per call by the prep sweep from the shared two-band transmission + the in-layer PE-cost shape Phi(h/zeta); the surface layer’s share folds into ctke_sfc, the sub-surface layers drain the sweep’s TKE reservoirs. Zero (never filled) unless epbl_sw_ctke .and. sf%has_sw. Same shape / lifetime / device contract as dcolht_s.

type(scratch_3d_buffer_t), public :: dcolht_s

d(column height)/d(S_k) (m/PSU).

type(scratch_3d_buffer_t), public :: dcolht_t

d(column height)/d(T_k): rho0*h_k * dSV_dT (m/degC) — steric sensitivity for the gravity-wave radiation term.

type(scratch_3d_buffer_t), public :: dpe_s

d(column PE)/d(S_k) (J/m^2/PSU).

type(scratch_3d_buffer_t), public :: dpe_t

d(column PE)/d(T_k): rho0*h_k * p_mid * dSV_dT (J/m^2/degC).

real(kind=wp), public :: ekman_scale_coef = 1.0_wp

Rotational inhibition of the mixing length.

logical, public :: enable = .false.

Master switch. Default off — all existing namelists and tests stay bit-identical. Requires vmix%use_closure; disables the KPP overlay (configure logs the override).

type(eos_t), public :: eos
logical, public :: epbl_sw_ctke = .true.

(PR-21) Charge the EPBL TKE ledger for penetrating shortwave (&ocean_thermo_nml epbl_sw_ctke). Default .true.; inert at sw_pen_frac = 0 (⇒ sf%has_sw = .false.) ⇒ bit-identical.

real(kind=wp), public, allocatable :: f_centre(:,:)

|f| at cell centres (1/s); filled by set_f_centre.

logical, public :: in_eos = .false.

&ocean_psurf_nml in_eos (E3): start this scheme’s column pressure stack at multilayer_state_t%p_top (the ice-shelf load + surface pressure, Pa) instead of at 0 Pa.

Read more…
logical, public :: is_init = .false.

True between init and destroy.

real(kind=wp), public, allocatable :: kd_int(:,:,:)

EPBL diapycnal diffusivity at interfaces (m^2/s), (nx, ny, nz+1); zero at bed (k=1) and surface (k=nz+1).

real(kind=wp), public, allocatable :: la(:,:)

Turbulent Langmuir number from the last call (diagnostic; 0 where use_lt is off or the column is dry).

real(kind=wp), public :: la_frac_hbl = 0.04_wp

Stokes surface-layer-average depth as a fraction of the BLD (MOM6 LA_DEPTH_RATIO).

real(kind=wp), public :: lt_enhance_coef = 0.447_wp

Enhancement coefficient (MOM6 LT_ENHANCE_COEF).

real(kind=wp), public :: lt_enhance_exp = -1.33_wp

La exponent (MOM6 LT_ENHANCE_EXP).

real(kind=wp), public :: lt_lac1 = -0.87_wp
real(kind=wp), public :: lt_lac2 = 0.0_wp
real(kind=wp), public :: lt_lac3 = 0.0_wp
real(kind=wp), public :: lt_lac4 = 0.95_wp
real(kind=wp), public :: lt_lac5 = 0.95_wp

Stability-modified Langmuir number coefficients (MOM6 LT_MOD_LAC1..5: MLD/Ekman, MLD/Obukhov stable, unstable, Ekman/Obukhov stable, unstable). All-zero => La_mod = La.

real(kind=wp), public :: lt_max_enhance = 5.0_wp

Cap on the multiplicative enhancement factor.

integer, public :: lt_scheme = EPBL_LT_RESCALE

Enhancement form: rescale (multiplicative) or additive.

real(kind=wp), public :: min_mix_len = 0.0_wp

Mixing-length floor (m).

real(kind=wp), public :: mixlen_exponent = 2.0_wp

Shape-function exponent (2 = KPP-like; fast path).

real(kind=wp), public, allocatable :: mld(:,:)

Converged active-mixing-layer depth (m) from the last call — the next step’s first guess (when mld_use_prev_guess) and the primary diagnostic.

logical, public :: mld_bisection = .false.

Plain bisection instead of false-position.

logical, public :: mld_iteration = .true.

Iterate the boundary-layer depth to self-consistency with the mixing-length shape function (MOM6 USE_MLD_ITERATION).

integer, public :: mld_max_its = 20
real(kind=wp), public :: mld_tol = 1.0_wp

Convergence tolerance on the MLD root-find (m).

logical, public :: mld_use_prev_guess = .false.

Seed the iteration from the previous step’s MLD (faster, ~1-3 iterations; off = always start at half depth).

real(kind=wp), public :: mstar_cap = -1.0_wp

Cap on mstar for the OM4/RH18 schemes; off when < 0.

real(kind=wp), public :: mstar_coef1 = 0.3_wp

OM4 stabilizing-balance coefficient (MOM6 MSTAR2_COEF1).

real(kind=wp), public :: mstar_const = 1.2_wp

Constant-scheme mstar (MOM6 MSTAR).

real(kind=wp), public :: mstar_conv_adj = 0.0_wp

Reduce mechanical mstar when convection dominates, in [0,1]; 0 = off (MOM6 MSTAR_CONV_ADJ).

integer, public :: mstar_scheme = EPBL_MSTAR_OM4
real(kind=wp), public :: nstar = 0.2_wp

Fraction of convectively released PE that becomes entrainment-driving TKE (MOM6 NSTAR).

real(kind=wp), public :: omega = 7.2921e-5_wp

Earth rotation rate (1/s), for the omega_frac blend.

real(kind=wp), public :: omega_frac = 0.0_wp

Blend |f| with 2*Omega: absf = sqrt((1-of) f^2 + of 4 Om^2).

real(kind=wp), public :: prandtl = 1.0_wp

Kv = prandtl * Kd into the momentum solve.

real(kind=wp), public :: rh18_cn1 = 0.275_wp
real(kind=wp), public :: rh18_cn2 = 8.0_wp
real(kind=wp), public :: rh18_cn3 = -5.0_wp
real(kind=wp), public :: rh18_cs1 = 0.2_wp
real(kind=wp), public :: rh18_cs2 = 0.4_wp

RH18 mstar fit coefficients (paper values).

real(kind=wp), public :: rho0 = 1035.0_wp

Boussinesq reference density (kg/m^3).

type(scratch_3d_buffer_t), public :: s0

Pre-mixing layer salinity (PSU).

type(scratch_3d_buffer_t), public :: t0

Pre-mixing layer temperature (degC).

real(kind=wp), public, allocatable :: tke_conv(:,:)
real(kind=wp), public, allocatable :: tke_conv_decay(:,:)
real(kind=wp), public :: tke_decay = 2.5_wp

Ratio of the natural Ekman depth to the mechanical-TKE decay scale (MOM6 TKE_DECAY).

logical, public :: tke_diags = .false.

Compute + store the per-column TKE budget terms (W/m^2). The column ledger closes to round-off — see the design doc §7; test_ocean_epbl asserts it.

real(kind=wp), public, allocatable :: tke_forcing(:,:)
real(kind=wp), public, allocatable :: tke_mech_decay(:,:)
real(kind=wp), public, allocatable :: tke_mixing(:,:)
real(kind=wp), public, allocatable :: tke_wind(:,:)
real(kind=wp), public :: translay_scale = 0.1_wp

Transition-layer floor of the shape function; must be in [0,1) when mld_iteration is on.

logical, public :: use_lt = .false.

Master Langmuir switch (default off — bit-identity).

real(kind=wp), public :: ustar_min = 1.0e-8_wp

Floor on u* (deliberate rdb floor — pure denominator guard in the TKE decay scale; MOM6 derives ~1e-10).

real(kind=wp), public :: von_karman = 0.41_wp

kappa in Kd = vstar * kappa * mixing_length.

real(kind=wp), public :: vstar_scale_fac = 1.0_wp

Overall vstar multiplier (∝ diffusivity).

integer, public :: vstar_scheme = EPBL_VSTAR_CUBE_ROOT
real(kind=wp), public :: vstar_surf_fac = 1.2_wp

RH18 vstar scheme: mechanical surface vstar ∝ u* factor.

real(kind=wp), public :: wstar_ustar_coef = 1.0_wp

Weight of the convective reservoir in the velocity scale.

Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_epbl_bytes
procedure, public, non_overridable :: destroy => ocean_epbl_destroy
procedure, public, non_overridable :: enter_data => ocean_epbl_enter_data
procedure, public, non_overridable :: exit_data => ocean_epbl_exit_data
procedure, public, non_overridable :: init => ocean_epbl_init
procedure, public, non_overridable :: set_f_centre => ocean_epbl_set_f_centre

Functions

public pure function epbl_lf17_la(ustar_w, zsl, ustokes, kphil) result(la)

Turbulent Langmuir number La = sqrt(u*/u_s_SL): the Stokes drift averaged over the surface layer of thickness zsl under the Phillips spectrum, in the singularity-safe form (Breivik et al. 2016 with Webb & Fox-Kemper 2015 directional spreading). No MIN_LANGMUIR / LA_DEPTH_MIN floors — those belong to MOM6’s profile-averaging wave paths, not LF17.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: ustar_w

Water-side u* (m/s).

real(kind=wp), intent(in) :: zsl

Surface-layer average depth (m) = la_frac_hbl * BLD.

real(kind=wp), intent(in) :: ustokes

From epbl_lf17_wave_state.

real(kind=wp), intent(in) :: kphil

From epbl_lf17_wave_state.

Return Value real(kind=wp)

public pure function epbl_mixlen_shape(z_depth, mld_guess, translay_scale, mixlen_exponent, shaped) result(shape_val)

Mixing-length shape factor in [translay_scale, 1]: 1 at the surface, decaying to the transition-layer floor at the MLD. shaped = .false. (no MLD iteration) returns 1.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: z_depth

Unconditional interface depth below the surface (m).

real(kind=wp), intent(in) :: mld_guess
real(kind=wp), intent(in) :: translay_scale
real(kind=wp), intent(in) :: mixlen_exponent
logical, intent(in) :: shaped

Return Value real(kind=wp)

public pure function parse_epbl_combine(name) result(tag)

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: name

Return Value integer

public pure function parse_epbl_lt_scheme(name) result(tag)

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: name

Return Value integer

public pure function parse_epbl_mstar_scheme(name) result(tag)

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: name

Return Value integer

public pure function parse_epbl_vstar_scheme(name) result(tag)

Arguments

Type IntentOptional Attributes Name
character(len=*), intent(in) :: name

Return Value integer

private pure function ocean_epbl_bytes(this) result(nbytes)

Counted allocatable footprint of the EPBL slot (0 when unallocated). One arr_bytes term per array — add a term here when a new allocatable joins the type.

Arguments

Type IntentOptional Attributes Name
class(ocean_epbl_t), intent(in) :: this

Return Value integer(kind=int64)

private pure function one_m_exp_x(x) result(f)

(1 - exp(-x)) / x, Taylor-safe at small x.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: x

Return Value real(kind=wp)


Subroutines

public pure subroutine epbl_compute(grid, this, ms, ss, dt, sf)

Run EPBL over the domain: fill this%kd_int (interface diffusivity) and this%mld. Call at thermo cadence with the thermo dt. Outer shim: dereferences the tracer-registry hTr arrays + the 2D Q_heat/Q_salt forcing fields on the host (array-of-DT and allocatable indirection blocks NVHPC device codegen), then forwards to the column kernel which reads q_T_kin(i,j) / q_S_kin(i,j) per column inside the DC.

Read more…

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_epbl_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms
type(ocean_surface_stress_t), intent(in) :: ss
real(kind=wp), intent(in) :: dt
type(ocean_surface_flux_t), intent(in) :: sf

public pure subroutine epbl_find_mstar(scheme, mstar_const, mstar_cap, mstar_coef1, c_ek, mstar_conv_adj, cn1, cn2, cn3, cs1, cs2, b0, ustar, bld, absf, mstar)

mstar = (mechanical TKE available for entrainment) / u^3. Schemes: constant; OM4 Ekman/Obukhov balance; RH18 fits. All followed by the optional convective reduction (mstar_conv_adj in [0,1]; the u=0 corner multiplies by (1 - adj), matching the reference behaviour).

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: scheme
real(kind=wp), intent(in) :: mstar_const
real(kind=wp), intent(in) :: mstar_cap
real(kind=wp), intent(in) :: mstar_coef1
real(kind=wp), intent(in) :: c_ek
real(kind=wp), intent(in) :: mstar_conv_adj
real(kind=wp), intent(in) :: cn1
real(kind=wp), intent(in) :: cn2
real(kind=wp), intent(in) :: cn3
real(kind=wp), intent(in) :: cs1
real(kind=wp), intent(in) :: cs2
real(kind=wp), intent(in) :: b0

Surface buoyancy flux (m^2/s^3); > 0 stabilizing.

real(kind=wp), intent(in) :: ustar

Surface friction velocity (m/s), already floored.

real(kind=wp), intent(in) :: bld

Boundary-layer depth guess (m).

real(kind=wp), intent(in) :: absf

|Coriolis| (1/s), possibly omega-blended.

real(kind=wp), intent(out) :: mstar

public pure subroutine epbl_lf17_wave_state(ustar_w, rho_ocn, u10, ustokes, kphil)

LF17 statistical wave state from the water-side friction velocity alone: COARE 3.5 fixed-point inversion u* -> U10 (Edson et al. 2013), then the Pierson-Moskowitz-based surface Stokes drift and Phillips peak wavenumber (Li & Fox-Kemper 2017; Breivik et al. 2016). BLD-independent — call once per column, outside the MLD iteration.

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: ustar_w

Water-side u* (m/s), > 0 (caller floors it).

real(kind=wp), intent(in) :: rho_ocn

Seawater reference density (kg/m^3).

real(kind=wp), intent(out) :: u10

10-m wind speed (m/s).

real(kind=wp), intent(out) :: ustokes

Surface Stokes drift (m/s).

real(kind=wp), intent(out) :: kphil

Phillips-spectrum peak wavenumber (1/m).

public pure subroutine epbl_lt_enhance(scheme, coef, expo, max_enh, vonkar, lac1, lac2, lac3, lac4, lac5, la, b0, ustar, bld, absf, mstar)

Apply the Langmuir enhancement to mstar (Reichl & Li 2019; Li et al. 2016 stability modification). The modified Langmuir number folds the boundary-layer stability regime in via Ekman / Obukhov / MLD length-scale ratios, split by the sign of the surface buoyancy flux; all-zero lac coefficients give La_mod = La exactly.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: scheme
real(kind=wp), intent(in) :: coef
real(kind=wp), intent(in) :: expo
real(kind=wp), intent(in) :: max_enh
real(kind=wp), intent(in) :: vonkar
real(kind=wp), intent(in) :: lac1
real(kind=wp), intent(in) :: lac2
real(kind=wp), intent(in) :: lac3
real(kind=wp), intent(in) :: lac4
real(kind=wp), intent(in) :: lac5
real(kind=wp), intent(in) :: la

Raw turbulent Langmuir number (> 0).

real(kind=wp), intent(in) :: b0

Surface buoyancy flux (m^2/s^3); > 0 stabilizing.

real(kind=wp), intent(in) :: ustar
real(kind=wp), intent(in) :: bld
real(kind=wp), intent(in) :: absf
real(kind=wp), intent(inout) :: mstar

public pure subroutine epbl_merge_into_kv_kt(this, nx, ny, nzp1, kv, kt)

Fold the EPBL diffusivity into the vmix interface fields. Called EVERY stage (the interior closure rewrites kv/kt each stage; kd_int itself refreshes at thermo cadence). Interior interfaces only — k=1 (bed) and k=nz+1 (surface) stay at the closed-boundary zero in both source and target.

Arguments

Type IntentOptional Attributes Name
type(ocean_epbl_t), intent(in) :: this
integer, intent(in) :: nx

Interface-field extents (explicit shape: assumed-shape dummies in a do concurrent kernel make NVHPC walk the descriptor with per-launch memcpys — this runs every stage).

integer, intent(in) :: ny

Interface-field extents (explicit shape: assumed-shape dummies in a do concurrent kernel make NVHPC walk the descriptor with per-launch memcpys — this runs every stage).

integer, intent(in) :: nzp1

Interface-field extents (explicit shape: assumed-shape dummies in a do concurrent kernel make NVHPC walk the descriptor with per-launch memcpys — this runs every stage).

real(kind=wp), intent(inout) :: kv(nx,ny,nzp1)

Momentum viscosity at interfaces; gets prandtl*kd.

real(kind=wp), intent(inout) :: kt(nx,ny,nzp1)

Tracer diffusivity at interfaces; gets kd.

private pure subroutine epbl_column_kernel(grid, this, ms, hT, hS, ss, dt, Q_heat_field, inv_rho0_cp, Q_salt_field, inv_rho0, sw_src_field, sw_ctke_active, sw_pen_frac, sw_R, sw_zeta1, sw_zeta2, wet_mask_field, p_top_in_eos, nx_arg, ny_arg)

Per-column EPBL solve. One do concurrent (j, i) with the serial work in k inside (j -> i -> k ordering); ALL sweep state is carried in scalars (design doc D6) — the only column arrays are the six iteration-invariant workspaces filled by the prep sweep.

Read more…

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_epbl_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms
real(kind=wp), intent(in) :: hT(:,:,:)

Temperature tracer hTr (degC*m), host-dereferenced.

real(kind=wp), intent(in) :: hS(:,:,:)

Salinity tracer hTr (PSU*m), host-dereferenced.

type(ocean_surface_stress_t), intent(in) :: ss
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: Q_heat_field(:,:)

2D heat-flux field (W/m²), host-dereferenced from sf%Q_heat.

real(kind=wp), intent(in) :: inv_rho0_cp

Precomputed 1/(rho0·cp) multiplier.

real(kind=wp), intent(in) :: Q_salt_field(:,:)

2D salt-flux field (kg/m²/s), host-dereferenced from sf%Q_salt.

real(kind=wp), intent(in) :: inv_rho0

Precomputed 1/rho0 multiplier.

real(kind=wp), intent(in) :: sw_src_field(:,:)

(PR-21) 2D irradiance source (W/m², >= 0 on the q_sw path), host-selected from sf%Q_heat or sf%q_sw. Read only when sw_ctke_active; otherwise the legacy sf%Q_heat is passed and ignored.

logical, intent(in) :: sw_ctke_active

(PR-21) Charge the TKE ledger for penetrating SW (host-side epbl_sw_ctke .and. sf%has_sw). False ⇒ the surface energetics + sweep run the unmodified legacy lines.

real(kind=wp), intent(in) :: sw_pen_frac

(PR-21) Two-band SW parameters (from sf), by value.

real(kind=wp), intent(in) :: sw_R

(PR-21) Two-band SW parameters (from sf), by value.

real(kind=wp), intent(in) :: sw_zeta1

(PR-21) Two-band SW parameters (from sf), by value.

real(kind=wp), intent(in) :: sw_zeta2

(PR-21) Two-band SW parameters (from sf), by value.

real(kind=wp), intent(in) :: wet_mask_field(:,:)

(PR-21) Wet mask — mirrors the deposition kernel’s I0 gate so the ledger and the tracer field account the same heat.

logical, intent(in) :: p_top_in_eos

(E3) Seed the column pressure stack at ms%p_top(i,j) rather than at 0 Pa — &ocean_psurf_nml in_eos, by value. .false. ⇒ the pre-E3 arithmetic, character for character.

integer, intent(in) :: nx_arg

Grid extents — used to bounds-check Q_* indexing.

integer, intent(in) :: ny_arg

Grid extents — used to bounds-check Q_* indexing.

private subroutine ocean_epbl_destroy(this)

Arguments

Type IntentOptional Attributes Name
class(ocean_epbl_t), intent(inout) :: this

private subroutine ocean_epbl_enter_data(this)

Arguments

Type IntentOptional Attributes Name
class(ocean_epbl_t), intent(inout) :: this

private subroutine ocean_epbl_enter_data_impl(this)

Arguments

Type IntentOptional Attributes Name
type(ocean_epbl_t), intent(inout) :: this

private subroutine ocean_epbl_exit_data(this)

Arguments

Type IntentOptional Attributes Name
class(ocean_epbl_t), intent(inout) :: this

private subroutine ocean_epbl_exit_data_impl(this)

Arguments

Type IntentOptional Attributes Name
type(ocean_epbl_t), intent(inout) :: this

private subroutine ocean_epbl_init(this, grid, nz_ml)

Allocate the persistent fields + column workspaces. Always allocates (configure runs after init, so enable isn’t known yet); the memory cost when off is the same 7-field footprint the vmix slot already pays.

Arguments

Type IntentOptional Attributes Name
class(ocean_epbl_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
integer, intent(in), optional :: nz_ml

private subroutine ocean_epbl_set_f_centre(this, grid, f_0, beta, y_ref)

Fill f_centre with the beta-plane Coriolis magnitude at cell centres: |f_0 + beta*(y - y_ref)|. Mirror of coriolis_adv_set_beta_plane (which fills corners). Call after init, before enter_data.

Arguments

Type IntentOptional Attributes Name
class(ocean_epbl_t), intent(inout) :: this
type(hgrid_t), intent(in) :: grid
real(kind=wp), intent(in) :: f_0
real(kind=wp), intent(in) :: beta
real(kind=wp), intent(in) :: y_ref