rdb_ocean_tidal_mixing Module

Bottom-intensified internal-tide diapycnal diffusivity. A fixed fraction of the barotropic-to-baroclinic tidal energy conversion E(x,y) [W m-2] dissipates locally above rough topography; the resulting turbulent diffusivity decays exponentially upward from the bed with scale zeta, converted to a per-layer Kd through the stratification (1/(dz*(N^2+Omega^2))). An INTERIOR closure: it is ADDED to the other interior diffusivities (KPP/EPBL/PP81/ kappa-shear) and goes through the single vmix_assemble gate.

References: * Jayne & St Laurent (2001), GRL 28, “Parameterizing tidal dissipation over rough topography” — the parameterized conversion E = 0.5*rho*kappa*<h^2>*U_tide^2. * St Laurent, Simmons & Garrett (2002), GRL 29, “Buoyancy forcing by turbulence above rough topography” — the local-dissipation fraction q and the bottom-anchored exponential vertical structure F(z) with decay scale zeta. * Simmons, Jayne, St Laurent & Weaver (2004), Ocean Modelling 6 — the global implementation that combines the two. Knob table: docs/generated_nml_knobs.md.

Discretization (conservative flux bookkeeping; St Laurent 2002): a downward TKE flux is tracked and the power dissipated IN each layer is converted to Kd = TKE_lay / (rho*dz*(N^2+Omega^2)). With the Adcroft-reciprocal normalization Inv_int = 1/(1-exp(-H/zeta)) the column-integrated deposited power is exactly q*mu*E (energy conservation, to round-off). The continuum equivalent is Kd(z) = [qmuE/(rho(N^2+Omega^2))] * exp(-z/zeta) / (zeta(1-exp(-H/zeta))), z measured UPWARD from the bed.

Interface convention (same as rdb_ocean_vmix / EPBL / kappa-shear): kd_int(:,:,K) lives at the bottom interface of layer K; global kd_int(:,:,1) is the bed and kd_int(:,:,nz+1) the free surface, both forced to exactly 0. Layers are bottom-up: k=1 bed, k=nz surface. The exp-decay anchors at the BED (k=1) and the sweep runs k=1 -> nz. The per-layer Kd_add(k) is split 50/50 across the layer’s two bounding interfaces (St Laurent 2002 interface deposition; see divergence note D2).


Uses

  • module~~rdb_ocean_tidal_mixing~~UsesGraph module~rdb_ocean_tidal_mixing rdb_ocean_tidal_mixing iso_fortran_env iso_fortran_env module~rdb_ocean_tidal_mixing->iso_fortran_env module~rdb_constants rdb_constants module~rdb_ocean_tidal_mixing->module~rdb_constants module~rdb_eos rdb_eos module~rdb_ocean_tidal_mixing->module~rdb_eos module~rdb_grid rdb_grid module~rdb_ocean_tidal_mixing->module~rdb_grid module~rdb_mem_report rdb_mem_report module~rdb_ocean_tidal_mixing->module~rdb_mem_report module~rdb_multilayer_state rdb_multilayer_state module~rdb_ocean_tidal_mixing->module~rdb_multilayer_state 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_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_tidal_mixing~~UsedByGraph module~rdb_ocean_tidal_mixing rdb_ocean_tidal_mixing module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_tidal_mixing module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_tidal_mixing module~rdb_ocean_state->module~rdb_ocean_dyn proc~validate_config validate_config proc~validate_config->module~rdb_ocean_tidal_mixing 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_state module~rdb_ocean_engine->module~rdb_ocean_diag_derived module~rdb_ocean_engine->module~rdb_ocean_diag_fills module~rdb_ocean_setup rdb_ocean_setup module~rdb_ocean_engine->module~rdb_ocean_setup module~rdb_ocean_setup->module~rdb_ocean_dyn module~rdb_ocean_setup->module~rdb_ocean_state

Variables

Type Visibility Attributes Name Initial
integer, private, parameter :: NZL = NZ_STACK_MAX

Maximum number of layers a single column kernel can solve.

integer, private, parameter :: NZLI = NZ_STACK_MAX+1

Interface array dimension (= NZL + 1).


Derived Types

type, public ::  ocean_tidal_mixing_t

Components

Type Visibility Attributes Name Initial
logical, public :: e_compute = .false.

v1.1 state-dependent E: when on, e_in = min(TKE_coef*N_bot, e_max). Default off (uses the prescribed e_uniform).

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

Bottom internal-tide energy input E (W m-2), (nx,ny).

real(kind=wp), public :: e_max = 1.0e3_wp

TKE_itide_max cap on E (W m-2).

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

Uniform bottom energy input E (W m-2); default 0 => inert even when enabled (structural path live, physics zero).

logical, public :: enable = .false.

Master switch. Default off — existing namelists and tests stay bit-identical. Requires vmix%use_closure + thermodynamics (validated at configure).

type(eos_t), public :: eos

Value copy of ocean_state%eos, set at configure — the buoyancy derivatives use the SAME EOS the dyn-core runs.

real(kind=wp), public :: frac_rough = 0.1_wp

Roughness clamp: <= (frac_rough*H)^2.

real(kind=wp), public :: gamma = 0.3333_wp

Local-dissipation fraction q (GAMMA_ITIDES).

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

Sub-grid topographic roughness variance (m^2) for v1.1 E.

