rdb_ocean_gm Module

Gent & McWilliams (1990) / Griffies (1998) skew-flux thickness diffusion. The eddy-induced (“bolus”) overturning is realized as a layer THICKNESS flux (never an explicit velocity), applied as its OWN sequential operator on the CURRENT thickness, after the dynamics of every outer step (rdb_continuity :: continuity_gm_apply, driven by rdb_ocean_dyn :: run_gm_step) — mirroring how MOM6 applies its thickness_diffuse step after the split-RK2 dynamics step, updating h in place.

Why sequential, not folded

The per-face availability cap h_avail = A·(h − H_VANISHED)/(4·dt) bounds four faces’ outflow by h − H_VANISHED, so h_new >= H_VANISHED — but ONLY for the h it was computed from. Until 2026-10 this slot computed uhD from the stage-entry h and FOLDED it into the resolved continuity sweeps (gm_fold_x/y), so the cap bounded the stage-entry thickness and the resolved outflow came on top: on the 1-degree Southern Ocean (z*, open steps) an 8.6 cm partial bed cell with two open faces onto fillers was drained by GM at the cap on all four faces and the resolved flux took it to −8.2e-4 m. Computed here from the thickness the dynamics LEFT, the cap bounds what is actually there (prototype: python_prototypes/gm_sequential/gm_sequential.py).

At each u/v face the eddy streamfunction is Sfn_unlim = -(KhTh * dy_Cu) * Slope using the STORED isopycnal slope from the slopes slot. The per-layer bolus transport is the vertical difference of the limited streamfunction, formed by the column recurrence (surface->bed, uhtot=0 at surface): uhD(k) = max( min(Sfn_in_H - uhtot, h_avail_i), -h_avail_{i+1} ) uhtot = uhtot + uhD(k) so Sum_k uhD = 0 (closes at the bed) — mass/tracer conservative.

Bottom-blocking (MOM6’s rule for the GM streamfunction) acts on the UNLIMITED streamfunction first: no transport from a donor layer that lies entirely below the receiving column’s bed, and a share scaled by the fraction above it for a donor layer that straddles it (gm_block_below_bed). On an open z-level step this is what keeps GM from pouring deep water through the step into the fillers below the shallow column’s bed.

Three limiters, in order: (1) safe-streamfunction blend toward a column-spread return flow where slope > slope_max; (2) mass- availability rsum bound (the conservation guard keeping each layer

= H_VANISHED); (3) per-layer donor cap. The donor side is keyed on the SIGN of uhtot (column i when uhtot<=0, else i+1).

KhTh is a 2D face field, constant-filled from &ocean_gm_nml khth (VarMix/MEKE seam populates it later via +=), CFL-clamped per face. gm_src(nx,ny) carries the GM PE release (>= 0 for a stable tilted column) for future MEKE coupling.

Bottom-up convention (k=1 bed, k=nz surface; interface K=1 bed, K=nz+1 surface); the slopes slot zeroes the slope at both caps so the streamfunction vanishes there and the recurrence closes.

Partial-step z-level faces (&vcoord_nml zfixed_closed_faces)

Under z_fixed a face column is not the whole water column: a layer that is an inert FILLER on either side (inside the bed or the ice draft) is a WALL for that layer at that face (metrics%open_u/open_v == 0). Continuity applies that mask to the resolved flux, and GM runs on its own (it does not pass through that mask), so GM must build its overturning on the OPEN part of each face column itself. With the knob on, each face first marks its open layers, ok(k) = open(k) .and. live(h_W(k)) .and. live(h_E(k)) (rdb_vl_is_live, the one vanished-layer predicate), and the recurrence then:

  • gives a not-ok layer ZERO transport and zero availability (h_avail = 0, so it adds nothing to rsum): the streamfunction is carried UNCHANGED across it, so it is 0 at the BOTTOM of the open column (it starts at 0 at the bed, and the bed-side closed / filler layers cannot change it);
  • closes the column into the TOPMOST open layer k_top_open (uhD(k_top_open) = -uhtot) instead of k = nz, so the streamfunction is also 0 at the TOP of the open column — the free surface, or the ice base with fillers above it. The full-column closure into nz would push the residual through a filler under the ice, or through a face whose top layer is closed.

Hence uhD == 0 on every closed face-layer and every filler, and Sum_k uhD = 0 at every face (the open-column integral IS the column integral). With nothing closed ok is all-true, k_top_open = nz and the arithmetic is the full-column form operation for operation. The slopes slot zeroes slope / N^2 at every interface not strictly inside a face’s open column on this path, so gm_src (the MEKE source) sees only the open column as well. Knob OFF ⇒ use_open = .false., ok all-true, the masks are never indexed ⇒ byte-identical.

