ddes Subroutine

private subroutine ddes(me, neq, t, y, tout, info, rtol, atol, idid, ypout, yp, yy, wt, p, phi, alpha, beta, psi, v, w, sig, g, gi, h, eps, x, xold, hold, told, delsgn, tstop, twou, fouru, start, phase1, nornd, stiff, intout, ns, kord, kold, init, ksteps, kle4, iquit, kprev, ivc, iv, kgi)

ddeabm merely allocates storage for ddes to relieve the user of the inconvenience of a long call list. consequently ddes is used as described in the comments for ddeabm.

Author

  • watts, h. a., (snla)

History

  • 820301 date written
  • 890531 changed all specific intrinsics to generic. (wrb)
  • 890831 modified array declarations. (wrb)
  • 891214 prologue converted to version 4.0 format. (bab)
  • 900328 added type section. (wrb)
  • 900510 convert xerrwv calls to xermsg calls, cvt gotos to if-then-else. (rwc)
  • 910722 updated author section. (als)
  • December, 2015 : Refactored this routine (jw)

Type Bound

ddeabm_class

Arguments

Type IntentOptional Attributes Name
class(ddeabm_class), intent(inout) :: me
integer, intent(in) :: neq
real(kind=wp), intent(inout) :: t
real(kind=wp), intent(inout), dimension(neq) :: y
real(kind=wp), intent(in) :: tout
integer, intent(inout), dimension(4) :: info
real(kind=wp), intent(inout), dimension(:) :: rtol
real(kind=wp), intent(inout), dimension(:) :: atol
integer, intent(inout) :: idid
real(kind=wp), intent(inout), dimension(neq) :: ypout
real(kind=wp), intent(inout), dimension(neq) :: yp
real(kind=wp), intent(inout), dimension(neq) :: yy
real(kind=wp), intent(inout), dimension(neq) :: wt
real(kind=wp), intent(inout), dimension(neq) :: p
real(kind=wp), intent(inout), dimension(neq, 16) :: phi
real(kind=wp), intent(inout), dimension(12) :: alpha
real(kind=wp), intent(inout), dimension(12) :: beta
real(kind=wp), intent(inout), dimension(12) :: psi
real(kind=wp), intent(inout), dimension(12) :: v
real(kind=wp), intent(inout), dimension(12) :: w
real(kind=wp), intent(inout), dimension(13) :: sig
real(kind=wp), intent(inout), dimension(13) :: g
real(kind=wp), intent(inout), dimension(11) :: gi
real(kind=wp), intent(inout) :: h
real(kind=wp), intent(inout) :: eps
real(kind=wp), intent(inout) :: x
real(kind=wp), intent(inout) :: xold
real(kind=wp), intent(inout) :: hold
real(kind=wp), intent(inout) :: told
real(kind=wp), intent(inout) :: delsgn
real(kind=wp), intent(inout) :: tstop
real(kind=wp), intent(inout) :: twou
real(kind=wp), intent(inout) :: fouru
logical, intent(inout) :: start
logical, intent(inout) :: phase1
logical, intent(inout) :: nornd
logical, intent(inout) :: stiff
logical, intent(inout) :: intout
integer, intent(inout) :: ns
integer, intent(inout) :: kord
integer, intent(inout) :: kold
integer, intent(inout) :: init
integer, intent(inout) :: ksteps
integer, intent(inout) :: kle4
integer, intent(inout) :: iquit
integer, intent(inout) :: kprev
integer, intent(inout) :: ivc
integer, intent(inout), dimension(10) :: iv
integer, intent(inout) :: kgi

Calls

proc~~ddes~~CallsGraph proc~ddes ddeabm_class%ddes proc~dintp dintp proc~ddes->proc~dintp proc~dsteps ddeabm_class%dsteps proc~ddes->proc~dsteps proc~report_error report_error proc~ddes->proc~report_error proc~dhstrt ddeabm_class%dhstrt proc~dsteps->proc~dhstrt proc~dhvnrm dhvnrm proc~dhstrt->proc~dhvnrm

Called by

proc~~ddes~~CalledByGraph proc~ddes ddeabm_class%ddes proc~ddeabm ddeabm_class%ddeabm proc~ddeabm->proc~ddes proc~ddeabm_with_event_wrapper ddeabm_with_event_class%ddeabm_with_event_wrapper proc~ddeabm_with_event_wrapper->proc~ddeabm proc~ddeabm_with_event_wrapper_vec ddeabm_with_event_class_vec%ddeabm_with_event_wrapper_vec proc~ddeabm_with_event_wrapper_vec->proc~ddeabm proc~ddeabm_wrapper ddeabm_class%ddeabm_wrapper proc~ddeabm_wrapper->proc~ddeabm

