rdb_ocean_lateral_mix Module

Flow-aware harmonic / biharmonic viscosity for the ocean dyn-core: per-face ah_face_* (m^2/s) and nu4_face_* (m^4/s), recomputed each step from the local flow and read by the horizontal-viscosity kernel in place of the scalar nu_h/nu_4 (closure LMIX_NONE ⇒ scalar fallback ⇒ bit-identical). The coastal path uses Smagorinsky in rdb_ml_horizontal_viscosity; the ocean path defaults to Leith, which scales with vorticity gradient and avoids over-damping coherent eddies. Leith (1968); Smagorinsky (1963); Fox-Kemper & Menemenlis (2008); Griffies & Hallberg (2000).


Uses

  • module~~rdb_ocean_lateral_mix~~UsesGraph module~rdb_ocean_lateral_mix rdb_ocean_lateral_mix iso_fortran_env iso_fortran_env module~rdb_ocean_lateral_mix->iso_fortran_env module~rdb_constants rdb_constants module~rdb_ocean_lateral_mix->module~rdb_constants module~rdb_grid rdb_grid module~rdb_ocean_lateral_mix->module~rdb_grid module~rdb_mem_report rdb_mem_report module~rdb_ocean_lateral_mix->module~rdb_mem_report module~rdb_multilayer_state rdb_multilayer_state module~rdb_ocean_lateral_mix->module~rdb_multilayer_state module~rdb_ocean_metrics rdb_ocean_metrics module~rdb_ocean_lateral_mix->module~rdb_ocean_metrics module~rdb_scratch_3d rdb_scratch_3d module~rdb_ocean_lateral_mix->module~rdb_scratch_3d pic_types pic_types module~rdb_constants->pic_types 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_metrics->iso_fortran_env module~rdb_ocean_metrics->module~rdb_constants module~rdb_ocean_metrics->module~rdb_grid module~rdb_ocean_metrics->module~rdb_mem_report module~rdb_ocean_metrics->module~rdb_error_ring module~rdb_io_netcdf rdb_io_netcdf module~rdb_ocean_metrics->module~rdb_io_netcdf module~rdb_ocean_bipolar rdb_ocean_bipolar module~rdb_ocean_metrics->module~rdb_ocean_bipolar module~rdb_ocean_fold rdb_ocean_fold module~rdb_ocean_metrics->module~rdb_ocean_fold module~rdb_ocean_status rdb_ocean_status module~rdb_ocean_metrics->module~rdb_ocean_status netcdf netcdf module~rdb_ocean_metrics->netcdf module~rdb_ocean_metrics->pic_logger module~rdb_ocean_metrics->pic_strings 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_io_netcdf->iso_fortran_env module~rdb_io_netcdf->module~rdb_constants module~rdb_io_netcdf->module~rdb_error_ring module~rdb_io_netcdf->netcdf module~rdb_io_netcdf->pic_logger module~rdb_io_netcdf->pic_strings iso_c_binding iso_c_binding module~rdb_io_netcdf->iso_c_binding module~rdb_ocean_bipolar->module~rdb_constants module~rdb_ocean_fold->module~rdb_constants 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_lateral_mix~~UsedByGraph module~rdb_ocean_lateral_mix rdb_ocean_lateral_mix module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_lateral_mix module~rdb_ocean_horizontal_viscosity rdb_ocean_horizontal_viscosity module~rdb_ocean_dyn->module~rdb_ocean_horizontal_viscosity module~rdb_barotropic_coupling rdb_barotropic_coupling module~rdb_ocean_dyn->module~rdb_barotropic_coupling module~rdb_ocean_bt_budget_probe rdb_ocean_bt_budget_probe module~rdb_ocean_dyn->module~rdb_ocean_bt_budget_probe module~rdb_ocean_horizontal_viscosity->module~rdb_ocean_lateral_mix module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_setup->module~rdb_ocean_lateral_mix module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_setup->module~rdb_ocean_horizontal_viscosity module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_setup->module~rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_lateral_mix module~rdb_ocean_state->module~rdb_ocean_dyn module~rdb_ocean_state->module~rdb_ocean_horizontal_viscosity proc~validate_config validate_config proc~validate_config->module~rdb_ocean_lateral_mix proc~validate_config->module~rdb_ocean_horizontal_viscosity module~rdb_barotropic_coupling->module~rdb_ocean_horizontal_viscosity 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_bt_budget_probe->module~rdb_ocean_horizontal_viscosity 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

Variables

