VerifyWindowedApply Subroutine

public 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.

Arguments

TypeIntentOptionalAttributesName
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)

Calls

proc~~verifywindowedapply~2~~CallsGraph proc~verifywindowedapply~2 VerifyWindowedApply proc~applytransferplanwindow ApplyTransferPlanWindow proc~verifywindowedapply~2->proc~applytransferplanwindow proc~restrictfromchildren RestrictFromChildren proc~applytransferplanwindow->proc~restrictfromchildren proc~prolongtochildren ProlongToChildren proc~applytransferplanwindow->proc~prolongtochildren tmp1 tmp1 proc~restrictfromchildren->tmp1 up up proc~restrictfromchildren->up tmp2 tmp2 proc~restrictfromchildren->tmp2 proc~prolongtochildren->tmp1 proc~prolongtochildren->tmp2

Called by

proc~~verifywindowedapply~2~~CalledByGraph proc~verifywindowedapply~2 VerifyWindowedApply proc~adapt_amrcontroller3d Adapt_AMRController3D proc~adapt_amrcontroller3d->proc~verifywindowedapply~2

Contents

Source Code


Source Code

  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