Non-finite guard: the streamfunction limiters are min/max clamps, which nvfortran’s relaxed FP lowers NaN-blind (CLAUDE.md) — a NaN slope would come out as a plausible ±rsum transport. A non-finite slope is therefore read as ZERO slope (no GM at that interface) before any clamp sees it; finite inputs are untouched.

Default off (&ocean_gm_nml enable=.false.) => slot allocated but gm_compute_transports no-ops => bit-identical. Refs: Gent & McWilliams (1990); Gent et al. (1995); Griffies (1998).


Uses

  • module~~rdb_ocean_gm~~UsesGraph module~rdb_ocean_gm rdb_ocean_gm ieee_arithmetic ieee_arithmetic module~rdb_ocean_gm->ieee_arithmetic iso_fortran_env iso_fortran_env module~rdb_ocean_gm->iso_fortran_env module~rdb_constants rdb_constants module~rdb_ocean_gm->module~rdb_constants module~rdb_grid rdb_grid module~rdb_ocean_gm->module~rdb_grid module~rdb_mem_report rdb_mem_report module~rdb_ocean_gm->module~rdb_mem_report module~rdb_multilayer_state rdb_multilayer_state module~rdb_ocean_gm->module~rdb_multilayer_state module~rdb_ocean_isopycnal_slopes rdb_ocean_isopycnal_slopes module~rdb_ocean_gm->module~rdb_ocean_isopycnal_slopes module~rdb_ocean_metrics rdb_ocean_metrics module~rdb_ocean_gm->module~rdb_ocean_metrics 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_isopycnal_slopes->iso_fortran_env module~rdb_ocean_isopycnal_slopes->module~rdb_constants module~rdb_ocean_isopycnal_slopes->module~rdb_grid module~rdb_ocean_isopycnal_slopes->module~rdb_mem_report module~rdb_ocean_isopycnal_slopes->module~rdb_multilayer_state module~rdb_ocean_isopycnal_slopes->module~rdb_ocean_metrics module~rdb_eos rdb_eos module~rdb_ocean_isopycnal_slopes->module~rdb_eos 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_efp->ieee_arithmetic module~rdb_efp->iso_fortran_env module~rdb_eos->module~rdb_constants module~rdb_eos->module~rdb_grid 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_gm~~UsedByGraph module~rdb_ocean_gm rdb_ocean_gm module~rdb_continuity rdb_continuity module~rdb_continuity->module~rdb_ocean_gm module~rdb_ocean_dyn rdb_ocean_dyn module~rdb_ocean_dyn->module~rdb_ocean_gm module~rdb_ocean_dyn->module~rdb_continuity module~rdb_ocean_meke rdb_ocean_meke module~rdb_ocean_dyn->module~rdb_ocean_meke module~rdb_ocean_meke->module~rdb_ocean_gm module~rdb_ocean_state rdb_ocean_state module~rdb_ocean_state->module~rdb_ocean_gm module~rdb_ocean_state->module~rdb_continuity module~rdb_ocean_state->module~rdb_ocean_dyn module~rdb_ocean_state->module~rdb_ocean_meke 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_ice_transport rdb_ice_transport module~rdb_ice_transport->module~rdb_continuity 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_ice_transport 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

Derived Types

type, public ::  ocean_gm_t

Gent-McWilliams thickness-diffusion state. All fields default to the inert (enable=.false.) configuration so an ocean run that never sets &ocean_gm_nml is bit-identical.

Components

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

Master switch. Off => gm_compute_transports and continuity_gm_apply are no-ops => bit-identity preserved. Requires the slopes slot (&ocean_slopes_nml enable); the loud invariant is checked at configure (configure_ocean_gm).

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

Potential-energy release -1/4 Sum_k rho0 KH Slope^2 N^2 h (W/m^2-ish; >= 0 for a stable tilted column), (nx,ny). CARRIED state: filled after the dynamics of step n, read by meke_step at the top of step n+1, so it is in the restart registry (gm_src).

logical, public :: is_init = .false.

True between init and destroy; gate on this (never on allocated, which misses the GPU mapping).

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

Thickness-diffusion coefficient KhTh (m^2/s); constant-filled into the 2D face fields (production 1e2-1e3).

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

Fraction of the diffusive CFL the face KH may use: KH = min(khth, 0.25*max_cfl/(dt*(idxCu^2+idyCv^2))).

