Main integration routine for the rk_variable_step_class.
Type | Intent | Optional | 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 |
subroutine integrate_variable_step(me,t0,x0,h,tf,xf) 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 real(wp) :: t,dt,t2,dt_new real(wp),dimension(me%n) :: x,xerr,tol logical :: last !! it is the last step logical :: accept !! the step is accepted integer :: i !! max step size reduction attempts counter integer :: p !! order of the method if (.not. associated(me%f)) then call me%raise_exception(RKLIB_ERROR_F_NOT_ASSOCIATED) return end if call me%begin_integration() call me%export_point(t0,x0,.true.) !first point if (abs(t0-tf)<=zero) then xf = x0 else t = t0 x = x0 dt = me%compute_initial_step(t0,tf,x0,h) 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,xerr) if (me%stopped) return if (me%stepsize_method%fixed_step_mode) then ! don't adjust the step size accept = .true. me%last_accepted_step_size = dt ! save it [really only needs to be done once] else ! evaluate error and compute new step size: xerr = abs(xerr) tol = me%rtol * abs(xf) + me%atol call me%stepsize_method%compute_stepsize(me%n,dt,tol,xerr,p,dt_new,accept) if (accept) me%last_accepted_step_size = dt ! save it dt = dt_new end if if (accept) then !accept this step me%num_steps = me%num_steps + 1 if (me%num_steps > me%max_number_of_steps) then call me%raise_exception(RKLIB_ERROR_TOO_MANY_STEPS) return end if 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 call me%raise_exception(RKLIB_ERROR_TOO_MANY_REDUCTIONS) return end if if (abs(dt) < abs(me%stepsize_method%hmin)) then call me%raise_exception(RKLIB_ERROR_MIN_STEP_SIZE) return end if last = ((dt>=zero .and. (t+dt)>=tf) .or. & !adjust last time step (dt<zero .and. (t+dt)<=tf)) ! if (last) dt = tf-t ! t2 = t + dt end if end do if (last) exit call me%export_point(t2,xf) !intermediate point x = xf t = t2 end do end if call me%export_point(tf,xf,.true.) !last point end subroutine integrate_variable_step