stepnf Subroutine

public subroutine stepnf(state, callbacks, sspar)

Uses

  • proc~~stepnf~~UsesGraph proc~stepnf stepnf module~hompack_core hompack_core proc~stepnf->module~hompack_core iso_c_binding iso_c_binding module~hompack_core->iso_c_binding module~hompack_kinds hompack_kinds module~hompack_core->module~hompack_kinds iso_fortran_env iso_fortran_env module~hompack_kinds->iso_fortran_env

This subroutine takes one step along the zero curve of the homotopy map using a predictor-corrector algorithm. The predictor uses a Hermite cubic interpolant, and the corrector returns to the zero curve along the flow normal to the Davidenko flow. stepnf also estimates a step size h for the next step along the zero curve. Normally, stepnf is used indirectly through fixpnf, and should be called directly only if it is necessary to modify the stepping algorithm's parameters.

Arguments

Type IntentOptional Attributes Name
type(nf_state), intent(inout) :: state

State variables for fixpnf.

type(hompack_f_callbacks), intent(in) :: callbacks

User-supplied function and Jacobian evaluation subroutines.

real(kind=dp), intent(in) :: sspar(:)

Step-size control parameters: (lideal, rideal, dideal, hmin, hmax, bmin, bmax, p).


Calls

proc~~stepnf~~CallsGraph proc~stepnf stepnf proc~qofs qofs proc~stepnf->proc~qofs proc~tangnf tangnf proc~stepnf->proc~tangnf interface~dgeqpf dgeqpf proc~tangnf->interface~dgeqpf interface~dormqr dormqr proc~tangnf->interface~dormqr

Called by

proc~~stepnf~~CalledByGraph proc~stepnf stepnf proc~fixpnf fixpnf proc~fixpnf->proc~stepnf proc~nf_solver_solve nf_solver%nf_solver_solve proc~nf_solver_solve->proc~fixpnf

Variables

Type Visibility Attributes Name Initial
real(kind=dp), public, parameter :: twou = 2*eps64
real(kind=dp), public, parameter :: fouru = 4*eps64
real(kind=dp), public :: dcalc
real(kind=dp), public :: hfail
real(kind=dp), public :: ht
real(kind=dp), public :: lcalc
real(kind=dp), public :: rcalc
real(kind=dp), public :: rholen
real(kind=dp), public :: temp
integer, public :: itnum
integer, public :: j
integer, public :: judy
integer, public :: np1
logical, public :: fail
integer, public, parameter :: max_newton = 4