Type Visibility Attributes Name Initial
integer, public, parameter :: LMIX_BIHARMONIC = 3

Constant-coefficient biharmonic.

integer, public, parameter :: LMIX_INVALID = -1

Sentinel for an unrecognised namelist string; aborts loudly at configure rather than silently falling back to background-only.

integer, public, parameter :: LMIX_LEITH = 1

Leith vorticity-gradient closure (default eddy-resolving).

integer, public, parameter :: LMIX_LEITH_BIHARM = 4

Leith-scaled biharmonic (Griffies & Hallberg 2000).

integer, public, parameter :: LMIX_NONE = 0

No flow-aware closure — falls back to the scalar nu_h field.

integer, public, parameter :: LMIX_SMAGORINSKY = 2

Smagorinsky strain-rate closure.


Derived Types

type, public ::  ocean_lateral_mix_t

Components

Type Visibility Attributes Name Initial
real(kind=wp), public :: ah_bg = 0.0_wp

Background harmonic viscosity (m^2/s), floored beneath the closure to avoid zero damping in laminar patches.

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

Harmonic viscosity at east faces (m^2/s), shape (nx+1, ny, nz_ml).

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

Harmonic viscosity at north faces (m^2/s), shape (nx, ny+1, nz_ml).

real(kind=wp), public :: ah_max = 1.0e4_wp

Upper clip on harmonic viscosity (m^2/s). Caps Leith spikes and enforces the viscous-CFL bound (nu·dt/dx² ≤ 0.5).

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

Leith dimensionless coefficient. Typical 1.0–2.0.

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

Nondimensional biharmonic Leith constant for LMIX_LEITH_BIHARM (Griffies & Hallberg 2000). Default 0.0 is a no-op; selecting the closure with it 0.0 warns at startup.

real(kind=wp), public :: c_smag = 0.15_wp

Smagorinsky dimensionless coefficient (fallback).

integer, public :: closure = LMIX_NONE

Active closure tag. Default LMIX_NONE ⇒ scalar-nu_h behaviour, bit-identical.

logical, public :: is_init = .false.

True between init and destroy. Prefer this to allocated(...) — tracks GPU device attachment too.

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

Live velocity-scale viscosity coefficient (m/s). When positive, A_vel = kh_vel_scale_live · L_grid · |u| (L_grid = sqrt(dxT·dyT)) is max-combined into the per-face harmonic viscosity every step. Default 0 ⇒ never computed ⇒ bit-identical. State-dependent (evaluated per step); distinct from the kh_vel_scale background-floor knob set once at configure. MOM6 KH_VEL_SCALE (Kh = U·Δ).

logical, public :: no_slip = .false.

Lateral BC at coasts (shared with Coriolis). .false. (default) = free-slip: corner shear strain sh_xy (and the Leith corner vorticity) is multiplied by wet_q so a land corner adds nothing. .true. = no-slip: factor 2 - wet_q. All-wet ⇒ wet_q≡1 ⇒ bit-identical.

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

Background biharmonic viscosity floor (m⁴/s).

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

Biharmonic viscosity at east faces (m⁴/s), shape (nx+1, ny, nz_ml). Populated only when smag_ah_active = .true..

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

Biharmonic viscosity at north faces (m⁴/s), shape (nx, ny+1, nz_ml). Populated only when smag_ah_active = .true..

real(kind=wp), public :: nu4_max = 1.0e12_wp

Static upper clip on biharmonic viscosity (m⁴/s) applied when filling nu4_face_* — a cheap ceiling on the strain term. The true stability guard is the per-cell biharmonic-CFL clamp applied downstream in the biharmonic kernel.

integer, public :: nx_total = 0
integer, public :: ny_total = 0
integer, public :: nz_ml = 0
logical, public :: resoln_scaled_visc = .false.

Hallberg (2013) resolution scaling. When .true. AND the optional VarMix res_fn_u/v face fields are passed, the dynamic coefficients are multiplied by Res_fn ∈ [0,1] before the clamps (suppressed where the deformation radius is resolved). Default .false. ⇒ unscaled ⇒ bit-identical.

logical, public :: smag_ah_active = .false.

When true, compute_smag_ah fills nu4_face_x/y each step from the local strain rate; the biharmonic kernel reads them instead of the scalar nu_4. Independent of closure — Smag_KH (Laplacian) and Smag_AH (biharmonic) can both be on.

real(kind=wp), public :: smag_bi_const = 0.06_wp

Nondimensional biharmonic Smagorinsky constant (typical 0.015–0.06).

