Positive-definite per-donor outflux limiter — meridional (y) pass
(P2). Mirror of pd_limit_zonal_impl; reads the post-zonal-apply
h_layer (= h*), which is exactly the availability the second Lie
pass must respect, and scales mass_flux_y so h_layer >= h_lim
holds after continuity_apply_meridional. Cell (i,j,k) outflow =
(north face j+1 when positive) + (south face j when negative);
interior face j ∈ 2..ny scaled by its upwind donor’s θ (south cell
j−1 when the face flux ≥ 0, else north cell j). See the zonal
twin for the θ construction, ghost range, MPI-seam determinism, and
the v1.1 v_cor re-matching rationale (MOM6 v_cor scaled by the same
per-face θ so it stays consistent with the limited flux).
| Type | Intent | Optional | 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) | :: | h_lim | |||
| real(kind=wp), | intent(in) | :: | iareaT(nx,ny) | |||
| real(kind=wp), | intent(in) | :: | h_layer(nx,ny,nz) | |||
| real(kind=wp), | intent(inout) | :: | mass_flux_y(nx,ny+1,nz) | |||
| real(kind=wp), | intent(inout) | :: | theta(nx,ny,nz) | |||
| integer, | intent(inout) | :: | n_limited | |||
| real(kind=wp), | intent(inout), | optional | :: | v_cor(nx,ny+1,nz) |
MOM6 |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| real(kind=wp), | private | :: | avail | ||||
| real(kind=wp), | private | :: | demand | ||||
| logical, | private | :: | do_vcor | ||||
| integer, | private | :: | i | ||||
| integer, | private | :: | j | ||||
| integer, | private | :: | k | ||||
| integer, | private | :: | n_lim | ||||
| real(kind=wp), | private | :: | out_n | ||||
| real(kind=wp), | private | :: | out_s | ||||
| real(kind=wp), | private | :: | outflow | ||||
| real(kind=wp), | private | :: | th_face |
subroutine pd_limit_meridional_impl(nx, ny, nz, dt, h_lim, iareaT, h_layer, & mass_flux_y, theta, n_limited, v_cor) !! Positive-definite per-donor outflux limiter — meridional (y) pass !! (P2). Mirror of `pd_limit_zonal_impl`; reads the post-zonal-apply !! `h_layer` (= h*), which is exactly the availability the second Lie !! pass must respect, and scales `mass_flux_y` so `h_layer >= h_lim` !! holds after `continuity_apply_meridional`. Cell `(i,j,k)` outflow = !! (north face `j+1` when positive) + (south face `j` when negative); !! interior face `j ∈ 2..ny` scaled by its upwind donor's θ (south cell !! `j−1` when the face flux ≥ 0, else north cell `j`). See the zonal !! twin for the θ construction, ghost range, MPI-seam determinism, and !! the v1.1 `v_cor` re-matching rationale (MOM6 `v_cor` scaled by the same !! per-face θ so it stays consistent with the limited flux). integer, intent(in) :: nx, ny, nz real(wp), intent(in) :: dt, h_lim real(wp), intent(in) :: iareaT(nx, ny) real(wp), intent(in) :: h_layer(nx, ny, nz) real(wp), intent(inout) :: mass_flux_y(nx, ny + 1, nz) real(wp), intent(inout) :: theta(nx, ny, nz) integer, intent(inout) :: n_limited real(wp), intent(inout), optional :: v_cor(nx, ny + 1, nz) !! MOM6 `v_cor` capture; when present, re-scaled by the SAME per-face θ !! as `mass_flux_y` so it stays consistent with the limited flux the !! mom6-scheme corrector reads. integer :: i, j, k, n_lim real(wp) :: out_n, out_s, outflow, demand, avail, th_face logical :: do_vcor do_vcor = present(v_cor) do concurrent(k=1:nz, j=1:ny, i=1:nx) & local(out_n, out_s, outflow, demand, avail) out_n = max(mass_flux_y(i, j + 1, k), 0.0_wp) out_s = max(-mass_flux_y(i, j, k), 0.0_wp) outflow = out_n + out_s demand = dt*outflow*iareaT(i, j) avail = max(h_layer(i, j, k) - h_lim, 0.0_wp) theta(i, j, k) = merge(avail/max(demand, H_DIV_EPS), 1.0_wp, demand > avail) end do ! v1.1: re-match v_cor to the limited flux (UNSCALED-flux donor sign), ! before the mass-flux sweep. See the zonal twin. if (do_vcor) then do concurrent(k=1:nz, j=2:ny, i=1:nx) local(th_face) if (mass_flux_y(i, j, k) >= 0.0_wp) then th_face = theta(i, j - 1, k) else th_face = theta(i, j, k) end if v_cor(i, j, k) = v_cor(i, j, k)*th_face end do end if n_lim = 0 do concurrent(k=1:nz, j=2:ny, i=1:nx) local(th_face) reduce(+:n_lim) if (mass_flux_y(i, j, k) >= 0.0_wp) then th_face = theta(i, j - 1, k) else th_face = theta(i, j, k) end if if (th_face < 1.0_wp .and. mass_flux_y(i, j, k) /= 0.0_wp) n_lim = n_lim + 1 mass_flux_y(i, j, k) = mass_flux_y(i, j, k)*th_face end do n_limited = n_limited + n_lim end subroutine pd_limit_meridional_impl