integrate Subroutine

private subroutine integrate(me, t0, x0, h, tf, xf, ierr)

Main integration routine for the rk_variable_step_class.

Type Bound

rk_variable_step_class

Arguments

Type IntentOptional Attributes Name
class(rk_variable_step_class), intent(inout) :: me
real(kind=wp), intent(in) :: t0

initial time

real(kind=wp), intent(in), dimension(:) :: x0

initial state

real(kind=wp), intent(in) :: h

initial abs(time step)

real(kind=wp), intent(in) :: tf

final time

real(kind=wp), intent(out), dimension(:) :: xf

final state

integer, intent(out), optional :: ierr

0 = no errors, <0 = error. if not present, an error will stop program.


Calls

proc~~integrate~~CallsGraph proc~integrate rk_module_variable_step::rk_variable_step_class%integrate order order proc~integrate->order proc~compute_stepsize rk_module_variable_step::stepsize_class%compute_stepsize proc~integrate->proc~compute_stepsize proc~hinit rk_module_variable_step::rk_variable_step_class%hinit proc~integrate->proc~hinit proc~hstart rk_module_variable_step::rk_variable_step_class%hstart proc~integrate->proc~hstart step step proc~integrate->step

Called by

proc~~integrate~~CalledByGraph proc~integrate rk_module_variable_step::rk_variable_step_class%integrate proc~rk_test_variable_step rk_module_variable_step::rk_test_variable_step proc~rk_test_variable_step->proc~integrate

Source Code

    subroutine integrate(me,t0,x0,h,tf,xf,ierr)

    implicit none

    class(rk_variable_step_class),intent(inout)     :: me
    real(wp),intent(in)               :: t0    !! initial time
    real(wp),dimension(:),intent(in)  :: x0    !! initial state
    real(wp),intent(in)               :: h     !! initial abs(time step)
    real(wp),intent(in)               :: tf    !! final time
    real(wp),dimension(:),intent(out) :: xf    !! final state
    integer,intent(out),optional      :: ierr  !! 0 = no errors,
                                               !! <0 = error.
                                               !! if not present, an error will stop program.

    real(wp) :: t,dt,t2,err,tol,dt_new
    real(wp),dimension(me%n) :: x,terr,etol,xp0
    logical :: last,export,accept
    integer :: i,p

    if (present(ierr)) ierr = 0

    if (.not. associated(me%f)) then
        if (present(ierr)) then
            ierr = -1
            return
        else
            error stop 'Error in integrate: f is not associated.'
        end if
    end if

    me%num_rejected_steps = 0
    export = associated(me%report)

    if (export) call me%report(t0,x0)  !first point

    if (t0==tf) then
        xf = x0
    else

        t = t0
        x = x0

        if (h==zero) then
            ! compute an appropriate initial step size:
            ! WARNING: this may not be working in all cases .....
            etol = me%rtol * me%stepsize_method%norm(x0) + me%atol
            call me%f(t0,x0,xp0)  ! get initial dx/dt
            select case (me%hinit_method)
            case(1)
                call me%hstart(t0,tf,x0,xp0,etol,dt)
            case(2)
                dt = me%hinit(t0,x0,sign(one,tf-t0),xp0,me%stepsize_method%hmax,me%atol,me%rtol)
            case default
                if (present(ierr)) then
                    ierr = -2
                    return
                else
                    error stop 'invalid hinit_method selection'
                end if
            end select
            !write(*,*) 'inital step size: ',dt
        else
            ! user-specified initial step size:
            dt = sign(h,tf-t0)  ! (correct sign)
        end if

        p = me%order()     !order of the method
        do
            t2 = t + dt
            last = ((dt>=zero .and. t2>=tf) .or. &  !adjust last time step
                    (dt<zero .and. t2<=tf))         !
            if (last) dt = tf-t                     !

            do i=0,me%stepsize_method%max_attempts

                ! take a step:
                call me%step(t,x,dt,xf,terr)

                ! evaluate error and compute new step size:
                err = me%stepsize_method%norm(terr)
                tol = me%stepsize_method%norm( me%rtol * xf + me%atol )
                call me%stepsize_method%compute_stepsize(dt,tol,err,p,dt_new,accept)
                dt = dt_new

                if (accept) then
                    !accept this step
                    exit
                else
                    !step is rejected, repeat step with new dt
                    me%num_rejected_steps = me%num_rejected_steps + 1

                    !note: if we have reached the min step size, and the error
                    !is still too large, we can't proceed.
                    if (i>=me%stepsize_method%max_attempts) then
                        if (present(ierr)) then
                            ierr = -3
                            return
                        else
                            error stop 'error: too many attempts to reduce step size.'
                        end if
                    end if
                    if (abs(dt) <= abs(me%stepsize_method%hmin)) then
                        if (present(ierr)) then
                            ierr = -4
                            return
                        else
                            error stop 'warning: min step size.'
                        end if
                    end if

                    !......
                    !... if we have two rejected steps and the step size hasn't changed..
                    !    then we need to abort, since no progress is being made...
                    !......

                    last = ((dt>=zero .and. t2>=tf) .or. &  !adjust last time step
                            (dt<zero .and. t2<=tf))         !
                    if (last) dt = tf-t                     !
                    t2 = t + dt

                end if

            end do

            if (last) exit
            if (export) call me%report(t2,xf)   !intermediate point
            x = xf
            t = t2
        end do

    end if

    if (export) call me%report(tf,xf)   !last point

    end subroutine integrate