real(kind=wp), public :: khth_slope_max = 0.01_wp

Slope magnitude (nondim) above which the safe-streamfunction blend takes over (slope_max).

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

Thickness diffusivity at u-faces (m^2/s), (nx+1,ny).

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

Thickness diffusivity at v-faces (m^2/s), (nx,ny+1).

integer, public :: nx_total = 0
integer, public :: ny_total = 0
integer, public :: nz_ml = 0
real(kind=wp), public :: rho0 = 1035.0_wp

Reference density (kg/m^3) for the gm_src PE-release scaling.

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

GM x-face transport (m^3/s), (nx+1,ny,nz). Filled every outer step from the post-dynamics thickness and applied at once by continuity_gm_apply.

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

GM y-face transport (m^3/s), (nx,ny+1,nz).

Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_gm_bytes
procedure, public, non_overridable :: destroy => ocean_gm_destroy
procedure, public, non_overridable :: enter_data => ocean_gm_enter_data
procedure, public, non_overridable :: exit_data => ocean_gm_exit_data
procedure, public, non_overridable :: init => ocean_gm_init

Functions

private pure function gm_block_below_bed(sfn, e_top_l, e_bot_l, bed_r, e_top_r, e_bot_r, bed_l) result(sfn_b)

MOM6 bottom-blocking (“Avoid moving dense water upslope from below the level of the bottom on the receiving side”). sfn is the unlimited streamfunction at an interface: the transport of everything BELOW it, > 0 from L to R. Its donor layer is the one just below the interface on the donor side ([e_bot, e_top]).

Read more…

Arguments

Type IntentOptional Attributes Name
real(kind=wp), intent(in) :: sfn
real(kind=wp), intent(in) :: e_top_l
real(kind=wp), intent(in) :: e_bot_l
real(kind=wp), intent(in) :: bed_r
real(kind=wp), intent(in) :: e_top_r
real(kind=wp), intent(in) :: e_bot_r
real(kind=wp), intent(in) :: bed_l

Return Value real(kind=wp)

private pure function gm_clamp_slope(s, smax) result(sc)

Clamp a slope to +/- smax (bounded slope for the PE release). A non-finite slope reads as 0 (no release) rather than being laundered into ±smax by the NaN-blind clamp (CLAUDE.md).

Arguments

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

Return Value real(kind=wp)

private pure function gm_h_frac(h_avail_k, rsum_k) result(hf)

Donor mass fraction h_avail(k)/rsum_above(k) (0 when no mass is available above). rsum_above(k) is the cumulative availability from the surface down to and including layer k, so hf in [0,1].

Arguments

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

Return Value real(kind=wp)

private pure function gm_pos_n2(n2) result(np)

max(N^2, 0) for the PE release, with a non-finite N^2 read as 0 (a bare max is NaN-blind under relaxed FP, CLAUDE.md).

Arguments

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

Return Value real(kind=wp)

private pure function ocean_gm_bytes(this) result(nbytes)

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

Return Value integer(kind=int64)


Subroutines

public subroutine gm_compute_transports(grid, metrics, this, slopes, ms, dt, khth_ext_u, khth_ext_v)

Fill uhD/vhD (m^3/s) with the GM bolus thickness transport and gm_src with the PE release, from the CURRENT ms%h_layer and the stored slopes. Run every outer step AFTER the dynamics, and immediately followed by continuity_gm_apply with the SAME dt and the same, untouched h_layer: the availability cap A·(h − H_VANISHED)/(4·dt) bounds that h and no other (see the module docstring). No-op when disabled, uninitialised, or the slopes slot is absent/disabled.

Read more…

Arguments

Type IntentOptional Attributes Name
type(hgrid_t), intent(in) :: grid
type(ocean_metrics_t), intent(in) :: metrics
type(ocean_gm_t), intent(inout) :: this
type(ocean_slopes_t), intent(in) :: slopes
type(multilayer_state_t), intent(in) :: ms
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in), optional :: khth_ext_u(:,:)
real(kind=wp), intent(in), optional :: khth_ext_v(:,:)

private pure subroutine gm_clamp_khth(nx, ny, dt, khth, khth_max_cfl, use_ext, khth_ext_u, khth_ext_v, idxCu, idyCu, idxCv, idyCv, wet_u, wet_v, khth_u, khth_v)

