pure subroutine fold_sample_masked_impl(accum, out, weight, mask_nx, mask_ny, &
dt, time_op)
!! Masked fold — multiplies sample by `weight(i, j)` before folding.
!! MAX/MIN treat `weight == 0` as "don't update" so masked-out cells
!! keep their seed value. Loop bounds clip to whichever extent is
!! smaller (accumulator vs mask) so an undersized mask doesn't OOB.
! assumed-shape-ok: diag fold — fires once per output frame (cadence-bounded).
real(wp), intent(inout) :: accum(:, :, :)
real(wp), intent(in) :: out(:, :, :) ! assumed-shape-ok: diag fold — cadence-bounded
real(wp), intent(in) :: weight(:, :) ! assumed-shape-ok: diag fold — cadence-bounded
integer, intent(in) :: mask_nx, mask_ny
real(wp), intent(in) :: dt
integer, intent(in) :: time_op
integer :: i, j, k, nx, ny, nz
real(wp) :: w
nx = min(size(accum, 1), mask_nx)
ny = min(size(accum, 2), mask_ny)
nz = size(accum, 3)
select case (time_op)
case (DIAG_OP_MEAN, DIAG_OP_INTEGRAL)
do concurrent(k=1:nz, j=1:ny, i=1:nx)
accum(i, j, k) = accum(i, j, k) + &
weight(i, j)*out(i, j, k)*dt
end do
case (DIAG_OP_MAX)
do concurrent(k=1:nz, j=1:ny, i=1:nx) &
local(w)
w = weight(i, j)
if (w > 0.0_wp) then
accum(i, j, k) = max(accum(i, j, k), out(i, j, k))
end if
end do
case (DIAG_OP_MIN)
do concurrent(k=1:nz, j=1:ny, i=1:nx) &
local(w)
w = weight(i, j)
if (w > 0.0_wp) then
accum(i, j, k) = min(accum(i, j, k), out(i, j, k))
end if
end do
case default
! INSTANT and unknown ops don't accumulate (caller-gated).
end select
end subroutine fold_sample_masked_impl