        
        program integra
c 
c     Author:         Alfio Borzi
c                         Institut für Mathematik
c                         Karl-Franzens-Univrsität Graz
c                         Heinrichstr. 36, A-8010 Graz
c                         Austria
c                         E-mail: alfio.borzi@kfunigraz.ac.at
c
c     Date:            24-01-2000
c     Project:         Multigrid for integral equations 
c     Language:     FORTRAN 77
c     Constraints:   None - Public domain software         
c-----------------------------------------------------------------------------
c     For the presentation of this code see:
c (1)    Alfio Borzi' and Anni Koubek, 
c         Computer Physics Communications 75 (1993) 118-126.
c     For the analysis of the convergence properties of this code see:
c (2)    Alfio Borzi' and Anni Koubek,
c         On a Multi-Grid Algorithm for the TBA Equations
c         In P.W. Hemker and P. Wesseling (Eds.), Multigrid Methods IV,
c             International Series on Numerical Mathematics, Vol. 116,
c             Birkhäuser Verlag, Basel, 1994.
c-----------------------------------------------------------------------------
c     The data structure of this code is as given in:
c     A. Brandt,  Multi-Level Adaptive Solutions to Boundary-Value Problems
c     Mathematics of Computation 31 (1977) 333-390.
c     This code is an implementation of the Nonlinear Multi-Grid Method
c     of the Second Kind (FAS scheme) described in:
c     W. Hackbusch
c     Multi-Grid Methods and Applications, Springer-Verlag, Berlin, 1985. 
c-----------------------------------------------------------------------------
c  solution of a system of NL integral equations with a multi-grid algorithm 
c------------------------multi-grid parameters----------------------------
c  non linear nested iteration is employed         
c  nx0 - number of intervals in the coarsest level k=1
c         if your solution is smooth and the domain smaller than -10 to 10
c         use nx0 = 4, otherwise increase
c  h0  - mesh size of the coarsest level
c         calculated automatically
c  x0  - inf extremum of the interval of integration (x0=-bb)
c         bb is calculated in BOUND
c  u   - initial approximated solution to the equations
c         is composed from known term (TN) and the solution for r -> 0;
c         if this is not adapted for your problem, change it.
c  f_ij - kernel of the integral equation
c                       / bb                  
c   ui(y)=tni(y)+sum_j( |  fij(y,x,u(x))dx) , i=0,..,nsys, j=0,..,nsys
c                       /-bb                   
c     provide the kernel directly in the function F 
c  m   - number of levels     
c  ni0 - number of relaxation in the coarsest level
c  ni1 - number of relaxation before transfer to a coarser grid
c  ni2 - number of relaxation before transfer to a finer grid
c  ng  - if ng=1 v-cycle , if ng=2 w-cycle
c  ngi - number of maximally allowed Multi-Grid cycles 
c  lin - initial level where the approximation is given
c  nrel- if nrel=1 only relaxation done if nrel=0 then nmgm
c  irel- number of maximally allowed relaxation (when nrel=1)
c  nsys- number of equations 
c  the solution, at each level, is stored in q(nsys,qdim)  
c                  m
c  qdim= 2 ( nx0 (2 - 1) + m ) 
c  zero=specifies the value of the residual norm to be reached
c--------------------output--------------------------------------------
c  the output is in OUTPUT.DAT
c  and when iwrite=0 we store
c  the residuals at each computing step in RES.DAT,
c  the CPU time used versus logarithm of the residual norm
c  in TIME.DAT (the subroutine time gives the CPU time used, be aware 
c  to put in the right intrinsic function of your machine) and the 
c  solutions in SOL.DAT. 
c----------------------------------------------------------------------
      implicit real *8 (a-h,o-z)
      common/mass/rm(100)
      common/par/nsys
      common/write/iwrite
      common/coef/pi
      common/zero/zero
      common/rr/r
c     
      external u,tn,f
c     
      qdim=100000
c     
      open(unit=22,status='old',file=
     *     'integra.dat')
      open(unit=23,status='old',file=
     *     'coeff.dat')
      open(unit=24,status='unknown',file=
     *     'res.dat')
      open(unit=25,status='unknown',file=
     *     'output.dat')
      open(unit=26,status='unknown',file=
     *     'time.dat')
      open(unit=27,status='unknown',file=
     *     'sol.dat')
c     
      pi=4.0d0*datan(1.0D0)
