! ! Numerical Mathematics and Computing, Fifth Edition ! Ward Cheney & David Kincaid ! Brooks/Cole Publ. Co. ! (c) 2003 ! ! Section 11.3 ! ! file: amrkad.f90 ! ! adaptive scheme for adams-moulton method for systems of ode's ! (amrkad,xpsys,amrk,amsys,rksys) program main integer, parameter :: n = 5 real:: ta,tb,h,emin, emax,hmin, hmax integer :: itmax,iflag real, dimension(0:n) :: x itmax = 25 ta = 0.0 tb = 1.0 t = ta x = (/1.0,2.0,-4.0,-2.0,7.0,6.0/) h = (tb -ta)/itmax emin = 1.0e-8 emax = 1.0e-2 hmin = 1.0e-4 hmax = 1.0 print "(2x,'ta and h:',(2x,2f10.5))",ta,h print "(5x,7e15.8)",(x(i),i=0,n) call amrkad(n,h,t,tb,x,itmax,emin,emax,hmin,hmax,iflag) print "('0 iflag =',i2)", iflag end program main subroutine xpsys(n,x,f) integer n real, dimension (0:n) :: x, f f(0) = 1.0 f(1) = x(2) f(2) = x(1)-x(3)- 9*x(2)**2 + x(4)**3 + 6*x(5) + 2*x(0) f(3) = x(4) f(4) = x(5) f(5) = x(5) -x(2) + exp(x(1)) - x(0) end subroutine xpsys subroutine amrkad(n,h,t,tb,x,itmax,emin,emax,hmin,hmax,iflag) integer :: itmax,iflag,m,irk,iam,nstep,i real, parameter :: epsi = 1.0e-6 real :: t,h,tb,emin,emax,hmin,hmax,dt real, dimension (0:n) :: x real, allocatable :: z(:,:), f(:,:) allocate (f(0:n,0:4),z(0:n,0:4)) m = 0 irk = 3 iam = 0 iflag = 3 nstep = 0 print "(2x,'initial values: nstep,t,h:',i5,1x,2(e10.3,1x))",nstep,t,h print "(8x,'x:',5(5x,e22.14))", x do i=0,n z(i,m) = x(i) end do if (abs(tb - t) < abs(4.0*h)) h = 0.25*h all: do if (abs(h) < hmin) then h = sign(1.0,h)*hmin iflag = 2 end if if (abs(h) > hmax) then h = sign(1.0,h)*hmax iflag =2 end if dt = abs(tb - t) if (dt < abs(h)) then iflag = 0 if (dt <= epsi*max(abs(tb),abs(t))) exit h = sign(1.0,dt)*h irk = 1 iam = 0 if ( (abs(h) < hmin) .or. (abs(h) > hmax)) then iflag = 2 exit end if end if if (iam == 0) then do k=1,irk call rk4sys(m,n,h,z,f) nstep = nstep + 1 t = t + h print "(2x,'RK: nstep,t,h:',i5,1x,2(e10.3,1x))",nstep,t,h print "(8x,'x:',5(5x,e22.14))", (z(i,m),i=0,n) end do if (nstep > itmax .or. irk == 1) exit end if call amsys(m,n,h,z,f,est) nstep = nstep + 1 t = t + h print "(2x,'AM: nstep,t,h,est:',i5,1x,3(e10.3,1x))",nstep,t,h,est print "(8x,'x:',5(5x,e22.14))",(z(i,m),i=1,n) if(nstep > itmax .or. iflag == 0) exit if (emin <= est .and. est <= emax) then irk = 0 iam = 1 else t = t - 4.0*h nstep = nstep - 4 m = 0 irk = 3 iam = 0 if (est < emin) then h = 2.0*h end if if (est > emax) then h = 0.5*h end if if ( (abs(h) < hmin) .or. (abs(h) > hmax)) then iflag = 2 exit end if end if end do all iflag = 1 do i=0,n x(i) = z(i,m) end do deallocate (f,z) end subroutine amrkad subroutine rk4sys(m,n,h,z,f) real, dimension (0:n,0:4) :: f, z real, allocatable :: y(:), g(:,:) integer :: i, n, m,mp1 real :: h allocate (y(0:n), g(0:n,3)) mp1 = mod(1+m,5) call xpsys(n,z(0,m),f(0,m)) in1: do i = 0,n y(i) = z(i,m) + 0.5*h*f(i,m) end do in1 call xpsys(n,y,g(0,1)) in2: do i = 0,n y(i) = z(i,m) + 0.5*h*g(i,1) end do in2 call xpsys(n,y,g(0,2)) in3: do i = 0,n y(i) = z(i,m) + h*g(i,2) end do in3 call xpsys(n,y,g(0,3)) in4: do i = 0,n z(i,mp1) = z(i,m) + h*(f(i,m) + 2.0*(g(i,1) + g(i,2)) + g(i,3))/6.0 end do in4 m = mp1 deallocate (y) end subroutine rk4sys subroutine amsys(m,n,h,z,f,est) real :: h, est,dlt, dltmax integer :: n, m, mp1,k,i,j real, dimension (0:n,0:4) :: f, z real, allocatable :: sum(:), y(:) dimension cp(4), cc(4) real, parameter :: cp = (/55.0,-59.0,37.0,-9.0/) real, parameter :: cc = (/ 9.0, 19.0,-5.0, 1.0/) allocate (sum(0:n), y(0:n)) mp1 = mod(m+1,5) call xpsys(n,z(0,m),f(0,m)) do i = 0,n sum(i) = 0.0 end do outer: do k = 1,4 j = mod(m-k+6,5) inner: do i = 0,n sum(i) = sum(i) + cp(k)*f(i,j) end do inner end do outer do i = 0,n y(i) = z(i,m) + h*sum(i)/24.0 end do call xpsys(n,y,f(0,mp1)) do i = 0,n sum(i) = 0.0 end do do k = 1,4 j = mod(mp1-k+6,5) do i = 0,n sum(i) = sum(i) + cc(k)*f(i,j) end do end do do i = 0,n z(i,mp1) = z(i,m) + h*sum(i)/24.0 end do dltmax = 0.0 do i = 0,n dlt = abs( (z(i,mp1) - y(i)))/ abs(z(i,mp1) ) if(dlt .gt. dltmax) then dltmax = dlt idlt = i end if end do est = (19.0/270.0)*dltmax m = mp1 deallocate (sum,y) end subroutine amsys