subroutine rkfs(f,neqn,y,t,tout,relerr,abserr,iflag,yp,h,f1,f2,f3, 1 f4,f5,savre,savae,nfe,kop,init,jflag,kflag) c c fehlberg fourth-fifth order runge-kutta method c c c rkfs integrates a system of first order ordinary differential c equations as described in the comments for rkf45 . c the arrays yp,f1,f2,f3,f4,and f5 (of dimension at least neqn) and c the variables h,savre,savae,nfe,kop,init,jflag,and kflag are used c internally by the code and appear in the call list to eliminate c local retention of variables between calls. accordingly, they c should not be altered. items of possible interest are c yp - derivative of solution vector at t c h - an appropriate stepsize to be used for the next step c nfe- counter on the number of derivative function evaluations c c logical hfaild,output c integer neqn,iflag,nfe,kop,init,jflag,kflag double precision y(neqn),t,tout,relerr,abserr,h,yp(neqn), 1 f1(neqn),f2(neqn),f3(neqn),f4(neqn),f5(neqn),savre, 2 savae c external f c double precision a,ae,dt,ee,eeoet,esttol,et,hmin,remin,rer,s, 1 scale,tol,toln,u26,epsp1,eps,ypk c integer k,maxnfe,mflag c double precision dabs,dmax1,dmin1,dsign c c remin is the minimum acceptable value of relerr. attempts c to obtain higher accuracy with this subroutine are usually c very expensive and often unsuccessful. c data remin/1.d-12/ c c c the expense is controlled by restricting the number c of function evaluations to be approximately maxnfe. c as set, this corresponds to about 500 steps. c data maxnfe/3000/ c c c check input parameters c c if (neqn .lt. 1) go to 10 if ((relerr .lt. 0.0d0) .or. (abserr .lt. 0.0d0)) go to 10 mflag=iabs(iflag) if ((mflag .eq. 0) .or. (mflag .gt. 8)) go to 10 if (mflag .ne. 1) go to 20 c c first call, compute machine epsilon c eps = 1.0d0 5 eps = eps/2.0d0 epsp1 = eps + 1.0d0 if (epsp1 .gt. 1.0d0) go to 5 u26 = 26.0d0*eps go to 50 c c invalid input 10 iflag=8 return c c check continuation possibilities c 20 if ((t .eq. tout) .and. (kflag .ne. 3)) go to 10 if (mflag .ne. 2) go to 25 c c iflag = +2 or -2 if ((kflag .eq. 3) .or. (init .eq. 0)) go to 45 if (kflag .eq. 4) go to 40 if ((kflag .eq. 5) .and. (abserr .eq. 0.0d0)) go to 30 if ((kflag .eq. 6) .and. (relerr .le. savre) .and. 1 (abserr .le. savae)) go to 30 go to 50 c c iflag = 3,4,5,6,7 or 8 25 if (iflag .eq. 3) go to 45 if (iflag .eq. 4) go to 40 if ((iflag .eq. 5) .and. (abserr .gt. 0.0d0)) go to 45 c c integration cannot be continued since user did not respond to c the instructions pertaining to iflag=5,6,7 or 8 30 stop c c reset function evaluation counter 40 nfe=0 if (mflag .eq. 2) go to 50 c c reset flag value from previous call 45 iflag=jflag if (kflag .eq. 3) mflag=iabs(iflag) c c save input iflag and set continuation flag value for subsequent c input checking 50 jflag=iflag kflag=0 c c save relerr and abserr for checking input on subsequent calls savre=relerr savae=abserr c c restrict relative error tolerance to be at least as large as c 2*eps+remin to avoid limiting precision difficulties arising c from impossible accuracy requests c rer=2.0d0*eps+remin if (relerr .ge. rer) go to 55 c c relative error tolerance too small relerr=rer iflag=3 kflag=3 return c 55 dt=tout-t c if (mflag .eq. 1) go to 60 if (init .eq. 0) go to 65 go to 80 c c initialization -- c set initialization completion indicator,init c set indicator for too many output points,kop c evaluate initial derivatives c set counter for function evaluations,nfe c estimate starting stepsize c 60 init=0 kop=0 c a=t call f(a,y,yp) nfe=1 if (t .ne. tout) go to 65 iflag=2 return c c 65 init=1 h=dabs(dt) toln=0. do 70 k=1,neqn tol=relerr*dabs(y(k))+abserr if (tol .le. 0.) go to 70 toln=tol ypk=dabs(yp(k)) if (ypk*h**5 .gt. tol) h=(tol/ypk)**0.2d0 70 continue if (toln .le. 0.0d0) h=0.0d0 h=dmax1(h,u26*dmax1(dabs(t),dabs(dt))) jflag=isign(2,iflag) c c c set stepsize for integration in the direction from t to tout c 80 h=dsign(h,dt) c c test to see if rkf45 is being severely impacted by too many c output points c if (dabs(h) .ge. 2.0d0*dabs(dt)) kop=kop+1 if (kop .ne. 100) go to 85 c c unnecessary frequency of output kop=0 iflag=7 return c 85 if (dabs(dt) .gt. u26*dabs(t)) go to 95 c c if too close to output point,extrapolate and return c do 90 k=1,neqn 90 y(k)=y(k)+dt*yp(k) a=tout call f(a,y,yp) nfe=nfe+1 go to 300 c c c initialize output point indicator c 95 output= .false. c c to avoid premature underflow in the error tolerance function, c scale the error tolerances c scale=2.0d0/relerr ae=scale*abserr c c c step by step integration c 100 hfaild= .false. c c set smallest allowable stepsize c hmin=u26*dabs(t) c c adjust stepsize if necessary to hit the output point. c look ahead two steps to avoid drastic changes in the stepsize and c thus lessen the impact of output points on the code. c dt=tout-t if (dabs(dt) .ge. 2.0d0*dabs(h)) go to 200 if (dabs(dt) .gt. dabs(h)) go to 150 c c the next successful step will complete the integration to the c output point c output= .true. h=dt go to 200 c 150 h=0.5d0*dt c c c c core integrator for taking a single step c c the tolerances have been scaled to avoid premature underflow in c computing the error tolerance function et. c to avoid problems with zero crossings,relative error is measured c using the average of the magnitudes of the solution at the c beginning and end of a step. c the error estimate formula has been grouped to control loss of c significance. c to distinguish the various arguments, h is not permitted c to become smaller than 26 units of roundoff in t. c practical limits on the change in the stepsize are enforced to c smooth the stepsize selection process and to avoid excessive c chattering on problems having discontinuities. c to prevent unnecessary failures, the code uses 9/10 the stepsize c it estimates will succeed. c after a step failure, the stepsize is not allowed to increase for c the next attempted step. this makes the code more efficient on c problems having discontinuities and more effective in general c since local extrapolation is being used and extra caution seems c warranted. c c c test number of derivative function evaluations. c if okay,try to advance the integration from t to t+h c 200 if (nfe .le. maxnfe) go to 220 c c too much work iflag=4 kflag=4 return c c advance an approximate solution over one step of length h c 220 call fehl(f,neqn,y,t,h,yp,f1,f2,f3,f4,f5,f1) nfe=nfe+5 c c compute and test allowable tolerances versus local error estimates c and remove scaling of tolerances. note that relative error is c measured with respect to the average of the magnitudes of the c solution at the beginning and end of the step. c eeoet=0.0d0 do 250 k=1,neqn et=dabs(y(k))+dabs(f1(k))+ae if (et .gt. 0.0d0) go to 240 c c inappropriate error tolerance iflag=5 return c 240 ee=dabs((-2090.0d0*yp(k)+(21970.0d0*f3(k)-15048.0d0*f4(k)))+ 1 (22528.0d0*f2(k)-27360.0d0*f5(k))) 250 eeoet=dmax1(eeoet,ee/et) c esttol=dabs(h)*eeoet*scale/752400.0d0 c if (esttol .le. 1.0d0) go to 260 c c c unsuccessful step c reduce the stepsize , try again c the decrease is limited to a factor of 1/10 c hfaild= .true. output= .false. s=0.1d0 if (esttol .lt. 59049.0d0) s=0.9d0/esttol**0.2d0 h=s*h if (dabs(h) .gt. hmin) go to 200 c c requested error unattainable at smallest allowable stepsize iflag=6 kflag=6 return c c c successful step c store solution at t+h c and evaluate derivatives there c 260 t=t+h do 270 k=1,neqn 270 y(k)=f1(k) a=t call f(a,y,yp) nfe=nfe+1 c c c choose next stepsize c the increase is limited to a factor of 5 c if step failure has just occurred, next c stepsize is not allowed to increase c s=5.0d0 if (esttol .gt. 1.889568d-4) s=0.9d0/esttol**0.2d0 if (hfaild) s=dmin1(s,1.0d0) h=dsign(dmax1(s*dabs(h),hmin),h) c c end of core integrator c c c should we take another step c if (output) go to 300 if (iflag .gt. 0) go to 100 c c c integration successfully completed c c one-step mode iflag=-2 return c c interval mode 300 t=tout iflag=2 return c end .