c     
      read(22,*) i1,i2
      read(22,*) zero,hx
      read(22,*) nrel,iwrite
      read(22,*) max,step,r0
      close(22)

      do 3 i=1,i2
    3 read(23,*) rm(i)
      close(23)
c
      nsys=i2
      nx0=4
      ni0=4
      ni1=1
      ni2=1
      ng=1
      ngi=3
      irel=50
c     
      l=1
      r=r0
      if(iwrite.eq.0) write(24,106) r
      call bound(bb,f)
      if(iwrite.eq.0) write(24,107) bb
      x0=-bb
      h0=2.0d0*bb/dfloat(nx0)
      xx=dlog(h0/hx)/dlog(2.0d0)
      m=1+nint(xx)
      lin=m-1
      if(iwrite.eq.0) then
      write(24,100) nsys,lin,m
      write(24,101) nx0,h0,hx,zero
      write(24,102) ni0,ni1,ni2
      write(24,103) ng,ngi,nrel,irel
      write(24,104) max,step,r0
      endif
c     
      call nlni(qdim,nx0,nrel,irel,lin,h0,x0,m,ni0,ni1,ni2,ng,ngi,
     *  u,tn,f)
c     
      if(iwrite.eq.0) call printsol(m)     
      call time(second)
      write(25,108) second
c     
  100 format(2x,'nsys=',i3,3x,'lin=',i3,5x,'m=',i3)
  101 format(2x,' nx0=',i3,3x,' h0=',e10.4,2x,'hx=',e10.4,
     *       2x,'zero=',e10.4)
  102 format(2x,' ni0=',i3,3x,'ni1=',i3,2x,' ni2=',i3)
  103 format(2x,'  ng=',i3,3x,'ngi=',i3,2x,'nrel=',i3,2x,'irel=',i3)
  104 format(2x,' max=',i3,2x,'step=',e10.4,4x,'r0=',e10.4)
  106 format(2x,'   r=',e10.4)
  107 format(2x,'  Bb=',e10.4)
  108 format(2x,' total cpu time (secs) ',e10.3)
      close(24)
      close(25)
      close(26)
      close(27)
      stop
      end
c----------------------------------------------------------------------

      subroutine bound(bb,f)
c  calculates the boundary (-bb,bb)
      implicit real *8 (a-h,o-z)
      common/mass/rm(100)
      common/par/nsys
      common/rr/r
      common/coef/pi

      zero=5.0d-16
      x=0.0d0
      y=0.0d0

      bb=0.0d0
      do 20 ne=1,nsys
      do 20 nv=1,nsys
      b=0.0d0
   30 b=b+0.50d0
      z=r*rm(nv)*dcosh(b)
      fb=f(ne,nv,x,y,z)
      if(dabs(fb).lt.zero) goto 21
      goto 30
   21 if(b.gt.bb) bb=b
   20 continue
      return
      end
c----------------------------------------------------------------------

      subroutine crsres(k,krhs,f)
c computes the r.h.s. in the coarser level k
      implicit real *8 (a-h,o-z)
      common q(10,100000),ist(1),irhs(1)
      common/par/nsys
      call key(k,ist,jj,h,x0)
      call key(krhs,irhs,jj,h,x0)
      io=ist(1)
      ir=irhs(1)
      do 2 ns=1,nsys
      do 1 j=1,jj
      call kappau(k,f,ns,j,sum)
    1 q(ns,ir+j)=q(ns,ir+j)+q(ns,io+j)-sum
    2 continue
      return
      end
c----------------------------------------------------------------------

      real *8 function f(ne,nv,y,x,z)
c  kernel of the integral equations
c  phi(x-y)*log(1+e^(-z))/(2 pi)
      implicit real *8 (a-h,o-z)
      common/rr/r
      common/par/nsys
      common/coef/pi
c
c here compute phi_{ab}(x-y)
c we set phi=-1
c
      phi=-1.
      f=-phi*dlog(1.0d0+dexp(-z))/(pi*2.0d0)
      return
      end
c----------------------------------------------------------------------

      real *8 function tn(n,x)
c  known term of the integral equations 
c  tn=r Ma cosh(x)
      implicit real *8 (a-h,o-z)
      common/mass/rm(100)
      common/coef/pi
      common/rr/r
      tn=r*rm(n)*dcosh(x)
      return
      end
c----------------------------------------------------------------------

      real *8 function u(n,x)
c  initial function for the integral equations
c  u=tn
      implicit real *8 (a-h,o-z)
      common/mass/rm(100)
      common/eps0/eps0(10)
      common/coef/pi
      common/rr/r
      u=r*rm(n)*dcosh(x)
      return
      end