type(scratch_3d_buffer_t), public :: vort_corner

Relative vorticity at C-grid corners.

Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_lateral_mix_bytes
procedure, public, non_overridable :: destroy => ocean_lateral_mix_destroy
procedure, public, non_overridable :: enter_data => ocean_lateral_mix_enter_data
procedure, public, non_overridable :: exit_data => ocean_lateral_mix_exit_data
procedure, public, non_overridable :: init => ocean_lateral_mix_init

Functions

public pure function has_biharmonic_backstop(nu_4, smag_ah, smag_bi_const, code, c_leith_bi, nu_4_bg) result(ok)

.true. iff the configured biharmonic dispatch will produce a STRICTLY POSITIVE dissipation coefficient somewhere. Drives the configure-time fail-loud guard requiring a biharmonic backstop when MEKE backscatter is on — the negative harmonic backscatter feeds a grid-scale mode that only a positive biharmonic can dissipate.

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: nu_4
logical, intent(in) :: smag_ah
real(kind=wp), intent(in) :: smag_bi_const
integer, intent(in) :: code
real(kind=wp), intent(in) :: c_leith_bi
real(kind=wp), intent(in) :: nu_4_bg

Return Value logical

public pure function lateral_closure_conflicts_smag_ah(code, smag_ah) result(conflict)

.true. iff the closure is LMIX_LEITH_BIHARM and smag_ah is on — both would fill nu4_face_* and smag_ah runs last, so it would silently overwrite the Leith-biharmonic fill (we do not max-combine biharmonic closures). Drives a fail-loud guard.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: code
logical, intent(in) :: smag_ah

Return Value logical

public pure function lateral_closure_is_implemented(code) result(ok)

.true. iff the closure code has a working dispatcher path. Drives the configure-time fail-loud guard. Keep in lock-step with the select case in ocean_lateral_mix_compute.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: code

Return Value logical

public pure function leith_biharm_is_inert(code, c_leith_bi) result(inert)

.true. iff the Leith-biharmonic closure is selected but its coefficient is <= 0 (PR-6 fail-loud). ν₄ is linear in c_leith_bi, so c_leith_bi <= 0 makes the whole closure a provable no-op — the user asked for biharmonic dissipation and got none. Returns .false. for any other closure (they do not read c_leith_bi, so the guard must not fire on them). Promotes the previous configure-time warning to an abort.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: code
real(kind=wp), intent(in) :: c_leith_bi

Return Value logical

public pure function parse_lateral_closure(name) result(code)

Translate a namelist string into an LMIX_* code. Returns LMIX_INVALID on an unrecognised value (fail loud at configure); only “none”/”off”/”” map to LMIX_NONE.

Arguments

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

Return Value integer

private pure function ocean_lateral_mix_bytes(this) result(nbytes)

Counted allocatable footprint of the lateral viscosity 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_lateral_mix_t), intent(in) :: this

Return Value integer(kind=int64)


Subroutines

public subroutine ocean_lateral_mix_compute(grid, metrics, this, ms, res_fn_u, res_fn_v)

Dispatcher — runs the compute kernel for the active closure tag. LMIX_LEITH/LMIX_SMAGORINSKY → harmonic ah_face_*; LMIX_LEITH_BIHARM → biharmonic nu4_face_*; LMIX_BIHARMONIC → scalar nu_4 in the apply step (no per-face fill); LMIX_NONE → no-op. The independent smag_ah_active switch separately fills nu4_face_* from the strain rate. this is optional so the driver can call unconditionally. res_fn_u/v (optional VarMix resolution-function fields): when supplied AND resoln_scaled_visc, scale the dynamic coefficients before the clamps; absent ⇒ unscaled ⇒ bit-identical.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_lateral_mix_t), intent(inout), optional :: this
type(multilayer_state_t), intent(in) :: ms
real(kind=wp), intent(in), optional :: res_fn_u(grid%nx_total+1,grid%ny_total)
real(kind=wp), intent(in), optional :: res_fn_v(grid%nx_total,grid%ny_total+1)

public pure subroutine ocean_lateral_mix_compute_leith(grid, metrics, this, ms, res_fn_u, res_fn_v)

Public only for the unit-test suite; ignore in production code. Populate ah_face_x/ah_face_y (m^2/s) with the Leith viscosity A_h(face) = max(ah_bg, min(ah_max, (C_L · dx)^3 · |∇ζ|)) where ζ is relative vorticity at C-grid corners (pass 1) and |∇ζ| the 2D gradient magnitude at each face (pass 2). Wall faces get the background viscosity.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_lateral_mix_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms
real(kind=wp), intent(in), optional :: res_fn_u(grid%nx_total+1,grid%ny_total)

