subroutine ke_regions_impl(h, u, v, nx, ny, nz, nghost, nx_phys, ny_phys, &
rim_w, east_w, ke_full, ke_rim, ke_east)
!! h-weighted layer KE over the three regions, one device pass.
!! Per cell: KE = Σ_k [ ¼(h_W·u_W² + h_E·u_E²) + ¼(h_S·v_S² + h_N·v_N²) ]
!! with h_face the centred face thickness (m³/s² per unit area;
!! uniform-Δx Cartesian, so the area factor is a constant and is
!! dropped — attribution only needs a consistent measure).
!! Explicit OpenACC reduction — a `sum()` intrinsic on a
!! present-mapped array silently runs host-side under NVHPC
!! non-managed mode and returns the stale host shadow.
integer, intent(in) :: nx, ny, nz, nghost, nx_phys, ny_phys
integer, intent(in) :: rim_w, east_w
real(wp), intent(in) :: h(nx, ny, nz)
real(wp), intent(in) :: u(nx + 1, ny, nz)
real(wp), intent(in) :: v(nx, ny + 1, nz)
real(wp), intent(out) :: ke_full, ke_rim, ke_east
integer :: i, j, k, i_lo, i_hi, j_lo, j_hi
real(wp) :: h_w, h_e, h_s, h_n, ke_cell
i_lo = nghost + 1
i_hi = nghost + nx_phys
j_lo = nghost + 1
j_hi = nghost + ny_phys
ke_full = 0.0_wp
ke_rim = 0.0_wp
ke_east = 0.0_wp
do concurrent(k=1:nz, j=j_lo:j_hi, i=i_lo:i_hi) reduce(+:ke_full, ke_rim, ke_east)
h_w = 0.5_wp*(h(i - 1, j, k) + h(i, j, k))
h_e = 0.5_wp*(h(i, j, k) + h(i + 1, j, k))
h_s = 0.5_wp*(h(i, j - 1, k) + h(i, j, k))
h_n = 0.5_wp*(h(i, j, k) + h(i, j + 1, k))
ke_cell = 0.25_wp*(h_w*u(i, j, k)*u(i, j, k) + &
h_e*u(i + 1, j, k)*u(i + 1, j, k)) + &
0.25_wp*(h_s*v(i, j, k)*v(i, j, k) + &
h_n*v(i, j + 1, k)*v(i, j + 1, k))
ke_full = ke_full + ke_cell
if (i - i_lo < rim_w .or. i_hi - i < rim_w .or. &
j - j_lo < rim_w .or. j_hi - j < rim_w) then
ke_rim = ke_rim + ke_cell
end if
if (i_hi - i < east_w) ke_east = ke_east + ke_cell
end do
end subroutine ke_regions_impl