c----------------------------------------------------------------------

      subroutine grdfn(n,jmax,hh,x00)
c  define a jmax array vn
      implicit real *8 (a-h,o-z)
      common/grd/nst(200),jmx(200),h(200),x0
      common/iiqq/iq
      nst(n)=iq
      jmx(n)=jmax
      h(n)=hh
      x0=x00
      iq=iq+jmax
      return
      end
c----------------------------------------------------------------------

      subroutine intadd(k1,k2)
c makes the Coarse Grid correction to the fine-grid solution
      implicit real *8 (a-h,o-z)
      common q(10,100000),ist(1),irhs(1)
      common/par/nsys
      dimension s(25000)
c     s(qdim/4)
      call key(k1,ist,jjf,hf,x0)
      call key(k2,irhs,jjc,hc,x0)
      ir=irhs(1)
      io=ist(1)
      do 1 ns=1,nsys
      do 2 jc=1,jjc
      jfc=2*jc-1
      s(jc)=q(ns,ir+jc)-q(ns,io+jfc)
    2 continue
      q(ns,io+1)=q(ns,io+1)+s(1)
      q(ns,io+2)=q(ns,io+2)+(5.d0*s(1)+15.d0*s(2)
     +           -5.d0*s(3)+s(4))/16.d0
      jjc2=jjc-2
      do 10 jc=2,jjc2
      jf=2*jc-1
      q(ns,io+jf)=q(ns,io+jf)+s(jc)
      q(ns,io+jf+1)=q(ns,io+jf+1)+(-s(jc-1)+9.d0*s(jc)
     +               +9.d0*s(jc+1)-s(jc+2))/16.d0
   10 continue
      q(ns,io+jjf-2)=q(ns,io+jjf-2)+s(jjc-1)
      q(ns,io+jjf-1)=q(ns,io+jjf-1)+(s(jjc-3)-5.*s(jjc-2)
     +                +15.d0*s(jjc-1)+5.d0*s(jjc))/16.d0
      q(ns,io+jjf)=q(ns,io+jjf)+s(jjc)
    1 continue
      return
      end
c----------------------------------------------------------------------

      subroutine intrp3(kc,kf)
c interpolates the initial solution given at level kc to be a solution
c at level kf
      implicit real *8 (a-h,o-z)
      common q(10,100000),iuf(1),iuc(1)
      common/par/nsys
      call key(kc,iuc,jjc,hc,x0)
      call key(kf,iuf,jjf,hf,x0)
      ic0=iuc(1)
      if0=iuf(1)
      do 1 ns=1,nsys
      q(ns,if0+1)=q(ns,ic0+1)
      q(ns,if0+2)=(5.d0*q(ns,ic0+1)+15.d0*q(ns,ic0+2)
     +  -5.d0*q(ns,ic0+3)+q(ns,ic0+4))/16.d0
      jjc2 = jjc-2
      do 10 jc=2,jjc2
      jf = 2*jc-1
      q(ns,if0+jf) = q(ns,ic0+jc)
      q(ns,if0+jf+1) = (-q(ns,ic0+jc-1)+9.d0*q(ns,ic0+jc)
     +               +9.d0*q(ns,ic0+jc+1)-q(ns,ic0+jc+2))/16.d0
   10 continue
      q(ns,if0+jjf-2) = q(ns,ic0+jjc-1)
      q(ns,if0+jjf-1) = (q(ns,ic0+jjc-3)-5.d0*q(ns,ic0+jjc-2)
     +         +15.d0*q(ns,ic0+jjc-1)+5.d0*q(ns,ic0+jjc))/16.d0
      q(ns,if0+jjf) = q(ns,ic0+jjc)
    1 continue
      return
      end
c----------------------------------------------------------------------

      subroutine kappau(k,f,ne,i,sum)
c integration subroutine
      implicit real *8 (a-h,o-z)
      common q(10,100000),ist(1)
      common/par/nsys
      call key(k,ist,jj,h,x0)
      sum=0.0d0
      y0=x0
      io=ist(1)
      do 2 ns=1,nsys
      y=(i-1)*h+y0
      x=x0
      z=q(ns,io+1)
      sum0=h*0.50d0*f(ne,ns,y,x,z)
      x=(jj-1)*h+x0
      z=q(ns,io+jj)
      sum0=sum0+h*0.50d0*f(ne,ns,y,x,z)
      do 1 l=2,jj-1
      x=(l-1)*h+x0
      z=q(ns,io+l)
      sum0=sum0+h*f(ne,ns,y,x,z)
    1 continue
      sum=sum+sum0
    2 continue
      return
      end
