ocean_meke_t Derived Type

type, public :: ocean_meke_t

Mesoscale eddy kinetic energy state. All fields default to the inert (enable=.false.) configuration so an ocean run that never sets &ocean_meke_nml is bit-identical.


Inherited by

type~~ocean_meke_t~~InheritedByGraph type~ocean_meke_t ocean_meke_t type~ocean_state_t ocean_state_t type~ocean_state_t->type~ocean_meke_t meke type~ocean_engine_t ocean_engine_t type~ocean_engine_t->type~ocean_state_t state type~ocean_handle_t ocean_handle_t type~ocean_handle_t->type~ocean_state_t state type~ocean_handle_t->type~ocean_engine_t engine

Components

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

Scaling on the barotropic-transport advection of MEKE (nondim); 0 (default) ⇒ the advection stage is skipped ⇒ bit-identical.

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

Weight on the deformation length scale Ldeform (nondim).

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

Weight on the Eady length scale Leady (needs VarMix SN) (nondim).

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

Weight on the frictional-arrest length scale Lfrict (nondim).

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

Weight on the grid length scale Lgrid (nondim).

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

Weight on the Rhines length scale Lrhines = sqrt(Ueddy/beta) (nondim). Default 0 ⇒ beta term inert; > 0 activates the Rhines scale (needs f_centre filled, done at setup).

logical, public :: backscatter = .false.

Master switch for the MEKE → momentum negative-viscosity energy return (capability Gap 2). Default .false. ⇒ the ku field stays 0 and meke_backscatter_apply adds nothing ⇒ bit-identical. When .true., meke_step fills ku and the driver subtracts it from the per-face harmonic viscosity, returning eddy energy to the resolved flow. HARMONIC only in v1 (the biharmonic Au return + EBT/SQG vertical structure BS_struct are deferred). Needs enable=.true. (so meke_step runs and refreshes ku) — inert otherwise.

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

Depth-integrated u-face mass transport (kg/s), (nx+1,ny); the barotropic transport that advects E. Filled only when advection_factor > 0.

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

Depth-integrated v-face mass transport (kg/s), (nx,ny+1).

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

gamma_t^2 (nondim), (nx,ny).

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

Background energy source (m^2/s^3).

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

gamma_b^2 (nondim), (nx,ny).

real(kind=wp), public :: cb = 25.0_wp

Coefficient in the gamma_bot (bottomFac2) expression (nondim).

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

Ratio of bottom eddy velocity to column-mean eddy velocity (nondim); enters bottomFac2.

real(kind=wp), public :: cdrag = 2.5e-3_wp

Bottom drag coefficient for MEKE (nondim). Copied from &ocean_bdrag_nml cdrag_side at configure if that is > 0, else this default; enters drag_rate + Lfrict.

real(kind=wp), public :: ct = 50.0_wp

Coefficient in the gamma_bt (barotrFac2) expression (nondim).

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

Local depth-independent linear MEKE dissipation rate (1/s).

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

Laplacian of MEKE workspace (biharmonic), (nx,ny).

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

Total column thickness (m), (nx,ny); used in Lfrict.

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

Scale factor accelerating MEKE time-stepping (nondim).

logical, public :: enable = .false.

Master switch. Off ⇒ meke_step is never called. Requires &ocean_gm_nml enable (needs gm%gm_src); loud configure check.

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

|f| at cell centres (1/s), (nx,ny); filled by set_f_centre from the same beta-plane the Coriolis slot uses (mirrors EPBL / kappa-shear). Drives beta = |grad f| for the Rhines length. Zero until filled ⇒ Rhines weight inert (alpha_rhines default 0).

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

Efficiency of mean->eddy frictional conversion (nondim); < 0 (default) ⇒ off ⇒ bit-identical. When >= 0, adds the frictional source -frcoeff*i_mass*ke_diss from the lateral-viscosity KE dissipation (hvisc%ke_diss).

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

Efficiency of PE->MEKE conversion (nondim). < 0 ⇒ GM source off.

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

1 / column mass (m^2/kg), (nx,ny).

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 :: k4 = -1.0_wp

Background biharmonic diffusion of MEKE (m^4/s). < 0 ⇒ off.

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

