pure subroutine ice_gather_flux_x_impl(uh, val, tr_flux_x_work, ncat, nx, ny)
!! Gather pass (race-free): `tr_flux_x_work(I,c) = val(donor of
!! I,c)`, donor by the sign of the FLUX. `uh` is exactly 0.0 at
!! the array-edge faces `I=1` and `I=nx+1` (the flux kernel zeros
!! them unconditionally), so the `I=1` donor-by-sign branch
!! (`uh>=0`) would read the out-of-bounds `val(0,j,c)` — guarded
!! explicitly below (`I==1`/`I==nx+1` fall back to the IN-BOUNDS
!! neighbour; the value is never actually consumed by the update
!! kernel there since `uh==0` at both those faces makes them
!! inert, but the gather must still avoid the invalid index).
!! Reads `val` ONLY at a donor cell — never writes `val` — so this
!! kernel has no race with any other iteration.
integer, intent(in) :: ncat, nx, ny
real(wp), intent(in) :: uh(nx + 1, ny, ncat)
real(wp), intent(in) :: val(nx, ny, ncat)
real(wp), intent(out) :: tr_flux_x_work(nx + 1, ny, ncat)
integer :: i, j, c
do concurrent(j=1:ny, i=1:nx + 1, c=1:ncat)
if (i == 1) then
tr_flux_x_work(i, j, c) = val(1, j, c)
else if (i == nx + 1) then
tr_flux_x_work(i, j, c) = val(nx, j, c)
else if (uh(i, j, c) >= 0.0_wp) then
tr_flux_x_work(i, j, c) = val(i - 1, j, c)
else
tr_flux_x_work(i, j, c) = val(i, j, c)
end if
end do
end subroutine ice_gather_flux_x_impl