pure subroutine remap_x_face_grounded(nx, ny, nz, h_old, h_new, mask, u_face_x)
!! Conservative east-face velocity remap gated on the grounded mask. A
!! face is active iff either adjacent cell is grounded (2 mask loads —
!! no neighbour-column re-scan); inactive faces are left byte-unchanged.
!! Face thickness is the arithmetic mean of the two adjacent cells
!! (outer walls take the single interior cell); the target side reads
!! h_new only where the mask is set — elsewhere h_new ≡ h_old by
!! construction, so h_old is read directly. `remap_column` preserves
!! the per-face momentum Sigma h_face . u.
integer, intent(in) :: nx, ny, nz
real(wp), intent(in) :: h_old(nx, ny, nz)
real(wp), intent(in) :: h_new(nx, ny, nz)
real(wp), intent(in) :: mask(nx, ny, 1)
real(wp), intent(inout) :: u_face_x(nx + 1, ny, nz)
integer :: I, j, k
real(wp) :: h_old_face(NZ_STACK_MAX), h_new_face(NZ_STACK_MAX)
real(wp) :: u_old(NZ_STACK_MAX), u_new(NZ_STACK_MAX)
real(wp) :: hnw, hne
logical :: active, gw, ge
do concurrent(j=1:ny, I=1:nx + 1) &
local(k, h_old_face, h_new_face, u_old, u_new, active, gw, ge, hnw, hne)
gw = .false.
ge = .false.
if (I >= 2) gw = mask(I - 1, j, 1) > 0.5_wp
if (I <= nx) ge = mask(I, j, 1) > 0.5_wp
active = gw .or. ge
if (active) then
do k = 1, nz
if (I == 1) then
h_old_face(k) = h_old(1, j, k)
h_new_face(k) = merge(h_new(1, j, k), h_old(1, j, k), ge)
else if (I == nx + 1) then
h_old_face(k) = h_old(nx, j, k)
h_new_face(k) = merge(h_new(nx, j, k), h_old(nx, j, k), gw)
else
h_old_face(k) = 0.5_wp*(h_old(I - 1, j, k) + h_old(I, j, k))
hnw = merge(h_new(I - 1, j, k), h_old(I - 1, j, k), gw)
hne = merge(h_new(I, j, k), h_old(I, j, k), ge)
h_new_face(k) = 0.5_wp*(hnw + hne)
end if
u_old(k) = u_face_x(I, j, k)
end do
call remap_column(REMAP_PPM, nz, h_old_face(1:nz), h_new_face(1:nz), &
u_old(1:nz), u_new(1:nz))
do k = 1, nz
u_face_x(I, j, k) = u_new(k)
end do
end if
end do
end subroutine remap_x_face_grounded