Fox-Kemper, Ferrari & Hallberg (2008) submesoscale mixed-layer-eddy
(MLE) restratification. Submesoscale eddies slump lateral buoyancy
fronts in the surface mixed layer via an overturning streamfunction
Psi(z) = Ce * (H_ml^2 / |f|) * (grad b_bar x z_hat) * mu(z)
injected as extra ML-confined per-layer mass transports uhml/vhml
added to ms%mass_flux_{x,y}_layer BEFORE the continuity divergence +
PPM tracer advection — never touching the velocity fields. The
per-layer weights a(k) satisfy sum_k a(k) = mu(0) - mu(-1) = 0
exactly (a closed overturning cell ⇒ mass/tracer conservative).
Vertical convention: k=1 bed, k=nz surface. The ML band walks from
the surface down; the FK sigma coordinate is 0 at the surface,
-1 at the ML base. H_ml is the EPBL epbl%mld. Timescale forms
(use_mom_mixrate): bare Ce/max(|f|,f_floor) (default), or FK11
momentum-mixrate (production-recommended; suppresses restratification
under vigorous mixing). Default off ⇒ bit-identical.
&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 BEFORE
mle_fold_x/y adds uhml/vhml, so the overturning must be built
on the OPEN part of each face column here. With the knob on:
rdb_vl_is_live), so no ML property is read from a
filler and the walk starts at the first live layer from the top
(the free surface, or the ice base under a draft);hf(k) = 0 off the open set ⇒ sigma is carried unchanged across
it ⇒ a(k) = mu(s) - mu(s) = 0): sigma = 0 at the TOP of the open
column, so a filler above it (ice draft) carries nothing;H_vel is clamped to the open-column thickness Sum_k hf(k).
The sigma walk must reach -1 inside the open column for
Sum_k a(k) = mu(0) - mu(-1) = 0; with the ML deeper than a
face’s open column (a deep column abutting a shallow step) the
unclamped walk stops above -1 and the face transport no longer
closes (prototype python_prototypes/mle_zfixed: Sum a = -0.93).
The clamped H_vel also sets the H_vel^2 amplitude and the
timescale’s H_vel: the cell a face can carry is at most as deep
as its open column;uhml/vhml are written EXACTLY zero off the open set.Hence the FK transport is zero on every closed face-layer and every
filler, its face streamfunction vanishes at the top of the open
column and below the ML (at the latest at the open column’s bottom),
and Sum_k uhml = 0 at every face. The open face thickness is
staged in uhml/vhml themselves by a host-gated pre-pass, so the
transport kernels never name the (1,1,1) mask placeholders with the
knob off. Knob OFF ⇒ byte-identical.
References: Fox-Kemper, Ferrari & Hallberg (2008); Fox-Kemper et al. (2011).
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private, | parameter | :: | H_NEGLECT | = | 1.0e-30_wp |
Empty-column guard (spec 3.1 / 3.4). |
| real(kind=wp), | private, | parameter | :: | MLE_H_AVAIL_MIN | = | 1.0e-6_wp |
Floor for the per-layer transport availability cap (m): a donor
layer may never be drained below this by the FK overturning.
Matched to the continuity / windowed-drain |
| real(kind=wp), | private, | parameter | :: | PI | = | 3.14159265358979323846_wp | |
| real(kind=wp), | private, | parameter | :: | VONKAR | = | 0.41_wp |
von Karman constant for the FK11 momentum-mixrate form. |
Fox-Kemper mixed-layer-eddy restratification state. All fields
default to the inert (enable=.false.) configuration so an
ocean run that never sets &ocean_foxkemper_nml is bit-identical.
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | public, | allocatable | :: | b_ml(:,:) |
ML-averaged buoyancy b_bar (m/s^2), |
||
| real(kind=wp), | public | :: | bodner_mstar | = | 0.5_wp |
Mechanical (u*) weight in |
|
| real(kind=wp), | public | :: | bodner_nstar | = | 0.066_wp |
Convective (w*) weight; |
|
| real(kind=wp), | public | :: | ce | = | 0.0625_wp |
FK08 coefficient Ce (typical 0.06-0.08). |
|
| real(kind=wp), | public | :: | cr | = | 0.0_wp |
Bodner efficiency coefficient |
|
| logical, | public | :: | enable | = | .false. |
Master switch. Off => |
|
| real(kind=wp), | public | :: | f_floor | = | 1.0e-5_wp |
|f| regularisation floor (1/s); ~|f| at 4 degN. |
|
| real(kind=wp), | public, | allocatable | :: | htot_ml(:,:) |
Accumulated ML thickness on the grid (<= mld) (m), |
||
| logical, | public | :: | is_init | = | .false. |
True between |
|
| real(kind=wp), | public | :: | min_wstar2 | = | 1.0e-24_wp |
Floor on |
|
| real(kind=wp), | public | :: | mld_decay_time | = | 0.0_wp |
Running-mean MLD filter time-scale (s). 0 ⇒ filter off (instantaneous EPBL MLD, bit-identical). Positive ⇒ the MLD resets instantly to a deeper value but decays over this scale when the diagnosed MLD retreats, bounding Psi ~ MLD² growth under a thinning/oscillating boundary layer. |
|
| real(kind=wp), | public, | allocatable | :: | mld_filtered(:,:) |
Running-mean filtered MLD (m), |
||
| integer, | public | :: | nx_total | = | 0 | ||
| integer, | public | :: | ny_total | = | 0 | ||
| integer, | public | :: | nz_ml | = | 0 | ||
| logical, | public | :: | resolution_taper | = | .false. |
Resolution-function taper hook. Hard config error if on without the resolution function (deferred). |
|
| real(kind=wp), | public | :: | tail_dh | = | 0.0_wp |
mu cubic-tail extension below the ML base. Default 0 ⇒ exact FK08 mu (the tail itself is deferred). |
|
| real(kind=wp), | public, | allocatable | :: | uhml(:,:,:) |
FK x-face transport (m^3/s), |
||
| logical, | public | :: | use_bodner | = | .false. |
Bodner et al. (2023) frontogenesis-arrest variant. When true the
|
|
| logical, | public | :: | use_mom_mixrate | = | .false. |
Use the FK11 momentum-mixrate timescale instead of the bare Ce/|f| floor form. Production-recommended; default off. |
|
| real(kind=wp), | public, | allocatable | :: | vhml(:,:,:) |
FK y-face transport (m^3/s), |
| procedure, public, non_overridable :: bytes => ocean_mle_bytes | |
| procedure, public :: destroy => ocean_mle_destroy | |
| procedure, public :: enter_data => ocean_mle_enter_data | |
| procedure, public :: exit_data => ocean_mle_exit_data | |
| procedure, public :: init => ocean_mle_init |
FK08 second-order vertical structure function mu(sigma). sigma in [-1,0]: 0 = surface interface, -1 = ML base. mu = 0 at sigma=0 (surface) and sigma <= -1 (ML base); peaks near sigma=-0.5.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | sigma |
Bodner et al. (2023) frontogenesis-arrest MLE timescale [s]:
ts = Cr · ds · |f| · h / w’u’
where the frontal-arrest length enters inline as |f|·h/w'u' and
w’u’ = max( (mstar·u³ + nstar·w³)^(2/3), min_wstar2 ),
w³ = max(0, -b0)·h (destabilizing buoyancy flux only)
ds = sqrt(0.5(dx²+dy²)) is the grid-scale front width. Because the
product is dimensionally a TIME, this drops straight into the FK
transport form uDml = ts·dyCu·idxCu·db·H² (the swap that turns
classic Fox-Kemper into Bodner). w'u' is floored so a quiescent,
unforced column (u→0, b0→0) never divides by zero.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | f_abs | |||
| real(kind=wp), | intent(in) | :: | ustar | |||
| real(kind=wp), | intent(in) | :: | h_vel | |||
| real(kind=wp), | intent(in) | :: | b0_face | |||
| real(kind=wp), | intent(in) | :: | ds | |||
| real(kind=wp), | intent(in) | :: | cr | |||
| real(kind=wp), | intent(in) | :: | mstar | |||
| real(kind=wp), | intent(in) | :: | nstar | |||
| real(kind=wp), | intent(in) | :: | min_wstar2 |
Friction velocity u* = sqrt(|tau|/rho0) at the u-face from the surface wind stress, averaged onto the face. Only used by the FK11 mixrate form. Returns 0 if stress fields are absent.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_surface_stress_t), | intent(in) | :: | ss | |||
| real(kind=wp), | intent(in) | :: | rho0 | |||
| integer, | intent(in) | :: | i | |||
| integer, | intent(in) | :: | j |
u* at the v-face; mirror of mle_face_ustar_x.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_surface_stress_t), | intent(in) | :: | ss | |||
| real(kind=wp), | intent(in) | :: | rho0 | |||
| integer, | intent(in) | :: | i | |||
| integer, | intent(in) | :: | j |
FK restratification timescale [s].
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | f_abs | |||
| real(kind=wp), | intent(in) | :: | ustar | |||
| real(kind=wp), | intent(in) | :: | h_vel | |||
| real(kind=wp), | intent(in) | :: | ce | |||
| real(kind=wp), | intent(in) | :: | f_floor | |||
| logical, | intent(in) | :: | use_mom_mixrate |
Counted allocatable footprint of the MLE / Fox-Kemper slot (0 when unallocated). One arr_bytes term per array — add a term here when a new allocatable joins the type.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_mle_t), | intent(in) | :: | this |
Fill uhml/vhml (m^3/s) with the FK MLE overturning transport.
Run once per outer step at thermo cadence, before the continuity
divergence. Steps: (1) b_ml + htot_ml at cell centres (surface→bed
band to mld, partial-weight the straddling layer); (2) uDml/vDml at
faces from grad b_bar, timescale, H_vel²; (2b) optional per-layer
availability cap (a scalar shrink keeping sum_k a(k)=0); (3) fold
the mu profile a(k) → uhml/vhml. No-op when enable=.false. or
the slot / state arrays are absent.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(ocean_mle_t), | intent(inout) | :: | this | |||
| type(multilayer_state_t), | intent(in) | :: | ms | |||
| type(ocean_epbl_t), | intent(in) | :: | epbl | |||
| type(ocean_surface_stress_t), | intent(in), | optional | :: | ss | ||
| real(kind=wp), | intent(in), | optional | :: | dt_limit |
Window (s) the FK transport is integrated over (= |
|
| type(ocean_bc_state_t), | intent(in), | optional | :: | bc |
Per-edge OBC tags. Masks the FK transport on closed (non-periodic) physical wall faces so no MLE overturning crosses a land boundary. Absent ⇒ array-edge zeroing only. |
Add the FK x-face transport into the per-layer zonal mass flux,
AFTER continuity_zonal_flux fills it and BEFORE the zonal
tracer advect / divergence — so the augmented flux transports
both h and tracers (conservative; no velocity touched).
No-op when disabled.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_mle_t), | intent(in) | :: | this | |||
| real(kind=wp), | intent(inout) | :: | mass_flux_x_layer(nx1,ny,nz) | |||
| integer, | intent(in) | :: | nx1 | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz |
Add the FK y-face transport into the per-layer meridional mass
flux. Mirror of mle_fold_x. No-op when disabled.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_mle_t), | intent(in) | :: | this | |||
| real(kind=wp), | intent(inout) | :: | mass_flux_y_layer(nx,ny1,nz) | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny1 | |||
| integer, | intent(in) | :: | nz |
Per-layer transport weights a(k) = mu(sigma_top) - mu(sigma_bot),
walking surface (k=nz) -> bed (k=1). sum_k a(k) = mu(0)-mu(-1) = 0
(closed cell => conservation). Layers below the ML base get
sigma <= -1 => mu=0 on both interfaces => a(k)=0 (ML-confinement).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| real(kind=wp), | intent(in) | :: | h_face(nz) | |||
| integer, | intent(in) | :: | nz | |||
| real(kind=wp), | intent(in) | :: | h_vel | |||
| real(kind=wp), | intent(out) | :: | a(nz) |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_mle_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_mle_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_mle_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_mle_t), | intent(inout) | :: | this |
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(ocean_mle_t), | intent(inout) | :: | this |
Allocate the 2D ML diagnostics + per-layer face transports. Always allocates (configure runs after init); the off-state footprint is two 2D + two face-shaped 3D arrays.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_mle_t), | intent(inout) | :: | this | |||
| type(hgrid_t), | intent(in) | :: | grid | |||
| integer, | intent(in), | optional | :: | nz_ml |