Staged hvisc KE-dissipation rate (kg/s³, ≤0), (nx,ny); copied from hv%ke_diss when the frictional source is wired, else 0. Feeds meke_source as -frcoeff·i_mass·ke_diss.

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

Background lateral diffusion of MEKE (m^2/s). < 0 ⇒ diffusion stage off.

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

Derived MEKE diffusivity kh (m^2/s), (nx,ny); fed (geom-mean) into VarMix’s face KhTh/KhTr.

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

Scaling converting MEKE into Kh (nondim). <= 0 ⇒ closure off.

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

Factor relating meke%kh (the derived diffusivity) to the diffusivity used for MEKE’s own lateral spreading (nondim).

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

Factor on the geometric-mean kh added into VarMix’s KhTh face field (nondim). 0 (default) ⇒ feedback inert ⇒ bit-identical.

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

Factor on the geometric-mean kh added into VarMix’s KhTr face field (nondim). 0 (default) ⇒ inert.

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

Derived harmonic backscatter viscosity Ku (m²/s), (nx,ny); ku = visc_coeff_ku·sqrt(2·gamma_t²·E)·Lmix. Zero unless backscatter. Subtracted (face-averaged, stability-floored) from the resolved harmonic viscosity by meke_backscatter_apply.

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

Mixing length scale Lmix (m), (nx,ny) (diagnostic).

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

Column mass (kg/m^2), (nx,ny); the harmonic-mass input for the lateral flux (= 1/i_mass where i_mass>0).

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

Eddy kinetic energy E (m^2/s^2), (nx,ny). PROGNOSTIC — restart-persistent.

real(kind=wp), public :: min_gamma2 = 1.0e-4_wp

Floor on gamma_b^2 / gamma_t^2 (nondim).

integer, public :: nx_total = 0
integer, public :: ny_total = 0
integer, public :: nz_ml = 0
real(kind=wp), public, allocatable :: rd_ws(:,:)

Staged copy of wavespeed%rd_over_dx (nondim), (nx,ny); zero when wavespeed absent ⇒ Ldeform→0.

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

Staged copy of varmix%sn_u (1/s), (nx+1,ny); zero when VarMix absent ⇒ Eady scale inert.

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

Staged copy of varmix%sn_v (1/s), (nx,ny+1).

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

Aggregate source (m^2/s^3), (nx,ny).

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

Resolved bed-layer speed² (m²/s²) at cell centres, (nx,ny); filled from ms when use_bbl_drag, else 0. Feeds meke_drag.

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

u-face MEKE flux workspace, (nx+1,ny).

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

Background (e.g. tidal) eddy velocity scale for bottom drag (m/s).

logical, public :: use_bbl_drag = .false.

Add the resolved bed-layer eddy velocity |u_bed|² to the MEKE bottom-drag rate drag_rate = rho0·i_mass·sqrt(cdrag²·(2·bf2·E + |u_bed|² + uscale²)) (MOM6 drag_rate_visc). Default off ⇒ the u_bbl² workspace stays 0 ⇒ bit-identical to the prior drag.

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

v-face MEKE flux workspace, (nx,ny+1).

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

MOM6 MEKE_VISCOSITY_COEFF_KU — the nondimensional efficiency of the harmonic backscatter viscosity Ku = visc_coeff_ku·sqrt(2·gamma_t²·E)·Lmix (m²/s). May be negative in MOM6 (negative viscosity); here it is the magnitude coefficient and the SIGN of the momentum effect is set by the SUBTRACTION in meke_backscatter_apply (A_net = A − Ku), so a positive visc_coeff_ku returns energy. 0 (default) ⇒ inert.


Type-Bound Procedures

procedure, public, non_overridable :: bytes => ocean_meke_bytes

  • private pure function ocean_meke_bytes(this) result(nbytes)

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

    Return Value integer(kind=int64)

procedure, public, non_overridable :: destroy => ocean_meke_destroy

procedure, public, non_overridable :: enter_data => ocean_meke_enter_data

procedure, public, non_overridable :: exit_data => ocean_meke_exit_data