logical, public :: is_init = .false.

True between init and destroy.

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

KAPPA_H2_FACTOR for the v1.1 E recompute.

real(kind=wp), public :: kappa_itides = 6.2832e-4_wp

Topographic wavenumber kappa (m^-1) for the v1.1 E recompute.

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

Tidal diffusivity at interfaces (m^2/s), (nx,ny,nz+1), global bottom-up: zero at bed (K=1) and surface (K=nz+1).

real(kind=wp), public :: kd_max = 1.0e-2_wp

Per-layer physical Kd cap (m^2/s); < 0 => no cap. Distinct from the vmix_assemble ceiling (the final clip).

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

Mask off where column depth H < min_zbot (m).

real(kind=wp), public :: mu = 0.2_wp

Mixing efficiency Gamma_mix (MU_ITIDES).

real(kind=wp), public :: omega2 = OMEGA_EARTH**2

Rotation floor Omega^2 (s^-2) on N^2; physics, not merely a 1/0 guard. The floor is plain Omega^2 (Melet et al. 2013 efficiency rescaling N^2/(N^2+Omega^2)), not (2*Omega)^2.

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

Kv = prandtl_tidal * Kd into the momentum solve.

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

Boussinesq reference density (kg/m^3).

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

RMS barotropic tidal velocity amplitude (m/s) for v1.1 E.

real(kind=wp), public :: zeta = 500.0_wp

Bottom decay scale (m) (INT_TIDE_DECAY_SCALE).

Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_tidal_mixing_bytes
procedure, public, non_overridable :: destroy => ocean_tidal_mixing_destroy
procedure, public, non_overridable :: enter_data => ocean_tidal_mixing_enter_data
procedure, public, non_overridable :: exit_data => ocean_tidal_mixing_exit_data
procedure, public, non_overridable :: init => ocean_tidal_mixing_init
procedure, public, non_overridable :: set_e_uniform => ocean_tidal_mixing_set_e_uniform

Functions

public pure function tidal_mixing_is_inert(enable, e_uniform, e_compute) result(inert)

.true. iff tidal mixing is enabled but has no energy source (PR-6 fail-loud): enable .and. e_uniform <= 0 .and. .not. e_compute. The bottom-intensified diffusivity Kd ∝ E, so a zero prescribed e_uniform with the e_compute estimator off makes Kd ≡ 0 exactly — the closure runs its whole flux sweep for nothing. e_compute=.true. supplies E internally, so that is NOT inert; a disabled closure is not “inert” either (it is simply off). Drives a configure abort.

Arguments

Type IntentOptional Attributes Name
logical, intent(in) :: enable
real(kind=wp), intent(in) :: e_uniform
logical, intent(in) :: e_compute

Return Value logical

private pure function ocean_tidal_mixing_bytes(this) result(nbytes)

Counted allocatable footprint of the tidal mixing 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_tidal_mixing_t), intent(in) :: this

Return Value integer(kind=int64)


Subroutines

public pure subroutine tidal_mixing_compute(grid, this, ms, dt)

Run tidal mixing over the domain: fill this%kd_int (interface diffusivity). Call at thermo cadence with the thermo dt. Outer shim: dereferences the tracer-registry hTr arrays on the host (the array-of-DT indirection blocks NVHPC device codegen), then forwards to the column kernel. dt is unused (the steady diagnostic Kd does not integrate in time) but carried for signature parity with the other interior closures.

Arguments

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

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

Fold the tidal diffusivity into the vmix interface fields, ADDITIVELY (interior-diffusivity semantics; St Laurent tidal mixing is an interior source like kappa-shear). Called EVERY stage (PP81 rewrites kv/kt each stage; kd_int itself refreshes at thermo cadence). Interior interfaces only — K=1 (bed) and K=nzp1 (surface) stay zero in both source and target.

Arguments

Type IntentOptional Attributes Name
type(ocean_tidal_mixing_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_tidal*kd.

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

Tracer diffusivity at interfaces; gets kd.

private subroutine ocean_tidal_mixing_destroy(this)

Arguments

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

private subroutine ocean_tidal_mixing_enter_data(this)

Arguments

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

private subroutine ocean_tidal_mixing_enter_data_impl(this)

Arguments

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

private subroutine ocean_tidal_mixing_exit_data(this)

Arguments

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

private subroutine ocean_tidal_mixing_exit_data_impl(this)

Arguments

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

private subroutine ocean_tidal_mixing_init(this, grid, nz_ml)

Allocate the persistent fields. Always allocates (configure runs after init, so enable is not known yet); the off-cost is one 2D field + one interface field.

Arguments

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

private subroutine ocean_tidal_mixing_set_e_uniform(this, e_value)

Fill the bottom energy field e_in with a uniform value. Host loop (setup phase); call after init, before enter_data.

Arguments

Type IntentOptional Attributes Name
class(ocean_tidal_mixing_t), intent(inout) :: this
real(kind=wp), intent(in) :: e_value

private pure subroutine tidal_mixing_column_kernel(grid, this, ms, hT, hS)

Per-column St-Laurent flux-bookkeeping sweep. One do concurrent (j, i) over owned cells; each column is a serial upward sweep k=1(bed) -> nz(surface) over fixed-size local() arrays (register-resident). Bottom-up global indexing throughout — no surface-down flip (the decay anchors at the bed).

Read more…

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_tidal_mixing_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.