c
      program bvort 
c
c  Integrate the barotropic vorticity equation on a 
c  beta plane.  This is meant to be simple and easily modified, and  
c  not highly efficient. Spatial differencing is second
c  order; time stepping is by a leap-frog, and occasional trapezoidal
c  correction in order to supress time splitting.
c
c  The basic case is very much like Veronis' classic 1966 model study 
c  (Deep Sea Research, 1966, p 17-55) in that the domain is a square basin, 
c  and the circulation of a single layer is driven by a wind stress.  The
c  model can also be configured as a channel, or as a completely cyclic
c  domain, however, neither of these cases has been checked carefully 
c  as of August 94. 
c 
c  Output from the model goes primarily to disk files that are later read in 
c  and plotted by Matlab programs (btime.m, blook.m). A very small amount
c  of data goes to the terminal during the integration. 
c
c  Written by Jim Price beginning in March 1994. Last modified in March 99.
c
c  NOTICE: This model code is only partially tested and debugged and very 
c  likely has errors embedded within it.  You are responsible for any and all 
c  results you may get.   
c
c  For compilation on an HP C180 (note use of double precision) 
c
c  f77 +O2 +DA2.0N +DS2.0A +autodblpad bvort.f -o bvort.x     
c
c  Rows and columns and the x and y directions are defined as follows:
c
c      (1,ny) ....  (nx,ny)
c        .             .
c        .             .
c        . . . . . . . .
c        .             .
c        .             .
c      (1,1)  ....  (nx,1)
c
c   
c  The variables stored in arrays are as follows:
c
c  s is the mass transport streamfunction, the thing you are after!,
c  sold and snew are the old and new time levels of s,
c  st is the time rate of change of s ,
c  u and v are the east and north velocty components, m/sec
c  del2s is the Laplacian of s (the vorticity), del2st is its time rate change,
c  kpa, kma etc. are defined below,
c  taux and tauy are the east and north wind stress/density components,
c  x and y are the east and north coordinates, m
c  bc, del2p, etc are used to compute the surface pressure (defined below),
c  bv, curlt etc. are used to hold the terms of the vorticity equation,
c  sd24 is used to hold the diffusion term (not used at present).
c
c  Units are dimensional, MKS.
c 
      parameter (nx=51, ny=51)
c 
      dimension s(nx,ny), sold(nx,ny), snew(nx,ny), st(nx,ny)
      dimension u(nx,ny), v(nx,ny)      
      dimension del2s(nx,ny), del2st(nx,ny)
      dimension kpa(nx), kma(nx), jma(ny), jpa(ny),
     1  kpd(ny), kmd(ny), jpd(nx), jmd(nx) 
      dimension taux(nx,ny), tauy(nx,ny) 
      dimension x(nx), y(ny), f(ny)
      dimension bc(nx,ny), del2p(nx,ny),  rlp(nx,ny)
      dimension bv(nx,ny), curlt(nx,ny), vdecay(nx,ny), rv(nx,ny),
     1 rjsv(nx,ny), vort(nx,ny), spd(nx,ny)
c
      integer  cyclic     
c
c  These files are used to save results that are later read in by Matlab
c  plotting programs. The names have ceased to have any meaning, and could be
c  changed here and in the Matlab programs.
c      
      open(unit=1,file='basin1.dat',status='unknown')
      open(unit=2,file='basin2.dat',status='unknown')
      open(unit=3,file='basin3.dat',status='unknown')
      open(unit=4,file='basin4.dat',status='unknown')
      open(unit=14,file='basin5.dat',status='unknown')
      open(unit=16,file='basin6.dat',status='unknown')
      open(unit=11,file='what.dat',status='unknown')
      open(unit=12,file='looktim.dat',status='unknown')
      open(unit=10,file='basin10.dat',status='unknown')
c
      ncx = nx/2 + 1
      nxm = nx - 1
      ncy = ny/2 + 1
      nym = ny - 1
      if(nym.eq.0) nym = 1 
c
c  To specify the model run there are a number of parameters than have to
c  be input (or defaulted). The default case is a basin with nominal wind
c  forcing and linear dissipation.
c
      write (6,1900)
 1900 format 
     1 (1x,/,'  Are you a novice user of this program? (1=yes, def=0)')
      nov = 0
      read (5,*) nov