Source Code

   subroutine stepnf(state, callbacks, sspar)
   !! This subroutine takes one step along the zero curve of the homotopy map using a
   !! predictor-corrector algorithm. The predictor uses a Hermite cubic interpolant, and
   !! the corrector returns to the zero curve along the flow normal to the Davidenko flow.
   !! [[stepnf]] also estimates a step size `h` for the next step along the zero curve.
   !! Normally, [[stepnf]] is used indirectly through [[fixpnf]], and should be called
   !! directly only if it is necessary to modify the stepping algorithm's parameters.

      use hompack_core, only: qofs
      implicit none

      type(nf_state), intent(inout) :: state
         !! State variables for [[fixpnf]].
      type(hompack_f_callbacks), intent(in) :: callbacks
         !! User-supplied function and Jacobian evaluation subroutines.
      real(dp), intent(in) :: sspar(:)
         !! Step-size control parameters:
         !! `(lideal, rideal, dideal, hmin, hmax, bmin, bmax, p)`.

      real(dp), parameter :: twou = 2*eps64, fouru = 4*eps64
      real(dp) :: dcalc, hfail, ht, lcalc, rcalc, rholen, temp
      integer :: itnum, j, judy, np1
      logical :: fail

      ! Newton iterations allowed before reducing the step size 'h'
      integer, parameter:: max_newton = 4

      np1 = state%n + 1
      state%crash = .true.

      associate (ws => state%workspace)

         ! The arclength 's' must be nonnegative
         if (state%s < zero) return

         ! If step size is too small, determine an acceptable one
         if (state%h < fouru*(one + state%s)) then
            state%h = fouru*(one + state%s)
            return
         end if

         ! If error tolerances are too small, increase them to acceptable values
         temp = norm2(state%y) + one
         if (0.5_dp*(state%relerr*temp + state%abserr) < twou*temp) then
            if (state%relerr /= zero) then
               state%relerr = fouru*(one + fouru)
               state%abserr = max(state%abserr, zero)
            else
               state%abserr = fouru*temp
            end if
            return
         end if

         ! STARTUP SECTION (FIRST STEP ALONG ZERO CURVE)

         state%crash = .false.
         if (state%start) then
            fail = .false.
            state%start = .false.

            ! Determine suitable initial step size
            state%h = min(state%h, 0.1_dp, sqrt(sqrt(state%relerr*temp + state%abserr)))

            ! Use linear predictor along tangent direction to start Newton iteration
            state%ypold(1) = one
            state%ypold(2:np1) = zero
            call tangnf(callbacks, state%s, state%n, state%y, state%yp, state%ypold, state%a, &
                        state%nfe, state%iflag, &
                        ws%qr, ws%alpha, ws%tz, ws%pivot)

            if (state%iflag > 0) return

            do

               ws%w = state%y + state%h*state%yp
               ws%z0 = ws%w

               do judy = 1, max_newton

                  ! Calculate the Newton step 'tz' at the current point 'w'
                  rholen = -one
                  call tangnf(callbacks, rholen, &
                              state%n, ws%w, ws%wp, state%ypold, state%a, &
                              state%nfe, state%iflag, &
                              ws%qr, ws%alpha, ws%tz, ws%pivot)
                  if (state%iflag > 0) return

                  ! Take Newton step and check convergence
                  ws%w = ws%w + ws%tz
                  itnum = judy

                  ! Compute quantities used for optimal step size estimation
                  if (judy == 1) then
                     lcalc = norm2(ws%tz)
                     rcalc = rholen
                     ws%z1 = ws%w
                  else if (judy == 2) then
                     lcalc = norm2(ws%tz)/lcalc
                     rcalc = rholen/rcalc
                  end if

                  ! Go to mop-up section after convergence
                  if (norm2(ws%tz) <= state%relerr*norm2(ws%w) + state%abserr) then
                     go to 600
                  end if

               end do

               ! No convergence in 'max_newton' iterations. Reduce h and try again.
               if (state%h <= fouru*(one + state%s)) then
                  state%iflag = 6
                  return
               end if
               state%h = state%h/2

            end do

         end if

         ! PREDICTOR SECTION

         fail = .false.

         do

            ! Compute point predicted by Hermite interpolant. Use step size 'h' computed on
            ! last call to 'stepnf'.
            do j = 1, np1
               ws%w(j) = qofs(state%yold(j), state%ypold(j), state%y(j), state%yp(j), &
                              state%hold, state%hold + state%h)
            end do

            ws%z0 = ws%w

            ! CORRECTOR SECTION
            do judy = 1, max_newton

               ! Calculate the Newton step 'tz' at the current point 'w'
               rholen = -one
               call tangnf(callbacks, rholen, &
                           state%n, ws%w, ws%wp, state%yp, state%a, state%nfe, &
                           state%iflag, ws%qr, ws%alpha, ws%tz, ws%pivot)
               if (state%iflag > 0) return

               ! Take Newton step and check convergence
               ws%w = ws%w + ws%tz
               itnum = judy

               ! Compute quantities used for optimal step size estimation.
               if (judy == 1) then
                  lcalc = norm2(ws%tz)
                  rcalc = rholen
                  ws%z1 = ws%w
               else if (judy == 2) then
                  lcalc = norm2(ws%tz)/lcalc
                  rcalc = rholen/rcalc
               end if

               ! Go to mop-up section after convergence
               if (norm2(ws%tz) <= state%relerr*norm2(ws%w) + state%abserr) then
                  go to 600
               end if

            end do

            ! No convergence in 'max_newton' iterations. Record failure at calculated 'h'
            ! Save this step size, reduce 'h' and try again.

            fail = .true.
            hfail = state%h

            if (state%h <= fouru*(one + state%s)) then
               state%iflag = 6
               return
            end if

            state%h = state%h/2

         end do

         ! MOP-UP SECTION

         ! 'yold'  and  'y'  always contain the last two points found on the zero curve of
         ! the homotopy map. 'ypold' and 'yp' contain the tangent vectors to the zero curve
         ! at  'yold'  and  'y' , respectively.
600      state%ypold = state%yp
         state%yold = state%y
         state%y = ws%w
         state%yp = ws%wp
         ws%w = state%y - state%yold

         ! Update arc length
         state%hold = norm2(ws%w)
         state%s = state%s + state%hold

         ! OPTIMAL STEP SIZE ESTIMATION SECTION

         ! Calculate the distance factor 'dcalc'
         ws%tz = ws%z0 - state%y
         ws%w = ws%z1 - state%y
         dcalc = norm2(ws%tz)
         if (dcalc /= zero) dcalc = norm2(ws%w)/dcalc

         ! The optimal step size hbar is defined by
         !
         !   ht = hold * [min(lideal/lcalc, rideal/rcalc, dideal/dcalc)]**(1/p)
         !
         !   hbar = min [ max(ht, bmin*hold, hmin), bmax*hold, hmax ]

         ! If convergence had occurred after 1 iteration, set the contraction factor 'lcalc'
         ! to zero.
         if (itnum == 1) lcalc = zero

         ! Formula for optimal step size
         if (lcalc + rcalc + dcalc == zero) then
            ht = sspar(7)*state%hold
         else
            ht = (one/max(lcalc/sspar(1), rcalc/sspar(2), &
                          dcalc/sspar(3)))**(one/sspar(8))*state%hold
         end if

         ! 'ht' contains the estimated optimal step size. Put it within reasonable bounds
         state%h = min( &
                   max(ht, sspar(6)*state%hold, sspar(4)), &
                   sspar(7)*state%hold, &
                   sspar(5) &
                   )

         if (itnum == 1) then
            ! If convergence had occurred after 1 iteration, don't decrease 'h'.
            state%h = max(state%h, state%hold)
         else if (itnum == max_newton) then
            ! If convergence required the maximum 'max_newton' iterations, don't increase 'h'.
            state%h = min(state%h, state%hold)
         end if

         ! If convergence did not occur in 'max_newton' iterations for a particular
         ! 'h = hfail', don't choose the new step size larger than 'hfail'.
         if (fail) state%h = min(state%h, hfail)

      end associate

   end subroutine stepnf