Flat, explicit-shape kernel (the “vmix incident” module –
assumed-shape dummies here produced 1.4M per-launch descriptor-
walk memcpys; explicit-shape only, no exceptions). Interior
interfaces k = 2..nzp1-1 only; boundary interfaces k=1 (bed) and
k=nzp1 (surface) stay at the closed-BC zero and are never
touched (same contract as PP81 / vmix_add_kv_ml_invz2).
Depth walk copied verbatim from vmix_add_kv_ml_invz2: z
accumulates the cumulative thickness of layers nz, nz-1, …
down to interface k – the depth of interface k below the free
surface. Masked out (left at the upstream PP81 value) above
the active BL (z < bl_depth); the BL owns its own convective
response (KPP w_* / EPBL convective TKE) and double-counting
would over-mix and defeat that scheme’s own energetics.
N^2 expression is bit-for-bit PP81’s (vmix_compute_pp81):
n2 = -g*(rho_k - rho_km1)/(rho0*dz_face), positive when
stable. dz_face is gated on H_VANISHED (dynamic-vanish
skip), NOT H_DIV_EPS/bare <= 0 – a pinched ZSTAR_FULL
interface must be skipped, not divided by (a 0/0 there would
otherwise be silently laundered to background by
vmix_assemble’s default un-guarded clip).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nzp1 | |||
| real(kind=wp), | intent(inout) | :: | kv(nx,ny,nzp1) | |||
| real(kind=wp), | intent(inout) | :: | kt(nx,ny,nzp1) | |||
| real(kind=wp), | intent(in) | :: | rho_layer(nx,ny,nzp1-1) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nzp1-1) | |||
| real(kind=wp), | intent(in) | :: | bl_depth(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | kd_conv | |||
| real(kind=wp), | intent(in) | :: | prandtl_conv | |||
| real(kind=wp), | intent(in) | :: | n2_thresh | |||
| real(kind=wp), | intent(in) | :: | rho0 |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | dz_face | ||||
| integer, | private | :: | i | ||||
| integer, | private | :: | j | ||||
| integer, | private | :: | k | ||||
| real(kind=wp), | private | :: | n2 | ||||
| integer, | private | :: | nz | ||||
| real(kind=wp), | private | :: | z |
pure subroutine vmix_convection_impl(nx, ny, nzp1, kv, kt, rho_layer, h_layer, & bl_depth, kd_conv, prandtl_conv, n2_thresh, rho0) !! Flat, explicit-shape kernel (the "vmix incident" module -- !! assumed-shape dummies here produced 1.4M per-launch descriptor- !! walk memcpys; explicit-shape only, no exceptions). Interior !! interfaces k = 2..nzp1-1 only; boundary interfaces k=1 (bed) and !! k=nzp1 (surface) stay at the closed-BC zero and are never !! touched (same contract as PP81 / `vmix_add_kv_ml_invz2`). !! !! Depth walk copied verbatim from `vmix_add_kv_ml_invz2`: `z` !! accumulates the cumulative thickness of layers nz, nz-1, ... !! down to interface k -- the depth of interface k below the free !! surface. Masked out (left at the upstream PP81 value) above !! the active BL (`z < bl_depth`); the BL owns its own convective !! response (KPP w_* / EPBL convective TKE) and double-counting !! would over-mix and defeat that scheme's own energetics. !! !! N^2 expression is bit-for-bit PP81's (`vmix_compute_pp81`): !! `n2 = -g*(rho_k - rho_km1)/(rho0*dz_face)`, positive when !! stable. `dz_face` is gated on `H_VANISHED` (dynamic-vanish !! skip), NOT `H_DIV_EPS`/bare `<= 0` -- a pinched ZSTAR_FULL !! interface must be skipped, not divided by (a `0/0` there would !! otherwise be silently laundered to background by !! `vmix_assemble`'s default un-guarded clip). integer, intent(in) :: nx, ny, nzp1 real(wp), intent(inout) :: kv(nx, ny, nzp1) real(wp), intent(inout) :: kt(nx, ny, nzp1) real(wp), intent(in) :: rho_layer(nx, ny, nzp1 - 1) real(wp), intent(in) :: h_layer(nx, ny, nzp1 - 1) real(wp), intent(in) :: bl_depth(nx, ny) real(wp), intent(in) :: kd_conv, prandtl_conv, n2_thresh, rho0 integer :: i, j, k, nz real(wp) :: dz_face, n2, z nz = nzp1 - 1 do concurrent(j=1:ny, i=1:nx) local(k, z, dz_face, n2) z = 0.0_wp do k = nz, 2, -1 z = z + h_layer(i, j, k) dz_face = 0.5_wp*(h_layer(i, j, k - 1) + h_layer(i, j, k)) if (dz_face <= H_VANISHED) cycle if (z < bl_depth(i, j)) cycle n2 = -GRAVITY*(rho_layer(i, j, k) - rho_layer(i, j, k - 1))/(rho0*dz_face) if (n2 < n2_thresh) then kt(i, j, k) = max(kt(i, j, k), kd_conv) kv(i, j, k) = max(kv(i, j, k), prandtl_conv*kd_conv) end if end do end do end subroutine vmix_convection_impl