pf_predictor_oc Subroutine

public subroutine pf_predictor_oc(pf, t0, dt, flags)

Step 1. Getting the initial condition on the finest level at each processor If we are doing multiple levels, then we need to coarsen to fine level Step 2: Proceed fine to coarse levels coarsening the fine solution and computing tau correction If RK_pred is true, just do some RK_steps

Arguments

Type IntentOptional AttributesName
type(pf_pfasst_t), intent(inout), target:: pf

PFASST main data structure

real(kind=pfdp), intent(in) :: t0

Initial time of this processor

real(kind=pfdp), intent(in) :: dt

time step

integer, intent(in), optional :: flags(:)

User defined flags


Calls

proc~~pf_predictor_oc~~CallsGraph proc~pf_predictor_oc pf_predictor_oc proc~end_timer end_timer proc~pf_predictor_oc->proc~end_timer proc~restrict_time_space_fas restrict_time_space_fas proc~pf_predictor_oc->proc~restrict_time_space_fas proc~pf_residual pf_residual proc~pf_predictor_oc->proc~pf_residual proc~pf_send pf_send proc~pf_predictor_oc->proc~pf_send proc~call_hooks call_hooks proc~pf_predictor_oc->proc~call_hooks proc~pf_recv pf_recv proc~pf_predictor_oc->proc~pf_recv proc~start_timer start_timer proc~pf_predictor_oc->proc~start_timer proc~interpolate_time_space interpolate_time_space proc~pf_predictor_oc->proc~interpolate_time_space proc~restrict_time_space_fas->proc~end_timer proc~restrict_time_space_fas->proc~call_hooks proc~restrict_time_space_fas->proc~start_timer proc~restrict_sdc restrict_sdc proc~restrict_time_space_fas->proc~restrict_sdc proc~pf_residual->proc~end_timer proc~pf_residual->proc~start_timer start_timer start_timer proc~pf_send->start_timer end_timer end_timer proc~pf_send->end_timer proc~call_hooks->proc~end_timer proc~call_hooks->proc~start_timer proc~pf_recv->start_timer proc~pf_recv->end_timer proc~interpolate_time_space->proc~end_timer proc~interpolate_time_space->proc~call_hooks proc~interpolate_time_space->proc~start_timer proc~pf_apply_mat pf_apply_mat proc~interpolate_time_space->proc~pf_apply_mat proc~restrict_sdc->proc~pf_apply_mat

Called by

proc~~pf_predictor_oc~~CalledByGraph proc~pf_predictor_oc pf_predictor_oc proc~pf_pfasst_block_oc pf_pfasst_block_oc proc~pf_pfasst_block_oc->proc~pf_predictor_oc

Contents

Source Code


