aboutsummaryrefslogtreecommitdiff
path: root/src/shmgp.F77
diff options
context:
space:
mode:
Diffstat (limited to 'src/shmgp.F77')
-rw-r--r--src/shmgp.F771455
1 files changed, 1455 insertions, 0 deletions
diff --git a/src/shmgp.F77 b/src/shmgp.F77
new file mode 100644
index 0000000..1982591
--- /dev/null
+++ b/src/shmgp.F77
@@ -0,0 +1,1455 @@
+
+c----------------------------------------------------------------------
+ subroutine umgs2(
+ + ac,aw,as,ae,an,asw,ase,ane,anw,q,f,pu,pd,pc,ru,rd,rc,gam,np2,
+ + ifd59,ifmg,ncyc,tol,nman,im,jm,id5,id9,idi,m,iskip,rmax,
+ + ipc,irc,irurd)
+ implicit real*8(a-h,o-z)
+c----------------------------------------------------------------------
+cdir$ noinline
+c** SUBROUTINE UMGS2
+c
+c** COPYRIGHT: Ecodynamics Research Associates, Inc.
+c
+c** Date written: June, 1990
+c** Author: Steve Schaffer
+c Mathematics Department
+c New Mexico Tech
+c Socorro, NM 87801
+c 505-835-5811
+c
+c** DESCRIPTION:
+c umgs2 is a black box symmetric matrix solver. It is written
+c in unsymmetric storage mode and can be used to solve mildly
+c nonsymmetric problems. The user provides a matrix and right hand
+c side vector corresponding to a 5 or 9 point finite difference/
+c finite volume discretization of a symmetric second order PDE.
+c umgs2 will construct a sequence of coarse grids and coarse
+c grid operators and then solve the matrix equation using a
+c y-direction semi-coarsening multigrid algorithm and return
+c the solution vector. If a sequence of matrix problems are
+c to be solved using the same matrix, computational time can
+c be saved by skipping the construction of the coarse grid
+c information in subsequent calls to umgs2.
+c
+c The matrix on the finest grid is stored in the arrays ac,aw,as,
+c an,asw,ase,ane and anw. The difference stencil at the point
+c (i,j) given by
+c
+c nw n ne anw(i,j) an(i,j) ane(i,j)
+c w c e = aw(i,j) ac(i,j) aw(i,j)
+c sw s se asw(i,j) as(i,j) ase(i,j)
+c
+c If the difference stencil on the fine grid is a 5 point stencil
+c then the arrays asw,ase,ane,anw are not used and the
+c stencil is given by
+c
+c n an(i,j)
+c w c e = aw(i,j) ac(i,j) ae(i,j)
+c s as(i,j)
+c
+c However, asw,ase,ane,anw still need to be dimensioned (by id9)
+c in the calling program as they are used in the coarse grid
+c calculations.
+c
+c** STORAGE
+c It is assumed that a set of ficticious points have been defined
+c along the entire boundary. These points have nothing to do with
+c the solution and are used for programming convenience and
+c vectorization purposes. Storage is allocated for the stencil
+c elements ac,aw,as,asw,ase, the solution vector, q, and the
+c right hand side vector, f, at these ficticious points. The
+c stencils at these ficticious points and all stencil connections
+c to them are set to zero in the subroutine useta which is called
+c by umgs2. The computational grid is depicted by
+c
+c x x x x x x x x
+c
+c x * * * * * * x
+c
+c x * * * * * * x
+c .
+c .
+c .
+c x * * * * * * x
+c
+c x * * * * * * x
+c
+c x x x x x x x x
+c
+c where x depicts the ficticious points and * depicts the interior
+c points. The total storage requirements for the fine grid problem
+c is then 5*im*jm for 5 point stencils and 7*im*jm for 9 point
+c stencils. The total storage requirements for the multigrid
+c solution is approximately 2 to 3 times that of the storage
+c requirements of the fine grid problem. (See DIMENSION PARAMETERS).
+c Note: The first im*jm elements of the arrays ac,aw,as,[asw,ase],
+c q and f correspond to the finest grid.
+c
+c** DIMENSION PARAMETERS
+c The arrays ac,aw,ae,asw,ase,q,f,pu,pd and pc are dimensioned as one
+c dimensional arrays in the calling program. They are dimensioned
+c as two dimensional arrays in the working subroutines. The one
+c dimensional storage of the arrays, say q, follows: n=(j-1)*jm+i,
+c where n is the element location in the one dimensional storage of
+c q corresponding to the (i,j)th element of the two dimensional
+c storage of q and jm is the number of grid points in the j
+c direction (including the two ficticious points).
+c
+c The dimension parameters are id5, id9, idi and idg. They can be
+c determined by running the companion program MSS2DIM.F.
+c id5 - Integer variable.
+c Dimension of the arrays ac,aw,as,ae,an,q and f in the
+c calling program. id5 is the total number of grid points
+c on the finest grid and all coarser grids.
+c id9 - Integer variable.
+c Dimension of the arrays asw,ase,ane,anw in the calling
+c program. If ifd59=5 then id9=idi. If ifd59=9 then
+c id9=id5.
+c idi - Integer variable.
+c Dimension of the work arrays pu and pd in the calling
+c program. idi is the total number of grid points on all
+c of the coarser grids.
+c idg - Integer variable.
+c Dimension of the work array gam in the calling program.
+c It is set to the value im, the number of grid points
+c in the i-direction on the finest grid.
+c
+c** INPUT
+c (Note: all variable types are set implicitly)
+c ac,aw,as
+c ae,an - Real arrays. Dimensioned (id5) in calling program.
+c See comments in DESCRIPTION and DIMENSION PARAMETERS.
+c asw,ase
+c ane,anw - Real arrays. Dimensioned (id9) in calling program.
+c See comments in DESCRIPTION and DIMENSION PARAMETERS.
+c f - Real array. Dimensioned (id5) in calling program.
+c f contains the right hand side vector of the matrix
+c equation to be solved by umgs2.
+c q - Real array. Dimensioned (id5) in calling program.
+c If ifmg=0, q contains the initial guess on the fine
+c grid. If ifmg=1, the initial guess on the fine grid
+c is determined by the full multigrid process and the
+c value of q on input to umgs2 not used.
+c ifd59 - Integer variable.
+c =5 - means a 5-point finite difference stencil (ac,aw and
+c as) is defined on the finest grid by the user.
+c =9 - means a 9-point finite difference stencil (ac,aw,as,
+c asw, ase) is defined on the finest grid by the user.
+c ifmg - Integer variable.
+c =0 - The full multigrid algorithm is not used to obtain a
+c good initial guess on the fine grid.
+c =1 - The full multigrid algorithm is used to obtain a good
+c initial guess on the fine grid.
+c ncyc - Integer variable.
+c The maximum number of multigrid v-cycles to be used.
+c If the maximum norm of the residual is not less than tol
+c at the end of ncyc cycles, the algorithm is terminated.
+c tol - Real variable.
+c >0 - The maximum norm of the residual is calculated at the
+c end of each multigrid cycle. The algorithm is terminated
+c when this maximum becomes less than tol or when the maximum
+c number of iterations (see ncyc) is exceeded. It is up to
+c the user to provide a meaningfull tolerance criteria for
+c the particular problem being solved.
+c =0 - Perform ncyc multigrid cycles. Calculate and print
+c the maximum norm of the residual after each cycle.
+c =-1. - Perform ncyc multigrid cycles. The maximum norm of
+c the final residual is calculated and returned in the
+c variable rmax in the calling list of umgs2.
+c =-2. - Perform ncyc multigrid cycles. The maximum norm of
+c the residual is not calculated.
+c iskip - Integer variable.
+c =0 - The coarse grid information, coarse grid operators
+c and interpolation coefficients are calculated by
+c umgs2. This information is stored in the arrays
+c ac, aw, as, asw, ase, pu, pd, np2 and the variable m
+c and returned to the calling program.
+c =1 - The calculation of the coarse grid information, coarse
+c grid operators and interpolation coefficients is
+c skipped. This option would be used when umgs2 has
+c been called with iskip=0 and is being called again
+c to solve a system of equations with the same matrix.
+c This would be the case in, say, parabolic problems
+c with time independent coefficients.
+c =-1 -The set up of pointers (ugrdfn) is skipped. Coarse grid
+c operators and interpolation coefficients are calculated
+c and the given matrix equation is solved. This option
+c would be used when umgs2 has been called with iskip=0
+c and is being called again to solve a system of
+c equations with a different matrix of the same
+c dimensions. This would be the case for, say,
+c parabolic problems with time dependent coefficients.
+c =-2 -The set up of pointers (ugrdfn) is skipped. Coarse grid
+c operators and interpolation coefficients are calculated
+c and returned to the calling program. No matrix solve.
+c ipc - Integer variable.
+c =0 or 1.
+c ipc is a multigrid parameter which determines the type of
+c interpolation to be used. Usually ipc=1 is best. However, if
+c the boundary contition equations have been absorbed into the
+c interior equations then ipc=0 can be used which results in a
+c slightly more efficient algorithm.
+c nman - Integer variable.
+c =0 usually.
+c =1 signals that the fine grid equations are singular for
+c the case when homogeneous Neumann boundary conditions are
+c applied along the entire boundary. In this case, the
+c difference equations are singular and the condition that
+c the integral of q over the domain be zero is added to the
+c set of difference equations. This condition is satisfied
+c by adding the appropriate constant vector to q on the fine
+c grid. It is assumed, in this case, that a well-defined
+c problem has been given to mgss2, i.e. the integral of f
+c over the domain is zero.
+c im - Integer variable.
+c The number of grid points in the x-direction (including two
+c ficticious points)
+c jm - Integer variable.
+c The number of grid points in the y-direction (including two
+c ficticious points)
+c lout - Integer variable.
+c = unit number of output file into which the maximum norm
+c of the residual after each multigrid v-cycle is printed.
+c Use: common /iout/ lout
+c
+c** INPUT/OUTPUT
+c q - Real array. Dimensioned (id5)
+c On input, if ifmg=0, q contains the initial guess on the
+c finest grid for umgs2. On output, q contains the final
+c solution on the finest grid.
+c ac-anw - Real arrays. See DIMENSION.
+c On input, ac, aw, as, [asw and ase] contain the stencil
+c coefficients for the difference operator on the finest
+c grid. When the iskip=1 option is used, these arrays
+c also are assumed to contain the coarse grid difference
+c stencil coeficients.
+c On output, when the iskip=0 option is used, the coarse
+c grid stencil coeficients are returned in ac - ase.
+c
+c ru,rd,rc - Real work arrays. Dimensioned (idi)
+c
+c pu,pd,pc - Real work arrays. Dimensioned (idi).
+c On input, when the iskip=1 option is used, these arrays
+c are assumed to contain the interpolation coefficients
+c used in the semi-coarsening multigrid algorithm.
+c On output, when the iskip=0 option is used, the
+c interpolation coeficients are returned in pu and pd.
+c np2 - Integer work array. Dimensioned np2(20,8).
+c On input, when the iskip=1,-1 or -2 option is used, np2 is
+c assumed to contain the grid information for umgs2.
+c On output, when the iskip=0 option is used, the grid
+c information for umgs2 is returned in np2.
+c** OUTPUT
+c rmax - If tol.ge.-1., the final residual norm is returned in rmax.
+c
+c** SUBROUTINES CALLED BY UMGS2
+c
+c - ugrdfn, ukey, uintad, urelax, urscal, ursrhs, useta
+c
+c** END OF DESCRIPTION OF UMGS2
+c .....................................................................
+ real*8 ac(id5),aw(id5),as(id5),ae(id5),an(id5),asw(id9),
+ + ase(id9),ane(id9),anw(id9),q(id5),f(id5)
+ real*8 pu(idi),pd(idi),pc(idi),gam(im)
+ integer np2(20,8)
+ real*8 ru(idi),rd(idi),rc(idi)
+ real*8 resid(0:40),confac(0:40)
+ common /io/ linp,lout
+c
+c-time tsu0=second()
+ if(iskip.eq.0) then
+ call ugrdfn(m,ifd59,is5,is9,isi,np2,im,jm)
+ iquit=0
+ if(m.gt.20) then
+ iquit=1
+ write(lout,*) ' m=',m,' > 20 - np2 is dimensioned np2(m=20,8)'
+ endif
+ if(is5.gt.id5) then
+ iquit=1
+ write(lout,*) ' id5=',id5,' too small. Should be set to',is5
+ endif
+ if(is9.gt.id9) then
+ iquit=1
+ write(lout,*) ' id9=',id9,' too small. Should be set to',is9
+ endif
+ if(isi.gt.idi) then
+ iquit=1
+ write(lout,*) ' idi=',idi,' too small. Should be set to',isi
+ endif
+ if(is5.lt.2*im*jm) then
+ iquit=1
+ write(lout,*) ' id5.lt.2*im*jm can cause problems in useta'
+ write(lout,*) ' this can be remedied by setting id5 larger'
+ endif
+ if(iquit.eq.1) return
+ endif
+ if(iskip.le.0) then
+c ---------- interpolation and coarse grid operators -----------
+ do 5 k=m-1,1,-1
+cdir$ inline
+ call ukey(k+1,np2,n5,n9,ni,jm,i9,j9,ifd,jr)
+ call ukey(k,np2,n5c,n9c,nic,jmc,i9c,j9c,ifdc,jrc)
+cdir$ noinline
+ if(k.eq.m-1) n5cqf=n5c
+ 5 call useta(
+ + ac(n5),aw(n5),as(n5),ae(n5),an(n5),asw(n9),ase(n9),
+ + ane(n9),anw(n9),ac(n5c),aw(n5c),as(n5c),ae(n5c),an(n5c),asw(n9c),
+ + ase(n9c),ane(n9c),anw(n9c),pu(nic),pd(nic),pc(nic),ru(nic),
+ + rd(nic),rc(nic),q(n5cqf),f(n5cqf),gam,
+ + im,jm,jmc,ifd,i9,j9,nman,k+1,m,jr,ipc,irc,irurd)
+ endif
+ if(iskip.eq.-2) return
+c
+ if(ifmg.ge.1) then
+ do 6 k=m-1,1,-1
+cdir$ inline
+ call ukey(k+1,np2,n5,n9,ni,jm,i9,j9,ifd,jr)
+ call ukey(k,np2,n5c,n9c,nic,jmc,i9c,j9c,ifdc,jrc)
+cdir$ noinline
+ 6 call ursrhs(f(n5),f(n5c),pu(nic),pd(nic),pc(nic),ru(nic),
+ + rd(nic),rc(nic),im,jm,jmc,m,k+1,jr,irc)
+ endif
+c-time tsu1=second()
+c-time write(lout,*) ' time for setup =',tsu1-tsu0
+ l=1
+ if(ifmg.eq.0) l=m
+ k=l
+ mcyc=0
+ rmaxo=1.
+c ---------- begin multigrid cycling ----------------------------
+c
+ if(l.eq.1) go to 20
+cdir$ inline
+ 10 call ukey(k,np2,n5,n9,ni,jm,i9,j9,ifd,jr)
+cdir$ noinline
+ call urelax(
+ + ac(n5),aw(n5),as(n5),ae(n5),an(n5),asw(n9),ase(n9),
+ + ane(n9),anw(n9),f(n5),q(n5),gam,
+ + im,jm,i9,j9,ifd,nman,k,m,jr,0,0)
+cdir$ inline
+ call ukey(k-1,np2,n5c,n9c,nic,jmc,i9c,j9c,ifdc,jrc)
+cdir$ noinline
+ call urscal(
+ + ac(n5),aw(n5),as(n5),ae(n5),an(n5),asw(n9),ase(n9),
+ + ane(n9),anw(n9),q(n5),f(n5),f(n5c),q(n5c),rc(nic),
+ + im,jm,jmc,ifd,i9,j9,k,m,jr,tol,rmax,ipc,irc)
+ if(k.eq.m.and.rmax.lt.tol) go to 60
+ if(k.eq.m.and.tol.ge.-.5) then
+ if(rmaxo.ne.0.) rate=rmax/rmaxo
+ rmaxo=rmax
+ if(mcyc.eq.0) rmax0=rmax
+ resid(mcyc)=rmax
+ confac(mcyc)=rate
+ endif
+ if(tol.eq.-.5) write(lout,*) ' down ',k,rmax
+ k=k-1
+ if(k.gt.1) go to 10
+c --------- solve coarsest grid ----------------------------------
+c
+cdir$ inline
+ 20 call ukey(1,np2,n5,n9,ni,jm,i9,j9,ifd,jr)
+cdir$ noinline
+ call urelax(
+ + ac(n5),aw(n5),as(n5),ae(n5),an(n5),asw(n9),ase(n9),
+ + ane(n9),anw(n9),f(n5),q(n5),gam,
+ + im,jm,i9,j9,ifd,nman,k,m,jr,0,0)
+ if(l.eq.1) go to 40
+c ---------- interpolate correction to next finer grid -----------
+c
+ 30 k=k+1
+cdir$ inline
+ call ukey(k,np2,n5,n9,ni,jm,i9,j9,ifd,jr)
+ call ukey(k-1,np2,n5c,n9c,nic,jmc,i9c,j9c,ifdc,jrc)
+cdir$ noinline
+ call uintad(
+ + q(n5),q(n5c),pu(nic),pd(nic),im,jm,jmc,1,jr,ipc)
+ call urelax(
+ + ac(n5),aw(n5),as(n5),ae(n5),an(n5),asw(n9),ase(n9),
+ + ane(n9),anw(n9),f(n5),q(n5),gam,
+ + im,jm,i9,j9,ifd,nman,k,m,jr,0,0)
+ if(tol.eq.-.5) then
+ call urscal(
+ + ac(n5),aw(n5),as(n5),ae(n5),an(n5),asw(n9),ase(n9),
+ + ane(n9),anw(n9),q(n5),f(n5),f(n5c),q(n5c),rc(nic),
+ + im,jm,jmc,ifd,i9,j9,k,m,jr,tol,rmax,ipc,irc)
+ write(lout,*) ' up ',k,rmax
+ endif
+ if(k.lt.l) go to 30
+ if(l.eq.m) go to 50
+c ---------- interpolate solution to new finest grid l+1 in fmg ----
+c
+ 40 l=l+1
+ k=l
+cdir$ inline
+ call ukey(l,np2,n5,n9,ni,jm,i9,j9,ifd,jr)
+ call ukey(l-1,np2,n5c,n9c,nic,jmc,i9c,j9c,ifdc,jrc)
+cdir$ noinline
+ call uintad(
+ + q(n5),q(n5c),pu(nic),pd(nic),im,jm,jmc,0,jr,0)
+ go to 10
+c
+ 50 if(nman.eq.1) call uneuman(q(n5),im,jm)
+ mcyc=mcyc+1
+c ---------- Cycle ncyc times on grid m ----------------------------
+ if(mcyc.lt.ncyc) go to 10
+c-time tmg1=second()
+c-time write(lout,*) ' time in ',ncyc,' cycles =',tmg1-tsu1
+c
+c ---------- print out final residual and work units ---------------
+ if(tol.ge.-1.) then
+cdir$ inline
+ call ukey(m,np2,n5,n9,ni,jm,i9,j9,ifd,jr)
+ call ukey(m-1,np2,n5c,n9c,nic,jmc,i9c,j9c,ifdc,jrc)
+cdir$ noinline
+ call urscal(
+ + ac(n5),aw(n5),as(n5),ae(n5),an(n5),asw(n9),ase(n9),
+ + ane(n9),anw(n9),q(n5),f(n5),f(n5c),q(n5c),rc(nic),
+ + im,jm,jmc,ifd,i9,j9,k,m,jr,1.,rmax,ipc,irc)
+ resid(mcyc)=rmax
+ confac(mcyc)=rmax/rmaxo
+ nb=0
+ ne=min0(6,mcyc)
+ 2029 write(lout,2033) (mc,mc=nb,ne)
+ write(lout,2032) (resid(mc),mc=nb,ne)
+ write(lout,2031) (confac(mc),mc=nb,ne)
+ nb=ne+1
+ ne=ne+min0(6,mcyc-ne)
+ if(nb.le.ne) go to 2029
+ fconfac=(rmax/rmax0)**(1./float(mcyc))
+ write(lout,2034) fconfac
+ 2034 format(30x,6(1h*)/,' average convergence factor =',f7.3,/,
+ + 30x,6(1h*))
+ 2033 format(7(4x,i2,4x))
+ 2031 format(7(1x,f9.3))
+ 2032 format(7(1x,e9.3))
+ endif
+ return
+ 60 write(lout,1003) mcyc,resid(mcyc),tol
+ return
+ 1003 format(' cyc=',i2,' max(res)=',1pe8.2/
+ + ' tolerance condition tol=',1pe8.2,' satisfied')
+ end
+c----------------------------------------------------------------------
+ subroutine ugrdfn(m,ifd59,is5,is9,isi,np2,imx,jmx)
+ implicit real*8(a-h,o-z)
+c----------------------------------------------------------------------
+cdir$ noinline
+c Given imx, jmx and ifd59 (See comments in mgss2), ugrdfn calculates
+c the number of grids that will be needed. Pointers into the arrays
+c ac, aw, as, asw, ase, q, f, pu, pd, pc, ru, rd and rc and the size
+c of each grid is calculated and stored in the array np2. The
+c subroutine ukey is called to retrieve the grid information.
+c .....................................................................
+ parameter(n5=1,n9=2,ni=3,jm=4,i9=5,j9=6,ifd=7,jred=8)
+ integer np2(20,8)
+ common /cs/ icorstr,iprint
+ iq5=1
+ iq9=1
+ iqi=1
+ m=1
+ np2(m,1)=jmx
+ np2(m,2)=3
+ 10 if(np2(m,1).le.3) go to 20
+ m=m+1
+ np2(m,1)=np2(m-1,1)/2+1
+ if(np2(m-1,2).eq.2.and.mod(np2(m-1,1),2).eq.1)
+ + np2(m,1)=np2(m,1)+1
+ np2(m,2)=2
+ go to 10
+ 20 do 30 k=1,m
+ np2(m-k+1,jm)=np2(k,1)
+ 30 np2(m-k+1,jred)=np2(k,2)
+ do 40 k=m,1,-1
+ ktot=imx*np2(k,jm)
+ np2(k,n5)=iq5
+ iq5=iq5+ktot
+ np2(k,n9)=iq9
+ if(k.lt.m.or.ifd59.eq.9) iq9=iq9+ktot
+ np2(k,ni)=iqi
+ 40 if(k.lt.m) iqi=iqi+ktot
+ do 50 k=1,m
+ np2(k,i9)=imx
+ np2(k,j9)=np2(k,jm)
+ 50 np2(k,ifd)=9
+ if(ifd59.eq.5) then
+ np2(m,i9)=1
+ np2(m,j9)=1
+ np2(m,ifd)=5
+ endif
+ is5=iq5-1
+ is9=iq9-1
+ isi=iqi-1
+ return
+ end
+c----------------------------------------------------------------------
+ subroutine ukey(k,np2,nn5,nn9,nni,jjm,ii9,jj9,iifd,jjred)
+ implicit real*8(a-h,o-z)
+c----------------------------------------------------------------------
+c Returns the grid pointers and dimension variables for grid k. The
+c information is stored in the array np2.
+c......................................................................
+ parameter(n5=1,n9=2,ni=3,jm=4,i9=5,j9=6,ifd=7,jred=8)
+ integer np2(20,8)
+ nn5=np2(k,n5)
+ nn9=np2(k,n9)
+ nni=np2(k,ni)
+ jjm=np2(k,jm)
+ ii9=np2(k,i9)
+ jj9=np2(k,j9)
+ iifd=np2(k,ifd)
+ jjred=np2(k,jred)
+ return
+ end
+c----------------------------------------------------------------------
+ subroutine uintad(q,qc,pu,pd,im,jm,jmc,iadd,jred,ipc)
+ implicit real*8 (a-h,o-z)
+c----------------------------------------------------------------------
+c iadd=1:
+c Interpolates and adds the coarse grid (kf-1) correction, qc, to the
+c fine grid (kf) approximation, q, at the black y-lines.
+c iadd=0:
+c In the full multigrid algorithm, the solution to the coarse grid
+c (kf-1) difference equation is interpolated to the fine grid (kf)
+c to be used as the initial guess vector for kf=2,3,...,m.
+c Interpolation is at black y-lines only.
+c .....................................................................
+ real*8 q(im,jm),qc(im,jmc),pu(im,jmc),pd(im,jmc)
+ im1=im-1
+ jm1=jm-1
+ jblack=5-jred
+c add correction to next finer grid
+ 1000 if(iadd.eq.1) then
+ jc=3-jred
+ do 10 j=jblack,jm1,2
+ jc=jc+1
+ do 10 i=2,im1
+ 10 q(i,j)=q(i,j)+pd(i,jc)*qc(i,jc)+pu(i,jc)*qc(i,jc+1)
+c
+c interpolate solution to next finer grid in fmg
+ 1001 else
+ jc=3-jred
+ do 40 j=jblack,jm1,2
+ jc=jc+1
+ do 40 i=2,im1
+ 40 q(i,j)=pd(i,jc)*qc(i,jc)+pu(i,jc)*qc(i,jc+1)
+ 1002 endif
+ return
+ end
+c----------------------------------------------------------------------
+ subroutine uneuman(q,im,jm)
+ implicit real*8 (a-h,o-z)
+c----------------------------------------------------------------------
+c For problems with homogeneous Neumann boundary contitions, the
+c condition that the integral of q over the domain be zero is added
+c to the set of difference equations in order to obtain a unique
+c solution.
+c......................................................................
+ real*8 q(im,jm)
+ im1=im-1
+ jm1=jm-1
+ con=0.
+ do 10 j=2,jm1
+ do 10 i=2,im1
+ 10 con=con+q(i,j)
+ con=con/((im-2)*(jm-2))
+ do 20 j=2,jm1
+ do 20 i=2,im1
+ 20 q(i,j)=q(i,j)-con
+ return
+ end
+c----------------------------------------------------------------------
+ subroutine urelax(ac,aw,as,ae,an,asw,ase,ane,anw,f,q,gam,
+ + im,jm,i9,j9,ifd,nman,k,m,jred,ipc,iprcud)
+ implicit real*8 (a-h,o-z)
+c----------------------------------------------------------------------
+c Performs red/black x-line relaxation. The Thomas algorithm is used
+c to solve the tridiagonal matrices.
+c** INPUT -
+c ac-anw= finite difference operator coeficients
+c q= initial approximation
+c f= right hand side vector
+c im,jm= the number of grid points in the x,y-directions
+c i9,j9= the i,j-dimensions of the arrays asw,ase
+c ifd= 5 or 9 - the size of the stencil
+c nman- =0 usually.
+c =1 signals that the fine grid equations are singular
+c for the case when Neumann boundary conditions are
+c applied along the entire boundary. In this case, the
+c equations on the coarsest grid (consisting of a single
+c line of unknowns) is a singular tridiagonal system
+c and the Thomas algorithm is modified on this grid to
+c obtain a solution with an arbitrary constant vector
+c component. This constant vector is removed on the
+c finest grid by the call to subroutine uneuman.
+c** OUTPUT -
+c q= final approximation after a red/black relaxation sweep
+c .....................................................................
+ real*8 ac(im,jm),aw(im,jm),as(im,jm),ae(im,jm),an(im,jm),
+ + asw(i9,j9),ase(i9,j9),ane(i9,j9),anw(i9,j9)
+ real*8 f(im,jm),q(im,jm),gam(im)
+ jm1=jm-1
+ im1=im-1
+ im2=im-2
+ jblack=5-jred
+c usual red/black relaxatio
+ nrel=2
+ jrb=jred
+c ipc ..brbr relaxation swee
+ 1000 if(iprcud.eq.1) then
+ nrel=ipc
+ if(mod(ipc,2).eq.0) jrb=jblack
+c 1 black relax for calc g pu,pd,ru,
+ 1001 elseif(iprcud.eq.2) then
+ nrel=1
+ jrb=jblack
+ 1002 endif
+c
+c
+ do 109 nrr=1,nrel
+ 5000 if(jrb.eq.jblack) then
+c black rela
+ 6000 if(jblack.le.jm1) then
+ 1400 if(iprcud.ne.2) then
+c
+ do 110 j=jblack,jm1,2
+ do 110 i=2,im1
+ 110 q(i,j)=f(i,j)-as(i,j)*q(i,j-1)-an(i,j)*q(i,j+1)
+ 7000 if(ifd.eq.9) then
+ do 120 j=jblack,jm1,2
+ do 120 i=2,im1
+ 120 q(i,j)=q(i,j)-asw(i,j)*q(i-1,j-1)-ase(i,j)*q(i+1,j-1)-
+ + anw(i,j)*q(i-1,j+1)-ane(i,j)*q(i+1,j+1)
+ 7001 endif
+ 1401 endif
+c black tridiagonal solve
+c**
+c** Moved calculation of loop 129 from loop 130 for vectorization
+c** on vector machines (ie. Cray)
+c** By: John Towns 2/6/92
+c**
+ do 129 j=jblack,jm1,2
+ 129 q(2,j)=q(2,j)/ac(2,j)
+
+c**
+c** Changed bet=(quantity) to bet=1./(quantity) to trade two divisions
+c** for one division and two multiplies (more efficient on all
+c** machines)
+c** By: John Towns 2/6/92
+c**
+
+c**
+c** Cray compiler directives to parallelize tridiagonal solve.
+c** By: John Towns 4/13/92
+c**
+
+cmic$ parallel private(bet,gam,i)
+cmic$1shared(ac,ae,aw,q,jblack,jm1,im1,im2)
+cmic$ do parallel
+ do 130 j=jblack,jm1,2
+ bet=1./ac(2,j)
+ do 140 i=3,im1
+ gam(i)=ae(i-1,j)*bet
+ bet=1./(ac(i,j)-aw(i,j)*gam(i))
+ 140 q(i,j)=(q(i,j)-aw(i,j)*q(i-1,j))*bet
+ do 150 i=im2,2,-1
+ 150 q(i,j)=q(i,j)-gam(i+1)*q(i+1,j)
+ 130 continue
+cmic$ end do
+cmic$ end parallel
+ 6001 endif
+c red relax
+ 5001 else
+c
+ do 210 j=jred,jm1,2
+ do 210 i=2,im1
+ 210 q(i,j)=f(i,j)-as(i,j)*q(i,j-1)-an(i,j)*q(i,j+1)
+ 1100 if(ifd.eq.9) then
+ do 220 j=jred,jm1,2
+ do 220 i=2,im1
+ 220 q(i,j)=q(i,j)-asw(i,j)*q(i-1,j-1)-ase(i,j)*q(i+1,j-1)-
+ + anw(i,j)*q(i-1,j+1)-ane(i,j)*q(i+1,j+1)
+ 1101 endif
+c tridiagonal solve
+c nman=1 ==> avoid singularity on coarsest grid
+ imm=im1
+ if(nman.eq.1.and.k.eq.1) then
+ imm=im-2
+ q(im1,2)=0.
+ gam(im1)=0.
+ endif
+c
+c**
+c** Moved calculation of loop 229 from loop 230 for vectorization
+c** on vector machines (ie. Cray)
+c** By: John Towns 2/6/92
+c**
+ do 229 j=jred,jm1,2
+ 229 q(2,j)=q(2,j)/ac(2,j)
+
+c**
+c** Changed bet=(quantity) to bet=1./(quantity) to trade two divisions
+c** for one division and two multiplies (more efficient on all
+c** machines)
+c** By: John Towns 2/6/92
+c**
+
+c**
+c** Cray compiler directives to parallelize tridiagonal solve.
+c** By: John Towns 4/13/92
+c**
+
+cmic$ parallel private(bet,gam,i)
+cmic$1shared(ac,ae,aw,q,jred,jm1,im2,imm)
+cmic$ do parallel
+ do 230 j=jred,jm1,2
+ bet=1./ac(2,j)
+ do 240 i=3,imm
+ gam(i)=ae(i-1,j)*bet
+ bet=1./(ac(i,j)-aw(i,j)*gam(i))
+ 240 q(i,j)=(q(i,j)-aw(i,j)*q(i-1,j))*bet
+ do 250 i=im2,2,-1
+ 250 q(i,j)=q(i,j)-gam(i+1)*q(i+1,j)
+ 230 continue
+cmic$ end do
+cmic$ end parallel
+ 5002 endif
+ jrb=5-jrb
+ 109 continue
+ return
+ end
+c----------------------------------------------------------------------
+ subroutine urscal(
+ + ac,aw,as,ae,an,asw,ase,ane,anw,q,f,fc,qc,rc,
+ + im,jm,jmc,ifd,i9,j9,kf,m,jred,tol,rmax,ipc,irc)
+ implicit real*8 (a-h,o-z)
+c----------------------------------------------------------------------
+c Defines the grid kf-1 right hand side, fc, as the restriction of the
+c grid kf residual. The restriction operator is the transpose of the
+c interpolation operator. Note: The grid kf residual is zero at the
+c black lines (j-direction) as a result of red/black relaxation.
+c Thus, the restriction is simple injection. The initial guess, qc,
+c for the coarse grid correction equation is set to zero. The
+c maximum norm of the residual is calculated and returned in rmax.
+c......................................................................
+ real*8 ac(im,jm),aw(im,jm),as(im,jm),ae(im,jm),an(im,jm),
+ + asw(i9,j9),ase(i9,j9),ane(i9,j9),anw(i9,j9)
+ real*8 f(im,jm),q(im,jm),fc(im,jmc),qc(im,jmc)
+ real*8 rc(im,jmc)
+ rmax=0.
+ im1=im-1
+ jm1=jm-1
+ jmc1=jmc-1
+ jc=1
+ do 10 j=jred,jm1,2
+ jc=jc+1
+ do 10 i=2,im1
+ 10 fc(i,jc)=f(i,j)-as(i,j)*q(i,j-1)-an(i,j)*q(i,j+1)-
+ + aw(i,j)*q(i-1,j)-ae(i,j)*q(i+1,j)-ac(i,j)*q(i,j)
+ 1000 if(ifd.eq.9) then
+ jc=1
+ do 20 j=jred,jm1,2
+ jc=jc+1
+ do 20 i=2,im1
+ 20 fc(i,jc)=fc(i,jc)-asw(i,j)*q(i-1,j-1)-ane(i,j)*q(i+1,j+1)-
+ + ase(i,j)*q(i+1,j-1)-anw(i,j)*q(i-1,j+1)
+ 1001 endif
+c zero out qc as initial guess
+ do 25 jc=1,jmc
+ do 25 i=1,im
+ 25 qc(i,jc)=0.
+c if kf=m calculate residual norm
+ 2000 if((kf.eq.m.and.tol.ge.0.).or.tol.eq.-.5) then
+ do 30 jc=2,jmc1
+ do 30 i=2,im1
+ resmax=abs(fc(i,jc))
+ 30 if(resmax.gt.rmax) rmax=resmax
+ 2001 endif
+c weight rhs if irc.ge.1
+ 3000 if(irc.eq.1.and.ipc.ge.1) then
+ do 40 jc=2,jmc1
+ do 40 i=2,im1
+ 40 fc(i,jc)=rc(i,jc)*fc(i,jc)
+ 3001 endif
+c
+ return
+ end
+c----------------------------------------------------------------------
+ subroutine ursrhs(f,fc,ru,rd,rc,im,jm,jmc,m,kf,jred,irc)
+ implicit real*8 (a-h,o-z)
+c----------------------------------------------------------------------
+c Restricts the right hand side vector on grid kf onto grid kf-1 when
+c the full multigrid (ifmg>0) option is used. The restriction operator
+c is NOT necessarily the transpose of the interpolation operator.
+c......................................................................
+ real*8 f(im,jm),fc(im,jmc),ru(im,jmc),rd(im,jmc),rc(im,jmc)
+ jm1=jm-1
+ im1=im-1
+ jc=1
+ 1000 if(irc.eq.0) then
+ do 10 j=jred,jm1,2
+ jc=jc+1
+ do 10 i=2,im1
+ 10 fc(i,jc)=ru(i,jc-1)*f(i,j-1)+rd(i,jc)*f(i,j+1)+f(i,j)
+ 1001 else
+ do 20 j=jred,jm1,2
+ jc=jc+1
+ do 20 i=2,im1
+ 20 fc(i,jc)=ru(i,jc-1)*f(i,j-1)+rd(i,jc)*f(i,j+1)+
+ + rc(i,jc)*f(i,j)
+ 1002 endif
+ return
+ end
+c----------------------------------------------------------------------
+ subroutine useta(
+ + ac,aw,as,ae,an,asw,ase,ane,anw,acc,awc,asc,aec,
+ + anc,aswc,asec,anec,anwc,pu,pd,pc,ru,rd,rc,qw,fw,gam,
+ + im,jm,jmc,ifd,i9,j9,nman,kf,m,jred,ipc,irc,irurd)
+ implicit real*8 (a-h,o-z)
+c----------------------------------------------------------------------
+cdir$ noinline
+c Calculates the interpolation coefficients from grid kf-1 to
+c grid kf and the coarse grid operator on grid kf-1.
+c** INPUT -
+c ac - anw = fine grid (kf) array stencil coeficients
+c m= total number of grids
+c kf= grid number of the fine grid
+c ifd= the size of the fine grid stencil (= 5 or 9)
+c i9,j9= the i,j-dimensions of the arrays asw,ase
+c qw,fw= coarse grid portions of q and f used for work arrays here
+c (See comments in MGSS2 for details)
+c** OUTPUT -
+c acc - anwc = coarse grid (kf-1) array stencil coeficients
+c pu,pd= arrays of interpolation coefficients from grid kf-1
+c to grid kf
+c .....................................................................
+ real*8 ac(im,jm),aw(im,jm),as(im,jm),ae(im,jm),an(im,jm),
+ + asw(i9,j9),ase(i9,j9),ane(i9,j9),anw(i9,j9),
+ + ru(im,jmc),rd(im,jmc),rc(im,jmc),
+ + pu(im,jmc),pd(im,jmc),pc(im,jmc),gam(im)
+ real*8 acc(im,jmc),awc(im,jmc),asc(im,jmc),aec(im,jmc),
+ + anc(im,jmc),aswc(im,jmc),asec(im,jmc),anec(im,jmc),anwc(im,jmc)
+ real*8 qw(im,jm),fw(im,jm)
+ common /io/ linp,lout
+ common /prsol/ iprsol
+c
+ pcscale=.001
+c
+ im1=im-1
+ jm1=jm-1
+ jmc1=jmc-1
+ jblack=5-jred
+c zeroing out connections to fictitious points
+ do 1 j=1,jm
+ do 2 i=1,im,im1
+ ac(i,j)=0.
+ aw(i,j)=0.
+ as(i,j)=0.
+ ae(i,j)=0.
+ 2 an(i,j)=0.
+ aw(2,j)=0.
+ 1 ae(im1,j)=0.
+ do 3 i=1,im
+ do 4 j=1,jm,jm1
+ ac(i,j)=0.
+ aw(i,j)=0.
+ as(i,j)=0.
+ ae(i,j)=0.
+ 4 an(i,j)=0.
+ as(i,2)=0.
+ 3 an(i,jm1)=0.
+ 1000 if(ifd.eq.9) then
+ do 5 j=1,jm
+ do 6 i=1,im,im1
+ asw(i,j)=0.
+ ase(i,j)=0.
+ ane(i,j)=0.
+ 6 anw(i,j)=0.
+ asw(2,j)=0.
+ anw(2,j)=0.
+ ase(im1,j)=0.
+ 5 ane(im1,j)=0.
+ do 7 i=1,im
+ do 8 j=1,jm,jm1
+ asw(i,j)=0.
+ ase(i,j)=0.
+ ane(i,j)=0.
+ 8 anw(i,j)=0.
+ ase(i,2)=0.
+ asw(i,2)=0.
+ ane(i,jm1)=0.
+ 7 anw(i,jm1)=0.
+ 1001 endif
+c
+ do 9 jc=1,jmc
+ do 9 i=1,im
+ pc(i,jc)=0.
+ pu(i,jc)=0.
+ pd(i,jc)=0.
+ rc(i,jc)=0.
+ ru(i,jc)=0.
+ 9 rd(i,jc)=0.
+c
+c calculation of interpolation coeficients
+c
+
+c define pc
+ 2000 if(ipc.ge.1) then
+ do 20 j=2,jm1
+ do 20 i=2,im1
+ fw(i,j)=0.
+ 20 qw(i,j)=1.
+c
+ call urelax(ac,aw,as,ae,an,asw,ase,ane,anw,fw,qw,gam,im,jm,
+ + i9,j9,ifd,nman,kf,m,jred,ipc,1)
+c scale pc
+ pcmax=0.
+ jc=1
+ do 40 j=jred,jm1,2
+ jc=jc+1
+ do 40 i=2,im1
+ pc(i,jc)=qw(i,j)
+ 40 pcmax=max(pcmax,abs(qw(i,j)))
+ do 50 jc=2,jmc1
+ do 50 i=2,im1
+ if(pc(i,jc).eq.0.) pc(i,jc)=pcscale
+ 50 pc(i,jc)=pc(i,jc)/pcmax
+c
+ 2001 else
+ do 55 jc=2,jmc1
+ do 55 i=2,im1
+ 55 pc(i,jc)=1.
+ 2002 endif
+c
+c define pu
+ jc=3-jred
+ do 60 j=jblack,jm1,2
+ jc=jc+1
+ 4000 if(ipc.eq.0) then
+ do 70 i=2,im1
+ 70 qw(i,j)=-an(i,j)
+ 5000 if(ifd.eq.9) then
+ do 80 i=2,im1
+ 80 qw(i,j)=qw(i,j)-ane(i,j)-anw(i,j)
+ 5001 endif
+ 4001 else
+ do 90 i=2,im1
+ 90 qw(i,j)=-an(i,j)*pc(i,jc+1)
+ 6000 if(ifd.eq.9) then
+ do 100 i=2,im1
+ 100 qw(i,j)=qw(i,j)-ane(i,j)*pc(i+1,jc+1)-anw(i,j)*pc(i-1,jc+1)
+ 6001 endif
+ 4002 endif
+ 60 continue
+c solve for pu
+ call urelax(ac,aw,as,ae,an,asw,ase,ane,anw,fw,qw,gam,im,jm,
+ + i9,j9,ifd,nman,kf,m,jred,ipc,2)
+c
+
+ jc=3-jred
+ do 102 j=jblack,jm1,2
+ jc=jc+1
+ 3020 if(j.lt.jm1) then
+ do 103 i=2,im1
+ 103 pu(i,jc)=qw(i,j)
+ 3021 endif
+ 102 continue
+c
+c define pd
+ jc=3-jred
+ do 106 j=jblack,jm1,2
+ jc=jc+1
+ 8000 if(ipc.eq.0) then
+ do 130 i=2,im1
+ 130 qw(i,j)=-as(i,j)
+ 9000 if(ifd.eq.9) then
+ do 140 i=2,im1
+ 140 qw(i,j)=qw(i,j)-ase(i,j)-asw(i,j)
+ 9001 endif
+c
+ 8001 else
+c
+ do 150 i=2,im1
+ 150 qw(i,j)=-as(i,j)*pc(i,jc)
+ 1100 if(ifd.eq.9) then
+ do 160 i=2,im1
+ 160 qw(i,j)=qw(i,j)-ase(i,j)*pc(i+1,jc)-asw(i,j)*pc(i-1,jc)
+ 1101 endif
+ 8002 endif
+ 106 continue
+c solve for pd
+ call urelax(ac,aw,as,ae,an,asw,ase,ane,anw,fw,qw,gam,im,jm,
+ + i9,j9,ifd,nman,kf,m,jred,ipc,2)
+c
+ jc=3-jred
+ do 105 j=jblack,jm1,2
+ jc=jc+1
+ 7010 if(j.gt.2) then
+ do 104 i=2,im1
+ 104 pd(i,jc)=qw(i,j)
+ 7011 endif
+ 105 continue
+c
+c define restriction operator
+c
+c define rc
+ 1200 if(irc.eq.1) then
+ do 500 jc=2,jmc1
+ do 500 i=2,im1
+ 500 rc(i,jc)=pc(i,jc)
+ else
+ do 502 jc=2,jmc1
+ do 502 i=2,im1
+ 502 rc(i,jc)=1.
+ 1201 endif
+c
+c compute qw = -Cb(inv) * eb*
+ 1300 if(irurd.ge.1) then
+ jc=3-jred
+ 3300 if(irurd.eq.1) then
+ do 560 j=jblack,jm1,2
+ jc=jc+1
+ do 560 i=2,im1
+ 560 qw(i,j)=1.
+ 3301 elseif(irurd.eq.2) then
+ do 561 j=jblack,jm1,2
+ jc=jc+1
+ do 561 i=2,im1
+ 561 qw(i,j)=(pd(i,jc)*pc(i,jc)+pu(i,jc)*pc(i,jc+1))
+ 3302 endif
+c
+ call urelax(ac,aw,as,ae,an,asw,ase,ane,anw,fw,qw,gam,im,jm,
+ + i9,j9,ifd,nman,kf,m,jred,ipc,2)
+c
+ jc=3-jred
+ do 566 j=jblack,jm1,2
+ jc=jc+1
+c compute ru = -b(j+1) * qw
+ 1400 if(j.lt.jm1) then
+ do 570 i=2,im1
+ 570 ru(i,jc)=-as(i,j+1)*qw(i,j)
+ 1500 if(ifd.eq.9) then
+ do 580 i=2,im1
+ 580 ru(i,jc)=ru(i,jc)-ase(i,j+1)*qw(i+1,j)-asw(i,j+1)*qw(i-1,j)
+ 1501 endif
+ 1401 endif
+c compute rd = -a(j-1) * c(j)(inv) * qw
+ 1600 if(j.gt.2) then
+ do 650 i=2,im1
+ 650 rd(i,jc)=-an(i,j-1)*qw(i,j)
+ 1700 if(ifd.eq.9) then
+ do 660 i=2,im1
+ 660 rd(i,jc)=rd(i,jc)-ane(i,j-1)*qw(i+1,j)-anw(i,j-1)*qw(i-1,j)
+ 1701 endif
+ 1601 endif
+ 566 continue
+c
+ 1301 else
+c else set ru=pu and rd=pd
+ jc=3-jred
+ do 670 j=jblack,jm1,2
+ jc=jc+1
+ do 670 i=2,im1
+ ru(i,jc)=pu(i,jc)
+ 670 rd(i,jc)=pd(i,jc)
+ 1303 endif
+c
+c calculating the coarse grid operator
+c
+ 1800 if(ipc+irc+irurd.eq.0) then
+ j=jred-2
+ do 200 jc=2,jmc1
+ j=j+2
+ do 200 i=2,im1
+ acc(i,jc)=ac(i,j)+an(i,j-1)*pu(i,jc-1)+as(i,j+1)*pd(i,jc)+
+ + pu(i,jc-1)*(as(i,j)+ac(i,j-1)*pu(i,jc-1))+
+ + pd(i,jc)*(an(i,j)+ac(i,j+1)*pd(i,jc))
+ awc(i,jc)=aw(i,j)+pd(i-1,jc)*aw(i,j+1)*pd(i,jc)+pu(i-1,jc-1)*
+ + aw(i,j-1)*pu(i,jc-1)
+ asc(i,jc)=as(i,j)*pd(i,jc-1)+pu(i,jc-1)*(as(i,j-1)+
+ + ac(i,j-1)*pd(i,jc-1))
+ aec(i,jc)=ae(i,j)+pd(i+1,jc)*ae(i,j+1)*pd(i,jc)+pu(i+1,jc-1)*
+ + ae(i,j-1)*pu(i,jc-1)
+ anc(i,jc)=an(i,j)*pu(i,jc)+pd(i,jc)*(an(i,j+1)+
+ + ac(i,j+1)*pu(i,jc))
+ aswc(i,jc)=pd(i-1,jc-1)*aw(i,j-1)*pu(i,jc-1)
+ asec(i,jc)=pd(i+1,jc-1)*ae(i,j-1)*pu(i,jc-1)
+ anec(i,jc)=pu(i+1,jc)*ae(i,j+1)*pd(i,jc)
+ 200 anwc(i,jc)=pu(i-1,jc)*aw(i,j+1)*pd(i,jc)
+ 1900 if(ifd.eq.9) then
+ j=jred-2
+ do 210 jc=2,jmc1
+ j=j+2
+ do 210 i=2,im1
+ awc(i,jc)=awc(i,jc)+asw(i,j+1)*pd(i,jc)+anw(i,j-1)*pu(i,jc-1)+
+ + pd(i-1,jc)*anw(i,j)+pu(i-1,jc-1)*asw(i,j)
+ aec(i,jc)=aec(i,jc)+ase(i,j+1)*pd(i,jc)+ane(i,j-1)*pu(i,jc-1)+
+ + pd(i+1,jc)*ane(i,j)+pu(i+1,jc-1)*ase(i,j)
+ aswc(i,jc)=aswc(i,jc)+asw(i,j-1)*pu(i,jc-1)+pd(i-1,jc-1)*asw(i,j)
+ asec(i,jc)=asec(i,jc)+ase(i,j-1)*pu(i,jc-1)+pd(i+1,jc-1)*ase(i,j)
+ anec(i,jc)=anec(i,jc)+ane(i,j+1)*pd(i,jc)+pu(i+1,jc)*ane(i,j)
+ 210 anwc(i,jc)=anwc(i,jc)+anw(i,j+1)*pd(i,jc)+pu(i-1,jc)*anw(i,j)
+ 1901 endif
+c
+ 1801 else
+c
+ j=jred-2
+ do 300 jc=2,jmc1
+ j=j+2
+ do 300 i=2,im1
+ acc(i,jc)=rc(i,jc)*(ac(i,j)*pc(i,jc)+
+ + as(i,j)*pu(i,jc-1)+
+ + an(i,j)*pd(i,jc))+
+ + ru(i,jc-1)*(ac(i,j-1)*pu(i,jc-1)+
+ + an(i,j-1)*pc(i,jc))+
+ + rd(i,jc)*(ac(i,j+1)*pd(i,jc)+
+ + as(i,j+1)*pc(i,jc))
+ awc(i,jc)=rc(i,jc)*aw(i,j)*pc(i-1,jc)+
+ + rd(i,jc)*aw(i,j+1)*pd(i-1,jc)+
+ + ru(i,jc-1)*aw(i,j-1)*pu(i-1,jc-1)
+ asc(i,jc)=rc(i,jc)*as(i,j)*pd(i,jc-1)+
+ + ru(i,jc-1)*(ac(i,j-1)*pd(i,jc-1)+
+ + as(i,j-1)*pc(i,jc-1))
+ aec(i,jc)=rc(i,jc)*ae(i,j)*pc(i+1,jc)+
+ + rd(i,jc)*ae(i,j+1)*pd(i+1,jc)+
+ + ru(i,jc-1)*ae(i,j-1)*pu(i+1,jc-1)
+ anc(i,jc)=rc(i,jc)*an(i,j)*pu(i,jc)+
+ + rd(i,jc)*(ac(i,j+1)*pu(i,jc)+
+ + an(i,j+1)*pc(i,jc+1))
+ aswc(i,jc)=ru(i,jc-1)*aw(i,j-1)*pd(i-1,jc-1)
+ asec(i,jc)=ru(i,jc-1)*ae(i,j-1)*pd(i+1,jc-1)
+ anec(i,jc)=rd(i,jc)*ae(i,j+1)*pu(i+1,jc)
+ 300 anwc(i,jc)=rd(i,jc)*aw(i,j+1)*pu(i-1,jc)
+ 2100 if(ifd.eq.9) then
+ j=jred-2
+ do 310 jc=2,jmc1
+ j=j+2
+ do 310 i=2,im1
+ awc(i,jc)=awc(i,jc)+(rd(i,jc)*asw(i,j+1)+
+ + ru(i,jc-1)*anw(i,j-1))*pc(i-1,jc)+
+ + rc(i,jc)*(anw(i,j)*pd(i-1,jc)+
+ + asw(i,j)*pu(i-1,jc-1))
+ aec(i,jc)=aec(i,jc)+(rd(i,jc)*ase(i,j+1)+
+ + ru(i,jc-1)*ane(i,j-1))*pc(i+1,jc)+
+ + rc(i,jc)*(ane(i,j)*pd(i+1,jc)+
+ + ase(i,j)*pu(i+1,jc-1))
+ aswc(i,jc)=aswc(i,jc)+ru(i,jc-1)*asw(i,j-1)*pc(i-1,jc-1)+
+ + rc(i,jc)*asw(i,j)*pd(i-1,jc-1)
+ asec(i,jc)=asec(i,jc)+ru(i,jc-1)*ase(i,j-1)*pc(i+1,jc-1)+
+ + rc(i,jc)*ase(i,j)*pd(i+1,jc-1)
+ anec(i,jc)=anec(i,jc)+rd(i,jc)*ane(i,j+1)*pc(i+1,jc+1)+
+ + rc(i,jc)*ane(i,j)*pu(i+1,jc)
+ 310 anwc(i,jc)=anwc(i,jc)+rd(i,jc)*anw(i,j+1)*pc(i-1,jc+1)+
+ + rc(i,jc)*anw(i,j)*pu(i-1,jc)
+ 2101 endif
+ 1802 endif
+cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ if(iprsol.eq.2.and.kf.eq.m.and.ifd.eq.5) then
+ do 111 j=2,jm1
+ do 111 i=2,im1
+ write(lout,1010) im,jm,an(i,j)
+ write(lout,1012) i,j,aw(i,j),ac(i,j),ae(i,j)
+ 111 write(lout,1011) as(i,j)
+ 1010 format(2(1x,i2),14x,f12.5)
+ 1011 format(20x,f12.5)
+ 1012 format(2(1x,i2),3(1x,f12.5))
+ endif
+ if(iprsol.eq.2.and.kf.eq.m.and.ifd.eq.9) then
+ do 115 j=2,jm1
+ do 115 i=2,im1
+ write(lout,1017) im,jm,anw(i,j),an(i,j),ane(i,j)
+ write(lout,1017) i,j,aw(i,j),ac(i,j),ae(i,j)
+ 115 write(lout,1016) asw(i,j),as(i,j),ase(i,j)
+ 1016 format(6x,3(1x,f12.5))
+ 1017 format(2(1x,i2),3(1x,f12.5))
+ endif
+cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ if(iprsol.eq.2.or.iprsol.eq.3) then
+ write(lout,*) ' coarse grid kf-1 ==',kf-1
+ do 211 jc=2,jmc1
+ do 211 i=2,im1
+ write(lout,2015) im,jmc,anwc(i,jc),anc(i,jc),anec(i,jc),pd(i,jc),
+ + rd(i,jc)
+ write(lout,2013) i,jc,awc(i,jc),acc(i,jc),aec(i,jc),pc(i,jc),
+ + rc(i,jc)
+ write(lout,2014) aswc(i,jc),asc(i,jc),asec(i,jc),pu(i,jc-1),
+ + ru(i,jc-1)
+ 211 write(lout,*) ' m, kf-1=',m,kf-1
+ 2014 format(9x,3(1x,f11.5),3x,2(f11.5,1x))
+ 2013 format(3x,2(1x,i2),3(1x,f11.5),3x,2(f11.5,1x))
+ 2015 format(3x,2(1x,i2),3(1x,f11.5),3x,2(f11.5,1x))
+ endif
+cxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ return
+ end
+c**********************************************************************
+ subroutine uoutpt(q,im,jm)
+ implicit real*8 (a-h,o-z)
+c**********************************************************************
+c Sample output subroutine. Prints out the values of q at the
+c interior points of the finest grid.
+c**********************************************************************
+ common /io/ linp,lout
+ real*8 q(im,jm)
+ im1=im-1
+ jm1=jm-1
+ ie=1
+ 20 ib=ie+1
+ ie=ib+min0(5,im1-ib)
+ do 10 j=jm1,2,-1
+ 10 write(lout,100) j,(q(i,j),i=ib,ie)
+ if(ie.lt.im1) go to 20
+ 100 format(1x,i2,1x,6(1x,f10.4))
+ return
+ end
+c**********************************************************************
+ subroutine uputf(ac,aw,as,ae,an,f,nx,ny,
+ + lo,nxd,nyd,i32su)
+ implicit real*8 (a-h,o-z)
+c**********************************************************************
+ real*8 ac(lo:nxd,lo:nyd),aw(lo:nxd,lo:nyd),
+ + as(lo:nxd,lo:nyd),ae(lo:nxd,lo:nyd),
+ + an(lo:nxd,lo:nyd),f(lo:nxd,lo:nyd)
+ real*8 a(20),b(20),ab(20)
+ integer il(20),ir(20),jb(20),jt(20)
+ integer ibc(4)
+ common /io/ linp,lout
+c
+c dcell is the value assigned to the diagonal element of a dead
+c cell, i.e. a cell that has 0 conections to all its neighbors.
+c icendif determines the differencing scheme for the first order terms
+c icendif=0 - central differencing, =1 - forward differencing.
+c
+ dcell = 1.
+ do 321 j=lo,nyd
+ do 321 i=lo,nxd
+ ac(i,j)=0.
+ aw(i,j)=0.
+ as(i,j)=0.
+ ae(i,j)=0.
+ 321 an(i,j)=0.
+c
+ nx1=nx+1
+ ny1=ny+1
+ read(linp,*) icendif
+ read(linp,*) ibc(1),ibc(2),ibc(3),ibc(4)
+ read(linp,*) nreg
+ hx=1./nx
+ hy=1./ny
+ hx2=hx*hx
+ hy2=hy*hy
+ hxy2=hx2*hy2
+ dcell=hxy2*dcell
+ write(lout,1011) ibc(1),ibc(2),ibc(3),ibc(4),icendif,dcell,hx,hy
+ 1011 format(' ibc_l ibc_b ibc_r ibc_t icendiff dcell hx hy'/
+ + 4x,i1,5x,i1,5x,i1,5x,i1,7x,i1,6x,e8.2,2x,f6.4,2x,f6.4/)
+c
+ do 10 irg=1,nreg
+ read(linp,*) il(irg),ir(irg),jb(irg),jt(irg)
+ read(linp,*) xk,yk,sreg,freg
+ read(linp,*) a(irg),b(irg),ab(irg)
+ write(lout,1000) il(irg),ir(irg),jb(irg),jt(irg),xk,yk,sreg,freg
+ 1000 format(1x,i3,',',i3,' X ',i3,',',i3,2x,1pe8.2,1x,1pe8.2,2x,
+ + 1pe8.1,1x,1pe8.1)
+ write(lout,1001) a(irg),b(irg),ab(irg)
+ 1001 format(17x,' a=',1pe10.3,' b=',1pe10.3,' ab=',1pe10.3)
+ xk=xk*hy2
+ yk=yk*hx2
+ sreg=sreg*hxy2
+ freg=freg*hxy2
+ a(irg)=a(irg)*hx2*hy
+ b(irg)=b(irg)*hx*hy2
+ ab(irg)=ab(irg)*hx*hy
+ if(icendif.eq.0) then
+ a(irg)=a(irg)/2.
+ b(irg)=b(irg)/2.
+ ab(irg)=ab(irg)/4.
+ endif
+ if(il(irg).eq.1) il(irg)=0
+ if(ir(irg).eq.nx) ir(irg)=nx1
+ if(jb(irg).eq.1) jb(irg)=0
+ if(jt(irg).eq.ny) jt(irg)=ny1
+ do 20 i=il(irg),ir(irg)
+ do 20 j=jb(irg),jt(irg)
+ aw(i,j)=xk
+ as(i,j)=yk
+ ac(i,j)=sreg
+ 20 f(i,j)=freg
+ 10 continue
+ write(lout,*) ' - - - - - - - - - - - - - - - - - - - - - - - - -'
+c defining coeficients by harmonic averaging
+ do 30 i=1,nx
+ asio=as(i,0)
+ do 30 j=1,ny1
+ aa=as(i,j)*asio
+ if(aa.gt.0.) then
+ t=2.*aa/(as(i,j)+asio)
+ asio=as(i,j)
+ as(i,j)=t
+ else
+ asio=as(i,j)
+ as(i,j)=0.
+ endif
+ 30 continue
+ do 40 j=1,ny
+ awoj=aw(0,j)
+ do 40 i=1,nx1
+ aa=aw(i,j)*awoj
+ if(aa.gt.0.) then
+ t=2.*aa/(aw(i,j)+awoj)
+ awoj=aw(i,j)
+ aw(i,j)=t
+ else
+ awoj=aw(i,j)
+ aw(i,j)=0.
+ endif
+ 40 continue
+ do 45 i=0,nx
+ do 45 j=0,ny
+ ae(i,j)=aw(i+1,j)
+ 45 an(i,j)=as(i,j+1)
+ do 50 i=1,nx
+ do 50 j=1,ny
+ ac(i,j)=ac(i,j)-aw(i,j)-as(i,j)-ae(i,j)-
+ + an(i,j)
+ 50 if(ac(i,j).eq.0.) ac(i,j)=dcell
+c adding on the unsymmetric terms
+ do 51 irg=1,nreg
+c icendif=0 ==> central diff g
+ if(icendif.eq.0) then
+ do 52 i=il(irg),ir(irg)
+ do 52 j=jb(irg),jt(irg)
+ aw(i,j)=aw(i,j)-a(irg)
+ ae(i,j)=ae(i,j)+a(irg)
+ an(i,j)=an(i,j)+b(irg)
+ 52 as(i,j)=as(i,j)-b(irg)
+c icendif=1 ==> upstream diff s
+ elseif(icendif.eq.1) then
+ do 54 i=il(irg),ir(irg)
+ do 54 j=jb(irg),jt(irg)
+ ac(i,j)=ac(i,j)-a(irg)
+ ae(i,j)=ae(i,j)+a(irg)
+ an(i,j)=an(i,j)+b(irg)
+ 54 ac(i,j)=ac(i,j)-b(irg)
+ endif
+ 51 continue
+c set boundary conditions for 5 point operator
+ do 60 j=1,ny
+c left boundary
+ ae(0,j)=aw(1,j)
+ if(ibc(1).eq.1) then
+ ac(0,j)=aw(1,j)
+ f(0,j)=2.*aw(1,j)*0.0
+ elseif(ibc(1).eq.2) then
+ ac(0,j)=-aw(1,j)
+ f(0,j)=hx*aw(1,j)*0.0
+ endif
+ if(ac(0,j).eq.0.) then
+ ae(0,j)=0.
+ ac(0,j)=dcell
+ f(0,j)=0.
+ endif
+c right boundary
+ aw(nx1,j)=ae(nx,j)
+ if(ibc(3).eq.1) then
+ ac(nx1,j)=ae(nx,j)
+ f(nx1,j)=2.*ae(nx,j)*0.
+ elseif(ibc(3).eq.2) then
+ ac(nx1,j)=-ae(nx,j)
+ f(nx1,j)=hx*ae(nx,j)*0.
+ endif
+ if(ac(nx1,j).eq.0.) then
+ aw(nx1,j)=0.
+ ac(nx1,j)=dcell
+ f(nx1,j)=0.
+ endif
+ 60 continue
+c
+ do 80 i=1,nx
+c lower boundary
+ an(i,0)=as(i,1)
+ if(ibc(2).eq.1) then
+ ac(i,0)=as(i,1)
+ f(i,0)=2.*as(i,1)*0.
+ elseif(ibc(2).eq.2) then
+ ac(i,0)=-as(i,1)
+ f(i,0)=hy*as(i,1)*0.
+ endif
+ if(ac(i,0).eq.0.) then
+ an(i,0)=0.
+ ac(i,0)=dcell
+ f(i,0)=0.
+ endif
+c upper boundary
+ as(i,ny1)=an(i,ny)
+ if(ibc(4).eq.1) then
+ ac(i,ny1)=an(i,ny)
+ f(i,ny1)=2.*an(i,ny)*0.
+ elseif(ibc(4).eq.2) then
+ ac(i,ny1)=-an(i,ny)
+ f(i,ny1)=2.*an(i,ny)*0.
+ endif
+ if(ac(i,ny1).eq.0.) then
+ as(i,ny1)=0.
+ ac(i,ny1)=dcell
+ f(i,ny1)=0.
+ endif
+ 80 continue
+c connections between ghost boundary points zeroed
+ do 83 j=1,ny1
+ as(0,j)=0.
+ an(0,j-1)=0.
+ as(nx1,j)=0.
+ 83 an(nx1,j-1)=0.
+ do 86 i=1,nx1
+ aw(i,0)=0.
+ ae(i-1,0)=0.
+ aw(i,ny1)=0.
+ 86 ae(i-1,ny1)=0.
+c corner stencils and rhs defined
+ if(i32su.eq.32) then
+ do 90 j=0,ny1,ny1
+ do 90 i=0,nx1,nx1
+ ac(i,j)=dcell
+ aw(i,j)=0.
+ ae(i,j)=0.
+ as(i,j)=0.
+ an(i,j)=0.
+ 90 f(i,j)=0.
+ endif
+c i32su=22 - boundary conditions absorbed
+ if(i32su.eq.22) then
+ do 100 j=1,ny
+ awac=aw(1,j)/ac(0,j)
+ ac(1,j)=ac(1,j)-awac*ae(0,j)
+ aw(1,j)=0.
+ f(1,j)=f(1,j)-awac*f(0,j)
+ ac(0,j)=0.
+ ae(0,j)=0.
+ f(0,j)=0
+ awac=aw(nx1,j)/ac(nx1,j)
+ ac(nx,j)=ac(nx,j)-awac*ae(nx1,j)
+ ae(nx,j)=0.
+ f(nx,j)=f(nx,j)-awac*f(nx1,j)
+ ac(nx1,j)=0.
+ aw(nx1,j)=0.
+ 100 f(nx1,j)=0.
+c
+ do 110 i=1,nx
+ asac=as(i,1)/ac(i,0)
+ ac(i,1)=ac(i,1)-asac*an(i,0)
+ as(i,1)=0.
+ f(i,1)=f(i,1)-asac*f(i,0)
+ ac(i,0)=0.
+ an(i,0)=0.
+ f(i,0)=0.
+ anac=an(i,ny)/ac(i,ny1)
+ ac(i,ny)=ac(i,ny)-anac*as(i,ny1)
+ an(i,ny)=0.
+ f(i,ny)=f(i,ny)-anac*f(i,ny1)
+ ac(i,ny1)=0.
+ as(i,ny1)=0.
+ 110 f(i,ny1)=0.
+ endif
+ return
+ end