pure subroutine apply_orlanski_west(u_layer, &
rx, u_prev, &
nx_total, ny_total, nz, &
i_w, j0, j1, &
rx_max, gamma_u, &
tau_in, tau_out, dt, u_data)
!! Orlanski radiation for the west open edge (Orlanski 1976).
!! Interior face index I = i_w+1 (1st), I-1 = i_w+2 (2nd).
!! Outward normal = -x. dhdx = u(i_w+1) - u(i_w+2) (westward gradient).
!! rx updated in-place; u_prev NOT updated here (done by the caller
!! after all edges are set).
integer, intent(in) :: nx_total, ny_total, nz
real(wp), intent(inout) :: u_layer(nx_total + 1, ny_total, nz)
real(wp), intent(inout) :: rx(ny_total, nz)
real(wp), intent(in) :: u_prev(ny_total, nz)
integer, intent(in) :: i_w, j0, j1
real(wp), intent(in) :: rx_max, gamma_u, tau_in, tau_out, dt, u_data
integer :: j, k
real(wp) :: u_int_1
real(wp) :: dhdt_jk, dhdx_jk, rx_raw, rx_new, u_b
real(wp) :: tau, g2
do concurrent(j=j0:j1) &
local(k, u_int_1, dhdt_jk, dhdx_jk, rx_raw, rx_new, u_b, tau, g2)
do k = 1, nz
u_int_1 = u_layer(i_w + 1, j, k) ! first interior face velocity
! West edge: outward = -x; dhdx = u(i_w+1) - u(i_w+2).
dhdt_jk = u_prev(j, k) - u_int_1
dhdx_jk = u_int_1 - u_layer(i_w + 2, j, k)
if (dhdt_jk*dhdx_jk > 0.0_wp) then
rx_raw = min(dhdt_jk/dhdx_jk, rx_max)
else
rx_raw = 0.0_wp
end if
! Running-mean update (gamma_u = 1 = instant, no memory).
rx_new = (1.0_wp - gamma_u)*rx(j, k) + gamma_u*rx_raw
rx(j, k) = rx_new
! Semi-implicit boundary update: u_b = (u_b_old + rx*u_int_1)/(1+rx).
! Anchors on the wall face's OWN per-layer value, so rx=0 leaves the
! baroclinic structure untouched (anchoring on BT velocity would
! collapse the boundary shear every quiet phase).
u_b = (u_layer(i_w, j, k) + rx_new*u_int_1)/(1.0_wp + rx_new)
! Optional nudging: "incoming" = dhdt*dhdx <= 0 ⟹ tau_in.
if (dhdt_jk*dhdx_jk <= 0.0_wp) then
tau = tau_in
else
tau = tau_out
end if
if (tau > 0.0_wp) then
g2 = dt/(tau + dt)
u_b = (1.0_wp - g2)*u_b + g2*u_data
end if
u_layer(i_w, j, k) = u_b
end do
end do
end subroutine apply_orlanski_west