Source Code

  subroutine pf_predictor_oc(pf, t0, dt, flags)
    type(pf_pfasst_t), intent(inout), target :: pf     !! PFASST main data structure
    real(pfdp),        intent(in   )         :: t0     !! Initial time of this processor
    real(pfdp),        intent(in   )         :: dt     !! time step
    integer,           intent(in   ), optional :: flags(:)  !!  User defined flags

    class(pf_level_t), pointer :: c_lev_p
    class(pf_level_t), pointer :: f_lev_p
    integer                   :: k               !!  Loop indices
    integer                   :: level_index     !!  Local variable for looping over levels
    real(pfdp)                :: t0k             !!  Initial time at time step k
    integer :: which, dir, send_tag 
 
    which = 1                   ! standard: predict and sweep forward-in-time
    dir = 1                     ! for MPI communication, standard is forward-in-time
    if(present(flags)) then
       if(flags(1)==2) then
          which = 2                ! if we are computing an adjoint, predict and sweep backward-in-time
          dir = 2                  ! communication has to be backwards as well
       end if
       if(flags(1)==0) which = 0   ! sweep forward and backward simultaneously on two components, communication only forwards
    end if
    call call_hooks(pf, 1, PF_PRE_PREDICTOR)
    call start_timer(pf, TPREDICTOR)
    
    if (pf%debug) print*, 'DEBUG --', pf%rank, 'beginning predictor'

    !! Step 1. Getting the  initial condition on the finest level at each processor
    !!         If we are doing multiple levels, then we need to coarsen to fine level
    f_lev_p => pf%levels(pf%nlevels)
    if (pf%q0_style < 2) then  !  Spread q0 to all the nodes
       if( (which == 0) .or. (which == 1)) call f_lev_p%ulevel%sweeper%spreadq0(f_lev_p, t0, 1, pf%state%step+1)
       if( (which == 0) .or. (which == 2)) call f_lev_p%ulevel%sweeper%spreadq0(f_lev_p, t0+dt, 2, pf%state%step+1)
    endif


    !!  Step 2:   Proceed fine to coarse levels coarsening the fine solution and computing tau correction
    if (pf%debug) print*,  'DEBUG --', pf%rank, 'do coarsen  in predictor'    
    if (pf%nlevels > 1) then  
       do level_index = pf%nlevels, 2, -1
          f_lev_p => pf%levels(level_index);
          c_lev_p => pf%levels(level_index-1)
          call pf_residual(pf, f_lev_p, dt, which)  
          if( (which == 0) .or. (which == 1)) call f_lev_p%ulevel%restrict(f_lev_p, c_lev_p, f_lev_p%q0, c_lev_p%q0, t0, 1)
          if( (which == 0) .or. (which == 2)) call f_lev_p%ulevel%restrict(f_lev_p, c_lev_p, f_lev_p%qend, c_lev_p%qend, t0+dt, 2)
          call restrict_time_space_fas(pf, t0, dt, level_index, which)  !  Restrict
          call save(c_lev_p, which)
       end do  !  level_index = pf%nlevels, 2, -1
    end if
    level_index = 1
    c_lev_p => pf%levels(1)

    ! Step 3. Do the "Burn in" step on the coarse level to make the coarse values consistent
    !         (this is skipped if the fine initial conditions are already consistent)
    ! The first processor does nothing, the second does one set of sweeps, the 2nd two, etc
    ! Hence, this is skipped completely if nprocs=1
    if (pf%q0_style .eq. 0) then  !  The coarse level needs burn in
       if (pf%debug) print*,  'DEBUG --', pf%rank, 'do burnin in pred', ' RK_pred', pf%RK_pred, ' PFASST_pred', pf%PFASST_pred
       !! If RK_pred is true, just do some RK_steps
       if (pf%RK_pred) then  !  Use Runge-Kutta to get the coarse initial data
          !  Get new initial conditions
          call pf_recv(pf, c_lev_p, 100000+pf%rank, .true., dir)

          !  Do a RK_step
          call c_lev_p%ulevel%sweeper%sweep(pf, level_index, t0, dt, 1, which )
          !  Send forward/backward
          if (dir == 1) send_tag = 100000+pf%rank+1
          if (dir == 2) send_tag = 100000+pf%rank-1
          call pf_send(pf, c_lev_p, send_tag, .false., dir)
       else  !  Normal PFASST burn in
          do k = 1, pf%rank + 1
             pf%state%iter = -k
             t0k = t0-(pf%rank)*dt + (k-1)*dt   ! Remember t0=pf%rank*dt is the beginning of this time slice so t0-(pf%rank)*dt is 0
                                                ! and we iterate up to the correct time step.
                                                ! for optimal control problem t, t0k has no influence on f_eval, so there this does something else

             ! Get new initial value (skip on first iteration)
             if (k > 1) then
                if ((which == 0) .or. (which == 1)) call c_lev_p%q0%copy(c_lev_p%qend, 1)
!                 if ((which == 0) .or. (which == 2)) call c_lev_p%qend%copy(c_lev_p%q0, 2) ! for which==0, we solve with zero terminal conditions,
                                                                                            ! but q0,2 is not zero (source term due to state sweeps)
                if (which == 2) call c_lev_p%qend%copy(c_lev_p%q0, 2)
                ! If we are doing PFASST_pred, we use the old values at nodes, otherwise spread q0
                if (.not. pf%PFASST_pred) then
                   if( (which == 0) .or. (which == 1)) call c_lev_p%ulevel%sweeper%spreadq0(c_lev_p, t0k, 1, pf%state%step+1)
