














































      subroutine bicgst2d(cc,ce,cw,cn,cs,u,rhs,
     &             eps,rmax,ier,im,jm)
c
c
c
c
      implicit none
c
      integer,intent(in) :: im,jm
      real*8,intent(inout) :: cc(im,jm),cn(im,jm),cs(im,jm),
     $     ce(im,jm),cw(im,jm)
      real*8,intent(out) :: eps
      real*8,intent(out) :: rmax
      real*8 :: u(im,jm),rhs(im,jm)
c
      integer ncyc
      integer iscale,i,j,k,ier
c
c
c
      ncyc = (im-2)*(jm-2)
      
      ier=0

c
c
c
c
c
      iscale=1
      do j = 2,jm-1
         do i = 2,im-1
            if (cc(i,j).eq.0.) iscale = 0
         enddo
      enddo
      
c
c
c
      if (iscale.eq.1) then


         do j = 2,jm-1
            do i = 2,im-1
               rhs(i,j)=rhs(i,j)/cc(i,j)
               cw(i,j)=cw(i,j)/cc(i,j)
               ce(i,j)=ce(i,j)/cc(i,j)
               cs(i,j)=cs(i,j)/cc(i,j)
               cn(i,j)=cn(i,j)/cc(i,j)
               cc(i,j)=1.
            enddo
         enddo
         
      endif
      
c
c
c
      
      call bicgstab2d (cc,cn,cs,ce,cw,u,rhs,eps,ncyc,rmax,ier,
     &     im,jm)
      if (rmax.gt.eps) then
         ier = -1
         print*,'Did not converge'
         print*,' maximum residual    = ',rmax
         print*,' tolerance           = ',eps
      endif
      
      return
      end
c
c
c
      subroutine bicgstab2d (cc,cn,cs,ce,cw,x,r,tol,ncyc,rnorm,
     $     ier,im,jm)
c
c
c
c
      implicit none
c
      integer,intent(in) :: im,jm
      integer :: ncyc
      real*8,intent(in) :: cc(im*jm),cn(im*jm)
      real*8,intent(in) :: cs(im*jm),ce(im*jm)
      real*8,intent(in) :: cw(im*jm)
      real*8,intent(in) :: tol
      real*8,intent(out):: rnorm
      integer,intent(out) :: ier
      real*8 x(im*jm),r(im*jm)
c
      integer :: i,j,k,kk
      real*8 :: p(im*jm),Ap(im*jm),w(im*jm),As(im*jm)
      real*8 :: omega, chi,chi1,chi2, delta, deltap, pp
c
c
c

      do i = 1,im*jm
         p(i) = 0.
         Ap(i) = 0.
         w(i) = 0.
         As(i) = 0.
      enddo
      
      kk = 0
 10   call usermv2d(cc,cn,cs,ce,cw,x,Ap,im,jm)

      
      do i = 1,im*jm
         r(i) = r(i)-Ap(i)
         p(i) = r(i)
      enddo

c
      delta = 0.

      do i = 1,im*jm
         delta = delta+r(i)
      enddo

      if (delta.eq.0.) then
        ier=-1
        return
      endif

      call usermv2d(cc,cn,cs,ce,cw,p,Ap,im,jm)

c
      pp = 0.

      do i = 1,im*jm
         pp = pp+Ap(i)
      enddo
      pp = pp/delta

      if (pp.eq.0.) then
        ier=-1
        return
      endif

c
      rnorm = 0.

      do i = 1,im*jm
         rnorm = rnorm + r(i)**2
      enddo
      rnorm=sqrt(rnorm)
      
c
      if (rnorm .lt. tol)  return
      
 1    continue
      kk = kk + 1

      omega = 1./pp


      do i = 1,im*jm
         w(i) = r(i) - omega*Ap(i)
      enddo

      call usermv2d(cc,cn,cs,ce,cw,w,As,im,jm)

c
      chi1 = 0.

      do i = 1,im*jm
         chi1 = chi1+As(i)*w(i)
      enddo
c
      chi2 = 0.

      do i = 1,im*jm
         chi2 = chi2+As(i)**2
      enddo

      chi = chi1/chi2


      do i = 1,im*jm
         r(i) = w(i) - chi*As(i)
         x(i) = x(i) + omega*p(i) + chi*w(i)
      enddo

      deltap = delta
c
      delta = 0.

      do i = 1,im*jm
         delta = delta+r(i)
      enddo

      if (delta.eq.0.) then
        goto 10
      endif


      do i = 1,im*jm
         p(i) = r(i) + (p(i)-chi*Ap(i))*omega*
     &        delta/(deltap*chi)
      enddo
      
      call usermv2d(cc,cn,cs,ce,cw,p,Ap,im,jm)

c
      pp = 0.

      do i = 1,im*jm
         pp = pp+Ap(i)
      enddo
      pp=pp/delta

      if (pp.eq.0.) then
        goto 10
      endif

      if (kk.gt.ncyc) then
        print*,' BI-CGStab solver reached maximum nuber of iterations.'
        ier=-1
        return
      endif

c
      rnorm = 0.

      do i = 1,im*jm
         rnorm = rnorm+r(i)**2
      enddo
      rnorm=sqrt(rnorm)
            
      if (rnorm .gt. tol) goto 1
      return
      end
c
c
c
      subroutine usermv2d(cc,cn,cs,ce,cw,x,y,im,jm)
c
c
c
c
c
c
      implicit none
c
      integer,intent(in) :: im,jm
      real*8,intent(in) :: cc(im*jm),cn(im*jm)
      real*8,intent(in) :: cs(im*jm),ce(im*jm)
      real*8,intent(in) :: cw(im*jm)
      real*8 :: x(im*jm), y(im*jm)
c
      integer :: i, j, k
c
c
c
c
      do i = im+1,im*jm-im-1
         y(i) = cw(i)*x(i-1)
     &        +cc(i)*x(i)
     &        +ce(i)*x(i+1)
     &        +cn(i)*x(i+im)
     &        +cs(i)*x(i-im)
      enddo
c
      return
      end
      