Fill the 2D face KhTh fields from the per-face base, CFL-clamped per face (native u-face idxCu/idyCu, v-face idxCv/idyCv) and zeroed on wall faces. Base = VarMix khth_ext_* when use_ext, else the scalar khth; the same diffusive-CFL min is applied either way.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nx
integer, intent(in) :: ny
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: khth
real(kind=wp), intent(in) :: khth_max_cfl
logical, intent(in) :: use_ext
real(kind=wp), intent(in) :: khth_ext_u(nx+1,ny)
real(kind=wp), intent(in) :: khth_ext_v(nx,ny+1)
real(kind=wp), intent(in) :: idxCu(nx+1,ny)
real(kind=wp), intent(in) :: idyCu(nx+1,ny)
real(kind=wp), intent(in) :: idxCv(nx,ny+1)
real(kind=wp), intent(in) :: idyCv(nx,ny+1)
real(kind=wp), intent(in) :: wet_u(nx+1,ny)
real(kind=wp), intent(in) :: wet_v(nx,ny+1)
real(kind=wp), intent(out) :: khth_u(nx+1,ny)
real(kind=wp), intent(out) :: khth_v(nx,ny+1)

private pure subroutine gm_column_x(nx, ny, nz, i_smax2, i4dt, use_open, dy_cu, areaT, h_layer, bathy, slope_x, khth_u, open_u, uhD)

u-face GM streamfunction + bolus-transport column recurrence. Interior u-face (i=2..nx) pairs columns iw=i-1 (west) and i (east). Bottom-up sweep: interior interfaces Kr=2 (bed-most) -> nz (surface-most), uhtot=0 at the bed; the surface BC (Sfn=0 at Kr=nz+1) is closed after the loop by uhD(nz)=-uhtot, giving Sum_k uhD=0 exactly. Interface Kr straddles ka=Kr (above) and kb=Kr-1 (below) and fills LAYER kb; the rsum bound keys on ka, the donor h_frac and per-layer cap on kb.

Read more…

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz
real(kind=wp), intent(in) :: i_smax2
real(kind=wp), intent(in) :: i4dt
logical, intent(in) :: use_open
real(kind=wp), intent(in) :: dy_cu(nx+1,ny)
real(kind=wp), intent(in) :: areaT(nx,ny)
real(kind=wp), intent(in) :: h_layer(nx,ny,nz)
real(kind=wp), intent(in) :: bathy(nx,ny)
real(kind=wp), intent(in) :: slope_x(nx+1,ny,nz+1)
real(kind=wp), intent(in) :: khth_u(nx+1,ny)
real(kind=wp), intent(in) :: open_u(nx+1,ny,nz)
real(kind=wp), intent(inout) :: uhD(nx+1,ny,nz)

private pure subroutine gm_column_y(nx, ny, nz, i_smax2, i4dt, use_open, dx_cv, areaT, h_layer, bathy, slope_y, khth_v, open_v, vhD)

v-face GM column recurrence — mirror of gm_column_x with the v-stagger. Interior v-face (j=2..ny) pairs columns js=j-1 (south) and j (north). See gm_column_x for the open-column (use_open) rule and the MOM6 nk_linear divergence note.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz
real(kind=wp), intent(in) :: i_smax2
real(kind=wp), intent(in) :: i4dt
logical, intent(in) :: use_open
real(kind=wp), intent(in) :: dx_cv(nx,ny+1)
real(kind=wp), intent(in) :: areaT(nx,ny)
real(kind=wp), intent(in) :: h_layer(nx,ny,nz)
real(kind=wp), intent(in) :: bathy(nx,ny)
real(kind=wp), intent(in) :: slope_y(nx,ny+1,nz+1)
real(kind=wp), intent(in) :: khth_v(nx,ny+1)
real(kind=wp), intent(in) :: open_v(nx,ny+1,nz)
real(kind=wp), intent(inout) :: vhD(nx,ny+1,nz)

private subroutine gm_compute_impl(nx, ny, nz, dt, khth, khth_max_cfl, slope_max, rho0, use_ext, use_open, dy_cu, dx_cv, idxCu, idyCv, idyCu, idxCv, areaT, wet_u, wet_v, h_layer, bathy, slope_x, slope_y, n2_u, n2_v, khth_ext_u, khth_ext_v, open_u, open_v, khth_u, khth_v, uhD, vhD, gm_src)

Flat-impl GM kernel. Passes: CFL-clamp the 2D face KhTh, the u-face and v-face column recurrences into uhD/vhD, the gm_src PE release. Each face’s column sweep is serial in k (the uhtot recurrence) but faces parallelise over (i,j).

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz
real(kind=wp), intent(in) :: dt
real(kind=wp), intent(in) :: khth
real(kind=wp), intent(in) :: khth_max_cfl
real(kind=wp), intent(in) :: slope_max
real(kind=wp), intent(in) :: rho0
logical, intent(in) :: use_ext
logical, intent(in) :: use_open

