Core integrator for dop853. parameters same as in dop853 with workspace added.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(dop853_class), | intent(inout) | :: | me | |||
real(kind=wp), | intent(inout) | :: | x | |||
real(kind=wp), | intent(inout), | dimension(:) | :: | y | ||
real(kind=wp), | intent(in) | :: | xend | |||
real(kind=wp), | intent(inout) | :: | hmax | |||
real(kind=wp), | intent(inout) | :: | h | |||
real(kind=wp), | intent(in), | dimension(:) | :: | rtol | ||
real(kind=wp), | intent(in), | dimension(:) | :: | atol | ||
integer, | intent(in) | :: | itol | |||
integer, | intent(in) | :: | iprint | |||
integer, | intent(in) | :: | iout | |||
integer, | intent(out) | :: | idid | |||
integer, | intent(in) | :: | nmax | |||
integer, | intent(in) | :: | nstiff | |||
real(kind=wp), | intent(in) | :: | safe | |||
real(kind=wp), | intent(in) | :: | beta | |||
real(kind=wp), | intent(in) | :: | fac1 | |||
real(kind=wp), | intent(in) | :: | fac2 | |||
integer, | intent(inout) | :: | nfcn | |||
integer, | intent(inout) | :: | nstep | |||
integer, | intent(inout) | :: | naccpt | |||
integer, | intent(inout) | :: | nrejct |
subroutine dp86co(me,x,y,xend,hmax,h,rtol,atol,itol,iprint, &
iout,idid,nmax,nstiff,safe, &
beta,fac1,fac2, &
nfcn,nstep,naccpt,nrejct)
implicit none
class(dop853_class),intent(inout) :: me
real(wp),intent(inout) :: x
real(wp),dimension(:),intent(inout) :: y
real(wp),intent(in) :: xend
real(wp),intent(inout) :: hmax
real(wp),intent(inout) :: h
real(wp),dimension(:),intent(in) :: rtol
real(wp),dimension(:),intent(in) :: atol
integer,intent(in) :: itol
integer,intent(in) :: iprint
integer,intent(in) :: iout
integer,intent(out) :: idid
integer,intent(in) :: nmax
integer,intent(in) :: nstiff
real(wp),intent(in) :: safe
real(wp),intent(in) :: beta
real(wp),intent(in) :: fac1
real(wp),intent(in) :: fac2
integer,intent(inout) :: nfcn
integer,intent(inout) :: nstep
integer,intent(inout) :: naccpt
integer,intent(inout) :: nrejct
real(wp),dimension(me%n) :: y1,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10
real(wp) :: atoli,bspl,deno,err,err2,erri,expo1,fac,fac11,&
facc1,facc2,facold,hlamb,hnew,posneg,rtoli,&
sk,stden,stnum,xout,xph,ydiff
integer :: i,iasti,iord,irtrn,j,nonsti,nrd
logical :: reject,last,event,abort
! initializations
nrd = me%nrdens
facold = 1.0e-4_wp
expo1 = 1.0_wp/8.0_wp - beta*0.2_wp
facc1 = 1.0_wp/fac1
facc2 = 1.0_wp/fac2
posneg = sign(1.0_wp,xend-x)
irtrn = 0 ! these were not initialized
nonsti = 0 ! in the original code
xout = 0.0_wp !
! initial preparations
atoli = atol(1)
rtoli = rtol(1)
last = .false.
hlamb = 0.0_wp
iasti = 0
call me%fcn(x,y,k1)
hmax = abs(hmax)
iord = 8
if ( h==0.0_wp ) then
h = me%hinit(x,y,posneg,k1,iord,hmax,atol,rtol,itol)
end if
nfcn = nfcn + 2
reject = .false.
me%xold = x
if ( iout/=0 ) then
irtrn = 1
me%hout = 1.0_wp
call me%solout(naccpt+1,me%xold,x,y,irtrn,xout)
abort = ( irtrn<0 )
else
abort = .false.
end if
if (.not. abort) then
do
! basic integration step
if ( nstep>nmax ) then
if ( iprint/=0 ) &
write (iprint,'(A,E18.4)') ' exit of dop853 at x=', x
if ( iprint/=0 ) &
write (iprint,*) ' more than nmax =' , nmax , 'steps are needed'
idid = -2
return
elseif ( 0.1_wp*abs(h)<=abs(x)*uround ) then
if ( iprint/=0 ) &
write (iprint,'(A,E18.4)') ' exit of dop853 at x=', x
if ( iprint/=0 ) &
write (iprint,*) ' step size too small, h=' , h
idid = -3
return
else
if ( (x+1.01_wp*h-xend)*posneg>0.0_wp ) then
h = xend - x
last = .true.
end if
nstep = nstep + 1
! the twelve stages
if ( irtrn>=2 ) call me%fcn(x,y,k1)
y1 = y + h*a21*k1
call me%fcn(x+c2*h,y1,k2)
y1 = y + h*(a31*k1+a32*k2)
call me%fcn(x+c3*h,y1,k3)
y1 = y + h*(a41*k1+a43*k3)
call me%fcn(x+c4*h,y1,k4)
y1 = y + h*(a51*k1+a53*k3+a54*k4)
call me%fcn(x+c5*h,y1,k5)
y1 = y + h*(a61*k1+a64*k4+a65*k5)
call me%fcn(x+c6*h,y1,k6)
y1 = y + h*(a71*k1+a74*k4+a75*k5+a76*k6)
call me%fcn(x+c7*h,y1,k7)
y1 = y + h*(a81*k1+a84*k4+a85*k5+a86*k6+a87*k7)
call me%fcn(x+c8*h,y1,k8)
y1 = y + h*(a91*k1+a94*k4+a95*k5+a96*k6+a97*k7+a98*k8)
call me%fcn(x+c9*h,y1,k9)
y1 = y + h*(a101*k1+a104*k4+a105*k5+a106*k6+a107*k7+&
a108*k8+a109*k9)
call me%fcn(x+c10*h,y1,k10)
y1 = y + h*(a111*k1+a114*k4+a115*k5+a116*k6+a117*k7+&
a118*k8+a119*k9+a1110*k10)
call me%fcn(x+c11*h,y1,k2)
xph = x + h
y1 = y + h*(a121*k1+a124*k4+a125*k5+a126*k6+a127*k7+&
a128*k8+a129*k9+a1210*k10+a1211*k2)
call me%fcn(xph,y1,k3)
nfcn = nfcn + 11
k4 = b1*k1+b6*k6+b7*k7+b8*k8+b9*k9+b10*k10+b11*k2+b12*k3
k5 = y + h*k4
! error estimation
err = 0.0_wp
err2 = 0.0_wp
if ( itol==0 ) then
do i = 1 , me%n
sk = atoli + rtoli*max(abs(y(i)),abs(k5(i)))
erri = k4(i) - bhh1*k1(i) - bhh2*k9(i) - bhh3*k3(i)
err2 = err2 + (erri/sk)**2
erri = er1*k1(i) + er6*k6(i) + er7*k7(i) + er8*k8(i) &
+ er9*k9(i) + er10*k10(i) + er11*k2(i) &
+ er12*k3(i)
err = err + (erri/sk)**2
end do
else
do i = 1 , me%n
sk = atol(i) + rtol(i)*max(abs(y(i)),abs(k5(i)))
erri = k4(i) - bhh1*k1(i) - bhh2*k9(i) - bhh3*k3(i)
err2 = err2 + (erri/sk)**2
erri = er1*k1(i) + er6*k6(i) + er7*k7(i) + er8*k8(i) &
+ er9*k9(i) + er10*k10(i) + er11*k2(i) &
+ er12*k3(i)
err = err + (erri/sk)**2
end do
end if
deno = err + 0.01_wp*err2
if ( deno<=0.0_wp ) deno = 1.0_wp
err = abs(h)*err*sqrt(1.0_wp/(me%n*deno))
! computation of hnew
fac11 = err**expo1
! lund-stabilization
fac = fac11/facold**beta
! we require fac1 <= hnew/h <= fac2
fac = max(facc2,min(facc1,fac/safe))
hnew = h/fac
if ( err<=1.0_wp ) then
! step is accepted
facold = max(err,1.0e-4_wp)
naccpt = naccpt + 1
call me%fcn(xph,k5,k4)
nfcn = nfcn + 1
! stiffness detection
if ( mod(naccpt,nstiff)==0 .or. iasti>0 ) then
stnum = 0.0_wp
stden = 0.0_wp
do i = 1 , me%n
stnum = stnum + (k4(i)-k3(i))**2
stden = stden + (k5(i)-y1(i))**2
end do
if ( stden>0.0_wp ) hlamb = abs(h)*sqrt(stnum/stden)
if ( hlamb>6.1_wp ) then
nonsti = 0
iasti = iasti + 1
if ( iasti==15 ) then
if ( iprint/=0 ) &
write (iprint,*) &
' the problem seems to become stiff at x = ', x
if ( iprint==0 ) then
idid = -4 ! fail exit
return
end if
end if
else
nonsti = nonsti + 1
if ( nonsti==6 ) iasti = 0
end if
end if
! final preparation for dense output
event = (iout==3) .and. (xout<=xph)
if ( iout==2 .or. event ) then
! save the first function evaluations
do j = 1 , nrd
i = me%icomp(j)
me%cont(j) = y(i)
ydiff = k5(i) - y(i)
me%cont(j+nrd) = ydiff
bspl = h*k1(i) - ydiff
me%cont(j+nrd*2) = bspl
me%cont(j+nrd*3) = ydiff - h*k4(i) - bspl
me%cont(j+nrd*4) = d41*k1(i)+d46*k6(i)+d47*k7(i)+&
d48*k8(i)+d49*k9(i)+d410*k10(i)+&
d411*k2(i)+d412*k3(i)
me%cont(j+nrd*5) = d51*k1(i)+d56*k6(i)+d57*k7(i)+&
d58*k8(i)+d59*k9(i)+d510*k10(i)+&
d511*k2(i)+d512*k3(i)
me%cont(j+nrd*6) = d61*k1(i)+d66*k6(i)+d67*k7(i)+&
d68*k8(i)+d69*k9(i)+d610*k10(i)+&
d611*k2(i)+d612*k3(i)
me%cont(j+nrd*7) = d71*k1(i)+d76*k6(i)+d77*k7(i)+&
d78*k8(i)+d79*k9(i)+d710*k10(i)+&
d711*k2(i)+d712*k3(i)
end do
! the next three function evaluations
y1 = y + h*(a141*k1+a147*k7+a148*k8+a149*k9+&
a1410*k10+a1411*k2+a1412*k3+a1413*k4)
call me%fcn(x+c14*h,y1,k10)
y1 = y + h*(a151*k1+a156*k6+a157*k7+a158*k8+&
a1511*k2+a1512*k3+a1513*k4+a1514*k10)
call me%fcn(x+c15*h,y1,k2)
y1 = y + h*(a161*k1+a166*k6+a167*k7+a168*k8+a169*k9+&
a1613*k4+a1614*k10+a1615*k2)
call me%fcn(x+c16*h,y1,k3)
nfcn = nfcn + 3
! final preparation
do j = 1 , nrd
i = me%icomp(j)
me%cont(j+nrd*4) = h*(me%cont(j+nrd*4)+d413*k4(i)+&
d414*k10(i)+d415*k2(i)+d416*k3(i))
me%cont(j+nrd*5) = h*(me%cont(j+nrd*5)+d513*k4(i)+&
d514*k10(i)+d515*k2(i)+d516*k3(i))
me%cont(j+nrd*6) = h*(me%cont(j+nrd*6)+d613*k4(i)+&
d614*k10(i)+d615*k2(i)+d616*k3(i))
me%cont(j+nrd*7) = h*(me%cont(j+nrd*7)+d713*k4(i)+&
d714*k10(i)+d715*k2(i)+d716*k3(i))
end do
me%hout = h
end if
k1 = k4
y = k5
me%xold = x
x = xph
if ( iout==1 .or. iout==2 .or. event ) then
call me%solout(naccpt+1,me%xold,x,y,irtrn,xout)
if ( irtrn<0 ) exit !abort
end if
! normal exit
if ( last ) then
h = hnew
idid = 1
return
end if
if ( abs(hnew)>hmax ) hnew = posneg*hmax
if ( reject ) hnew = posneg*min(abs(hnew),abs(h))
reject = .false.
else
! step is rejected
hnew = h/min(facc1,fac11/safe)
reject = .true.
if ( naccpt>=1 ) nrejct = nrejct + 1
last = .false.
end if
h = hnew
end if
end do
end if
if ( iprint/=0 ) write (iprint,'(A,E18.4)') ' exit of dop853 at x=', x
idid = 2
end subroutine dp86co