procedure, public, non_overridable :: init => ocean_meke_init

  • private subroutine ocean_meke_init(this, grid, nz_ml)

    Allocate the prognostic field, the derived diffusivity, and the Strang-stage workspaces. Always allocates (configure runs after init); setup uses plain host allocation (no do concurrent before enter_data).

    Arguments

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

procedure, public, non_overridable :: set_f_centre => ocean_meke_set_f_centre

  • private subroutine ocean_meke_set_f_centre(this, grid, f_centre)

    Copy a pre-filled cell-centre Coriolis magnitude |f| (1/s) onto the MEKE slot, so beta = |grad f| for the Rhines length is live. The caller (setup) builds f_centre with the same metrics_fill_coriolis path the Coriolis / VarMix / EPBL slots use (handles beta-plane AND spherical). Host loop — call after init, before enter_data.

    Arguments

    Type IntentOptional Attributes Name
    class(ocean_meke_t), intent(inout) :: this
    type(hgrid_t), intent(in) :: grid
    real(kind=wp), intent(in) :: f_centre(grid%nx_total,grid%ny_total)

Source Code

   type :: ocean_meke_t
      !! Mesoscale eddy kinetic energy state.  All fields default to the
      !! inert (`enable=.false.`) configuration so an ocean run that never
      !! sets `&ocean_meke_nml` is bit-identical.
      logical :: is_init = .false.
         !! True between `init` and `destroy`; gate on this (never on
         !! `allocated`, which misses the GPU mapping).
      logical :: enable = .false.
         !! Master switch.  Off ⇒ `meke_step` is never called.  Requires
         !! `&ocean_gm_nml enable` (needs `gm%gm_src`); loud configure check.

      ! ---- Source / sink coefficients ----
      real(wp) :: gmcoeff = -1.0_wp
         !! Efficiency of PE->MEKE conversion (nondim).  < 0 ⇒ GM source off.
      real(wp) :: frcoeff = -1.0_wp
         !! Efficiency of mean->eddy frictional conversion (nondim); < 0
         !! (default) ⇒ off ⇒ bit-identical.  When >= 0, adds the frictional
         !! source `-frcoeff*i_mass*ke_diss` from the lateral-viscosity KE
         !! dissipation (`hvisc%ke_diss`).
      real(wp) :: bgsrc = 0.0_wp
         !! Background energy source (m^2/s^3).
      real(wp) :: damping = 0.0_wp
         !! Local depth-independent linear MEKE dissipation rate (1/s).

      ! ---- Lateral transport ----
      real(wp) :: kh = -1.0_wp
         !! Background lateral diffusion of MEKE (m^2/s).  < 0 ⇒ diffusion
         !! stage off.
      real(wp) :: k4 = -1.0_wp
         !! Background biharmonic diffusion of MEKE (m^4/s).  < 0 ⇒ off.
      real(wp) :: khmeke_fac = 0.0_wp
         !! Factor relating `meke%kh` (the derived diffusivity) to the
         !! diffusivity used for MEKE's own lateral spreading (nondim).
      real(wp) :: advection_factor = 0.0_wp
         !! Scaling on the barotropic-transport advection of MEKE (nondim);
         !! 0 (default) ⇒ the advection stage is skipped ⇒ bit-identical.

      ! ---- KhTh closure ----
      real(wp) :: khcoeff = 1.0_wp
         !! Scaling converting MEKE into Kh (nondim).  <= 0 ⇒ closure off.
      real(wp) :: cd_scale = 0.0_wp
         !! Ratio of bottom eddy velocity to column-mean eddy velocity
         !! (nondim); enters bottomFac2.
      real(wp) :: cb = 25.0_wp
         !! Coefficient in the gamma_bot (bottomFac2) expression (nondim).
      real(wp) :: ct = 50.0_wp
         !! Coefficient in the gamma_bt (barotrFac2) expression (nondim).
      real(wp) :: min_gamma2 = 1.0e-4_wp
         !! Floor on gamma_b^2 / gamma_t^2 (nondim).
      real(wp) :: uscale = 0.0_wp
         !! Background (e.g. tidal) eddy velocity scale for bottom drag (m/s).
      real(wp) :: dtscale = 1.0_wp
         !! Scale factor accelerating MEKE time-stepping (nondim).
      real(wp) :: cdrag = 2.5e-3_wp
         !! Bottom drag coefficient for MEKE (nondim).  Copied from
         !! `&ocean_bdrag_nml cdrag_side` at configure if that is > 0,
         !! else this default; enters drag_rate + Lfrict.
      logical :: use_bbl_drag = .false.
         !! Add the resolved bed-layer eddy velocity `|u_bed|²` to the MEKE
         !! bottom-drag rate `drag_rate = rho0·i_mass·sqrt(cdrag²·(2·bf2·E +
         !! |u_bed|² + uscale²))` (MOM6 `drag_rate_visc`).  Default off ⇒ the
         !! `u_bbl²` workspace stays 0 ⇒ bit-identical to the prior drag.

      ! ---- Length-scale alpha weights (default all 0 ⇒ Lmix path inert) ----
      real(wp) :: alpha_deform = 0.0_wp
         !! Weight on the deformation length scale Ldeform (nondim).
      real(wp) :: alpha_rhines = 0.0_wp
         !! Weight on the Rhines length scale Lrhines = sqrt(Ueddy/beta)
         !! (nondim).  Default 0 ⇒ beta term inert; > 0 activates the
         !! Rhines scale (needs `f_centre` filled, done at setup).
      real(wp) :: alpha_eady = 0.0_wp
         !! Weight on the Eady length scale Leady (needs VarMix SN) (nondim).
      real(wp) :: alpha_frict = 0.0_wp
         !! Weight on the frictional-arrest length scale Lfrict (nondim).
      real(wp) :: alpha_grid = 0.0_wp
         !! Weight on the grid length scale Lgrid (nondim).

      ! ---- Feedback seam factors ----
      real(wp) :: khth_fac = 0.0_wp
         !! Factor on the geometric-mean kh added into VarMix's KhTh face
         !! field (nondim).  0 (default) ⇒ feedback inert ⇒ bit-identical.
      real(wp) :: khtr_fac = 0.0_wp
         !! Factor on the geometric-mean kh added into VarMix's KhTr face
         !! field (nondim).  0 (default) ⇒ inert.

      ! ---- Backscatter (negative-viscosity momentum energy return, v1) ----
      logical :: backscatter = .false.
         !! Master switch for the MEKE → momentum negative-viscosity
         !! energy return (capability Gap 2).  Default `.false.` ⇒ the
         !! `ku` field stays 0 and `meke_backscatter_apply` adds nothing
         !! ⇒ bit-identical.  When `.true.`, `meke_step` fills `ku` and the
         !! driver subtracts it from the per-face harmonic viscosity,
         !! returning eddy energy to the resolved flow.  HARMONIC only in
         !! v1 (the biharmonic `Au` return + EBT/SQG vertical structure
         !! `BS_struct` are deferred).  Needs `enable=.true.` (so `meke_step`
         !! runs and refreshes `ku`) — inert otherwise.
      real(wp) :: visc_coeff_ku = 0.0_wp
         !! MOM6 `MEKE_VISCOSITY_COEFF_KU` — the nondimensional efficiency
         !! of the harmonic backscatter viscosity
         !! `Ku = visc_coeff_ku·sqrt(2·gamma_t²·E)·Lmix` (m²/s).  May be
         !! negative in MOM6 (negative viscosity); here it is the magnitude
         !! coefficient and the SIGN of the momentum effect is set by the
         !! SUBTRACTION in `meke_backscatter_apply` (`A_net = A − Ku`), so a
         !! positive `visc_coeff_ku` returns energy.  0 (default) ⇒ inert.

      ! ---- Cached extents ----
      integer :: nx_total = 0
      integer :: ny_total = 0
      integer :: nz_ml = 0

      ! ---- Prognostic + derived 2D fields ----
      real(wp), allocatable :: meke(:, :)
         !! Eddy kinetic energy E (m^2/s^2), `(nx,ny)`.  PROGNOSTIC —
         !! restart-persistent.
      real(wp), allocatable :: kh_diff(:, :)
         !! Derived MEKE diffusivity kh (m^2/s), `(nx,ny)`; fed (geom-mean)
         !! into VarMix's face KhTh/KhTr.
      real(wp), allocatable :: le(:, :)
         !! Mixing length scale Lmix (m), `(nx,ny)` (diagnostic).
      real(wp), allocatable :: ku(:, :)
         !! Derived harmonic backscatter viscosity Ku (m²/s), `(nx,ny)`;
         !! `ku = visc_coeff_ku·sqrt(2·gamma_t²·E)·Lmix`.  Zero unless
         !! `backscatter`.  Subtracted (face-averaged, stability-floored)
         !! from the resolved harmonic viscosity by `meke_backscatter_apply`.

      ! ---- Strang-stage workspace ----
      real(wp), allocatable :: i_mass(:, :)
         !! 1 / column mass (m^2/kg), `(nx,ny)`.
      real(wp), allocatable :: depth_tot(:, :)
         !! Total column thickness (m), `(nx,ny)`; used in Lfrict.
      real(wp), allocatable :: bottom_fac2(:, :)
         !! gamma_b^2 (nondim), `(nx,ny)`.
      real(wp), allocatable :: barotr_fac2(:, :)
         !! gamma_t^2 (nondim), `(nx,ny)`.
      real(wp), allocatable :: src(:, :)
         !! Aggregate source (m^2/s^3), `(nx,ny)`.
      real(wp), allocatable :: uflux(:, :)
         !! u-face MEKE flux workspace, `(nx+1,ny)`.
      real(wp), allocatable :: vflux(:, :)
         !! v-face MEKE flux workspace, `(nx,ny+1)`.
      real(wp), allocatable :: del2(:, :)
         !! Laplacian of MEKE workspace (biharmonic), `(nx,ny)`.
      real(wp), allocatable :: mass_ws(:, :)
         !! Column mass (kg/m^2), `(nx,ny)`; the harmonic-mass input for the
         !! lateral flux (= 1/i_mass where i_mass>0).
      real(wp), allocatable :: u_bbl2(:, :)
         !! Resolved bed-layer speed² (m²/s²) at cell centres, `(nx,ny)`;
         !! filled from `ms` when `use_bbl_drag`, else 0.  Feeds `meke_drag`.
      real(wp), allocatable :: ke_diss_ws(:, :)
         !! Staged hvisc KE-dissipation rate (kg/s³, ≤0), `(nx,ny)`; copied
         !! from `hv%ke_diss` when the frictional source is wired, else 0.
         !! Feeds `meke_source` as `-frcoeff·i_mass·ke_diss`.
      real(wp), allocatable :: rd_ws(:, :)
         !! Staged copy of `wavespeed%rd_over_dx` (nondim), `(nx,ny)`; zero
         !! when wavespeed absent ⇒ Ldeform→0.
      real(wp), allocatable :: f_centre(:, :)
         !! |f| at cell centres (1/s), `(nx,ny)`; filled by `set_f_centre`
         !! from the same beta-plane the Coriolis slot uses (mirrors EPBL /
         !! kappa-shear).  Drives `beta = |grad f|` for the Rhines length.
         !! Zero until filled ⇒ Rhines weight inert (alpha_rhines default 0).
      real(wp), allocatable :: sn_u_ws(:, :)
         !! Staged copy of `varmix%sn_u` (1/s), `(nx+1,ny)`; zero when VarMix
         !! absent ⇒ Eady scale inert.
      real(wp), allocatable :: sn_v_ws(:, :)
         !! Staged copy of `varmix%sn_v` (1/s), `(nx,ny+1)`.
      real(wp), allocatable :: baro_hu(:, :)
         !! Depth-integrated u-face mass transport (kg/s), `(nx+1,ny)`;
         !! the barotropic transport that advects E.  Filled only when
         !! `advection_factor > 0`.
      real(wp), allocatable :: baro_hv(:, :)
         !! Depth-integrated v-face mass transport (kg/s), `(nx,ny+1)`.
   contains
      procedure, non_overridable :: init => ocean_meke_init
      procedure, non_overridable :: destroy => ocean_meke_destroy
      procedure, non_overridable :: enter_data => ocean_meke_enter_data
      procedure, non_overridable :: exit_data => ocean_meke_exit_data
      procedure, non_overridable :: set_f_centre => ocean_meke_set_f_centre
      procedure, non_overridable :: bytes => ocean_meke_bytes
   end type ocean_meke_t