c----------------------------------------------------------------------

      subroutine key(k,ist,jmax,hh,x00)
c  set ist such that vk(j)=q(.,ist(1)+j)
c  and set jmax=jmx(k) and x00=x0
      implicit real *8 (a-h,o-z)
      common/grd/nst(200),jmx(200),h(200),x0
      dimension ist(1)
      jmax=jmx(k)
      is=nst(k)-jmax-1
      is=is+jmax
      ist(1)=is
      x00=x0
      hh=h(k)
      return
      end

c----------------------------------------------------------------------

      subroutine nlni(qdim,nx0,nrel,irel,lin,h0,x0,m,ni0,ni1,ni2,ng,ngi,
     *   u,tn,f)
c  non-linear nested iteration
      implicit real *8 (a-h,o-z)
      dimension err(10)
      external u,tn,f
      common/par/nsys
      common/write/iwrite
      common/zero/zero
      common/finer/l1
      common/iiqq/iq
      iq=1
      do 1 k=1,m
      k2=2**(k-1)
      call grdfn(k,nx0*k2+1,h0/k2,x0)
    1 call grdfn(k+m,nx0*k2+1,h0/k2,x0)
c
      if(iq.gt.qdim) stop'increase qdim '
c          
      if(iwrite.eq.0) write(26,*)' time, Log(residual norm)'
c
      if(nrel.eq.0) goto 10
      l=m
      call putf(l,u)
      call putf(l+m,tn)
      if(iwrite.eq.0) write(24,*)'level=',l
      if(iwrite.eq.0) write(24,100)
      l1=l
      do 3 i=1,irel
      call relax(l,l+m,f,err)
      errmax=err(1)
      do 5 j=1,nsys
    5 if(err(j).gt.errmax) errmax=err(j)
      call time(second)
      residual=dlog10(errmax)
      if(iwrite.eq.0) write(26,*) second, residual
      if(errmax.lt.zero) goto 11 
    3 continue
      goto 11
c     
   10 call putf(lin,u)
      do 2 l=lin,m
      if(iwrite.eq.0) write(24,*)'level=',l
      if(iwrite.eq.0) write(24,100)
      l1=l
      call nmgm(nx0,nrel,h0,l,m,ni0,ni1,ni2,ng,ngi,u,tn,f)
      if(l.eq.m)goto 11
      call intrp3(l,l+1)
    2 continue
  100 format(3x,'e 1',5x,'e 2',5x,'e 3',5x,'e 4',5x,'e 5'
     *,5x,'e 6',5x,'e 7',5x,'e 8',5x,'e 9',5x,'e 10')
   11 return
      end
c----------------------------------------------------------------------

      subroutine nmgm(nx0,nrel,h0,l,m,ni0,ni1,ni2,ng,ngi,
     *   u,tn,f)
c  non-linear multi-grid method
      implicit real *8 (a-h,o-z)
      dimension err(10)
      common/par/nsys
      common/write/iwrite
      common/zero/zero     
      external u,tn,f
      dimension it(20)
c     
      errmax=0.0d0
      k=l
      call putf(k+m,tn)
      it(k)=ngi
   10 if(k.eq.1) goto 30
   20 do 1 i=1,ni1
      call relax(k,k+m,f,err) 
    1 continue
      if(k.eq.l) then
      errmax=err(1)
      do 60 j=1,nsys
   60 if(err(j).gt.errmax) errmax=err(j)
      if(k.eq.m) then
      call time(second)
      residual=dlog10(errmax)
      if(iwrite.eq.0) write(26,*) second, residual
      end if
      end if
      call rescal(k,k-1+m,k+m,f)
      call putu(k,k-1)
      k=k-1
      call crsres(k,k+m,f)
      it(k)=ng
      go to 10
   30 do 2 i=1,ni0
      call relax(1,1+m,f,err)
    2 continue
   40 if(k.eq.l) return
      k=k+1
      call intadd(k,k-1)
      do 3 i=1,ni2
      call relax(k,k+m,f,err)
    3 continue
      it(k)=it(k)-1
      if(k.eq.l) then
      errmax=err(1)
      do 50 j=1,nsys
   50 if(err(j).gt.errmax) errmax=err(j)
      if(k.eq.m) then
      call time(second)
      residual=dlog10(errmax)
      if(iwrite.eq.0) write(26,*) second, residual
      end if
      end if
      if(errmax.lt.zero.and.k.eq.l) it(l)=0
      if(l.lt.m) it(l)=0
      if(it(k).eq.0) goto 40
      go to 20
      end