VarMix resolution function at u-faces (nondim, [0,1]). When present AND this%resoln_scaled_visc, scales A_h before clamp.

real(kind=wp), intent(in), optional :: res_fn_v(grid%nx_total,grid%ny_total+1)

VarMix resolution function at v-faces.

public pure subroutine ocean_lateral_mix_compute_leith_biharm(grid, metrics, this, ms)

Public only for the unit-test suite; ignore in production code. Populate nu4_face_x/nu4_face_y (m⁴/s) with the 2-D Leith biharmonic viscosity A_4(face) = clamp(C_lb · grid_sp⁶ · inv_PI6 · |∇²ζ|, nu4_bg, nu4_max) where ζ is C-grid corner relative vorticity, ∇²ζ its 5-point corner Laplacian, grid_sp⁶ = grid_sp_h2³, and inv_PI6 = (1/π)⁶. Per-face |∇²ζ| is the mean of the two adjacent corner Laplacians. Wall faces get nu4_bg. Leith (1968); Griffies & Hallberg (2000).

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_lateral_mix_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms

public pure subroutine ocean_lateral_mix_compute_smag(grid, metrics, this, ms, res_fn_u, res_fn_v)

Populate ah_face_x/ah_face_y (m^2/s) with the Smagorinsky Laplacian viscosity A_h(face) = max(ah_bg, min(ah_max, (C_S · dx)^2 · |D|)) where |D| = sqrt(D_T^2 + D_S^2) is the deformation-tensor magnitude — tension D_T = ∂u/∂x − ∂v/∂y (cell centred) and shear D_S = ∂v/∂x + ∂u/∂y (corner) — averaged onto the face. Wall faces get the background viscosity (wall-adjacent rows re-use the next interior row). Smagorinsky (1963); C_S ≈ 0.15–0.2.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_lateral_mix_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms
real(kind=wp), intent(in), optional :: res_fn_u(grid%nx_total+1,grid%ny_total)

VarMix resolution function at u-faces (nondim, [0,1]). When present AND this%resoln_scaled_visc, scales A_h before clamp.

real(kind=wp), intent(in), optional :: res_fn_v(grid%nx_total,grid%ny_total+1)

VarMix resolution function at v-faces.

public pure subroutine ocean_lateral_mix_compute_smag_ah(grid, metrics, this, ms)

Public only for the unit-test suite; ignore in production code. Populate nu4_face_x/nu4_face_y (m⁴/s) with the biharmonic Smagorinsky viscosity A_4(face) = clamp(C_b · L⁴ · |D|, nu4_bg, nu4_max) where L² = 2·dx²·dy²/(dx²+dy²) (harmonic mean of dx²,dy²) and |D| is the strain-rate magnitude from compute_smag. Wall faces get nu4_bg. SMAG_BI_CONST ≈ 0.015–0.06.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_lateral_mix_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms

public pure subroutine ocean_lateral_mix_compute_vel_scale(grid, metrics, this, ms, seed_bg)

Public only for the unit-test suite; ignore in production code. Live velocity-scale viscosity (MOM6 KH_VEL_SCALE, Kh = U·Δ): per face A_vel = kh_vel_scale_live · L_grid · |u_face| (L_grid = sqrt(dxT·dyT)), max-combined into ah_face_* so it floors — never reduces — the active closure. seed_bg = .true. first fills every face with ah_bg (used when no closure ran); .false. only raises faces where A_vel exceeds the closure. No-op when kh_vel_scale_live <= 0.

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_lateral_mix_t), intent(inout) :: this
type(multilayer_state_t), intent(in) :: ms
logical, intent(in) :: seed_bg

private subroutine ocean_lateral_mix_destroy(this)

Arguments

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

private subroutine ocean_lateral_mix_enter_data(this)

Arguments

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

private subroutine ocean_lateral_mix_enter_data_impl(this)

Arguments

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

private subroutine ocean_lateral_mix_exit_data(this)

Arguments

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

private subroutine ocean_lateral_mix_exit_data_impl(this)

Arguments

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

private subroutine ocean_lateral_mix_init(this, grid, nz_ml)

Allocate the face viscosity coefficients + corner-vorticity scratch. Default nz_ml = 1 preserves the barotropic-only constructor; pass nz_ml = ms%nz_ml for the multilayer driver.

Arguments

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