Apply the transfer plan a second time on the HOST, from the same migrated window the backend just used, and compare. SELF_AMR_TRANSFER_VERIFY=1.
The comparison is to a TOLERANCE, and that is not a weakening of anything: the device kernel's contractions are compiled to FMAs and its descent prolongs only onto the child on the recorded path, so it agrees with the portable reference to round-off rather than bitwise. This is a different question from whether the window ARRIVED intact, which is byte movement, is checked by SELF_AMR_MIGRATE_VERIFY, and is exact. Keeping them as two switches is what stops the strict one being relaxed to match the loose one.
On a CPU build both applies are the same code and the difference is identically zero, which is a cheap check that the harness itself is wired up.
Diagnostic only: it costs a whole second apply plus a device-to-host copy of the new field, and it refreshes the host mirror that the default path deliberately leaves stale.
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(DGModel3D_t), | intent(inout) | :: | model | |||
| type(TransferPlan3D), | intent(in) | :: | plan | |||
| type(Lagrange), | intent(in) | :: | interp | |||
| integer, | intent(in) | :: | eFirst | |||
| integer, | intent(in) | :: | eLast | |||
| integer, | intent(in) | :: | wFirst | |||
| integer, | intent(in) | :: | wLast | |||
| real(kind=prec), | intent(in) | :: | uWin(1:interp%N+1,1:interp%N+1,1:interp%N+1,wFirst:wLast,1:model%nvar) |
subroutine VerifyWindowedApply(model,plan,interp,eFirst,eLast,wFirst,wLast,uWin)
!! Apply the transfer plan a second time on the HOST, from the same migrated window the
!! backend just used, and compare. SELF_AMR_TRANSFER_VERIFY=1.
!!
!! The comparison is to a TOLERANCE, and that is not a weakening of anything: the device
!! kernel's contractions are compiled to FMAs and its descent prolongs only onto the child on
!! the recorded path, so it agrees with the portable reference to round-off rather than
!! bitwise. This is a different question from whether the window ARRIVED intact, which is
!! byte movement, is checked by SELF_AMR_MIGRATE_VERIFY, and is exact. Keeping them as two
!! switches is what stops the strict one being relaxed to match the loose one.
!!
!! On a CPU build both applies are the same code and the difference is identically zero, which
!! is a cheap check that the harness itself is wired up.
!!
!! Diagnostic only: it costs a whole second apply plus a device-to-host copy of the new field,
!! and it refreshes the host mirror that the default path deliberately leaves stale.
implicit none
class(DGModel3D_t),intent(inout) :: model
type(TransferPlan3D),intent(in) :: plan
type(Lagrange),intent(in) :: interp
integer,intent(in) :: eFirst
integer,intent(in) :: eLast
integer,intent(in) :: wFirst
integer,intent(in) :: wLast
real(prec),intent(in) :: uWin(1:interp%N+1,1:interp%N+1,1:interp%N+1,wFirst:wLast,1:model%nvar)
! Local
real(prec),allocatable :: uRef(:,:,:,:,:)
integer :: Np,nLocal
real(prec) :: err,fieldScale,tol
Np = interp%N+1
nLocal = eLast-eFirst+1
allocate(uRef(1:Np,1:Np,1:Np,1:nLocal,1:model%nvar))
call ApplyTransferPlanWindow(plan,interp,model%nvar,uWin,wFirst,wLast,eFirst,eLast,uRef)
call model%solution%UpdateHost()
err = maxval(abs(model%solution%interior(1:Np,1:Np,1:Np,1:nLocal,1:model%nvar)-uRef))
fieldScale = maxval(abs(uRef))
! Derived from epsilon rather than written as a literal, which is both the convention in
! SELF_Constants and the portable way to say it: kind VALUES are processor-dependent. The
! slack over sqrt(epsilon) is for FMA contraction accumulated through a tensor-product
! restrict or prolong, which is the only reason host and device differ here at all.
tol = 100.0_prec*sqrt(epsilon(1.0_prec))
if(err > tol*max(fieldScale,1.0_prec)) then
print*,__FILE__,':',__LINE__, &
' : Error : TRANSFER_VERIFY rank ',model%mesh%decomp%rankId, &
' the windowed apply disagrees with the host reference: max|diff| = ',err, &
' field scale ',fieldScale
stop 1
endif
print*,"TRANSFER_VERIFY rank ",model%mesh%decomp%rankId, &
" windowed apply agrees, max|diff| = ",err
deallocate(uRef)
endsubroutine VerifyWindowedApply