Inject the MEKE harmonic backscatter into the per-face resolved
harmonic viscosity (capability Gap 2, v1). Subtracts a face-average
of the cell-centred ku field from ah_face_x/ah_face_y so the
NET coefficient A_net = A_resolved − Ku can go NEGATIVE — that
negative viscosity is the energy return into the momentum tendency
(the hvisc Laplacian kernel reads these same face fields).
STABILITY: a negative explicit Laplacian viscosity AMPLIFIES
grid-scale modes — a pure negative Laplacian is unconditionally
unstable (g = 1 + |A|·dt·k² > 1). The floor does NOT by itself
make the operator stable; it bounds the negative mode’s GROWTH
RATE so a co-present POSITIVE biharmonic (Smag_AH / nu_4 /
leith_biharm) can dissipate the grid-scale mode the backscatter
feeds. The net magnitude is floored at the forward-Euler bound
|A|·dt·(idx²+idy²) ≤ backscatter_cfl·0.5, i.e.
A_floor = −backscatter_cfl·0.5/(dt·(idx²+idy²)) per face
(backscatter_cfl = 0.8 safety; MOM6 BACKSCATTER_UNDERBOUND
analogue). Result: ah_face <- max(A_resolved − Ku, A_floor).
A biharmonic backstop is therefore MANDATORY when backscatter
is on — enforced fail-loud at configure (validate_config).
No-op (bit-identical) when backscatter is off or the slot is
uninitialised. GPU-resident: explicit-shape flat-impl dispatch.
Run AFTER ocean_lateral_mix_compute (which fills ah_face_*) and
BEFORE ocean_horizontal_viscosity_compute_tendencies consumes them.
Uses the PREVIOUS thermo step’s ku (a one-step lag, like the
kh→KhTh feedback) — meke_step refreshes ku once per outer step.
REQUIRES a flow-aware lateral closure (&ocean_hvisc_nml
lateral_closure = leith/smag ⇒ LMIX_*): the hvisc Laplacian
only reads ah_face_* when closure /= LMIX_NONE. With the
default scalar-nu_h path the modified faces are never consumed,
so backscatter has no effect (it is still bit-identical when off).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| type(hgrid_t), | intent(in) | :: | grid | |||
| type(ocean_metrics_t), | intent(in) | :: | metrics | |||
| type(ocean_meke_t), | intent(in) | :: | this | |||
| real(kind=wp), | intent(in) | :: | dt | |||
| real(kind=wp), | intent(inout) | :: | ah_face_x(:,:,:) | |||
| real(kind=wp), | intent(inout) | :: | ah_face_y(:,:,:) |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | nx | ||||
| integer, | private | :: | ny | ||||
| integer, | private | :: | nz |
pure subroutine meke_backscatter_apply(grid, metrics, this, dt, ah_face_x, ah_face_y) !! Inject the MEKE harmonic backscatter into the per-face resolved !! harmonic viscosity (capability Gap 2, v1). Subtracts a face-average !! of the cell-centred `ku` field from `ah_face_x`/`ah_face_y` so the !! NET coefficient `A_net = A_resolved − Ku` can go NEGATIVE — that !! negative viscosity is the energy return into the momentum tendency !! (the hvisc Laplacian kernel reads these same face fields). !! !! STABILITY: a negative explicit Laplacian viscosity AMPLIFIES !! grid-scale modes — a pure negative Laplacian is unconditionally !! unstable (`g = 1 + |A|·dt·k² > 1`). The floor does NOT by itself !! make the operator stable; it bounds the negative mode's GROWTH !! RATE so a co-present POSITIVE biharmonic (Smag_AH / `nu_4` / !! `leith_biharm`) can dissipate the grid-scale mode the backscatter !! feeds. The net magnitude is floored at the forward-Euler bound !! `|A|·dt·(idx²+idy²) ≤ backscatter_cfl·0.5`, i.e. !! `A_floor = −backscatter_cfl·0.5/(dt·(idx²+idy²))` per face !! (`backscatter_cfl = 0.8` safety; MOM6 `BACKSCATTER_UNDERBOUND` !! analogue). Result: `ah_face <- max(A_resolved − Ku, A_floor)`. !! A biharmonic backstop is therefore MANDATORY when `backscatter` !! is on — enforced fail-loud at configure (`validate_config`). !! !! No-op (bit-identical) when `backscatter` is off or the slot is !! uninitialised. GPU-resident: explicit-shape flat-impl dispatch. !! Run AFTER `ocean_lateral_mix_compute` (which fills `ah_face_*`) and !! BEFORE `ocean_horizontal_viscosity_compute_tendencies` consumes them. !! Uses the PREVIOUS thermo step's `ku` (a one-step lag, like the !! kh→KhTh feedback) — `meke_step` refreshes `ku` once per outer step. !! !! REQUIRES a flow-aware lateral closure (`&ocean_hvisc_nml !! lateral_closure` = `leith`/`smag` ⇒ `LMIX_*`): the hvisc Laplacian !! only reads `ah_face_*` when `closure /= LMIX_NONE`. With the !! default scalar-`nu_h` path the modified faces are never consumed, !! so backscatter has no effect (it is still bit-identical when off). type(hgrid_t), intent(in) :: grid type(ocean_metrics_t), intent(in) :: metrics type(ocean_meke_t), intent(in) :: this real(wp), intent(in) :: dt real(wp), intent(inout) :: ah_face_x(:, :, :) real(wp), intent(inout) :: ah_face_y(:, :, :) integer :: nx, ny, nz if (.not. this%is_init) return if (.not. this%backscatter) return if (.not. allocated(this%ku)) return nx = grid%nx_total ny = grid%ny_total nz = size(ah_face_x, 3) if (this%nx_total /= nx .or. this%ny_total /= ny) return call meke_backscatter_apply_impl(nx, ny, nz, dt, BACKSCATTER_CFL, this%ku, & metrics%idxCu, metrics%idyCu, & metrics%idxCv, metrics%idyCv, & ah_face_x, ah_face_y) end subroutine meke_backscatter_apply