c
      if(nov.eq.1) then 
      write (6,1920)
 1920 format (1x,//, 
     1 1x,'    This model integrates a barotropic vorticity ',/,
     1 1x,' equation over a square domain. The default case is a',/,
     4 1x,' wind-driven basin much like the classic Veronis (1966,',/,
     5 1x,' DSR, pp 17) study (and which is the best single ',/,
     6 1x,' reference for the model dynamics). Other model ',/,
     6 1x,' configurations are also possible, including an',/,
     6 1x,' east-west channel, or a completely symmetric domain. In',/,
     7 1x,' the latter case, the streamfunction field can be ',/,
     8 1x,' initializd with a blob.',/)
      write (6,1921)
 1921 format (     
     9 1x,'   There is a very small list of output to the terminal.',/,
     1 1x,' Most of the data goes to disk files for later plotting',/,
     2 1x,' by Matlab programs (see the listing for details).',///,
     2 1x,'   The program will now ask for data that you can default',/,
     3 1x,' to values in parentheses by entering commas.',/)
c           
      write (6,1901) 
 1901 format (1x,/,'  RUNTIM defines the number of days to run,',//,
     11x,' IWRTD is the interval (days) between writing output data ',/,
     21x,' to disk files for later plotting',/)
      end if                        
c
c  runtim is the number of days to run, wrtt is the time interval between
c  writing to the screen and wrtd is the interval for writing to the disk
c  files.
c
      runtim = 100.
      wrtt = 0.5
      wrtd = 10.
c      
      write (6,777)  
  777 format (1x,/,'  Enter RUNTIM (def=100.),  IWRTD (def=10.)')
      read (5,*) runtim,  wrtd
c
c  The boundary conditions are specified via the following flags:
c
c  noslip = 0 for free slip BCs on the sidewalls of a basin (the default)
c     "   = 1 for no slip BCs on the sidewalls of a basin (note: this
c              option has not been fully implemented as of Aug 94)
c  cyclic = 0 gives a fully enclosed domain (a square basin)
c     "   = 1 for cyclic BCs on east and west sides, and slip or noslip on the 
c             north and south sides according to the flags above
c             (this makes an east-west channel)
c  cyclic = 2 for cyclic BCs all the way around (probably makes sense only if
c             beta effect is zero)
c  Note: only the basin case (cyclic = 0) has been fully tested.
c     
c      if(nov.eq.1) then
c      write (6,1902)
c 1902 format (1x,//,
c     c '  Boundary conditions are specified by 2 flags:',//,
c     1 1x,' NOSLIP = 0 gives free slip boundary conditions on walls',/,
c     2 1x,'   "    = 1 gives no slip boundary conditions on walls,',//,
c     3 1x,' CYCLIC = 0 gives a basin (walls all around),',/,
c     4 1x,'   "    = 1 gives an east-west channel,',/,
c     5 1x,'   "    = 2 gives a completely symmetric (open) domain',/)
c      end if
c            
      noslip = 0
      cyclic = 0 
c
c      write (6,9922) 
c 9922 format
c     1 (1x,' Enter bc flags: NOSLIP (def=0), CYCLIC (def=0)')
c      read (5,*) noslip, cyclic
c
c  Set up some arrays used to specify indices in difference equations.
c  kpa, kma etc. are used in the advection terms; kpd, kmd are used in the
c  diffusion terms.
c
c  These are set up differently for solid or cyclic boundaries.
c
      do 81 j=1,nx
      jpa(j) = j + 1
      jma(j) = j - 1 
      jpd(j) = j + 1
      jmd(j) = j - 1
   81 continue
      jma(1) = 1
      jpa(nx) = nx  
      jmd(1) = 2
      jpd(nx) = nx -1 
c
c  If this is a channel or completely cyclic domain then
c      
      if(cyclic.eq.1.or.cyclic.eq.2) then
      jma(1) = nx
      jpa(nx) = 1    
      jmd(1) = nx
      jpd(nx) = 1
      end if
c 
      do 80 k=1,ny
      kpa(k) = k + 1
      kma(k) = k - 1 
      kpd(k) = k + 1
      kmd(k) = k - 1
   80 continue
      kpa(ny) = ny  
      kma(1) = 1 
      kpd(ny) = ny - 1
      kmd(1) = 2