!                    if( (which == 0) .or. (which == 2)) call c_lev_p%ulevel%sweeper%spreadq0(c_lev_p, t0k+dt, 2, pf%state%step+1)
                   if( which == 2) call c_lev_p%ulevel%sweeper%spreadq0(c_lev_p, t0k+dt, 2, pf%state%step+1)
                end if
             end if
             !  Do some sweeps
             if( which == 0 .or. which == 1 ) call c_lev_p%ulevel%sweeper%sweep(pf, level_index, t0k, dt, pf%nsweeps_burn, 1)
             if( which == 2 )                 call c_lev_p%ulevel%sweeper%sweep(pf, level_index, t0k, dt, pf%nsweeps_burn, 2)
          end do
       endif  !  RK_pred
    end if  ! (q0_style .eq. 0)

    ! Step 4: Now we have everyone burned in, so do some coarse sweeps
    if (pf%nlevels > 1) then
      pf%state%pstatus = PF_STATUS_ITERATING
      pf%state%status  = PF_STATUS_ITERATING
      if (pf%debug) print*,  'DEBUG --', pf%rank, 'do sweeps  in predictor', ' Pipeline_pred', pf%Pipeline_pred    
      level_index=1
      c_lev_p => pf%levels(level_index)

      if (pf%Pipeline_pred) then
        do k = 1, c_lev_p%nsweeps_pred
          pf%state%iter =-(pf%rank + 1) -k

          !  Get new initial conditions          
          call pf_recv(pf, c_lev_p, c_lev_p%index*110000+pf%rank+k, .true., dir)

          !  Do a sweep
          call c_lev_p%ulevel%sweeper%sweep(pf, c_lev_p%index, t0, dt, 1, which)
          !  Send forward/backward
          if (dir == 1) send_tag = c_lev_p%index*1110000+pf%rank+1+k
          if (dir == 2) send_tag = c_lev_p%index*1110000+pf%rank-1+k
          call pf_send(pf, c_lev_p, send_tag, .false., dir)
       end do ! k = 1, c_lev_p%nsweeps_pred-1
      else  !  Don't pipeline
        !  Get new initial conditions
        call pf_recv(pf, c_lev_p, c_lev_p%index*100000+pf%rank, .true., dir)
 
        !  Do sweeps
        if(which == 0 .or. which == 1) call c_lev_p%ulevel%sweeper%sweep(pf, level_index, t0, dt, c_lev_p%nsweeps_pred, 1) !which ! why only state?
        if(which == 2)                 call c_lev_p%ulevel%sweeper%sweep(pf, level_index, t0, dt, c_lev_p%nsweeps_pred, 2) !which
        !  Send forward/backward
        if (dir == 1) send_tag = c_lev_p%index*100000+pf%rank+1
        if (dir == 2) send_tag = c_lev_p%index*100000+pf%rank-1
        call pf_send(pf, c_lev_p, send_tag, .false., dir)
      endif  ! (Pipeline_pred .eq. .true) then
    end if ! pf%nlevels > 1

    !  Step 5:  Return to fine level sweeping on any level in between coarsest and finest
    if (pf%debug) print*,  'DEBUG --', pf%rank, 'returning to fine level in predictor'
    do level_index = 2, pf%nlevels  !  Will do nothing with one level
       f_lev_p => pf%levels(level_index);
       c_lev_p => pf%levels(level_index-1)
       call interpolate_time_space(pf, t0, dt, level_index, c_lev_p%Finterp, which)
       if ((which == 0) .or. (which == 1)) call interpolate_q0(pf, f_lev_p, c_lev_p, 1)
       if (which == 2)                     call interpolate_qend(pf, f_lev_p, c_lev_p) ! for which==0, qend never changes, so don't need to interpolate
       !  Do sweeps on level unless we are at the finest level
       if (level_index < pf%nlevels) then
          call f_lev_p%ulevel%sweeper%sweep(pf, level_index, t0, dt, f_lev_p%nsweeps_pred, which)
       end if
    end do

    call end_timer(pf, TPREDICTOR)
    call call_hooks(pf, -1, PF_POST_PREDICTOR)

    pf%state%iter   = 0
    pf%state%status = PF_STATUS_ITERATING
    pf%state%pstatus = PF_STATUS_ITERATING

    if (pf%debug) print*,  'DEBUG --', pf%rank, 'ending predictor'    
  end subroutine pf_predictor_oc