z-level closed faces active (metrics%use_closed_faces). .false. ⇒ open_u/open_v are never indexed.

real(kind=wp), intent(in) :: dy_cu(nx+1,ny)
real(kind=wp), intent(in) :: dx_cv(nx,ny+1)
real(kind=wp), intent(in) :: idxCu(nx+1,ny)
real(kind=wp), intent(in) :: idyCv(nx,ny+1)
real(kind=wp), intent(in) :: idyCu(nx+1,ny)
real(kind=wp), intent(in) :: idxCv(nx,ny+1)
real(kind=wp), intent(in) :: areaT(nx,ny)
real(kind=wp), intent(in) :: wet_u(nx+1,ny)
real(kind=wp), intent(in) :: wet_v(nx,ny+1)
real(kind=wp), intent(in) :: h_layer(nx,ny,nz)
real(kind=wp), intent(in) :: bathy(nx,ny)

Bed depth D (m, positive down; slopes%bathy): the bed of each column is at z = −D for the bottom-blocking limiter.

real(kind=wp), intent(in) :: slope_x(nx+1,ny,nz+1)
real(kind=wp), intent(in) :: slope_y(nx,ny+1,nz+1)
real(kind=wp), intent(in) :: n2_u(nx+1,ny,nz+1)
real(kind=wp), intent(in) :: n2_v(nx,ny+1,nz+1)
real(kind=wp), intent(in) :: khth_ext_u(nx+1,ny)
real(kind=wp), intent(in) :: khth_ext_v(nx,ny+1)
real(kind=wp), intent(in) :: open_u(nx+1,ny,nz)

Per-layer 0/1 u-face open mask (metrics%open_u), read only when use_open; an inert device-present stand-in otherwise.

real(kind=wp), intent(in) :: open_v(nx,ny+1,nz)

v-face twin of open_u.

real(kind=wp), intent(out) :: khth_u(nx+1,ny)
real(kind=wp), intent(out) :: khth_v(nx,ny+1)
real(kind=wp), intent(out) :: uhD(nx+1,ny,nz)
real(kind=wp), intent(out) :: vhD(nx,ny+1,nz)
real(kind=wp), intent(out) :: gm_src(nx,ny)

private pure subroutine gm_pe_release(nx, ny, nz, slope_max, rho0, h_layer, slope_x, slope_y, n2_u, n2_v, khth_u, khth_v, gm_src)

GM potential-energy release at cell centres for the MEKE seam: gm_src = 1/4 * Sum_k rho0 * (KHSlope^2N^2) * h over the four straddling faces, summed over interior interfaces; slope clamped to slope_max, N^2 floored at 0. gm_src >= 0 for a stable tilted column. An interface value is attributed to the layer below it (kb=K-1); bed + surface carry zero slope/N^2.

Arguments

Type IntentOptional Attributes Name
integer, intent(in) :: nx
integer, intent(in) :: ny
integer, intent(in) :: nz
real(kind=wp), intent(in) :: slope_max
real(kind=wp), intent(in) :: rho0
real(kind=wp), intent(in) :: h_layer(nx,ny,nz)
real(kind=wp), intent(in) :: slope_x(nx+1,ny,nz+1)
real(kind=wp), intent(in) :: slope_y(nx,ny+1,nz+1)
real(kind=wp), intent(in) :: n2_u(nx+1,ny,nz+1)
real(kind=wp), intent(in) :: n2_v(nx,ny+1,nz+1)
real(kind=wp), intent(in) :: khth_u(nx+1,ny)
real(kind=wp), intent(in) :: khth_v(nx,ny+1)
real(kind=wp), intent(out) :: gm_src(nx,ny)

private subroutine ocean_gm_destroy(this)

Arguments

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

private subroutine ocean_gm_enter_data(this)

Arguments

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

private subroutine ocean_gm_enter_data_impl(this)

Arguments

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

private subroutine ocean_gm_exit_data(this)

Arguments

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

private subroutine ocean_gm_exit_data_impl(this)

Arguments

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

private subroutine ocean_gm_init(this, grid, nz_ml)

Allocate the 2D face KhTh fields, per-layer face transports, and the gm_src PE-release diagnostic. Always allocates (configure runs after init); host allocation (no do concurrent before enter_data).

Arguments

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