pure subroutine apply_orlanski_south(v_layer, &
rx, v_prev, &
nx_total, ny_total, nz, &
j_s, i0, i1, &
rx_max, gamma_u, &
tau_in, tau_out, dt, v_data)
!! Orlanski radiation for the south open edge (Orlanski 1976).
!! Interior face J = j_s+1 (1st), J-1 = j_s+2 (2nd).
!! Outward normal = -y. dhdx = v(j_s+1) - v(j_s+2) (southward gradient).
integer, intent(in) :: nx_total, ny_total, nz
real(wp), intent(inout) :: v_layer(nx_total, ny_total + 1, nz)
real(wp), intent(inout) :: rx(nx_total, nz)
real(wp), intent(in) :: v_prev(nx_total, nz)
integer, intent(in) :: j_s, i0, i1
real(wp), intent(in) :: rx_max, gamma_u, tau_in, tau_out, dt, v_data
integer :: i, k
real(wp) :: v_int_1
real(wp) :: dhdt_ik, dhdx_ik, rx_raw, rx_new, v_b
real(wp) :: tau, g2
do concurrent(i=i0:i1) &
local(k, v_int_1, dhdt_ik, dhdx_ik, rx_raw, rx_new, v_b, tau, g2)
do k = 1, nz
v_int_1 = v_layer(i, j_s + 1, k)
! South edge: outward = -y; dhdx = v(j_s+1) - v(j_s+2).
dhdt_ik = v_prev(i, k) - v_int_1
dhdx_ik = v_int_1 - v_layer(i, j_s + 2, k)
if (dhdt_ik*dhdx_ik > 0.0_wp) then
rx_raw = min(dhdt_ik/dhdx_ik, rx_max)
else
rx_raw = 0.0_wp
end if
rx_new = (1.0_wp - gamma_u)*rx(i, k) + gamma_u*rx_raw
rx(i, k) = rx_new
! Per-layer anchor — see the west kernel's comment.
v_b = (v_layer(i, j_s, k) + rx_new*v_int_1)/(1.0_wp + rx_new)
if (dhdt_ik*dhdx_ik <= 0.0_wp) then
tau = tau_in
else
tau = tau_out
end if
if (tau > 0.0_wp) then
g2 = dt/(tau + dt)
v_b = (1.0_wp - g2)*v_b + g2*v_data
end if
v_layer(i, j_s, k) = v_b
end do
end do
end subroutine apply_orlanski_south