!
! Numerical Mathematics and Computing, Fifth Edition
! Ward Cheney & David Kincaid
! Brooks/Cole Publ. Co.
! (c) 2003
!
! Using the Computer Problem Chapter 11
!
! file: amrk.f90
!
! Adams-Moulton method for systems of ode's (amrk,rksys,amsys,xpsys)

program main
      integer, parameter :: n = 5, nsteps = 100
      real, parameter :: a = 0.0, b = 1.0
      real ::  h	
      real, dimension (0:n) :: x

      x = (/1.0,2.0,-4.0,-2.0,7.0,6.0/)
      h = (b - a)/nsteps
      call amrk(n,h,x,40)
end program main
  
subroutine xpsys(n,x,f) 
      real, dimension (0:n) :: x, f   
      integer n
      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 amrk(n,h,x,nsteps)  
      integer :: n, nsteps, m, i, k
      real :: h, est
      real, dimension (0:n) :: x
      real, allocatable :: z(:,:), f(:,:)
      allocate (f(0:n,0:4),z(0:n,0:4))
      m = 0       
      do i=0,n  
        z(i,m) = x(i)       
      end do
      do k=1,3
         call rk4sys(m,n,h,z,f)
        print *,"k=",k
         print *,"z",(z(i,m),i=0,n)
      end do   
      do k = 4,nsteps
        call amsys(m,n,h,z,f,est)
        print *,"k = ", k
        print *, "est = ",est
        print *,"z",(z(i,m),i=0,n)
      end do
      do i=0,n  
        x(i) = z(i,m)       
      end do
      deallocate (f,z)
end subroutine amrk 
  
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 