Source Code

   subroutine ddes(me, neq, t, y, tout, info, rtol, atol, idid, &
                   ypout, yp, yy, wt, p, phi, alpha, beta, psi, v, w, sig, g, gi, &
                   h, eps, x, xold, hold, told, delsgn, tstop, twou, fouru, start, &
                   phase1, nornd, stiff, intout, ns, kord, kold, init, ksteps, &
                   kle4, iquit, kprev, ivc, iv, kgi)

      implicit none

      class(ddeabm_class), intent(inout)        :: me
      integer, intent(in)                       :: neq
      real(wp), intent(inout)                   :: t
      real(wp), dimension(neq), intent(inout)    :: y
      real(wp), intent(in)                      :: tout
      integer, dimension(4), intent(inout)       :: info
      real(wp), dimension(:), intent(inout)      :: rtol
      real(wp), dimension(:), intent(inout)      :: atol
      integer, intent(inout)                    :: idid
      real(wp), dimension(neq), intent(inout)    :: ypout
      real(wp), dimension(neq), intent(inout)    :: yp
      real(wp), dimension(neq), intent(inout)    :: yy
      real(wp), dimension(neq), intent(inout)    :: wt
      real(wp), dimension(neq), intent(inout)    :: p
      real(wp), dimension(neq, 16), intent(inout) :: phi
      real(wp), dimension(12), intent(inout)     :: alpha
      real(wp), dimension(12), intent(inout)     :: beta
      real(wp), dimension(12), intent(inout)     :: psi
      real(wp), dimension(12), intent(inout)     :: v
      real(wp), dimension(12), intent(inout)     :: w
      real(wp), dimension(13), intent(inout)     :: sig
      real(wp), dimension(13), intent(inout)     :: g
      real(wp), dimension(11), intent(inout)     :: gi
      real(wp), intent(inout)                   :: h
      real(wp), intent(inout)                   :: eps
      real(wp), intent(inout)                   :: x
      real(wp), intent(inout)                   :: xold
      real(wp), intent(inout)                   :: hold
      real(wp), intent(inout)                   :: told
      real(wp), intent(inout)                   :: delsgn
      real(wp), intent(inout)                   :: tstop
      real(wp), intent(inout)                   :: twou
      real(wp), intent(inout)                   :: fouru
      logical, intent(inout)                    :: start
      logical, intent(inout)                    :: phase1
      logical, intent(inout)                    :: nornd
      logical, intent(inout)                    :: stiff
      logical, intent(inout)                    :: intout
      integer, intent(inout)                    :: ns
      integer, intent(inout)                    :: kord
      integer, intent(inout)                    :: kold
      integer, intent(inout)                    :: init
      integer, intent(inout)                    :: ksteps
      integer, intent(inout)                    :: kle4
      integer, intent(inout)                    :: iquit
      integer, intent(inout)                    :: kprev
      integer, intent(inout)                    :: ivc
      integer, dimension(10), intent(inout)      :: iv
      integer, intent(inout)                    :: kgi

      integer :: k, l, m, ltol, natolp, nrtolp
      real(wp) :: a, absdel, del, dt, ha, u
      logical :: crash
      character(len=8) :: xern1
      character(len=16) :: xern3, xern4

      if (me%error) return  ! if user-triggered error

      ! on the first call, perform initialization

      if (info(1) == 0) then
         u = d1mach4    ! machine unit roundoff quantity
         twou = 2.0_wp*u   ! set associated machine dependent parameters
         fouru = 4.0_wp*u   !
         iquit = 0          ! set termination flag
         init = 0          ! set initialization indicator
         ksteps = 0          ! set counter for attempted steps
         intout = .false.    ! set indicator for intermediate-output
         stiff = .false.    ! set indicator for stiffness detection
         kle4 = 0          ! set step counter for stiffness detection
         start = .true.     ! set indicators for steps code
         phase1 = .true.     !
         nornd = .true.     !
         info(1) = 1          ! reset info(1) for subsequent calls
      end if

      ! check validity of input parameters on each entry

      if (info(1) /= 0 .and. info(1) /= 1) then
         write (xern1, '(i8)') info(1)
         call report_error('ddes', 'in ddeabm, info(1) must be '// &
                           'set to 0 for the start of a new problem, and must be '// &
                           'set to 1 following an interrupted task.  you are '// &
                           'attempting to continue the integration illegally by '// &
                           'calling the code with info(1) = '//xern1, 3, 1)
         idid = -33
      end if

      if (info(2) /= 0 .and. info(2) /= 1) then
         write (xern1, '(i8)') info(2)
         call report_error('ddes', 'in ddeabm, info(2) must be '// &
                           '0 or 1 indicating scalar and vector error tolerances, '// &
                           'respectively.  you have called the code with info(2) = '// &
                           xern1, 4, 1)
         idid = -33
      end if

      if (info(3) /= 0 .and. info(3) /= 1) then
         write (xern1, '(i8)') info(3)
         call report_error('ddes', 'in ddeabm, info(3) must be '// &
                           '0 or 1 indicating the interval or intermediate-output '// &
                           'mode of integration, respectively.  you have called '// &
                           'the code with  info(3) = '//xern1, 5, 1)
         idid = -33
      end if

      if (info(4) /= 0 .and. info(4) /= 1) then
         write (xern1, '(i8)') info(4)
         call report_error('ddes', 'in ddeabm, info(4) must be '// &
                           '0 or 1 indicating whether or not the integration '// &
                           'interval is to be restricted by a point tstop.  you '// &
                           'have called the code with info(4) = '//xern1, 14, 1)
         idid = -33
      end if

      if (neq < 1) then
         write (xern1, '(i8)') neq
         call report_error('ddes', 'in ddeabm,  the number of '// &
                           'equations neq must be a positive integer.  you have '// &
                           'called the code with  neq = '//xern1, 6, 1)
         idid = -33
      end if

      nrtolp = 0
      natolp = 0
      do k = 1, neq
         if (nrtolp == 0 .and. rtol(k) < 0.0_wp) then
            write (xern1, '(i8)') k
            write (xern3, '(1pe15.6)') rtol(k)
            call report_error('ddes', 'in ddeabm, the relative '// &
                              'error tolerances rtol must be non-negative.  you '// &
                              'have called the code with  rtol('//xern1//') = '// &
                              xern3//'.  in the case of vector error tolerances, '// &
                              'no further checking of rtol components is done.', 7, 1)
            idid = -33
            nrtolp = 1
         end if

         if (natolp == 0 .and. atol(k) < 0.0_wp) then
            write (xern1, '(i8)') k
            write (xern3, '(1pe15.6)') atol(k)
            call report_error('ddes', 'in ddeabm, the absolute '// &
                              'error tolerances atol must be non-negative.  you '// &
                              'have called the code with  atol('//xern1//') = '// &
                              xern3//'.  in the case of vector error tolerances, '// &
                              'no further checking of atol components is done.', 8, 1)
            idid = -33
            natolp = 1
         end if

         if (info(2) == 0) exit
         if (natolp > 0 .and. nrtolp > 0) exit
      end do

      if (info(4) == 1) then
         if (sign(1.0_wp, tout - t) /= sign(1.0_wp, tstop - t) &
             .or. abs(tout - t) > abs(tstop - t)) then
            write (xern3, '(1pe15.6)') tout
            write (xern4, '(1pe15.6)') tstop
            call report_error('ddes', 'in ddeabm, you have '// &
                              'called the code with tout = '//xern3//' but '// &
                              'you have also told the code (info(4) = 1) not to '// &
                              'integrate past the point tstop = '//xern4// &
                              ' these instructions conflict.', 14, 1)
            idid = -33
         end if
      end if

      ! check some continuation possibilities

      if (init /= 0) then
         if (t == tout) then
            write (xern3, '(1pe15.6)') t
            call report_error('ddes', 'in ddeabm, you have '// &
                              'called the code with  t = tout = '//xern3// &
                              '  this is not allowed on continuation calls.', 9, 1)
            idid = -33
         end if

         if (t /= told) then
            write (xern3, '(1pe15.6)') told
            write (xern4, '(1pe15.6)') t
            call report_error('ddes', 'in ddeabm, you have '// &
                              'changed the value of t from '//xern3//' to '// &
                              xern4//'  this is not allowed on continuation calls.', &
                              10, 1)
            idid = -33
         end if

         if (init /= 1) then
            if (delsgn*(tout - t) < 0.0_wp) then
               write (xern3, '(1pe15.6)') tout
               call report_error('ddes', 'in ddeabm, by '// &
                                 'calling the code with tout = '//xern3// &
                                 ' you are attempting to change the direction of '// &
                                 'integration.  this is not allowed without '// &
                                 'restarting.', 11, 1)
               idid = -33
            end if
         end if
      end if

      ! invalid input detected

      if (idid == -33) then
         if (iquit /= -33) then
            iquit = -33
            info(1) = -1
         else
            call report_error('ddes', 'in ddeabm, invalid '// &
                              'input was detected on successive entries.  it is '// &
                              'impossible to proceed because you have not '// &
                              'corrected the problem, so execution is being '// &
                              'terminated.', 12, 2)
         end if
         return
      end if

      ! rtol = atol = 0. is allowed as valid input and interpreted as
      ! asking for the most accurate solution possible. in this case,
      ! the relative error tolerance rtol is reset to the smallest value
      ! fouru which is likely to be reasonable for this method and machine

      do k = 1, neq
         if (rtol(k) + atol(k) <= 0.0_wp) then
            rtol(k) = fouru
            idid = -2
         end if
         if (info(2) == 0) exit
      end do

      if (idid == -2) then
         ! rtol=atol=0 on input, so rtol is changed to a small positive value
         info(1) = -1
         return
      end if

      ! branch on status of initialization indicator
      !  init=0 means initial derivatives and nominal step size and direction not yet set
      !  init=1 means nominal step size and direction not yet set
      !  init=2 means no further initialization required

      if (init == 0) then
         ! more initialization --
         ! -- evaluate initial derivatives
         init = 1
         a = t
         call me%df(a, y, yp)
         if (me%error) return ! user-triggered error
         if (t == tout) then
            idid = 2
            ypout = yp
            told = t
            return
         end if
      end if

      if (init == 1) then
         ! -- set independent and dependent variables
         !                      x and yy(*) for steps
         ! -- set sign of integration direction
         ! -- initialize the step size
         init = 2
         x = t
         yy = y
         delsgn = sign(1.0_wp, tout - t)
         h = sign(max(fouru*abs(x), abs(tout - x)), tout - x)
      end if

      ! on each call set information which determines the allowed interval
      ! of integration before returning with an answer at tout

      del = tout - t
      absdel = abs(del)

      do

         ! if already past output point, interpolate and return
         if (abs(x - t) >= absdel) then
            call dintp(x, yy, tout, y, ypout, neq, kold, phi, ivc, iv, kgi, gi, alpha, g, w, xold, p)
            idid = 3
            if (x == tout) then
               idid = 2
               intout = .false.
            end if
            t = tout
            told = t
            return
         end if

         ! if cannot go past tstop and sufficiently close, extrapolate and return
         if (info(4) == 1 .and. abs(tstop - x) < fouru*abs(x)) then
            dt = tout - x
            y = yy + dt*yp
            call me%df(tout, y, ypout)
            if (me%error) return ! user-triggered error
            idid = 3
            t = tout
            told = t
            return
         end if

         ! intermediate-output mode
         if (info(3) /= 0 .and. intout) then
            idid = 1
            y = yy
            ypout = yp
            t = x
            told = t
            intout = .false.
            return
         end if

         ! monitor number of steps attempted

         if (ksteps > me%maxnum) then
            ! a significant amount of work has been expended
            idid = -1
            ksteps = 0
            if (stiff) then
               ! problem appears to be stiff
               idid = -4
               stiff = .false.
               kle4 = 0
            end if
            y = yy
            ypout = yp
            t = x
            told = t
            info(1) = -1
            intout = .false.
            return
         end if

         ! limit step size, set weight vector and take a step

         ha = abs(h)
         if (info(4) == 1) ha = min(ha, abs(tstop - x))
         h = sign(ha, h)
         eps = 1.0_wp
         ltol = 1
         do l = 1, neq
            if (info(2) == 1) ltol = l
            wt(l) = rtol(ltol)*abs(yy(l)) + atol(ltol)
            if (wt(l) <= 0.0_wp) then
               ! relative error criterion inappropriate
               idid = -3
               y = yy
               ypout = yp
               t = x
               told = t
               info(1) = -1
               intout = .false.
               return
            end if
         end do

         call me%dsteps(neq, yy, x, h, eps, wt, start, hold, kord, kold, crash, phi, p, &
                        yp, psi, alpha, beta, sig, v, w, g, phase1, ns, nornd, ksteps, &
                        twou, fouru, xold, kprev, ivc, iv, kgi, gi)
         if (me%error) return !user-triggered error

         if (crash) then
            ! tolerances too small
            idid = -2
            rtol = eps*rtol
            atol = eps*atol
            y = yy
            ypout = yp
            t = x
            told = t
            info(1) = -1
            intout = .false.
            return
         end if

         ! (stiffness test) count number of consecutive steps taken with the
         ! order of the method being less or equal to four

         kle4 = kle4 + 1
         if (kold > 4) kle4 = 0
         stiff = (kle4 >= 50)
         intout = .true.

      end do

   end subroutine ddes