Using The Gaussian Elimination Method For Large Banded Matrix Equations
Using The Gaussian Elimination Method For Large Banded Matrix Equations
                            Ming-Hokng Maa
                    Massachusetts Institute of Technology
                            Cambridge, MASS
                              Changqing Li
                         Andersen Consulting LLP
                            Minneapolis, MN
                                 Qing He
                       East China Normal University
                             ShangHai, China.
Table of Content. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . I
Abstract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . I I
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Methodology- . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
                                                           I
                             Abstract
                               II
INTRODUCTION
with 200 grids per side will generate a banded coefficient matrix
with a dimension.of 400 x 40000.       If four bytes are used to
numerical scheme is simple and has been available for more than
                                   1
hard-disks on the order of gigabytes(GB) or more have become
Computer source codes are listed in the Appendices and are also
METHODOLOGY
equation.
                                              2
we can find the analytical solution to compare the results
obtained from each approach.
p   = ~~ 2
               {[1-2(-1) 0 ]cosh(nx) -             [ [1-2(-1)"]coth(nrr) +
       1 nrr
show the significant change of p for 0 < y < 0.001. Thus the p
                                               3
SIMULTANEOUS LINEAR ALGEBRA EQUATIONS
p.l",J
    1 . + r p .. _ - 2(1+r) P,· J. + r P,· J"+l + P,-+ 1, j. = 0
              l,J 1                     I                I
                                                                      •••••••••••   (3)
2                                    + p11   =   0
2                                    + P,z = o
2                                    + P,3 = o
2  +   Ps        4   p9    +   P,o +   P19   =   0
2  +   p9        4   P,o   +   0   +   Pzo   =   0
P, +   1         4   p11   +   P12 +   P21   =   0
Pz +   P,,       4   P,z   +   P13 +   P22   =   0
p3 +   P12       4   p13   +   P14 +   p23   =   0              .................   (4)
                                                     4
Fig. 3.         The solutions are the p values at each intersection
point.         In Fig. 3 , they are marked as p 1 , p 2 , p 3 ,                                ••• ,   p 99 , p 100 •
A P = B • • • • • • •• • • • • • • • • • • • • • • • • • • • • • • •• • • •• • • • • • • • • • • • • • • (5)
           0     0    0            0     1    1·             1    1    1             1     1
           0     0    0            0     0     0             0    0    0             0     0
           0     0    0            0     0     0             0    0    0             0     0
           0     1    1            1     1    1              1    1    1             1    1
 A    =   -4 -4 -4                -4 -4 -4                 -4 -4 -4                 -4 -4         ........        ( 6)
           1     1    1            1     1    1              1    1    1             1    0
           0     0    0            0     0    0              0    0    0             0    0
           0     0    0            0     0    0              0    0    0             0    0
           1     1    1            1     1    1              1    1    0             0    0
                                                             5
  BT   = [- 3   -2 -2      •• - 2 - 1 0 0        .. .       0 1 0   .• .   0 1 0 . . .      0 0]       . • (8 )
the band width and N is the total number of unknown points within
the study domain. The band width is the sum of the upper band
width, MU, the lower band width, ML, and the unit width of
diagonal elements, i.e., M                   =   MU + ML + 1.               The upper band width,
MU, is the maximum count of the element P.1+ 1 IJ. from the diagonal
column and j+1 th row and continues with increasing row number
and then continues on the first grid point (or the lower
                                                        6
          0         0         0              0        a1,u          a1,n-L       a1, n-L-1        a1,n-1       al,n
          0         0         0              0           0              0            0               0          0
          0         0         0             0            0              0            0               0          0
          0       ad-1, 2   ad-1,3       ad-1, u-1   ad-1, u       ad-1,n-L     ad-1, n-L-1      ad-1, n -1   ad-1, n
1l = ad, 1 ad,2 ad,3 ad,u-1 ad,u ad, n-L ad, n-L-1 ad,n- 1 ad,n .. (9)
         d+1, 1   ad+1, 2   ad+1,3       ad•1,u-1    ad•l, u       ad+1, n-L    ad+1, n-L-1      ad+1,n-1       0
          0         0         0             0            0              0           0               0           0
          0         0         0             0            0              0           0               0           0
        am, 1     am,2      am,3          am,u-1     a
                                                         m,u
                                                                   a
                                                                       m, n-L       0               0           0
a1,u'' a1,u+1' , and a 1,n are not necessary all in the same row,
i.e., row 1. In this example, however, they are all in the same
same row. Similarly, am, 1 , am,Z' ... , and am,L are not necessary all
in row M.
                                                               7
FULL BANDED MATRIX EQUATION SOLVER
computer (PC) with the coarse grid. Fig. 4 plots the results
job. It is still very slow for this size because of disk and
identical to Fig. 1.
       The input data for the program P_BANDED.FOR was generated
users could easily modify the input file for different equations.
                                   8
matrix would be quite different.               The solution procedure for the
banded matrix equation, however, would remain essentially the
same.
the band width is large. Eq. 2 indicates that only the diagonal
terms (ad,i with j=1, N), the two immediate off-diagonal terms (ad-
   . and ad+      •   with j=1, N), the upper border terms (a 1    •   with j=1,
1, J           1, J                                               ,J
N) , and the lower border terms ( am,j with j=1, N) are possibly
non-zero terms. All other elements are zero. The entire banded
                                           9
        0       0   0     0      0       0                0          0
        0       0   0     0      0       0                0          0
        0       0   0     0      0       0                0          0
        0       0   0     0      0       0                0          0
        0       0   0     0
0 0 0 0 0 0 0 0
w= 0 0 0 0 0 0 0 0 ( 1 0)
ad,1
d •1,1 ad•1,nk•m
0 0 0 0 0 0 0 0
        0       0   0     0      0       0                0          0
       am,1
                                am,u   am,u•l       am,   n+m-1
excluded after column NK+M when fetch a block (length NK) of data
                                  10
         0          0            0          0           0        u1 ,M      U1,NK+M
         0           0           0
         0           0           0
         0           0           0
         0           0       UM-2,3
       ~+1,1       ~+1,2
                             m
                                 M+1,3   mM+1 ,M-2   mM+1 ,M-1   ~+l,M     m
                                                                               M+1,NK+M
In general, the larger the NK, the smaller the number of disk
be at least 4 x M.
      After applying the procedure of Gaussian Elimination Method
saved in the first M rows (row 1 toM). The space from row M+1
                                                11
the first M row, from column 1 to NK, was written into hard disk
as a temporary file. The multipliers in row M+1 to M+ML were
working matrix. Some data at the end of this block must again be
the last disk file was read first (and deleted), and the backward
block.     This process also repeated for all the blocks to find out
P.
i.e., a grid size of 102 x 102. With the thrifty banded matrix
                                        12
400.    Thus, the size of executable codes reduces to about 2 MB.
Of course, one needs about 40 MB of disk space for writing
PC was about 160 sec. The results are identical to that given in
Fig. 1.
       Source list of this thrifty banded matrix solver, a FORTRAN
file is the same as that used for the program P_BANDED.FOR, and
the results were also plotted using the MATLAB program P_PLOT.M.
elimination. If there are many linear systems (all with the same
                                  13
coefficient matrix) to be solved,. then the forward elimination
should only be calculated once, and the results, multipliers,
of this study.
     For very large banded matrix equations, i.e., a large N, the
matrix equation may differ, but the banded matrix solver remains
the same.
     The use of the Gaussian Elimination Method with Partial
                                14
                                                                       ;   .
developed for computers with limited resources, however, this
ACKNOWLEDGMENTS
acknowledged.
REFERENCES
Dongarra, J.J., J.R. Bunch, C.B. Moler, and G.W. Stewwart, 1979,
                                  15
    2
        1.8 1.6
1
1.2 0.8
                        1                        2          2.5   3
                                    X
                             16
                    a                                                                                                             n=10000
    1.5
at x=0.5 ..,..
              ·--.,.............
p
                                   ···,"-....
                                            ·--...................____
    0.5                                                 at x=2.0--~·--........
                                                                              ....     -··-·-·-..........,
                                                                                                             --....
                                                                                                                      -·--··-·-·---.........._..__
                                                                                                                                                 ··.......• ..
     o+---~--~--~--~----.---.---.----.---.--~
          0                               rt/5                                        3rt/5                                  4rt/5
2~-----------------------------------------,
p
                                                                                  . ····~-----·----·-···· ...•
                                                                                            at x=2.0                               ~--.....
                                                                                                                                             \,
    0.5
                                                                                                                                                     \\
                                                                                                                                                         \
                                             '
     O~TT~=-~onmr-rrnnm-.llnmr-rr~rr-TTTmm-.-~mm
     1 E-06                 1 E-05               0.0001          0.001               0.01                    0.1                            1                    10
                                                                              y
                                                                         17
    12                                                       I   T
                   I                                             I
    11
             P.n                                                 I               Pwc
    10
             pg               I                 I        I                       pgg
     9
              Pa                                                             I
     8
                   I                                     I I     I                     I
             p6
     7
y            Ps               I
     6
     5
             p4                                 I
     4
             p3                                                  I
             p2         P,2                                                      P92
     3
     1
                                                             I           I
                                                                             I
         1         2          3         4   5   6        7   8   9       10        11      12
                                                    18
y
                 1                      2              3
                             X
                        19
Appendix I.       Source Lists of FORTRAN program P_BANDED.FOR
         program p_banded
c
c    This program is to calculate the velocity potential (p)       in the
c    area 0.0 <= x <= 3.1416,  0.0 <= y <= 3.1416.
c
c    a thrify storage method was constructed first, and then,
c    convert to that required by LINPACK, and uses a minor modified
c    LINPAK subroutines to solve it.
c
c    Because of the formidible slow pace when runing this program
c    with high resolution, we can only limited the parameter KQ to a
c    small number.
c
         parameter (iq=110,jq=110, IW=310, kq=400, Lq=3, mq=203)
         implicit complex (z)
         character*45 title, label
         character*20 infile, outfile, recfile
         character*1 id, q1
         common /matrx/ za(kq,S), ia(kq,S), zb(kq)
         common /gener/ mp, np, dx, dy, r, p(iq,jq), id(iq,jq)
         common /unknw/ n,imap(kq) ,jmap(kq) ,irow(iq)
         common /labbl/ ind(iq) ,jin(iq,Lq) ,jout(iq,Lq)
         common /works/ zabd(iw,kq), ipvt(kq)
c
c        boundary conditions
c
         bcx0=2
         bcxn=O
         bcy0=1
         bcyn=O
c
         print*,'Select 1. p_s.grd;       2. p_m.grd   3.   p_L.grd:   '
         read(*,*) iption
         go to (10, 12, 14), iption
    10   infile='p s.grd'
         outfile='P bs.out'
         recfile='p=bs.rec'
         go to 20
    12   infile='p_m.grd'
         outfile='p_bm.out'
         recfile='p_bm.rec'
         go to 20
    14   infile='p_L.grd'
         outfile='p_bL.out'
         recfile='p_bL.rec'
    20   continue
c
         open(9, file=infile, status='old')
         open(10, file=outfile, status='unknown')
         open(11, file=recfile, status='unknown')
                                    I-1
c
c   mp,np : Max. grid numbers in x andy direction, respectively.
c   dx,dy : grid sizes in x andy direction, respectively.
c
      read(9,' (a45) ') title
      write(11,' (a45) ') title
      read(9,*) mp,np,dx,dy
      if(mp .gt. iq) then
      print*, 'IQ is smaller than MP, Change IQ to ',mp
      stop
      end if
      if(np .gt. jq) then
      print*,'JQ is smaller than nP, Change JQ to' ,np
      stop
      end if
c
       r == (dx/dy)**2
c
c      ID code for each grid point
c        0, interior point
c
c           1,   upper boundary condition
c           2,   lower boundary condition
c           3,   left boundary condition
c           4,   right boundary condition
c
c           5,   left bottom corner B.C.
c           6,   left top corner B.C.
c           7,   right bottom corner B.C.
c           8,   right top corner B.C.
c
c           e, grid point that is not included in the study domain
c
c      Th~       following is an example
c
c      j
c      "'         np    6111111111118eeeeeeeeeeeeeeeeeee
c                       3000000000004eeeeeeeeeeeeeeeeeee
c                       30000000000001111111111111111118
c                       30000000000000000~00000000000004
c                       30000000000000000000000000000004
c                       30000000000000000000000000000004
c                       30000000000000000000000000000004
c                       52200000000000000000000000222227
c                       eee30000000000000000000004eeeeee
c                       eee30000000000000000000004eeeeee
c                       eee30000000000000000000004eeeeee
c                   1   eee52222222222222222222227eeeeee
c                       1                              mp
c
c
            ---------------------------------------------->   i
       read(9,30) label
                                       I-2
           write(11,30) label
           read(9,30) label
           write(11,30) label
    30     format (a50)
           do j=1,np
              jj=np-j+1
           read(9,45) jns, (id(i,jj) ,i=1,mp)
    45        format(i5, (110a1) )
           if(jns .ne. jj) then
              write(11,50) jj,jns
    50            format(' Sequence is wrong for ID input at' ,2i5)
              stop
              end if
           end do
           print*,'Completed reading ID code matrix'
           close(9)
c
c        construct the unknow COLUMN matrix X, in the matrix eq. AX=B
c        find each unknown's location: imap(map) ,jmap(map)
c
c        ind(i} : no. of isolated sector in each culomn, x grid.
c        for this particular case, ind(i) are all 1.
c        because no land points in the middle of study domain.
c        jin(i,index)   begin grid number for an isolated sector in a
c                       column
c        jout(i,index): end grid number for an isolated sector in a
c                       culomn
c        map        the number of total unknow, or the length of X.
c                   later, it is reassigned as N
c        irow(i)    the total number of unknow vel. Potential in each
c                   column
c
            map=O
            do i=1,mp
            icount=O
            in=O
            iout=1
            index=1
            do j=1,np
                   if(id(i,j) .eq. '0'   then
                      icount=icount+1
                      map=map+1
                      imap(map)=i
                      jmap(map)=j
                      if(in .eq. 0) then
                          jin(i,index)=j
                          in=1
                          iout=O
                      end if
                   end if
c
                  if( id(i,j)   .eq. '1'   .and. iout .eq. 0) then
                                       I-3
                         jout(i,index)=j
                         iout=1
                         in=O
                         index=index+1
                      end if
                  end do
               irow(i)=icount
               ind(i)=index-1
c
c        ind(i) should be >= 1, except for the entire column are all
c        boundary points.  if not, something wrong.
c
                  write(11,55) i, ind(i), irow(i), jin(i,1), jout(i,1)
    55            format(' i,ind,irow,jin,jout=' ,SiS)
                                    I-7
          do j=1,np
             write ( 1 0 , 2 0 0 ) j , (p ( i , j ) , i = 1, mp )
    200      format(i5/(10f8.4))
             end do·
          close(10)
          close ( 11)
                                                 I-8
           za(map 1 4)=r
           za(map 1 5)=1.0
           ia(mapll)=map-idistl(i j)+1      1
           ia(map 1 2)=map-l
           ia(map 1 3)=map
           ia(mapl4)=map+1
           ia(mapiS)=map+idistr(ilj)-1
           zb(map)=(0.0 1 0.0)
           icount=icount+1
           iid(1)=1
           end if
c
c   for those has a Boundary grind point on the left
c
        if(id(i-1 1 j) .eq.     1
                                  3 1
                                        .and. id(i 1 j-1)   .eq.   1
                                                                       01   .and.
      *    id ( i I j +1) . eq. 1 0 1 ) then
           za(map 1)=0.0
                    1
           za(map 1 2)=r
           za(map 1 3)=-2.0*(1.0+r)
           za(map 1 4)=r
           za(map 1 5)=1.0
           ia(map 1 1)=0
           ia(map 1 2)=map-1
           ia(map 1 3)=map
           ia(map 1 4)=map+1
           ia(map 1 5)=map+idistr(i 1 j)-1
           zb(map)=(-2.0 1 0.0)
           icount=icount+1
           iid(2)=1
           end if
c
c   for those has a Boundary grind point on the right
c
        if(id(i+1 1 j) .eq. 4  1
                                 .and. id(i 1 j-1)
                                    1
                                                            .eq.   1
                                                                       01   .and.
      *     id ( i j +1) . eq.
                I              0
                               1
                                   then
                                    1
                                        )
            za(map 1 1)=1.0
            za(map 1 2)=r
            za(map 1 3)=-2.0*(1.0+r)
            za(map 1 4)=r
            za(map 1 5)=0.0
            ia(map 1 1)=map-idistl(i 1 j)+1
            ia(map 1 2)=map-1
            ia(map 1 3)=map
            ia(map 1 4)=map+1
            ia(map 1 5)=0
            zb(map)=(O.O, 0.0)
            icount=icount+1
            iid(3)=1
            end if
c
c   for those has a Boundary grind point on the top
c
                                            I-9
         if(id(i,j+1) .eq. '1' .and. id(i-1,j)   .eq.   '0'   .and.
     *        id(i+1,j) .eq. '0') then
              za(map,1)=1.0
              za(map,2)=r
              za(map,3)=-2.0*(1.0+r)
              za(map,4)=0
              za(map,5)=1.0
              ia(map,1)=map-idistl(i,j)+1
              ia(map,2)=map-1
            . ia (map, 3) =map
              ia(map,4)=0
              ia(map,S)=map+idistr(i,j)-1
              zb(map)=(O.O, 0.0)
              icount=icount+1
              iid(4)=1
              end if
c
c for these grid points that has a Boundary at bottom
c
       if(id(i,j-1) .eq. '2' .and. id(i-1,j) .eq. '0' .and.
     *    id(i+1,j) .eq. '0' ) then
          za(map,1)=1.0
          za(map,2)=0
          za(map,3)=-2.0*(1.0+r)
          za(map,4)=r
          za(map,5)=1.0
          ia(map,1)=map-idistl(i,j)+1
          ia(map,2)=0
          ia(map,3)=map
          ia(map,4)=map+1
          ia(map,S)=map+idistr(i,j)-1
          zb(map)=(-1.0, 0.0)
          icount=icount+1
          iid(5)=1
          end if
c
c For those grid points that are left bottom corner
c
       if(id(i-1,j) .eq. '3' .and. id(i,j-1) .eq. '2') then
          za(map,1)=0.0
          za(map,2)=0
          za(map,3)=-2.0*(1.0+r)
          za(map,4)=r
          za(map,5)=1.0
          ia(map,1)=0
           ia(map,2)=0
           ia(map,3)=map
           ia(map,4)=map+1      .
           ia(map,S)=map+idistr(i,j)-1
           zb(map)=(-3.0, 0.0)
           icount=icount+1
           iid(6)=1
                                  I-10
         end if
c
c For those grid points that are left top corner Boundary points
c
      if(id(i-l,j) .eq. '3' .and. id(i,j+l) .eq. '1') then
         za(map,l)=O.O
         za(map,2)=r
         za(map,3)=-2.0*(1.0+r)
         za(map,4)=0.0
         za(map,S)=l.O
         ia(map,l)=O
         ia(map,2)=map-l
         ia(map,3)=map
         ia(map,4)=0
         ia(map,S)=map+idistr(i,j)-1
         zb (map) = (- 2 . 0, 0 . 0)
         icount=icount+l
         iid(7)=1
         end if
c
c For those grid points that are right bottom boundary points
c
      if(id(i+l,j) .eq. '4' .and. id(i,j-1) .eq. ' 2 ' ) then
         za(map,l)=l.O
         za(map,2)=0
         za(map,3)=-2.0*(1.0+r)
         za(map,4)=r
         za(map,S)=O.O
         ia(map,l)=map-idistl(i,j)+l
         ia(map,2)=0
         ia· (map, 3) =map
         ia(map,4)=map+l
         ia(map,S)=O
         zb(map)={-1.0, 0.0)
         icount=icount+l
         iid(8)=1
         end if
c
c For those grid points that are right top boundary points
c
      if(id(i+l,j) .eq. '4' .and. id(i,j+l) .eq. '1') then
         za(map,l)=l.O
         za(map,2)=r
         za(map,3)=-2.0*(l.O+r)
         za(map,4)=0
         za(map,S)=O.O
         ia(map,l)=map-idistl(i,j)+l
         ia(map,2)=map-l
         ia(map,3)=map
         ia(map,4)=0
         ia(map,S)=O
          zb(map)=(O.O, 0.0)
                              I-ll
            icount=icount+1
            iid(9)=1
            end if
c
         if( icount .ne. 1) then
             ier=1
             write(11,10) ier, icount, (iid(k) ,k=1,9)
    10       format(' ier, icount=' ,2i5,' id(1)-id(9)=' ,9i2)
             end if
         return
         end
c
c----------------------------------------------------------------
c
         integer function idistr(i,j)
         parameter (iq=110,jq=110, IW=310, kq=400, Lq=3)
         implicit complex (z)
         character*1 id
         common /matrx/ za(kq,S), ia(kq,S), zb(kq)
         common /gener/ mp, np, dx, dy, r, p(iq,jq), id(iq,jq)
         common /unknw/ n,imap(kq) ,jmap(kq) ,irow(iq)
         common /labbl/ ind(iq) ,jin(iq,Lq) ,jout(iq,Lq)
         common /works/ zabd(iw,kq), ipvt(kq)
c
c    Calculates the distance between points (i+1,j) and (i,j).      It
c    means how many grid points, which are solved for, are in
c    between. It counts vertically from the point(i,j) and up
c    (i,j+1),(i,j+2), ... , (i,np), then (i+1,1), (i+1,2), ... , t o
c    (i+1,j).   In the matrix equation, this distance represents the
c    up band width at that particular diagonal element (i,j).
c
         do k=1,ind(i)
            if(j .ge. jin(i,k)   .and. j   .le. jout(i,k)   ) mark1=k
            end do
c
         do k=1,ind(i+1)
            if(j .ge. jin(i+1,k)   .and. j   .le. jout(i+1,k) ) mark2=k
            end do
c
         idd=jout(i,mark1)-j+1 + j-jin(i+1,mark2)
c
         do k=mark1+1, ind(i)
            idd=idd + jout(i,k)-jin(i,k)+1
            end do
c
         do k=1,mark2-1
            idd=idd + jout(i+1,k)-jin(i+1,k)+1
            end do
c
         idistr=idd
c
         return
                                   I-12
       end
c
c
       integer function idistl(i,j)
c
       parameter (iq=110,jq=110, IW=310, kq=400, Lq=3)
       implicit complex (z)
       character*1 id
       common /matrx/ za(kq,S), ia(kq,S), zb(kq)
       common /gener/ mp, np, dx, dy, r, p(iq,jq), id(iq,jq)
       common /unknw/ n,imap(kq) ,jmap(kq) ,irow(iq)
       common /labbl/ ind(iq) ,jin(iq,Lq) ,jout(iq,Lq)
       common /works/ zabd(iw,kq), ipvt(kq)
       common /tempo/ zam(203,kq)
c
c   Calculate the distance between point (i-1,j) and (i,j). The
c   distance means how many grid points, which are solved for, are
c   in between. It counts vertically from (i,j) downward (i,j-1),
c   (i, j -2), ... , (i,1) and restarted from previous i line
c   (i-1, np), (i-1, np-1), ... , to (i-1, j).
c
       do k=1,ind(i-1)
          if(j .ge. jin(i-1,k)   .and. j   .le. jout(i-1,k)) mark1=k
          end do
c
       do k=1,ind(i)
          if(j .ge. jin(i,k)   .and. j   .le. jout(i,k)) mark2=k
          end do
c
       idd=jout(i-1,mark1)-j+1 + j-jin(i,mark2)
c
       do k=markl+1,ind(i-1)
          idd=idd+jout(i-1,k)-jin(i-1,k)+1
          end do
c
       do k=1,mark2-1
          idd=idd+jout(i,k)-jin(i,k)+1
          end do
c
       idistl=idd
       return
       end
c
c
       SUBROUTINE CGBFA(LDA, N, ML, MU, INFO)
c
c   Original Date of WRITTEN Aug. 14 1978 by MOLER, C. B.,
c   PURPOSE Factors a COMPLEX band matrix by Gaussian elimination
c            and partial pivoting.
c
c   CGBFA is usually called by CGBCO, but it can be called
c         directly with a saving in time if RCOND is not needed.
                                 I-13
c
c   On Entry
c
C ABD   COMPLEX(LDA, N), contains the matrix in band storage.  The
c       columns of the matrix are stored in the columns of ABD and
c       the diagonals of the matrix are stored in rows ML+1
c       through 2*ML+MU+1 of ABD. See comments below for details.
c
c LDA INTEGER,        the leading dimension of the array ABD
c                         LDA must be .GE. 2*ML + MU + 1 .
c
c N      INTEGER,     the order of the original matrix.
c
c ML     INTEGER,     number of diagonals below the main diagonal.
c                     0 .LE. ML .LT. N
c
c MU     INTEGER,     number of diagonals above the main diagonal.
c                   0   . LE. MU . LT. N. More efficient. if ML . LE. MU
c
c On Return
c
c ABD an upper triangular matrix in band storage and the
c        multipliers which were used to obtain it. The
c        factorization can be written A = L*U where L is a
c        product of permutation and unit lower triangular matrices
c        and U is upper triangular.
c
c    IPVT INTEGER(N), an integer vector of pivot indices.
c
c    INFO INTEGER
c     = 0   normal value.
c     = K if    U(K,K) .EQ. 0.0 . This is not an error condition,
c           but it does indicate that CGBSL will divide by zero if
c           called. Use RCOND in CGBCO for a reliable indication
c           of singularity.
c
c This uses rows ML+1 through 2*ML+MU+1 of ABD. In addition, the
c first ML rows in ABD are used for elements generated during
 c the triangularization. The total no. of rows needed in ABD is
 c 2*ML+MU+1. The ML+MU by ML+MU upper left triangle and the ML
 c x ML lower right triangle are not referenced.
 c
 c LINPACK. This version dated 08/14/78 .
 c Cleve Moler, University of New Mexico, Argonne National Lab.
 c
 c Subroutines and Functions called from this subroutine
 c
 c      BLAS CAXPY, CSCAL, ICAMAX
 c      Fortran ABS,AIMAG,MAXO,MINO,REAL
 c
 c REF: DONGARRA J.J., BUNCH J.R., MOLER C.B., STEWART G.W.,
 c                *LINPACK USERS GUIDE*, SIAM, 1979.
                                  I-14
C   ROUTINES CALLED     CAXPY,CSCAL,ICAMAX
c
c Revised by Jerome P.-Y. Maa on Nov. 96.
c 1. Move the matrix abd(Lda, 1) and Ipvt(1) to common block.   so
c    that the limitiation of LDA = IW can be relaxed.  In other
c    words, the parameter IW specified don't have to be exactly
c    equal to LDA.
c 2. uses implicit statement for complex variables
c
      parameter (IW=310, kq=400)
      implicit complex (z)
      character*1 q1
      common /works/ zabd(iw,kq), ipvt(kq)
      REAL CABS1
      CABS1(ZDUM) = ABS(REAL(ZDUM)) + ABS(AIMAG(ZDUM))
c
C   FIRST EXECUTABLE STATEMENT     CGBFA
c
          M = ML + MU + 1
          INFO = 0
c
C ZERO INITIAL FILL-IN COLUMNS
c
       JO = MU + 2
       J1 = MINO(N,M) - 1
       IF (J1 .LT. JO) GO TO 30
       DO 20 JZ = JO, J1
          IO = M + 1 - JZ
          DO 10 I = IO, ML
              zABD(I,JZ) = (O.OEO,O.OEO)
    10      · CONTINUE
    20    CONTINUE
    30 CONTINUE
       JZ = J1
          JU = 0
c
c   GAUSSIAN ELIMINATION WITH PARTIAL PIVOTING
c
          NM1 = N - 1
          IF (NM1 .LT. 1) GO TO 130
          DO 120 K = 1, NM1
             KP1 = K + 1
c
C ZERO NEXT FILL-IN COLUMN
c
             JZ = JZ + 1
             IF (JZ .GT. N) GO TO 50
             IF (ML .LT. 1) GO TO 50
                DO 40 I = 1, ML
                   zABD(I,JZ) = (O.OEO,O.OEO)
     40         CONTINUE
     50      CONTINUE
                                      I-15
c
C FIND L = PIVOT INDEX
c
             LM = MINO(ML N-K)
                           1
             L = ICAMAX(LM+1 1 ZABD(M 1 K) 1 1) + M- 1
             IPVT(K) = L + K - M
c
C ZERO PIVOT IMPLIES THIS COLUMN ALREADY TRIANGULARIZED
c
             IF (CABS1(zABD(LIK))        .EQ. O.OEO) GO TO 100
c
C INTERCHANGE IF NECESSARY
c
                 IF (L .EQ. M) GO TO 60
                    zT = zABD (L 1 K)
                    zABD(L K) = zABD(M K)
                           1                   1
                    zABD(M 1 K) = zT
     60          CONTINUE
c
C COMPUTE MULTIPLIERS
c
                 zT = -(1.0E0 1 0.0EO)/zABD(M 1 K)
                 CALL CSCAL(LMI zTI zABD(M+1 1 K)       1   1)
c
C ROW ELIMINATION WITH COLUMN INDEXING
c
                JU = MINO(MAXO(JU MU+IPVT(K)) N)
                                     1              1
                MM = M
                IF (JU .LT. KP1) GO TO 90
                DO 80 J = KP1 1 JU
                   L = L - 1
                   MM=MM-1
                   zT = zABD(L 1 J)
                   IF (L .EQ. MM) GO TO 70
                       zABD(L 1 J) = zABD(MM 1 J)
                       zABD(MM 1 J) = zT
     70            CONTINUE
                   CALL CAXPY(LMI zTI zABD(M+1 1 K) 1 1 1 zABD(MM+1 1 J) 1 1)
     80         CONTINUE
     90         CONTINUE
             GO TO 110
    100      CONTINUE
                INFO = K
                print* 1 'L,k,abd=' ,L,k,zabd(L,k)
                read(*,' (a1) ') q1
    110      CONTINUE
    120   CONTINUE
    130   CONTINUE
          IPVT(N) = N
          IF (CABS1(zABD(M,N)) .EQ. O.OEO) then
             INFO = N
             print*,'n,zabd(m,n)= 1 n, zabd(m,n)
                                         I
                                             I-16
              end if                                                     .;   .
c
           RETURN
           EOO
c
c
c
           SUBROUTINE CGBSL(LDA, N, ML, MU, zb)
c
C Original written on Aug. 14, 78, revised on       Aug. 1, 82
C  AUTHOR MOLER, C. B., (U. OF NEW MEXICO)
c
c   DESCRIPTION
c
c          CGBSL solves the complex band system
c          A* X= B or CTRANS(A) * X = B
c          using the factors computed by CGBCO or CGBFA.
c
c   On Entry
c
c             COMPLEX(LDA, N) , the output from CGBCo or CGBFA,
c                               passed by common block.
c    LDA      INTEGER,    the leading dimension of the array ABD
c    N        INTEGER,    the order of the original matrix.
c    ML       INTEGER,    number of diagonals below the main diagonal.
c    MU       INTEGER,    number of diagonals above the main diagonal.
c    IPVT     INTEGER(N), the pivot vector from CGBCO or CGBFA.
c                         passed to this subroutine by common block.
c    zB       COMPLEX(N)I the right hand side vector.
c
c   On Return
c
c    zB         the solution vector    X .
c
c   Error Condition
c
c   A division by zero will occur if the input factor contains a
c   ze~o on the diagonal.  Technically this indicates singularity
c   but it is often caused by improper arguments or improper
c   setting of LDA . It will not occur if the subroutines are
c   called correctly and if CGBCO has set RCOND .GT. 0.0 or CGBFA
c   has set INFO .EQ. 0 .
c
c    LINPACK. This version dated 08/14/78 .
c    Cleve Moler, University of New Mexico, Argonne National Lab.
c
c    subroutines and Functions used in this subroutine
c
c         BLAS CAXPY, zCDOTC   Fortran CONJG,MINO
c
c   REF:      DONGARRA J.J., BUNCH J.R., MOLER C.B., STEWART G.W.,
c                   LINPACK USERS GUIDE, SIAM, 1979.
                                      I-17
c
c   Modified by Jerome Maa on Nov. 1996
c   1. the matrix ZABD, IPVT are transferred by common block
c   2. delete the Job parameter, so this subroutin~ only for
c      solving   AX=B
c   3. use implicit for complex variables
c
       parameter (IW=310, kq=400)
       implicit complex (z)
       common /works/ zabd(iw,kq), ipvt(kq)
       dimension zb(1)
c
       M = MU + ML + 1
       NM1 = N - 1
c
C   SOLVE   A   *   X = B, but first to do the same factoralization and
c                          partial pivoting on the column matrix ZB.
c
       IF (ML .EQ. 0) GO TO 30
       IF (NM1 .LT. 1) GO TO 30
       DO K = 1, NM1
          LM = MINO(ML,N-K)
          L = IPVT (K)
          zT = zB (L)
          IF (L .EQ. K) GO TO 10
          zB (L) = zB (K)
          zB(K) = zT
    10    CONTINUE
          CALL CAXPY(LM, zT, zABD(M+1 1 K)      1    1 1 zB(K+1), 1)
          end. do
    30    CONTINUE
c
C . NOW SOLVE       A*X = B
c
       DO KB = 1 1 N
          K=N+1-KB
          zB(K) = zB(K)/zABD(M,K)
          LM = MINO(K~M) - 1
          LA = M - LM
          LB = K - LM
          zT = -zB (K)
          CALL CAXPY(LM 1 zT, zABD(LAIK)    I       1 1 zB(LB), 1)
          end do
c
C   Recovery sequence of unknown
c
       DO 1000 KB=1,N
          K=N+1-KB
          L=IPVT (K)
          zT=zB(L)
          IF(L. EQ. K) GOTO 1000
          zB (L) =ZB (K)
                                    I-18
               zB(K)=zT
    1000       continue
c
            RETURN
            END
c
c
            SUBROUTINE CSCAL(N,CA,CX,INCX)
c
c    PURPOSE Complex vector scale x = a*x
c    WRITTEN on Oct. 1, 79, REVISION on Aug. 01, 82
c    CATEGORY NO.  D1A6
c    KEYWORDS BLAS,COMPLEX,LINEAR ALGEBRA,SCALE,VECTOR
c    AUTHORS LAWSON, C. L., (JPL),    HANSON, R. J., (SNLA)
c         KINCAID, D. R., (U. OF TEXAS), and KROGH, F. T., (JPL)
c
c    DESCRIPTION
c
c                      B L A S Subprogram
c          Description of Parameters
c
c           --Input--
c              N number of elements in input vector(s)
c             CA complex scale factor
c             ex complex vector with N elements
c           INCX storage spacing between elements of ex
c
c       --Output--
c      CSCAL complex result (unchanged if N .LE. 0)
c
c       replace complex ex by complex CA*CX.
c       For I = 0 to N-1, replace CX(1+I*INCX) with ,
c                                 CA * CX(1+I*INCX)
c    REF: LAWSON C.L., HANSON R.J., KINCAID D.R., KROGH F.T.,
c         "BASIC LINEAR ALGEBRA SUBPROGRAMS FOR FORTRAN USAGE, 11
c          ALGORITHM NO. 539, TRANSACTIONS ON MATHEMATICAL
c          SOFTWARE, VOLUME 5, NUMBER 3, SEPTEMBER 1979, 308-323
c    ROUTINES CALLED   (NONE)
c
        COMPLEX CA,CX(1)
C    FIRST EXECUTABLE STATEMENT       CSCAL
        IF(N .LE. 0) RETURN
        NS = N*INCX
        DO I = 1,NS,INCX
            ex ( I ) = CA *ex ( I )
            end do
        RETURN
        END
c
c
           SUBROUTINE CAXPY(N,CA,CX,INCX,CY,INCY)
c
                                      I-19
C   WRITTEN on Oct. 01, 79, REVISION on April 25, 84
C   CATEGORY NO. D1A7
C   KEYWORDS BLAS,COMPLEX,LINEAR ALGEBRA,TRIAD,VECTOR
c   AUTHOR LAWSON c. L.
                     I      JPL) ·, HANSON R. J.
                             I   (              I  SNLA)     I   (
                                   I-21
       SUMMAX = SUMRI
       ICAMAX = II
    10     II = II + 1
    20     CONTINUE
       RETURN
       END
c
c
       COMPLEX FUNCTION zCDOTC(N,CX,INCX,CY,INCY)
C***BEGIN PROLOGUE zCDOTC
C***DATE WRITTEN    791001    (YYMMDD)
C***REVISION DATE 820801      (YYMMDD)
C***CATEGORY NO. D1A4
C***KEYWORDS BLAS,COMPLEX,INNER PRODUCT,LINEAR ALGEBRA,VECTOR
C***AUTHOR LAWSON, C. L., (JPL)
C            HANSON, R. J., (SNLA)
C            KINCAID, D. R., (U. OF TEXAS)
C            KROGH, F. T., (JPL)
C***PURPOSE Dot product of complex vectors, uses complx
c             conjugate of first vector
C***DESCRIPTION
c
c                 B L A S Subprogram
c     Description of Parameters
c
c      --Input--
c         N number of elements in input vector(s)
c        ex complex vector with N elements
c      INCX storage spacing between elements of ex
c        CY complex vector with N elements
c      INCY . storage spacing between elements of CY
c
c      --Output--
c     zCDOTC complex result (zero if N .LE. 0)
c
c  Returns the dot product for complex ex and CY, uses
C CONJUGATE(CX)
C zCDOTC=SUM for I=O to N-1 of CONJ(CX(LX+I*INCX))*CY(LY+I*INCY)
C where LX= 1 if INCX .GE. 0, else LX= (-INCX)*N, and LY is
C defined in a similar way using INCY.
C***REFERENCES
C           LAWSON C.L., HANSON R.J., KINCAID D.R., KROGH F.T.,
C           *BASIC LINEAR ALGEBRA SUBPROGRAMS FOR FORTRAN USAGE*,
C           ALGORITHM NO. 539, TRANSACTIONS ON MATHEMATICAL
C           SOFTWARE, VOLUME 5, NUMBER 3, SEPTEMBER 1979, 308-323
C***ROUTINES CALLED (NONE)
C***END PROLOGUE zCDOTC
c
      COMPLEX CX(1) ,CY(1)
C***FIRST EXECUTABLE STATEMENT    zCDOTC
      zCDOTC = (0.,0.)
      IF(N .LE. O)RETURN
                                 I-22
   IF(INCX.EQ.INCY .AND. INCX.GT.O) GO TO 20
   KX = 1
   KY = 1
   IF(INCX.LT.O) KX = 1+(1-N)*INCX
   IF(INCY.LT.O) KY = 1+(1-N)*INCY
        DO 10 I = 1,N
        zCDOTC = zCDOTC + CONJG(CX(KX))*CY(KY)
        KX = KX + INCX
        KY = KY + INCY
10      CONTINUE
   RETURN
20 CONTINUE
   NS = N*INCX
        DO 30 I=1,NS,INCX
        zCDOTC = CONJG(CX(I))*CY(I) + zCDOTC
30      CONTINUE
   RETURN
   END
                            I-23
    Appendix II.    Source List of FORTRAN Porgram P_THRIFT.FOR
            program p_thrify
 c
 c    This program solves the Laplace equation (p) in the area
 c    0.0 <=X<= 3.1416,    0.0 <= y <= 3.1416.
 c    using the thrifty band matrix solver
 c    This method was first developed by Li, c. (1995), and later,
 c    improved and docummented by Jerome P.-Y. Maa
 c
 c    The Govern Equation is    dA2(p)/dxA2 + dA2(p)/dyA2 = o
 c    The finite difference equation is:
 c    p(i-1,j) +r*p(i,j-1) -2*(1+r)*p(i,j) +r*p(i,j+1) +p(i+1,j)       o
 c
 c    The   boundary   conditions are:
 c    p =   2 at X =   0
c     p =   1 at y =   0
c     p =   0 at X =   y  pi
c
c     INFILE and OUTFILE : to store input and main output data.
c     RECFILE is used to store routine checking information.   If the
c             program run O.K., it can be deleted.
c     A MATLAB program PHIPLT.M has been developed to plot the
c     output results.  It uses Matlab version 4.01 for windows, and
c     read output data from the OUTFILE directly.
c
c     Data in the file INFILE are generated by another program
c     ID.FOR for the examples given in this program.
c
c     In this example, there is no need to use complex variable.
c     But, it was used anyway for general applications.
c
c     Jerome P.-Y. Maa         Virginia Institute of Marine Science.
c
         parameter (iq=110, jq=110, iw=310, jw=560, kq=10000, Lq=3)
c
         implicit complex (z)
         character*45 title, label
         character*20 infile, outfile, recfile
         character*1 id, q1
c
         common    /matrx/   za(kq,5), ia(kq,5), zb(kq)
         common    /gener/   mp, np, dx, dy, r, mu, mL, m, Lda
         common    /iando/   p(iq,jq), id(iq,jq)
         common    /unknw/   n, imap(kq), jmap(kq), irow(iq)
         common    /labbl/   ind(iq), jin(iq,Lq), jout(iq,Lq)
         common    /works/   zw(iw,jw)I ipvt(kq)
c
c        boundary conditions
c
         bcx0=2
                                          II-1
            bcxn=O                                                            ....
            bcy0=1
            bcyn=O
c
            print*,'There are three resolutions for this case:'
            print*,'       coarse, middle, and fine resolution'
            print*,'Select 1. p s.grd; 2. p_m.grd;    3. p_L.grd
            read(*,*) iption   -
            go to (10, 12, 14), iption
    10      infile='p s.grd'
            outfile='p ts.out'
            recfile='p-ts.rec'
            go to 20
    12      infile='p m.grd'
            outfile='p_tm.out'
            recfile='p_tm.rec'
            go to 20
    14      infile='p L.grd'
            outfile='p tL.out'
            recfile='p=tL.rec'
    20      continue
c
            open(9, file=infile, status='old')
            open(10, file=outfile, status='unknown')
            open(11, file=recfile, status='unknown')
c
c        mp,np        Max. grid numbers in x and y direction, respectively.
c        dx,dy        grid sizes in x and y direction, respectively.
c
           read(9,'(a45)') title
           write(11,' (a45) ') title
           read(9,*) mp,np,dx,dy
           if(mp .gt. iq) then
           print*,'IQ is smaller than MP, Change IQ to' ,mp
           stop
           end if
           if(np .gt. jq) then
           print*,'JQ is smaller than NP, Change JQ to' ,np
           stop
           end if
c
            r = (dx/dy)**2
c
c           ID code for each grid point
c             0, interior point
c
c                1,   upper boundary condition
c                2,   lower boundary condition
c                3,   left boundary condition
c                4,   right boundary condition
c
c                5, left bottom corner B.C.
                                         II-2
c                6, left top corner B.C.
c                7, right bottom corner B.C.
c                8, right top corner B.C.
c
c               e, grid point that is not included in the study domain
c
c           The following is an example
c
c           j
            A
c                   np    6111111111118eeeeeeeeeeeeeeeeeee
c                         3000000000004eeeeeeeeeeeeeeeeeee
c                         30000000000001111111111111111118
c                         30000000000000000000000000000004
c                         30000000000000000000000000000004
c                         30000000000000000000000000000004
c                         30000000000000000000000000000004
c                         52200000000000000000000000222227
c                         eee30000000000000000000004eeeeee
c                         eee30000000000000000000004eeeeee
c                         eee30000000000000000000004eeeeee
c                     1   eee52222222222222222222227eeeeee
c                         1                              mp
c               ---------------------------------------------->   i
c
            read(9,30) label
            write(11,30) label
            read(9,30) label
            write(11,30) label
    30      format (a50)
            do j=1,np
                jj=np-j+1
            read(9,45) jns, (id(i,jj) ,i=1,mp)
    45         format(iS, (110a1) )
            if(jns .ne. jj) then
               write(11,50) jj,jns
    50             format(' Sequence is wrong for ID input at' ,2i5)
               stop
               end if
            end do
            print*, 'Completed reading ID code matrix'
            close(9)
c
c        construct the unknow COLUMN matrix X, in the full matrix eq.
c        AX=B. Find each unknown's location: imap(map) ,jmap(map)
c
c        ind(i)  : no. of isolated sector in each culornn, x grid.
c                  for this particular case, ind(i) are all 1 because
c                  no land points in the middle of study domain.
c        jin(i,index): begin grid number for an isolated sector in a
c                       column
c        jout(i,index): end grid number for an isolated sector in a
c                        culornn
                                        II-3
c        map           the number of total unknow, or the length of X.
c                      later, it is reassigned as N
c        irow (i)      the total number of unknow, P, in each column
c
               map=O
               do i=1,mp
                     icount=O
               in=O
               iout=1
               index=1
               do j=l,np
                      if ( id ( i, j) . eq. '0' ) then
                           icount=icount+1
                          map=map+1
                           imap(map)=i
                           jmap(map)=j
                           if(in .eq. 0) then
                                jin(i,index)=j
                                in=1
                                iout=O
                          end if
                      end if
c
                      if( id(i,j) .eq. '1'      .and. iout .eq. 0) then
                          jout(i,index)=j
                          iout=l
                          in=O
                          index=index+l
                     end if
                  end· do
               irow(i)=icount
               ind(i)=index-1
c
c        ind(i) should be >= 1, except for the entire column are all
c        boundary points.  if not, something wrong.
c
                  write(11,55) i, ind(i), irow(i), jin(i,l), jout(i,l)
    55            format(' i,ind,irow,jin,jout=' ,SiS)
                                             II-4
    6S        format('-----------------------------------            -----------
                                                                      '/
                    N=' ,iS,' << KQ=' ,iS//' It is better to reduce KQ'
         *      1
       *            real(zb(map) )
  90                format(1x,2iS,2x,SiS,2x 1 6f6.2)
                else
                 print* 1 'stop 1 error in DOMAIN at iljlmap='          I    i,j 1 map
                 stop
                end if
c
c    find the band width
c
             if( ia(map 1 S) .ne. 0 ) then
                mu c=abs(ia(mapiS) - ia(map,3)
             else -
                mu c=O
             end if
             if(mu .lt. mu c) mu=mu c
             if( ia(map 1 1) .ne. 0 ) then
                mL_c=abs(ia(mapl1} - ia(mapl3}
                                         I I-S
             else
                 mL c=O
             end if
             if(mL .lt. mL_c) mL=mL c
          end do
c
          m=mL+mu+1
          Lda=m+mL
          write(*,100) m, n, mu, mL, Lda
    100 format(' Band width, m = ',i7/' Data point, N = ',i7/
        *         ' Upper B.W., mu = ',i7/' Lower B.W., mL = ',i7/
        *         ' Lda for Zw     = ',i7)
          if(Lda .gt. iw) then
             print*,'Please increase IW to ',Lda
             stop
             end if
c
c uses the complex thrifty band matrix solver to solve ZAF*ZX= ZB
c
      call bmsolver(ier_code)
c
      if(ier code .eq. 0) then
         do map=1, n
            i=imap(map)
            j=jmap(map)
            p(i,j)=real(zb(map)
            end do
         do j=1,np
            p(1,j) = bcxO
            p(mp,j) = bcxn
            end do
         do i=1,mp
            p(i,1) = bcyO
            p(i 1 np) = bcyn
            end do
             p(1 1 1) = O.S*(bcyO+bcxO)
             p(1,np) = O.S*(bcyn+bcxO)
             p(mp,1) = O.S*(bcyO+bcxn)
             p(mp 1 np) = O.S*(bcyn+bcxn)
             do j=1,np
                write ( 10 I 12 0 ) j , (p ( i , j ) 1 i =1, mp)
    120         format(i5/(10f8.4))
                end do
             end if
          close(10)
          close(11)
                                             II-6
         print*, 'program stop'
         print*, 'The solution is in the file ',outfile
         print*,'and oher details, if needed, is in     recfile
         stop
         end
c
c
*****************************************************************
*
c
         subroutine BMsolver(ierr code)
 c
 c   It solves a complex banded matrix equation ZAF * ZX = ZB
c    where ZAF is a complex band matrix with dimension (m * n)
c       ZX and ZB are two complex column matrices with length (n) .
c
c    Because of the hudge size of ZAF, e.g., (300 x 50000), it is
c    designed to solve this problem using the following two steps.
c
c    First, don't use the full size of ZAF, instead, uses two small
c    matrices: ZA & IA that each only uses 50000 x 5 to save space.
c
c    ZA : a complex matrix (n * 5) to store the coefficent matrix in
c         a matrix equation ZAF*ZX= ZB. Because of using the finite
c         difference method to solve an elliptic equation, there are
c         only 5 elements to be saved for the coefficient matrix.
c         The band width, however, is much much large than 5 with a
c         lot of "zero." By doing so, we need another matrix
c    IA : to save the corresponding locations.
c
c    Second, uses a working matrix, ZW(IW,JW), and do a systematical
c
c    swap between a hard disk and memory.  For this reason, be sure
c    that you do have enough space in your hard disk. For example, a
c    complex matrix with size of (300 x 50000) requires 120 MB for
c    storage, if using 4 byte for a real number.  If using 8 bytes,
c    then, 240 MB is needed.
c
c    IW,JW: IW should be >= m+ml, where ml is the lower band width.
c           The size of JW depends on the available computer memory.
c           In general, the large the JW, the less the disk IO, and
c           thus, the faster the computing speed. As a rule of
c           thumb, you may select JW = 2*IW and tried to see if your
c           computer has enough memory to run the program.
c
c    The proceedures follows that given in the subroutine CGBFA &
c    CGBSL from LINPACK. The major difference is just doing it one
c    block at a time, stores the results in hard disk sequently.
c    After forward elimination, reverse the process by reading the
c    data from hard disk and do back substitute for the solution.
c
         parameter (iq=llO, jq=llO, iw=310, jw=560, kq=lOOOO)
                                  II-7
c
            implicit complex (z)
            character*8 tmpfile
            character*3 chrc
            character*l id, ql
c
            common    /matrx/      za(kq,S), ia(kq,S), zb(kq)
            common    /gener/      mp, np, dx, dy, r, mu, mL, m, Lda
            common    /iando/      p(iq,jq), id(iq,jq)
            common    /unknw/      n, imap(kq), jmap(kq), irow(iq)
            common    /works/      zw(iw,jw), ipvt(kq)
c
            cabsl(zdum)=abs(real(zdum)) + abs(aimag(zdum))
c
c        Gaussian elimination with partial pivoting
c
c        NK: # of columns for the working matrix that will be saved.
c        NW: The number of column needed for working, nw=m-l+nk
c        NS: An index to show the number of working matrix.
c
c        check working matrix dimension
c
            nk=3SO
            nw=m+nk-1
c
             if(nw .gt. jw) then
             write(*,lO) iw, jw, Lda, nw
    :o           format(' The working matrix, ZW(iw,jw), iw,jw=', 2iS/
           *            ' IW shoult be >=',iS, ' and JW must be >=',iS/
           *            ' Please change program and re-run .'//
           *            ' If no memory, you can reduce the NK')
             ierr code=l
             return
             end if
c
c        clear up the working matrix
c
           do i=l,iw
              do j=l,nw
                 ZW ( i 1 j ) = ( 0 • 0 1 0 • 0 )
                 end do
              end do
c
c    construct the first working matrix, ZW, which has a size of
c    (Lda x nw) . The thrify storaged matrices are expanded, only
c    to the first (nk x S) block.
c
c    The flag is used to recording only once when the ZA data
c    starts lost.
c
            ns=O
            mapl=O
                                                    II-8
      iflag=1
      ne=nw
      if(ne .gt. n) ne=n
      do map=1,ne
          do i=1,5
            j=ia(map,i)
            if(j .ne. 0) then
               if(j .le. nk+m-1) then
                   ids=j-map
                   zw(m-ids,j)=za(map,i)
                 else
                   if(iflag .eq. 1) then
                      map1=map
                      iflag=O
                      end if
                 end if
               end if
            end do
        end do
c
c Gaussian elimination with partial pivoting
c
      j1=minO(n,m)-1
      jz=j1
      ju=O
      nt=O
      index=O
c
  100 continue
c
      if(ju .ne. 0) ju=ju-nk
      if(jz .ne. j1) jz=jz-nk
c
c index=O,    the first, 2nd, ... , block of matrix.
c       =1,   the last block of matrix
c
      if(index .eq. 0 .and. ne .ne. n) then
          nc=nk
        else
          nc=n-ns*nk-1
        end if
c
      do k=1,nc
      kp1=k+1
      kr=ns*nk + k
c
c   find L = pivot index
c
      Lm=minO(mL,n-ns*nk-k)
      L=icamax(Lm+1, zw(m,k), 1) + m -1
      ipvt(kr)=L+kr-m
c
                                II-9
c     zero pivot implies that this column are all zeros, a singular
c     matrix.
c
          if (cabs1 (zw (L, k))   .lt. 0 .10e-8) goto 120
c
c    interchange if necessary
c
          if(L .ne. m) then
             zt==ZW(L,k)
             zw(L,k)==zw(m,k)
             zw(m,k)==zt
             end if
c
c    compute multipliers
c
          zt==-(1.0eO,O.OeO)/zw(m 1k)
          call cscal(Lm 1 zt 1 zw(m+11k) I 1)
c
c    swap ZB array, if necessary
c
          Lp==ipvt (kr)
          zt==zb(Lp)
          if(Lp .ne. kr) then
              zb(Lp)==zb(kr)
              zb(kr)==zt
              end if
          call caxpy(Lml. ztl zw(m+11k)     I   11   zb(kr+1), 1)
c
c   row elimenation with column indexing
c
          ju=minO(maxO(ju, mu+ipvt(kr)-ns*nk), n-ns*nk)
          mm=m
          if(ju .ge. kp1) then
             do j=kp1,ju
                L=L-1
                mm=mm-1
                zt=zw(L,j)
                if(L .ne. mm) then
                    zw(L,j)=zw(mm,j)
                    zw(mm,j)=zt
                    end if
                call caxpy(Lml ztl zw(m+1,k), 1, zw(mm+1,j), 1)
                end do
             end if
c
             goto 150
    120      continue
             print*,'Zero diagonal element at (L,k)=', L, k
             stop
    150      continue
c
             end do
                                        II-10
c
c   Eexcept the last working matrix, write the upper triangular
c   matrix (from j=1,nk) into hard disk.  For the last one, i.e.,
c   nc<>nk, go to back substitute directly.
c
       if(nc .eq. nk) then
       nt=nt+1
       print*,'Writing tern. file#', nt
       tmpfile='t'//chrc(nt)//' .tmp'
       open(12,file=tmpfile,form='unformatted')
       write ( 12 ) ( ( z w ( i , j ) , i = 1 , m) , j =1 , nk)
       close(12)
c
c   moving the rest working matrix forward to the beginning
c
       do j=nk+1, nk+m-1
          L=j-nk
          do i=1,Lda
             zw(i,L)=zw(i,j)
             end do
          end do
c
c   clear the rest working area for reading new working matrix
c
       do j=m, nk+m-1
          do i=1,Lda
             ZW ( i j ) = (0 • 0 0 • 0 )
                     1           1
             end do
          end do
c
c read in a full block of ZA and IA, by two steps
c
      ns=ns+1
      if( (ns+1)*nk+m-1 .lt. n) then
         ne=nk
         index=O
c
c For intermediate blocks, read in ZA and IA by two steps.
c First read in the upper triangular matrix that were cut off
c at the previous time when constructing the working matrix.
c
         if(map1 .ne. 0) then
            do map=map1, m-1+ns*nk
               do i=4,5
                  j=ia(map,i)
                  if(j .ne. 0) then
                     if(j .gt. m-1+ns*nk) then
                         ids=j-map
                         zw(m-ids,j-ns*nk)=za(map,i)
                         end if
                     end if
                  end do
                                           II-11
                   end do
                end if
c
c   now read in next block of ZA and IA
c
          iflag=1
          map1=0
          do k=1,ne
              map=k + ns*nk + m-1
                 do i=1,5
                 j=ia(map,i)
                 if(j .ne. 0) then
                        if(j .le. ns*nk+ne+m-1) then
                            ids=j-map
                            zw(m-ids,j-ns*nk)=za(map,i)
                          else
                            if(iflag .eq. 1) then
                               map1=map
                               iflag=O
                               end if
                          end if
                     end if
                 end do
              end do
c
c   End of read in a block of ZA and IA.
c
         else
c
c   This is to read the last block of ZA and IA
c
          ne=n-(m-1+ns*nk)
          index=1
          if(map1 .ne. 0) then
              do map=map1,m-1+ns*nk
                 do i=4,5
                     j=ia(map,i)
                     if(j .ne. 0) then
                        if(j .gt. m-1+ns*nk) then
                            ids=j-map
                            zw(m-ids,j-ns*nk)=za(map,i)
                            end if
                        end if
                     end do
                 end do
              end if
c
c now reads the last block of ZA and IA
c
            iflag=1
         map1=0
         do k=1,ne
                                 II-12
                    map=m-1+ns*nk+k
                    do i=1,5
                       j=ia(map,i)
                       if(j .ne. 0) then
                           if(j .le. m-1+ns*nk+ne) then
                           ids=j-map
                           zw(m-ids,j-ns*nk)=za(map,i)
                         else
                           ierr code=2
                           print*,' If this happen, it is wrong.' .
                           print*, 'At the last block, no overflow'
                           return
                         end if
                       end do
                    end do
                iflag=1
                end if
c
                goto 100
c
            else
c
c         backward substitution from the last submatrix
c
             if( nt .eq. 0) nc=n-1
             do kb=1,nc+1
                kr=n+1-kb
                k=nc+2-kb
                zb(kr)=zb(kr)/zw(m,k)
                Lm=minO(kr,m)-1
                La=m-Lm
                Lb=kr-Lm
                zt=-zb(kr)
                call caxpy(Lm, zt, zw(La,k), 1, zb(Lb), 1)
                end do
c
c     If one loop can include all elements, i.e., for a small banded
c     matrix, just stops after this.
c
            if( nt .eq. 0 ) go to 400
           end if
c
c     complete the rest backward substitute
c
           ns=O
    200    continue
c
c     clear the working matrix for reading new submatrix from disk.
c
           do j=1,nk+m-1
              do i=1,m
                 zw ( i , j ) = ( 0 . 0 , 0 . 0 )
                                                    II-13
                end do
             end do
c
          print*1 1Reading tern. file # 1
                                            1 nt
          open(121file=tmpfile 1 form= 1unformatted 1 )
          read(12) ((zw(i 1 j) 1 i=1,m) ,j=1 1nk)
          close(12 1 status='delete')
c
          do kb=1 1nk
             kr=n+1-(nc+1)-ns*nk-kb
             k=nk+1-kb
             zb(kr)=zb(kr)/zw(m,k)
             Lm=minO(kr,m)-1
             La=m-Lm
             Lb=kr-Lm
             zt=-zb(kr)
             call caxpy(Lm, zt, zw(La,k)        I   1, zb(Lb), 1)
             end do
          ns=ns+1
          nt=nt-1
          tmpfile='t'//chrc(nt)//' .tmp'
          if(nt .gt. 0) goto 200
    400   continue
c
c     To restore the original sequence of ZB. Since it starts
c     at the 2nd. we started at 2nd too for restoring.
c
         print*,'Restore the original sequency'
         do 1000 kb=2 1n
            k=n+1-kb
            L=ipvt (k)
            zt=zb (L)
            if( L .eq. k ) go to 1000
            print*,'pivoting at L,k,kb= 1 ,L,k 1kb
            zb(L)=zb(k)
            zb(k)=zt
    1000    continue
c
          return
          end
c
c
      character*3 function chrc(nt)
c
c It changes an input integer number NT to character
c CHANGQING LI 06/94
c
      character*1 c1
      character*2 c2
      character*3 c3
c
                                     II-14
       i1==nt
       i2==i1/10
       if(i2 .gt. 0) then
           i3==i2/10
           if(i3 .gt. 0) then
              i4==i3/10
              if(i4 .gt. 0) then
                print*,'----------------------------------------'
                print*,'The given integer is> 999, not allowed.'
                print*,'---------------------------------------- 1
                chrc=='-1'
               else
                c3==char(48+i3)//char(48+i2-i3*10)//char(48+i1-i2*10)
                chrc==c3
               end if
            else
               c2==char(48+i2)//char(48+i1-i2*10)
               chrc==c2
            end if
          else
            c1==char(48+i1)
            chrc==c1
          end if
c
       return
       end
c
c
       SUBROUTINE CSCAL(N,CA,CX,INCX)
c
c   PURPOSE Complex vector scale x == a*x
C   WRITTEN on Oct. 1, 79, REVISION on Aug. 01, 82
C   CATEGORY NO. D1A6
C   KEYWORDS BLAS,COMPLEX,LINEAR ALGEBRA,SCALE,VECTOR
C   AUTHORS LAWSON, C. L., (JPL),    HANSON, R. J., (SNLA)
C         KINCAID, D. R., (U. OF TEXAS), and KROGH, F. T.,    (JPL)
c
C   DESCRIPTION
c
c                 B L A S Subprogram
c     Description of Parameters
c
c      --Input--
C         N number of elements in input vector(s)
c        CA complex scale factor
c        ex complex vector with N elements
c      INCX storage spacing between elements of ex
c
c      --Output--
C     CSCAL complex result (unchanged if N .LE. O)
c
c      replace complex   ex   by complex CA*CX.
                                   II-15
C      For I = 0 to N-1, replace CX(1+I*INCX) with
C                                CA * CX (l+I*INCX)
C   REF: LAWSON C.L., HANSON R.J., KINCAID D.R., KROGH F.T.,
C        "BASIC LINEAR ALGEBRA SUBPROGRAMS FOR FORTRAN USAGE,"
C         ALGORITHM NO. 539, TRANSACTIONS ON MATHEMATICAL
C         SOFTWARE, VOLUME 5, NUMBER 3, SEPTEMBER 1979, 308-323
C   ROUTINES CALLED (NONE)
c
       COMPLEX CA,CX(1)
C   FIRST EXECUTABLE STATEMENT   CSCAL
       IF(N .LE. 0) RETURN
       NS = N*INCX
        DO I = 1,NS,INCX
           CX(I) = CA*CX(I)
           end do
       RETURN
       END
c
c
       SUBROUTINE CAXPY(N,CA,CX,INCX,CY,INCY)
c
C   WRITTEN on Oct. 01, 79, REVISION on April 25, 84
C   CATEGORY NO. D1A7
C   KEYWORDS BLAS,COMPLEX,LINEAR ALGEBRA,TRIAD,VECTOR
C   AUTHOR LAWSON, C. L., (JPL), HANSON, R. J., (SNLA)
C           KINCAID, D. R., (U. OF TEXAS), KROGH, F. T.,   (JPL)
C   PURPOSE Complex computation y = a*x + y
C   DESCRIPTION
c
C                 B L A S Subprogram
C     Description of Parameters
c
C      --Input--
C         N number of elements in input vector(s)
C        CA complex scalar multiplier
C        ex complex vector with N elements
C      INCX storage spacing between elements of ex
C        CY complex vector with N elements
C      INCY storage spacing between elements of CY
c
C      --Output--
C        CY complex result (unchanged if N .LE. 0)
c
C      Overwrite complex CY with complex CA*CX + CY.
C      For I = o to N-1, replace
c         CY(LY+I*INCY) with CA*CX(LX+I*INCX) + CY(LY+I*INCY),
c         where
c         LX= 1 if INCX .GE. 0, else LX= (-INCX)*N
C         and LY is defined in a similar way using INCY.
C   REFERENCES
c          LAWSON c. L. HANSON R. J. KINCAID D. R. KROGH F. T.
                      I              I           I             I
    c
            COMPLEX CX(1) ,CY(1) ,CA
    c   FIRST EXECUTABLE STATEMENT CAXPY
            CANORM = ABS(REAL(CA)) + ABS(AIMAG(CA))
            IF(N.LE.O.OR.CANORM.EQ.O.EO) RETURN
            IF(INCX.EQ.INCY.AND.INCX.GT.O) GO TO 20
           KX = 1
           KY = 1
            IF(INCX.LT.O) KX = 1+(1-N)*INCX
           IF(INCY.LT.O) KY = 1+{1-N)*INCY
             DO 10 I = 1,N
             CY(KY) = CY(KY) + CA*CX(KX)
             KX = KX + INCX
             KY = KY + INCY
        10 CONTINUE
           RETURN
        20 CONTINUE
           NS = N*INCX
             DO 30 I=1,NS,INCX
             CY(I) = CA*CX(I) + CY(I)
        30      CONTINUE
           RETURN
           END
c
c
           INTEGER FUNCTION ICAMAX(N,CX,INCX)
c
C       WRITTEN on Oct. 01, 79, REVISed on Aug. 01, 82
C       CATEGORY NO. D1A2
C       KEYWORDS BLAS,COMPLEX,LINEAR ALGEBRA,MAXIMUM COMPONENT,VECTOR
C       AUTHOR LAWSON, C. L., (JPL), HANSON, R. J., (SNLA)
C               KINCAID, D. R., (U. OF TEXAS), KROGH, F. T., (JPL)
c       PURPOSE Find the location (or index) of the largest component
c                of a complex vector
C       DESCRIPTION
c
c                    B L A S Subprogram
c        Description of Parameters
c
C         --Input--
C            N number of elements in input vector(s)
c           ex complex vector with N elements
c         INCX storage spacing between elements of ex
c
c          --Output--
c       ICAMAX smallest index (zero if N .LE. 0)
c
C          Returns the index of the component of CX having the
c          largest sum of magnitudes of real and imaginary parts.
                                   II-17
C      ICAMAX = first I, I = 1 to N, to m~n~m~ze
C      ABS(REAL(CX(1-INCX+I*INCX))) + ABS(IMAG(CX(1-INCX+I*INCX)})
C   REFERENCES
C          LAWSON C.L., HANSON R.J., KINCAID D.R., KROGH F.T.,
C          *BASIC LINEAR ALGEBRA SUBPROGRAMS FOR FORTRAN USAGE*,
C           ALGORITHM NO. 539, TRANSACTIONS ON MATHEMATICAL
C           SOFTWARE, VOLUME 5, NUMBER 3, SEPTEMBER 1979, 308-323
C   ROUTINES CALLED (NONE)
c
c
      COMPLEX CX(1)
C***FIRST EXECUTABLE STATEMENT ICAMAX
      ICAMAX = 0
      IF(N.LE.O) RETURN
      ICAMAX = 1
      IF(N .LE. 1) RETURN
      NS = N*INCX
      II = 1
      SUMMAX = ABS(REAL(CX(1))) + ABS(AIMAG(CX(1)))
      DO 20 I=1,NS,INCX
      SUMRI = ABS(REAL(CX(I))) + ABS(AIMAG(CX(I}))
      IF(SUMMAX.GE.SUMRI) GO TO 10
      SUMMAX = SUMRI
      ICAMAX = II
   10     II = II + 1
   20     CONTINUE
      RETURN
      END
c
c--------------------------------------------------------
c
        subroutine domain(i, j, map, ier)
c
       parameter (iq=110, jq=110, kq=10000, Lq=3)
       implicit complex (z)
       character*1 id
       common /matrx/ za(kq,5), ia(kq,5), zb(kq)
       common /gener/ mp, np, dx, dy, r, mu, mL, m, Lda
       common /iando/ p(iq,jq), id(iq,jq)
       common /unknw/ n,imap(kq) ,jmap(kq) ,irow(iq)
       common /labbl/ ind(iq) ,jin(iq,Lq) ,jout(iq,Lq)
c
        dimension iid(9)
c
c   The finite difference governing equation, the Laplace equation,
c   with r = (dx/dy)**2, is
c
c   p(i-1,j) +r*p(i,j-1) -(2+2r)*p(i,j) +r*p(i,j+1) +p(i+1,j) = 0
c
c   In storage, the coefficient of p(i-1,j) is stored in (map,1)'
c               the coefficient of p(i,j-1) is stored in (map,2)'
c               the coefficient of p(i,j)   is stored in (map,3),
                                II-18
c               the coefficient of p(i,j+1) is stored 1'n (map, 4) ,
c           and the cbefficient of p(i+1,j) is stored in (map,S)
c
       ier=O
       do k=1,9
           iid(k)=O
           end do
       icount=O
c
c For those grid point that are not neighbored to a boundary
c
       if ( id ( i -1 j) • eq • 0
                   I          I   I   and • id ( i+1 j) . eq . ' 0 ' . and .
                                      •           I
                                          II-19
             za(map,2)=r
             za(map,3)=-2.0*(1.0+r)
             za(map,4)=r
             za(map,S)=O.O
             ia(map,1)=map-idistl(i,j)+1
             ia(map,2)=map-1
             ia(map,3)=map
             ia(map,4)=map+1
             ia(map,S)=O
             zb(map)=(O.O, 0.0)
             icount=icount+1
             iid(3)=1
             end if
c
c   for those has a Boundary grind point on the top
c
          if(id(i,j+1) .eq. '1' .and. id(i-1,j)   .eq. '0'   .and.
      *       id(i+1,j) .eq. '0' ) then
              za(map,1)=1.0
              za(map,2)=r
              za(map,3)=-2.0*(1.0+r)
              za(map,4)=0
              za(map,5)=1.0
             ia(map,1)=map-idistl(i,j)+l
              ia(map,2)=map-l
             ia(map,3)=map
             ia(map,4)=0
             ia(map,S)=map+idistr(i,j) -1
             zb(map)=(O.O, 0.0)
             icount=icount+l
             iid(4)=1
             end if
c
c for these grid points that has a Boundary at bottom
c
       if(id(i,j-1) .eq. '2' .and. id(i-l,j) .eq. '0' .and.
     *    id ( i+l, j) . eq. '0' ) then
          za(map,1)=1.0
          za(map,2)=0
          za(map,3)=-2.0*(1.0+r)
          za(map,4)=r
          za(map,S)=l.O
          ia(map,1)=map-idistl(i,j)+l
          ia(map,2)=0
          ia(map,3)=map
          ia(map,4)=map+l
          ia(map,S)=map+idistr(i,j)-1
          zb(map)=(-1.0, 0.0)
          icount=icount+l
          iid(5)=1
          end if
c
                                  II-20
c For those grid points that are left bottom corner
c
      if(id(i-1,j) .eq. '3' .and. id(i,j-1) .eq. '2') then
          za(map,1)=0.0
          za(map,2)=0
          za(map,3)=-2.0*(1.0+r)
          za(map,4)=r
          za(map,5)=1.0
          ia(map,1)=0
          ia(map,2)=0
          ia(map,3)=map
          ia(map,4)=map+1
          ia(map,S)=map+idistr(i,j)-1
          zb(map)=(-3.0, 0.0)
          icount=icount+1
          iid(6)=1
          end if
c
c For those grid points that are left top corner Boundary points
c
      if(id(i-1,j) .eq. '3' .and. id(i,j+1) .eq. '1') then
          za(map,1)=0.0
          za(map,2)=r
          za(map,3)=-2.0*(1.0+r)
          za(map,4)=0.0
          za(map,5)=1.0
          ia(map,1)=0
          ia(map,2)=map-1
          ia(map,3)=map
          ia(map,4)=0
          ia(map,S)=map+idistr(i,j)-1
          zb(map)=(-2.0, 0.0)
          icount=icount+1
          iid(7)=1
         end if
c
c For those grid points that are right bottom boundary points
c
      if(id(i+1,j) .eq. '4' .and. id(i,j-1) .eq. ' 2 ' ) then
          za(map,1)=1.0
          za(map,2)=0
          za(map,3)=-2.0*(1.0+r)
          za(map,4)=r
          za(map,S)=O.O
          ia(map,1)=map-idistl(i,j)+1
          ia(map,2)=0
          ia(map,3)=map
          ia(map,4)=map+1
          ia(map,S)=O
          zb(map)=(-1.0, 0.0)
          icount=icount+1
          iid(8)=1
                              II-21
                                                                           .:   .
          end if
c
c For those grid points that are right top boundary points
c
       if ( id ( i+1, j) . eq. '4' . and. id ( i, j +1) . eq. '1' ) then
            za(map,1)=1.0
            za(map,2)=r
            za(map,3)=-2.0*(1.0+r)
            za(map,4)=0
            za(map,S)=O.O
           ia(map,1)=map-idistl(i,j)+1
           ia(map,2)=map-1
           ia(map,3)=map
           ia(map,4)=0
            ia(map,S)=O
            zb(map)=(O.O, 0.0)
            icount=icount+1
            iid(9)=1
           end if
c
       if( icount .ne. 1) then
            ier=1
           write(11,10) icount, (iid(k) ,k=1,9)
  10        format(' icount=' ,iS,' id(1)-id(9)=' ,9i2/
     *                ' Only one of the ids can be 1, check ID array')
           end if
       return
       end
c
c----------------------------------------------------------------
c
       integer function idistr(i,j)
       parameter (iq=110, Lq=3)
       common /labbl/ ind(iq) ,jin(iq,Lq) ,jout(iq,Lq)
c
c   Calculates the distance between points (i+1,j) and (i,j).     It
c   means how many grid points, which are looking for, are in
c   between. It counts vertically from the point(i,j) and up
c   (i,j+1), (i,j+2), ... , (i,np), then (i+1,1), (i+1,2), ... , to
c   (i+1,j).   In the matrix equation, this distance represents the
c   up band width at that particular diagonal element (i,j)
c
       do k=1,ind(i)
          if(j .ge. jin(i,k)    .and. j   .le. jout(i,k) ) mark1=k
          end do
c
       do k=1,ind(i+1)
          if(j .ge. jin(i+1,k)    .and. j   .le. jout(i+1,k)   ) mark2=k
          end do
c
       idd=jout(i,mark1)-j+1 + j-jin(i+1,mark2)
c
                                  II-22
       do k=mark1+1, ind(i)
          idd=idd + jout(i,k)-jin(i,k)+1
          end do
c
       do k=1,mark2-l
          idd=idd + jout(i+1,k)-jin(i+1,k)+l
          end do
c
       idistr=idd
c
       return
       end
c
c
       integer function idistl(i,j)
c
       parameter (iq=110, Lq=3)
       common /labbl/ ind(iq) ,jin(iq,Lq) 1 jout(iq 1Lq)
c
c   Calculate the distance between point (i-1,j) and (i,j). The
c   distance means how many grid points, which are solved for, are
c   in between. It counts vertically from (i,j) downward (i,j-1),
c   (i 1 j-2), ... , (i 11) and restarted from previous i line
c   (i-1,np) 1  (i-1,np-1)
                         1   •••   to (i-1,j).
                                   ,
c
      do k=l,ind(i-1)
         if(j .ge. jin(i-1,k)          .and. j   .le. jout(i-1,k)) markl=k
         end do
c
      do k=1, ind (i)
         if(j .ge. jin(ilk)        .and. j     .le. jout(i,k)) mark2=k
         end do
c
      idd=jout(i-1 1mark1)-j+1 + j-jin(ilmark2)
c
      do   k=mark1+11ind(i~1)
           idd=idd+jout(i-11k)-jin(i-l,k)+1
           end do
c
      do k=1,mark2-1
         idd=idd+jout(i,k)-jin(i,k)+1
         end do
c
      idistl=idd
      return
      end
                                       II-23
Appendix III.          Source List of FORTRAN Program ID.FOR
              program id matrix
c
c        This program generates the input ID matrix, I.D. codes for
c        each cell
c
              parameter (iq=400,jq=200, kq=SOO, Lq=2000)
              character*1 id
              character*12 outfile
              character*30 header
              character*SO title
c
              common/const/ mp, np, dx, dy, r
              common/array/ id(iq,jq)
              common/bound/ nobc, ibc(Lq), jbc(Lq), zp(Lq)
c
c        mp        mesh number in x direction
c        np        mesh number in y direction
c        dx        spatial step in x-direction
c        dy        spatial step in y-direction
c         r        square of dx/dy
c
c        ID code for water depth
c              0, interior cell
c              1, upper boundary condition
c              2, lower boundary condition
c              3, left boundary condition
c              4, right boundary condition
c              5, left bottom corner B.C.
c              6, left top corner B.C.
c              7, right bottom corner B.C.
c              8, right top corner B.C.
c              e, land point
c
              title=' Laplace equation with specified Dirichlet B.C.'
              print*,'Select 1. large grid;    2. middle grid; '
              print*,'       3. small grid
              read(*,*) iption
              go to (10, 12, 14) iption
    10        mp=101
              np=101
              outfile='p_L.grd'
              go to 20
    12        mp=62
              np=62
              outfile='p_m.grd'
              go to 20
    14        mp=12
              np=12
              outfile='p_s.grd'
    20        continue
                                      III-1
c
           ·dx=3 .1415926/ (mp-1)
            dy=3.1415926/(np-1)
c
c         velocity potential
c
             if(mp .ge. iq .or. np .ge. jq) write(*,30) mp,np, iq jq
    30       format(' Given array (mp,np)=' ,2i5,' is> than alloc~ted'
           *          (iq,jq)=',2i5)                                     I
c
           open(8,file=outfile,form='formatted')
           write(8,' (a80) ') title
           write(8,40) mp, np, dx, dy
     40    format(2i5, 2f12.8)
c
      nobc=O
c
c first establish the ID code for the entire grid point
c
      do j=1, np
         do i=1, mp
             id ( i j ) 0
                       1   =I   I
             end do
         end do
c
c given boundary at the right hand side
c
      do j=2,np-1
         nobc=nobc+1
         id(mp,j)='4'
         ibc(nobc)=mp
         jbc(nobc)=j
         zp(nobc)=O
         end do
c
c left side B.C.
c
      do j=2,np-1
         id(1,j)='3'
         nobc=nobc+1
         ibc(nobc)=1
         jbc(nobc)=j
         zp(nobc)=2.0
         end do
c
c top B.C.
c
      do i=2,mp-1
         id(i,np)='1'
         nobc=nobc+1
         ibc(nobc)=i
          jbc(nobc)=np
                                    III-2
           zp(nobc)=O.O
           end do
    c
    c bottom B.C.
   c
           do i=2,mp-1
                id(i,1)='2'
                nobc=nobc+1
                ibc(nobc)=i
                jbc(nobc)=1
               zp(nobc)=1.0
               end do
   c
  c check the array assignment
  c
           if(nobc .gt. Lq) then
               write(*,SO) nobc, Lq, nobc
     SO        format(' The# of Radiation B.C.=' ,i6,' > Lq=' ,i6/'
         *        ' Change the statement to Lq=' ,i6,' and re-run')
               stop
               end if
  c
  c other minor modification
  c
          id(mp,np)='e'
          id(1,1)='e'
          id(1,np)='e'
          id(mp,1)='e'
 c
          header=' I.D. code for each grid point'
          write(8,' (a30) ') header
         write(8,60) np
    60    format('      j                 i = 1, ... ,',iS)
         do j=1,np
              jj=np-j+1
              write ( 8 , 7 0 ) J J , ( i d ( i , j j ) , i =1, mp)
   70         format(i4,1x,130a1)
              end do
c
         header='Given B.C. at following points'
         write(8,' (iS,2x,a30) ') nobc, header
         write ( 8, 8 0)
   80    format('          n         i            j           B.V.')
         do i=1,nobc
              write(8,90) i,ibc(i) ,jbc(i) ,zp(i)
              end do
  90     format(3iS,2f12.6)
c
         close(8)
         stop
        end
                                 III-3
 Appendix IV. Source List of MATLAB program, P_PLOT.M
 % Program phi_plt.M
 % MathLab M file for plotting the output P matrix generated
 % It uses MathLab ver. 4.2C.1 for WINDOWS
clc;
disp('Available files     for reading are : ');
disp(' 1. p bs.out;        2. p_bm.out  3. p_bL.out');
disp(' 4 p=ts.out;         5. p_tm.out  6. p_tL.out');
disp(' 0. exit ');
optlon=input('Select a     number : ');
while option
   if option == 1
       [fid, message]=fopen('d:\break\p_bs.out');
      end
   if option == 2
       [fid, message]=fopen('d:\break\p_bm.out');
      end
  if option == 3
       [fid, message]=fopen('d:\break\p_bL.out');
      end
  if option == 4
       (fid, message]=fopen('d:\break\p_ts.out');
      end
  if option == 5
       (fid, message]=fopen('d:\break\p_tm.out');
      end
  if option == 6
      (fid, message]=fopen('d:\break\p_tL.out');
      end
%
% contour values for water depth
v_dep=(O 0.1 0.2 0.4 0.8 1.0 1.2 1.4 1.6 1.8 2];
% read data
     ftitle=fgetl(fid);
     disp (I I) j
     disp(ftitle);
     mp=fscanf(fid, '%d', 1);
     np=fscanf(fid, '%d', 1);
                                    IV-1
   disp(['m= ',int2str(mp) ,'  n=     int2str(np)] ) ;
   dx=fscanf(fid, '%f', 1);
   dy=fscanf(fid, '%f', 1);
   disp( ['dx= ',num2str(dx),'  dy= '   num2str(dy)] ) ;
% read solution
   p= [] ;
   for ii=1:np
       nk=fscanf(fid, '%d', 1);
       if nk -= ii
           disp(['Seq. error, i=' ,int2str(nk),   '<>   ii' ,int2str(ii)]);
           disp ('paused') ;
           pause;
           end
       a=fscanf(fid,'%f', mp);
       p ( i i , 1 : mp) =a' ;
       end
   clear a;
   fclose(fid);
  xmin=O;
  xmax=3.1415926;
  ymin=O;
  ymax=xmax;
  elf;
  axes('position', [0.1 0.1 0.88 0.88]);
   [mmm nnn]=size(p);
  dxx=(xmax-xmin)/(nnn-1);
  dyy=(ymax-ymin)/(mmm-1);
  x=xmin:dxx:xmax;
  y=ymin:dyy:ymax;
  axis ratio=(xmax-xmin)/(ymax-ymin);
  data-ratio=1;
  cl=contour(x, y, p, v_dep);
  set(gca,'aspectratio', [axis_ratio, data ratio]);
  set(gca,'xlim', [xmin,xmax], 'ylim', [ymin~ymax]);
  hold on;
  clabel(cl, 'manual');
  xlabel('X '); ylabel('Y ');
  title('Band Matrix Solution');
                                 IV-2
 Appendix V.       Source listing of P_EXACT.M
 ,9.,
  0
no=4000;
dx=0.031415926;
dy=dx;
m=(pi/dx)+l;
y=O:dy:pi; x=y; y=y';
z=zeros(m,m);
for n=l:no
   ff=l-2*(-l)"'n;
   aa=exp(-2*n*pi);
   bb=exp(-n*x);
   cc=exp(n*(x-2*pi));
   dd=exp(n*(x-pi));
   ee=exp(-n*(x+pi));
   gg=sin(n*y);
        z=z+2/(n*pi)*gg*((ff*(bb-cc)-dd+ee)/(1-aa)+l);
        end
fid=fopen('c:\break\P_exact.dat', 'w');
format short;
fprintf(fid,'~alytical solution of a Laplace Equation\n');
fprintf(fid,'w~th b.C.: p=l@ x=O; p=2@ y=O; p=O at x=y=pi\n');
for i=l:m
   fprintf(fid, '%d\n', i);
   a=z(i,l:m);
                                   V-1
l l lil 1001010362
        l~lil fl ili ]Ji il ~ l l i~l l]l i~li j~il
                            fprintf(fid,              '%7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f
                                                       %7.4f %7.4f %7.4f\n', a);
                    fprintf(fid,                      '\n');
                    end
                 fclose(fid);
                %mesh(z);
                %pause;
                v=[0.01 0.1 0.2 0.3 0.4 0.5 0.6 0.8 0.9 1 1.2 1.4 1.6 1.8 1.9 2];
                c=contour(x,y,z,v);
                axis('square');
                clabel(c,'manual');
                xlabel ('X');
                ylabel('Y');
                                                                  , Maa,   • - Y • Gauss~an
                                                                    UsingP the          .
                                                                  , elimination roetho~ for
                                                                                                 J'·
                                                                    large banded matr~x
OEMCO
V-2