module IVPRKP ! version 20120824 ! This file ivprkp.f90 is part of the EPPEER-package for explicit ! parallel peer methods by B.A.Schmitt and R.Weiner available at ! www.mathematik.uni-marburg.de\~schmitt\peer ! It contains implementations of well-known Runge-Kutta methods of other ! authors from literature ! -- variable definitions integer, save :: rstages, rorder, rmxsteps, rkfcn,rksteps,rkrej real(8), save :: ratol, rrtol, rhmin, rhmax ! Runge-Kutta tables, function value first stage real(8), dimension(:), allocatable, save :: rkb, rkc, rke real(8), dimension(:,:), allocatable, save :: rka logical :: rfsal contains !-- RKSETPARAM sets integration parameters subroutine rksetparam(rtol,atol) implicit none real(8), intent(in) :: rtol, atol rrtol = rtol ratol = atol end subroutine rksetparam !-- RKMETH performs Runge-Kutta integration subroutine rkmeth(n,fcn,t,tend,y,hs,jobrep,par) implicit none interface pure subroutine fcn(t,u,udot,par) real(8), intent(in) :: t real(8), dimension(:), intent(in) :: u real(8), dimension(:), intent(out) :: udot real(8), dimension(:), intent(in) :: par end subroutine fcn end interface integer, intent(in) :: n integer :: jobrep ! control and status report real(8) :: t,tend,hs real(8), dimension(n) :: y real(8), dimension(:), intent(in) :: par integer :: stg,ic,id ! local variables real(8) tc, rer, rc, hn real(8), dimension(n) :: fv1, yc, ye real(8), dimension(n,2:rstages) :: ks logical :: o1step ! -- rksteps = 0; rkrej = 0 rhmax = tend-t o1step = (jobrep.ne.0) ! only one single step jobrep = 0 if (.not. allocated(rka)) jobrep=-1 ! rksetcoeff not called call fcn(t,y,fv1,par); rkfcn = 1 if (hs==0D0) & ! compute initial stepsize call rkinsteps(n,fcn,t,y,fv1,hs,par) do while (abs(t-tend)>1D-14 .and. (jobrep==0)) ! repeat until tend rksteps = rksteps+1 if ((t-tend)*(t+hs-tend)<0D0) hs = tend-t ! allows tend 1.D0) then ! reject step rkrej = rkrej+1 if (hn rmxsteps) jobrep=2 ! failure, too many steps hs = hn end do ! integration steps end subroutine rkmeth !-- RKSETCOEFF creates coefficient matrices, sets defaults subroutine rksetcoeff(mnr,mname) implicit none integer :: mnr character(len=16), intent(out), optional :: mname rfsal = .false. select case(mnr) ! case(2) ! RK2(1) if (present(mname)) mname = "RK1(2)" rstages = 2; rorder = 2 allocate(rka(rstages,rstages),rkb(rstages),rkc(rstages),rke(rstages)) rka(2,1)=1.D0/2.D0 rkc = (/ 0.D0, 1.D0/2.D0 /) rkb = (/ 0.D0, 1.D0 /) rke = (/-1.D0, 1.D0 /) case(3) ! RK3(2) if (present(mname)) mname = "RK2(3)" rstages = 3; rorder = 3 allocate(rka(rstages,rstages),rkb(rstages),rkc(rstages),rke(rstages)) rka(2,1)=1.D0 rka(3,1)=1.D0/4.D0; rka(3,2)=1.D0/4.D0; rkc = (/ 0.D0, 1.D0, 0.5D0 /) rkb = (/ 1.D0/6.D0, 1.D0/6.D0, 2.D0/3.D0 /) rke = (/-1.D0/3.D0,-1.D0/3.D0, 2.D0/3.D0 /) case(4) ! RKFB4(5) if (present(mname)) mname = "RKFB4(5)" rstages = 6; rorder = 4 allocate(rka(rstages,rstages),rkb(rstages),rkc(rstages),rke(rstages)) rka(2,1) = 1D0/4 rka(3,1) = 3D0/32; rka(3,2)=9D0/32 rka(4,1)=1932.D0/2197; rka(4,2)=-72.D2/2197; rka(4,3)=7296.D0/2197 rka(5,1)=439.D0/216; rka(5,2)=-8.D0; rka(5,3)=368.D1/513; rka(5,4)=-845.D0/4104; rka(6,1)=-8.D0/27; rka(6,2)=2.D0; rka(6,3)=-3544.D0/2565; rka(6,4)=1859.D0/4104; rka(6,5)=-11.D0/40; rkc = (/ 0.D0, 1.D0/4, 3.D0/8, 12.D0/13, 1.D0, 1.D0/2 /) rkb = (/ 25D0/216,0D0,1408D0/2565,2197D0/4104,-1D0/5,0D0 /) rke = (/ 16D0/135,0D0,6656D0/12825,28561D0/56430,-9D0/50,2D0/55 /) rke = rkb - rke ! for difference of solutions case(5) ! DoPri5(4) if (present(mname)) mname = "DoPri5(4)" rstages = 7; rorder = 5 rfsal = .true. ! first stage as last allocate(rka(rstages,rstages),rkb(rstages),rkc(rstages),rke(rstages)) rka(2,1)=0.2D0 rka(3,1)=3.D0/40.D0; rka(3,2)=9.D0/40.D0 rka(4,1)=44.D0/45.D0; rka(4,2)=-56.D0/15.D0; rka(4,3)=32.D0/9.D0 rka(5,1)=19372.D0/6561.D0; rka(5,2)=-25360.D0/2187.D0; rka(5,3)=64448.D0/6561.D0; rka(5,4)=-212.D0/729.D0 rka(6,1)=9017.D0/3168.D0; rka(6,2)=-355.D0/33.D0 rka(6,3)=46732.D0/5247.D0; rka(6,4)=49.D0/176.D0 rka(6,5)=-5103.D0/18656.D0 rka(7,1)=35.D0/384.D0; rka(7,2)=0.D0; rka(7,3)=500.D0/1113.D0 rka(7,4)=125.D0/192.D0; rka(7,5)=-2187.D0/6784.D0 rka(7,6)=11.D0/84.D0 rkb = (/35.D0/384.D0,0.D0,500.D0/1113.D0,125.D0/192.D0,-2187.D0/6784.D0, & 11.D0/84.D0, 0D0 /) rkc = (/0D0, 0.2D0, 0.3D0,0.8D0,8.D0/9.D0,1.D0,1.D0 /) rke = (/71.D0/57600.D0,0.D0,-71.D0/16695.D0,71.D0/1920.D0,-17253.D0/339200.D0, & 22.D0/525.D0,-1.D0/40.D0 /) case default ! if (present(mname)) mname = "error" mnr = -1 end select ! set default parameters rmxsteps = 1000000 rhmin = 1.D-10 ratol = 1.D-5; rrtol=ratol end subroutine rksetcoeff ! -- inisteps computes initial stepsize [dopri/Hairer-Wanner] subroutine rkinsteps(n,fcn,t,y,fv1,hs,par) implicit none interface pure subroutine fcn(t,u,udot,par) real(8), intent(in) :: t real(8), dimension(:), intent(in) :: u real(8), dimension(:), intent(out) :: udot real(8), dimension(:), intent(in) :: par end subroutine fcn end interface integer, intent(in) :: n real(8), dimension(:), intent(in) :: y, fv1 real(8), dimension(:), intent(in) :: par real(8) :: t,hs, h,h1,rc,dnf,dny,der2,der12 real(8), dimension(n) :: y2, f2 integer :: id dnf = 0.D0; dny = 0.D0 do id = 1,n rc = ratol+rrtol*abs(y(id)) dnf = dnf +(fv1(id)/rc)**2 dny = dny +(y(id)/rc)**2 end do if (min(dnf,dny)<1D-10) then h = 1.D-6 else h =1.D-2*sqrt(dny/dnf) end if h = min(h,rhmax) y2 = y+h*fv1 ! explicit Euler step call fcn(t+h,y2,f2,par) der2 = 0.D0 do id = 1,n rc = ratol+rrtol*abs(y(id)) der2 = der2 +((f2(id)-fv1(id))/rc)**2 end do der2 = sqrt(der2)/h ! estimate for second derivative der12 = max(der2,sqrt(dnf)) if (der12<=1.D-15) then h1 = max(1.D-6,h*1.D-3) else h1 = (1.D-2/der12)**(1.D0/rorder) end if hs = min(1D2*h,h1,rhmax) end subroutine rkinsteps !-- RKGETSTATS returns integration statistics subroutine rkgetstats(nsteps,nrej,nfcn) implicit none integer, intent(out) :: nsteps, nrej, nfcn nsteps = rksteps nrej = rkrej nfcn = rkfcn end subroutine rkgetstats ! -- FREECOEFF releases all memory subroutine rkfreecoeff deallocate(rka,rkb,rkc,rke) end subroutine rkfreecoeff end module IVPRKP