c
c  If this is a cyclic domain then 
c      
      if(cyclic.eq.2) then
      kpa(ny) = 1 
      kma(1) = ny 
      kpd(ny) = 1
      kmd(1) = ny
      end if
c 
c  Define the first and last points over which the interior calculation
c  will be done. 
c
      jf = 2
      jl = nx - 1
      if(cyclic.eq.1.or.cyclic.eq.2) then
      jf = 1
      jl = nx
      end if
c
      kf = 2
      kl = ny - 1
      if(cyclic.eq.2) then
      kf = 1
      kl = ny
      end if
c            
c  htot is the total water depth, and tau is the wind stress amplitude.
c  rnonl can be set to zero to remove nonlinear terms (be careful!)
c 
      if(nov.eq.1) then
      write (6,1903) 
 1903 format (1x,//,1x,' HTOT is the water column depth (m),',//,
     1 1x,' TAU is the wind stress amplitude (Pa),',//,
     2 1x,' RNONL multiplies the nonlinear term in the vort. eqn.',//)
      end if
c                
      htot = 500.
      tau = 0.1 
      rnonl = 1.
c     
      write (6,436) 
  436 format (1x,
     1 ' Enter HTOT (def=500.), TAU (def=0.1), RNONL (def=1.0)')
      read (5,*) htot, tau, rnonl
c
c  Make tau into a friction velocity squared so that density does not appear.
c                 
      r0 = 1025.
      tau = tau/r0   !   divide tau by nominal seawater density   
c
      g = 9.8
c 
c  Set the horizontal and temporal resolution.
c     
      if(nov.eq.1) then
      write (6,1904) 
 1904 format 
     1 (1x,//,1x,' DX is the horizontal grid resolution (km),',//,
     2 1x,' DT is the time step (sec)',//)
      end if
c            
      dx = 20. 
      dy = 20.
      dt = 2.e4 
c
      write (6,778) 
  778 format (1x,' Enter DX (def=20.), DT (def=2.e4.)') 
      read (5,*) dx, dt
c
      dx = dx*1000.
      dy = dx      
      sdx = 1./(2.*dx)
      sdy = 1./(2.*dy)
c
      
c
c  Set the horizontal diffusivity and decay time scale. The latter is used 
c  to calcualte a linear drag coefficient, as in Stommel 1948 and Veronis 1966.
c  To set this linear decay process to zero, set decayt < 0.
c     
      if(nov.eq.1) then
      write (6,1906) 
 1906 format 
     1 (1x,//,1x,' DIFFUS is the diffusion coefficient (m*m/s),',//,
     2 1x,' DECAYT is the decay time in a linear drag form (days)',//)
      end if
c            
      diff = 0. 
      decayt = 20.
      difmax = 0.25*(dx*dy)/dt
      write (6,442) 
  442 format (1x,' Enter DECAYT (def=20. 1/days) ')
      read (5,*) decayt       
c      
      decay = 0.
      if(decayt.gt.0.1) decay = 1./(decayt*8.64e4)
c      
      time = 0.
c
      pi = 4.*atan(1.)
      tpi = 2.*pi
      di = tpi/float(nx - 1)
      dj = tpi/float(ny - 1)
c
      rlat = 30.
      ibeta = 1 
c       
c  Set the latitude and beta (0, 1, or -1).
c      
      if(nov.eq.1) then
      write (6,1907) 
 1907 format (1x,//,1x,' RLAT is the latitude (deg),',//,
     1 1x,' IBETA multiplies beta (=0 to give beta=0)',//)
      end if
c            
      write (6,4467) 
 4467 format (1x,' Enter RLAT (def=30.), IBETA (def=1) ')
      read (5,*) rlat, ibeta
c
      ieq = 0
      if(abs(rlat).lt.0.01) ieq = 1
      f0 = 2.*7.292e-5*sin(rlat*tpi/360.)
      beta = float(ibeta)*2.*7.292e-5*cos(rlat*tpi/360.)/6370.e3
c 
c  Compute the x and y coordinates (km). 
c     
      do 9 j=1,nx
      x(j) = float(j-ncx)*dx/1000. 
    9 continue      
      do 10 k=1,ny
      y(k) = float(k-ncy)*dy/1000.
      f(k) = f0 + y(k)*1000.*beta
   10 continue
c 
c  Set the wind stress fields here. Use sin(y) to have downward pumping
c  over the entire basin, with a maximum stress on the north and south
c  boundaries (as in Stommel, 1948). Use cos(y) to have a max wind stress 
c  at y = 0.  To add a 'doldrums' to the sin(y) form, set dolamp to about 0.5. 
c 
      dolamp = 0.0 
      doltau = dolamp*tau
      ndol = ny - int(0.8*ny)   
      do 8010 j=1,nx
      do 8010 k=1,ny
      taux(j,k) = tau*sin(y(k)*3.1415/(2.*abs(y(1))))
      taux(j,k) = taux(j,k) + 
     c      doltau*exp( -(abs((y(ndol)-y(k)))/(100.))**2 )
      tauy(j,k) = 0. 
c
c  try inserting regions of zero stress curl by setting squez = 2, say
c
      squez = 1.0
      ysq = squez*y(k)*3.1415/(2.*abs(y(1)))
      taux(j,k) = tau*sin(ysq)
      if(ysq.gt.(3.14159/2.)) taux(j,k) = tau
      if(ysq.lt.(-3.14159/2.)) taux(j,k) = -tau
      if(j.eq.ncx) write (6,9932) y(k), ysq, taux(j,k)
 9932 format (1x,' y, ysq, taux', 5e12.4)
c    
 8010 continue
c
c  Write the wind stress to a file.
c
      do 8012 k=1,ny
      write (16,8013) y(k), taux(ncx,k), tauy(ncx,k)
 8012 continue
 8013 format (10e15.5)
c
c
c  If this is a completely cyclic domain then initialize s (it may 
c  not make sense to have tau set nonzero).
c
c      if(cyclic.eq.2) then
c      
      if(nov.eq.1) then
      write (6,1908) 
 1908 format 
     1 (1x,//,' SAMP is the amplitude of an initial s blob (m*m/s),',//,
     2 1x,' SSIZE is the horizontal size of the blob (km)',//)
      end if
c             
      samp = 0.
      ssize = 400.
      write (6,3400) 
 3400 format 
     c  (1x,' Enter SAMP (def= 0. (try 2.e7)), SSIZE (def = 400.)')
      read (5,*) samp, ssize
c
      do 3401 j=1,nx
      do 3401 k=1,ny
      rs = (x(j))**2 + (y(k))**2 
      s(j,k) = samp*exp(-rs/ssize**2)
 3401 continue 
c      end if                       
c
c Initialize the old s fields.
c
      do 16 j=1,nx
      do 16 k=1,ny
      sold(j,k) = s(j,k)
   16 continue
c 
c  Evaluate the important non-d parameters; sno is the streamfunction
c  amplitude (dimensional), ekno is the Ekman number, rno is the Rossby
c  number. This scaling holds in the interior, and hence will lead to
c  a huge underestimate of the Rossby and Ekman numbers in the western 
c  boundary layer.
c
      rl = float(nx-1)*dx
      ekno = decay/f0
      blth = 3.1415*(decay/beta)/1000.
      rno = tau/(htot*(beta**2)*(rl**3))
      sno = tau/(htot*beta)
      if(cyclic.eq.2) sno = samp
      write (6,2244)  blth, ekno, rno
 2244 format 
     1 (1x,///,'  The blthick (km), Ekman and Rossby nos are:',
     2 /,6x,3f12.4 //)
c       
c 
c  Write some data defining this run to file what.dat for use by later analysis.
c
      nnn = 1
      xnnx = 0.
      write (11,1110) nx, ny, nnn, dt, dx, dy, x(1), y(1), htot,
     c  f0, beta, tau, decay, sno, ekno, rno 
 1110 format (3i8, 20e15.5)
c
c  ncycle is the number of time steps taken.
c
      ncycle = 0
c
c  Begin time stepping here.         
c
   90 continue  
c
      leap = 0
      ncycle = ncycle + 1
c
      time = time + dt
      dtime = time/(24.*3600.)
c
c  Compute the average kinetic energy and enstrophy.
c     
      ske = 0.                                   
      rke = 0.
      se = 0.
      do 2000 j=jf,jl
      do 2000 k=kf,kl
      ske = ske + htot*(u(j,k)**2 + v(j,k)**2)/2.
      se = se + del2s(j,k)**2
      rke = rke + 1.
 2000 continue      
      ske = ske/rke          
      se = se/rke
c 
c  Check to see if it's time to write to the screen.
c
      if(timt.gt.wrtt.or.ncycle.eq.1) then
      if(ncycle.eq.1) write (6,1990)
 1990 format (1x, 
     1'  The data listed below are:',/,
     2 1x,' time (days), kinetic energy, enstrophy')      
      write (6,653)  dtime, ske, se  
  653 format (1x,f10.3,2e12.3)
      timt = timt - wrtt
      end if
      timt = timt + dt/8.64e4
c 
c  Write data to disk for later analysis and plotting.
c
c  Write out some data as a time series. 
c
      if(mod(ncycle,5).eq.1) then 
c
c  Evaluate the basin-averaged vorticity balance
c
      vorta = 0.
      curlta = 0.
      rsjva = 0.
      bva = 0.
      vdeca = 0.
      npa = 0.
c
      do 248 j=2,nxm
      do 248 k=2,nym
      npa = npa + 1
      vorta = vorta + vort(j,k)
      curlta = curlta + curlt(j,k)
      rjsva = rjsva + rjsv(j,k)
      bva = bva + bv(j,k)
      vdeca = vdeca + vdecay(j,k)
  248 continue
c
      do 249 k=2,nym
      bva = bva + 0.5*(bv(2,k) + bv(nxm,k))
      vdeca = vdeca + 0.5*(vdecay(2,k) + vdecay(nxm,k))
  249 continue
c
      rnpa = float(npa)
      rnpap = rnpa + float(nym-1)
      vorta = vorta/rnpa
      bva = bva/rnpap
      vdeca = vdeca/rnpap
      curlta = curlta/rnpa
      rjsva = rsjva/rnpa
c   
c  A time series of many variables 
c 
      nbx = 3
      ndl = ndol + 3
c          
      write (10,2234) dtime, ske, se, vort(ncx,ncy), bv(ncx,ncy),
     1  curlt(ncx,ncy),vdecay(ncx,ncy),rjsv(ncx,ncy),
     2  vort(nbx,ncy), bv(nbx,ncy),
     3  curlt(nbx,ncy),vdecay(nbx,ncy),rjsv(nbx,ncy),
     4  vorta, bva, curlta, vdeca, rjsva,
     5  vort(ncx,ndl), bv(ncx,ndl),
     6  curlt(ncx,ndl),vdecay(ncx,ndl),rjsv(ncx,ndl) 
 2234 format (1x, 100e10.3)
c
c  The streamfunction profile across the central latitude
c
      write (14,2214) (s(j,ncy), j=1,nx)
 2214 format(120e12.4)
      end if
c 
c  Write to disk for contour plots of some fields. This data is used by a 
c  Matlab plotting program called basin.m
c     
      if(timd.gt.wrtd.or.ncycle.eq.1) then      
      m = 1 
c 
      do 700 j=jf,jl
      jp = jpa(j)
      jm = jma(j) 
      do 700 k=kf,kl
      kp = kpa(k)
      km = kma(k)
c      
      u(j,k) = -sdy*(s(j,kp) - s(j,km))/htot
      v(j,k) = sdx*(s(jp,k) - s(jm,k))/htot
      sxx = (1./dx**2)*(s(jp,k) + s(jm,k) - 2.*s(j,k))
      syy = (1./dy**2)*(s(j,kp) + s(j,km) - 2.*s(j,k))
      del2p(j,k) = f(k)*(sxx + syy)
      rv(j,k) = sxx + syy
      spd(j,k) = sqrt(u(j,k)**2 + v(j,k)**2)
      bc(j,k) = 0.
c      
  700 continue             
c
c  Estimate the surface pressure that is consistent with this s field (if
c  it were steady). This is a long and complex thing of marginal use as a
c  diagnostic only (not needed for the integration).   
c
c  Evaluate the normal derivative on the east and west sides.
c
      do 800 k=1,ny
      dsdx1 = (s(2,k) - s(1,k))/dx
      dsdx2 = (s(nx,k) - s(nxm,k))/dy
      bc(1,k) = f(k)*dsdx1 + taux(1,k)/htot
      bc(nx,k) = f(k)*dsdx2 + taux(nx,k)/htot
  800 continue
c
c  South and north sides.
c  
      do 801 j=1,nx
      bc(j,1) = f(1)*(s(j,2) - s(j,1))/dx + tauy(j,1)/htot
      bc(j,ny) = f(ny)*(s(j,ny) - s(j,nym))/dy + tauy(j,ny)/htot
  801 continue         
c     
      ibc = 1
      idmean = 0
c      
      call sorbc
     1 (del2p,bc,ibc,cyclic,idmean,dx,dy,nx,ny,jma,jpa,kma,kpa,rlp)
c                         
      do 1206 k=1,ny
      write (1,1298) (rv(j,k),j=1,nx)      
      write (2,1298) (v(j,k),j=1,nx) 
      write (3,1298) (s(j,k),j=1,nx) 
      write (4,1298) (rlp(j,k),j=1,nx)
 1206 continue
 1298 format (200e12.4)
      timd = timd - wrtd 
c 
c  Write the present time (days) to file looktim.dat
c
      write (12,1212) dtime
 1212 format (f10.3)
      end if
c
      timd = timd + dt/8.64e4  
c
c  Come here to start the second pass of a leap-frog tapezoidal correction
c  (this avoids adding to time or ncycle).
c
  901 continue
c
c  Compute the velocity and the vorticity. 
c
      do 101 j=jf,jl
      jp = jpa(j)
      jm = jma(j)
c      
      do 101 k=kf,kl
      kp = kpa(k)
      km = kma(k)
c 
      u(j,k) = -sdy*(s(j,kp) - s(j,km))/htot
      v(j,k) = sdx*(s(jp,k) - s(jm,k))/htot
c
      sxx = s(jp,k) + s(jm,k) - 2.*s(j,k)
      syy = s(j,kp) + s(j,km) - 2.*s(j,k)
      del2s(j,k) = sxx/dx**2 + syy/dy**2
  101 continue
c
c  OK, now you are ready to evaluate the vorticity eqn. 
c
c  Compute the terms in the vorticity tendency equation.
c                                                      
      do 201 j=jf,jl
      jp = jpa(j)
      jm = jma(j)
c
      do 201 k=kf,kl
      kp = kpa(k)
      km = kma(k)
c
c  the beta term
c
      bv(j,k) = -beta*v(j,k)*htot
c
c  the curl of the wind stress
c      
      curlt(j,k) = sdx*(tauy(jp,k) - tauy(jm,k)) - 
     1   sdy*(taux(j,kp) - taux(j,km))  
c
c  the linear decay form of dissipation as if by bottom friction
c     
      vdecay(j,k) = -decay*del2s(j,k)
c
c  the diffusion form of dissipation
c
c      vdiff(j,k) = 
c     1  (diff/dx**2)*(del2s(jmd(j),k) + del2s(jpd(j),k) - 2.*del2s(j,k))
c     2+ (diff/dy**2)*(del2s(j,kmd(k)) + del2s(j,kpd(k)) - 2.*del2s(j,k))      
c
c  the Jacobian, or advection term, written in flux form
c      
      rjsv(j,k) = 
     1 - ( sdx*(u(jp,k)*del2s(jp,k) - u(jm,k)*del2s(jm,k)) +
     2 sdy*(v(j,kp)*del2s(j,kp) - v(j,km)*del2s(j,km)) )
c
c  sum the terms
c
      vort(j,k) = 
     1    curlt(j,k) + vdecay(j,k) 
     2       + bv(j,k) + rnonl*rjsv(j,k)     
c                        + vdiff(j,k)      ! diffusion term c'd out c
c
c  add to the tendency (this is needed for the trapezoidal correction)
c     
      del2st(j,k) = del2st(j,k) + vort(j,k)
c
  201 continue                
c
c  Call the elliptic solver sorbc to calculate st, the time rate change of 
c  the streamfunction.
c 
c  Set the matrix bc to zero for this since s is specififed as part of the bc.
c
      do 930 j=1,nx
      do 930 k=1,ny
      bc(j,k) = 0.
  930 continue
c 
c  ibc sets the kind of boundary condition applied on solid boundaries; 
c  ibc = 0 sets s to zero (free slip boundary conditions)
c  ibc = 1 sets both s and the normal derivative of s to zero (for no slip 
c  boundary conditions). the flag cyclic tells the subroutine which boundaries
c  are solid.
c    
      ibc = noslip
      idmean = 0  
      call sorbc 
     1 (del2st,bc,ibc,cyclic,idmean,dx,dy,nx,ny,jma,jpa,kma,kpa,st)
c
c  Step ahead, noting whether this is a straight leap-frog (leap = 0), a 
c  leap-frog to be followed by a trapezoidal correction (leap = 1), or
c  the trapezoidal correction itself (leap = 2). A trapezoidal 
c  correction is done for ntrap succesive steps every nncyc steps in order 
c  to supress time splitting (try ntrap < 0 to see time splitting).
c
      nncyc = 15
      ntrap = 3
c
      if(mod(ncycle,nncyc).lt.ntrap) leap = leap + 1 
c     
      tstep = 2.*dt
      if(leap.eq.2) tstep = 0.5*dt      
c  
      do 300 j=1,nx
      do 300 k=1,ny
      snew(j,k) = sold(j,k) + tstep*st(j,k)
  300 continue
c 
      if(ncycle.eq.1) go to 310 
c
c  Shuffle time levels around, as required for the kind of time step.
c 
c  The following is for a straight leap-frog, or the trapezoidal corrector.
c    
      if(leap.eq.0) then
      do 3300 j=1,nx 
      do 3300 k=1,ny
      sold(j,k) = s(j,k)
      s(j,k) = snew(j,k) 
      del2st(j,k) = 0.
 3300 continue 
      end if
c
c  This is for a leap-frog that will be followed by a trapezoidal correction. 
c
      if(leap.eq.1) then
      do 3301 j=1,nx 
      do 3301 k=1,ny
      sold(j,k) = s(j,k)
      s(j,k) = snew(j,k) 
 3301 continue
c
c  The first stage of a leap-trap time step is done; go back up and re-do
c  the calculations for the trapezoidal correction.  
c
      go to 901
      end if
c
      if(leap.eq.2) then
      do 3500 j=1,nx 
      do 3500 k=1,ny
      s(j,k) = snew(j,k) 
      del2st(j,k) = 0.
 3500 continue 
      end if 
c
c
c  The time step is finished. Check the time, and then loop back 
c  up to start another time step. 
c
      if(dtime.gt.runtim) go to 9999
c 
      go to 90
c
  310 continue
c
c  Come here once at the start of the integration to do a forward time step
c  to get started.
c
      do 400 j=1,nx
      do 400 k=1,ny
      sold(j,k) = s(j,k)
      s(j,k) = snew(j,k)
  400 continue
c
      go to 90
c
 9999 continue
c
      stop 
      end
c      
      subroutine 
     1 sorbc(f,bc,ibc,icyclic,idmean,dx,dy,nx,ny,jm,jp,km,kp,u)
c
c  This subroutine solves the Poisson equation, DelSq(u) = f, by simultaneous 
c  overrelaxation. Taken from Numerical Recipes, modified heavily, and 
c  documented by Jim Price. 
c
c  f is input, and is the source term, 
c  bc is input and is the normal derivative used in evaluating the
c  boundary values (input as a matrix for convenience though only the
c  boundaries are used),
c  ibc = 0 for u = specified bcs, in which case bc is not used
c      = 1 for du/dy = bc(y=0,x), etc., bcs.
c  icyclic = 0 for solid boundaries,
c          = 1 for a channel (cyclic in x direction only),
c          = 2 for a fully cyclic domain.
c  idmean = 1 to demean the field f. This makes sense if the bcs are
c  specified by normal derivatives all the way around.
c  dx and dy are input and are the grid intervals.
c  ny and nx are the array dimensions. Note that the Poisson equation is
c   solved over the interior points only. The boundaries are dealt with 
c   separately. 
c  The integer arrays jm, jp, km, kp are input to specify indices needed to
c  evaluate the Laplacian (needed to specify bcs; i.e, symmetric or not). 
c  u is a first guess at the answer on input, and is returned as the 
c   answer on output. If boundary conditions are u specified on the boundaries,
c   then u has those bcs upon input. 

c
c      
      dimension f(nx,ny),bc(nx,ny),u(nx,ny),jm(nx),jp(nx),
     1  km(ny),kp(ny)
      real omega
c
c  Compute rjac, an overrelaxation parameter used to aid convergence.  
c 
      rn = sqrt(float(nx**2) + float(ny**2))
      rjac = cos(3.1415/rn)
c 
c  These maxits and epsilon values are rather arbitrary.
c      
      maxits = 1000
      eps = 1.e-5
      anormf = 0.
c
      a = 1./(dx**2)
      b = 1./(dy**2)      
      c = -2.*(dx**2 + dy**2)/((dx**2)*(dy**2)) 
c   
      omega = 1.0 
c
      jf = 2
      jl = nx - 1
      if(icyclic.eq.1.or.icyclic.eq.2) then
      jf = 1
      jl = nx  
      end if            
c      
      kfm = 1
      kl = ny - 1      
      if(icyclic.eq.2) then
      kfm = 0
      kl = ny   
      end if 
      kf = kfm + 1
c      
      do 12 j=jf,jl
      do 12 k=kf,kl         
      anormf = anormf + abs(f(j,k))
   12 continue
c  
      do 16 n=1,maxits
      anorm = 0.
      jsw = 1      
      do 15 ipass=1,2
      lsw = jsw
c      
      do 14 j=jf,jl
      do 13 k=lsw+kfm,kl,2
c     
      resid = b*(u(jp(j),k) + u(jm(j),k)) + a*(u(j,kp(k)) + u(j,km(k)))
     1 +  c*u(j,k) - f(j,k)
      anorm = anorm + abs(resid)
      u(j,k) = u(j,k) - omega*resid/c
c      
   13 continue
      lsw = 3 - lsw
   14 continue
      jsw = 3 - jsw
c      
      if(n.eq.1.and.ipass.eq.1) then
      omega = 1.0/(1.0 - 0.5*rjac**2)
      anorm1 = anorm
      else
      omega = 1.0/(1.0 - 0.25*rjac**2*omega)
      endif
c
c  Apply normal derivative bcs, if ibc = 1. Otherwise, assume
c  that u has already been set along the boundaries.
c
      if(ibc.eq.1) then 
c
c  March along the north and south sides, noting whether the bc looks forward
c  or backward to the boundary. do this only if not a symmetric domain.
c     
      if(icyclic.eq.2) go to 299 
      do 20 j=1,nx
      u(j,1) = u(j,2) - bc(j,1)*dy
      u(j,ny) = u(j,ny-1) + bc(j,ny)*dy 
   20 continue   
  299 continue
c 
c  March along the east and west sides if this is not a channel.
c           
      if(icyclic.eq.1.or.icyclic.eq.2) go to 219
      do 21 k=2,ny-1
      u(1,k) = u(2,k) - bc(1,k)*dx
      u(nx,k) = u(nx-1,k) + bc(nx,k)*dx
   21 continue   
  219 continue
c
c
      end if      
c  
c  End of the boundary conditions.
c      
   15 continue
c 
c  Check for convergence.
c    
      epsnorm = eps*anormf
      if(anorm.lt.epsnorm) go to 99 
c   
   16 continue 
c   
      write (6,1) n, rjac, omega, anorm1, anorm, epsnorm  
    1 format (1x,///, '   maxits passed in sorbc ', i6, 5e9.3)
c
   99 continue
c
c  Demean u if the bcs are zero normal derivative all the way around, or if
c  the domain is fully symmetric. 
c 
      if(idmean.eq.1) then
      do 50 j=1,nx
      do 50 k=1,ny
      um = um + u(j,k)
   50 continue
      um = um/float(nx*ny)
      do 51 j=1,nx
      do 51 k=1,ny
      u(j,k) = u(j,k) - um
   51 continue 
      end if             
c 
      return
      end
      
      
            
                     
      
                        