c----------------------------------------------------------------------

      subroutine printsol(k)
c  prints (for any nstep) the solutions of the integral equations  
      implicit real *8 (a-h,o-z)
      common q(10,100000),ist(1)
      common/par/nsys
      common/rr/r     
      call key(k,ist,jj,h,x0)
      nstep=2**5
      jstep=1
      if(jj.gt.(nstep+1)) jstep=(jj-1)/nstep
      write(27,100) r
      write(27,101)
      do 1 n=1,nstep+1
      x=x0+(n-1)*jstep*h
      write(27,102) x,(q(ns,ist(1)+(n-1)*jstep+1),ns=1,nsys)
    1 continue
  100 format(3x,'r= ',e10.4)
  101 format(4x,'x',6x,'s 1',5x,'s 2',5x,'s 3',5x,'s 4',5x,'s 5'
     *,5x,'s 6',5x,'s 7',5x,'s 8',5x,'s 9',5x,'s 10')
  102 format(11(1pe8.1))
      return
      end
c----------------------------------------------------------------------

      subroutine putf(k,f)
c  put the function f at level k
      implicit real *8 (a-h,o-z)
      common q(10,100000),ist(1)
      common/par/nsys
      call key (k,ist,jj,h,x0)
      io=ist(1)
      do 2 ns=1,nsys
      do 1 j=1,jj
      x=(j-1)*h+x0
    1 q(ns,io+j)=f(ns,x)
    2 continue
      return
      end
c----------------------------------------------------------------------

      subroutine putu(kf,kc)
c  fine-to-coarse grid transfer operator
      implicit real *8 (a-h,o-z)
      common q(10,100000),iuf(1),iuc(1)
      common/par/nsys
      call key(kf,iuf,jjf,hf,x0)
      call key(kc,iuc,jjc,hc,x0)
      if=iuf(1)
      ic=iuc(1)
      do 2 ns=1,nsys
      jf=-1
      do 1 jc=1,jjc
      jf=jf+2
    1 q(ns,ic+jc)=q(ns,if+jf)
    2 continue
      return
      end
c----------------------------------------------------------------------

      subroutine relax(k,krhs,f,err)
c  Gauss-Seidel iteration
      implicit real *8 (a-h,o-z)
      dimension err(10)
      common q(10,100000),ist(1),irhs(1)
      common/finer/m
      common/par/nsys
      common/write/iwrite
c
      call key(k,ist,jj,h,x0)
      call key(krhs,irhs,jj,h,x0)
      ir=irhs(1)
      io=ist(1)
      do 3 ns=1,nsys
      err(ns)=0.0d0
      do 1 j=1,jj
      call kappau(k,f,ns,j,sum)
      qsol=sum+q(ns,ir+j)
c     compute the dynamic residuals
      er=q(ns,io+j)-qsol
      err(ns)=err(ns)+er*er
      q(ns,io+j)=qsol
    1 continue
      err(ns)=dsqrt(err(ns))
    3 continue
      if(k.eq.m.and.iwrite.eq.0) write(24,101)(err(j),j=1,nsys)
  101 format(10(1pe8.1))
      return
      end
c----------------------------------------------------------------------

      subroutine rescal(k,krhc,krhf,f)
c  computes the residual at level k and transfers it on k-1
      implicit real *8 (a-h,o-z)
      common q(10,100000),ist(1),irhc(1),irhf(1)
      common/par/nsys
      call key(k,ist,jjf,hf,x0)
      call key(krhc,irhc,jjc,hc,x0)
      call key(krhf,irhf,jjf,hf,x0)
      io=ist(1)
      if=irhf(1)
      ic=irhc(1)
      do 2 ns=1,nsys
      do 1 jc=1,jjc
      jf=2*jc-1
      call kappau(k,f,ns,jf,sum)
    1 q(ns,ic+jc)=q(ns,if+jf)+sum-q(ns,io+jf)
    2 continue
      return
      end
c----------------------------------------------------------------------

      subroutine time(second)
c  gives the CPU-time
      implicit real *8 (a-h,o-z)
      second=999.
c for unix? use mclock()/100.d0
c for windows use      CALL DCLOCK@(T1)
      return 
      end
c----------------------------------------------------------------------

