c
       program pwpmain
c
c
c  This main program is used to drive the pwp subroutine with
c  a daily cycle of heating, or, an arbitrary (observed) time
c  series of surface flux data.
c
c  The program assumes the following logical units:
c   5 is the terminal for input,
c   6 is the terminal for output,
c   7 may be opened for data storage (optional),
c   8 may be opened to read air/sea flux data (optional),
c   9 may be opened to read the initial t, s profile (optional).
c
c
c  Written by Jim Price, april 27, 1989. Please direct any
c  comments or questions to Jim Price, WHOI, Woods Hole, MA
c  02543, USA, tel. 508-289-2526.
c
c  Version 2:  changed the gradient Ri relaxation method.
c  Version 3:  clarified the bulk Ri relaxation.
c  Version 4:  fixed an error that disabled background diffusion.
c
c  Last editted on 20 Jan, 1999 by JFP.
c
c
      character*16 ifile
c
c  The arrays below store the values of:
c  east and north current (u, v),
c  temperature and salinity (t, s),
c  density (d, sigma units), and
c  depth of the grid points, z.
c
c  All units are mks, except density, d, which is in sigma
c  units.
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cpw, rg, rb, em1, em2, em3
      dimension z(500)
c
c  The arrays below are used to store the initial z,t,s.
c
      dimension zo(500), to(500), so(500), do(500)
c
c  The arrays below store times series of surface flux data.
c  Depending upon the time step and length of the record you
c  could easily run out of these.
c
      dimension daya(2500), qia(2500), qla(2500), txa(2500),
     x tya(2500), empa(2500)
c
c  nzmax should match the size of the initial profile arrays
c  dimensioned above, and nmet should match the flux arrays.
c
      nzmax = 500
      nmet = 2500
c
      write (6,800)
  800 format (
     x 1x, 'This program provides a means to run the pwp',/,
     x 1x, 'upper ocean model. To run this model you must',/,
     x 1x, 'prescribe the air/sea fluxes, the initial',/,
     x 1x, 'temperature and salinity profile, and several',/,
     x 1x, 'parameters defining the site and the model.',/,
     x 1x, 'The site and model parameters are listed below,',/,
     x 1x, 'where default values and units given in parentheses.',/,
     x 1x, 'To choose the default enter a comma.',/)
      write (6,802)
  802 format (
     x 1x, 'beta1, longwave extinction coefficient (0.6 m)',/,
     x 1x, 'beta2, shortwave extinction coefficient (20.0 m)',/,
     x 1x, 'rlat,  latitude (31.0)',/,
     x 1x, 'udrag, decay time scale of current (9999. days)',/,
     x 1x,/,
     x 1x, 'dt,    time step (1000. sec)',/,
     x 1x, 'days,  the number of days to run (1.0 day)',/,
     x 1x, 'dz,    grid interval (1.0 m)',/,
     x 1x,/,
     x 1x, 'rb,    critical bulk richardson number (0.65)',/,
     x 1x, 'rg,    critical gradient richardson number (0.25)',/,
     x 1x, 'em1,   coefficient of buoyancy production (0.)',/,
     x 1x, 'em2,   coefficient of shear production (0.)',/,
     x 1x, 'em3,   coefficient of ustar**3 (0.)',/)
c
c
c  Initialize rlat, the latitude.
c
      rlat = 31.
c
c  Initialize the solar radiation absorption;
c  beta1 is the  non-penetrating part of the insolation,
c  beta2 is the penetrating (shortwave) part.
c  values below are appropriate for fairly clear waters.
c
      beta1 = 0.60
      beta2 = 20.
c
c  Initialize udrag, the e-folding time (days) of current
c  due to unresolved processes.
c
      udrag = 9999.
c
c
      write (6,888)
  888 format (1x,'Enter beta1, beta2, rlat, udrag.')
      read (5,*)  beta1, beta2, rlat, udrag
c
c
c
c  dt and dz are the time step (sec) and the vertical grid
c  interval (m), and  days is the number of days to run
c  the integration.
c
      dt = 1.0e3
      dz = 1.0
      days = 1.
c
      write (6,706)
  706 format (1x,/,1x,'Enter dt, days, dz.')
      read (5,*) dt, days, dz
c
      dtd = dt/8.64e4
      f = 2.*7.292e-5*sin(rlat*3.141/180.)
c
c
c  Model constants are rb, the critical bulk richardson number,
c  rg, the critical gradient richardson number, and emn, the
c  coefficients that multiply the energy source terms in
c  the turbulent energy budget. Values set below are the PWP
c  model values.
c
      rb = 0.65
      rg = 0.25
      em1 = 0.
      em2 = 0.
      em3 = 0.
c
      write (6,772)
  772 format (1x,/,1x,'Enter rb, rg, em1, em2, em3.')
      read (5,*) rb,rg,em1,em2,em3
c
c
c
c  Set up to input air/sea flux data.
c
      write (6,457)
  457 format (1x,//,
     x 1x,'You can prescribe the air/sea flux data by:',/,
     x 1x,'specifying the parameters of an idealized diurnal',/,
     x 1x,'cycle from terminal input (enter 1 (default)), or, ',/,
     x 1x,'read the air/sea flux data from a disk file (enter 2).')
c
      metu = 1
      read (5,*) metu
c
      if(metu.eq.1) then
c
      write (6,2790)
 2790 format (1x,/,1x,'In order to define the air-sea fluxes ',/,
     x 1x, 'for a diurnal cycle, the program will now ',/,
     x 1x, 'query for the values of the following variables, all ',/,
     x 1x, 'of which may be defaulted to the values in parens.',/,
     x 1x, '(which are from day 131 of the PWP paper):',/)
      write (6,801)
  801 format (
     x 1x, 'qimax,  noon amplitude of insolation (978. w/m**2)',/,
     x 1x, 'ql,     steady heat loss (-126. w/m**2)',/,
     x 1x, 'tx,     steady east wind stress (0.07 pa)',/,
     x 1x, 'emp,    evaporation minus precipitation (0.0 m/sec)',/,
     x 1x, 'pqfac,  duration of insolation (10.0 hours)',/)
c
c  Initialize the amplitude of solar insolation (qi), the
c  heat loss (ql), and the wind stress (tx, uses east only).
c
      qimax = 978.
      ql = -126.
      tx = 0.07
      emp = 0.
c
c  Initialize pqfac, the duration of daylight in hours.
c
      pqfac = 10.
c
c
      write (6,777)
  777 format (1x,'Enter qimax, ql, tx, emp, pqfac.')
      read (5,*) qimax,ql,tx,emp,pqfac
c
c  Convert pqfac to a non-d form.
c
      pqfac = pqfac/12.
      if(pqfac.lt.0.00001) then 
      pqfac = 0.00001
      end if

      end if
c
c  Come here if you intend to read a time series of flux data from
c  a disk file.
c
      if(metu.eq.2) then
c
      write (6,117)
  117 format (1x,/,1x,'Enter the name of the the air/sea flux file.')
      read (5,116) ifile
  116 format (a16)
      open (unit=8,file=ifile)
c
c
      do 233 j=1,nmet
      read (8,*,end=459) daya(j), qia(j), qla(j), txa(j), tya(j),
     x empa(j)
c
c
      if(daya(j).lt.-9.) go to 459
c
      nmeto = nmeto + 1
c
      if(nmeto.lt.25) then
      write (6,8838) nmeto, daya(j), qia(j), qla(j), txa(j), tya(j),
     x empa(j)
 8838 format (1x,'First 25 flux data:', i4, f7.2,2f7.0,2f7.2,e10.3)
      end if
c
c
  233 continue
  459 continue
c
c  Set nmet equal to actual number of observations
c
      nmet = nmeto
c
      write (6,8833)
 8833 format (1x,/,1x,'Enter the starting time (day).')
      read (5,*) day0
c
      end if
c
c  Finished with specifying air/sea flux data.
c
c
c
c  Initialize the z, t, s, d profiles.
c
c  Read in the data used to define the initial t,s profiles
c  from logical unit nunit (read in below). The data
c  is presumed to be free format, with each record being a
c  triple (z, t, s).  The first record should be the surface
c  value, i.e., 0., 20., 36. is a reasonable surface value,
c  and the last true value should be deep enough to avoid
c  entering into the caluclation (unless intentional).
c  The end of file is defined either by the end
c  of the data (if read from a disk file), or by a z value less
c  than -10.  These data are then linearly interpolated to give
c  profiles at dz resolution needed by the model.
c
      write (6,458)
  458 format (1x,//,
     x 1x,'The initial temperature and salinity profile can',/,
     x 1x,'be defined by:',/,
     x 1x,'data hardwired into the program (enter 1, default), or',/,
     x 1x,'enter z, t, s data from the terminal (enter 2), or,'/,
     x 1x,'read the data from a disk file (enter 3).')
c
      mzts = 1
      read (5,*) mzts
c
      if(mzts.eq.1) then
      nts = 4
      zo(1) = 0.
      zo(2) = 10.
      zo(3) = 11.
      zo(4) = 250.
      to(1) = 20.
      to(2) = 20.
      to(3) = 10.
      to(4) = 10.
      so(1) = 36.
      so(2) = 36.
      so(3) = 36.
      so(4) = 36.
      end if
      if(mzts.eq.1) go to 53
c
      if(mzts.eq.3) then
      write (6,3290)
 3290 format (1x,/,1x,'Enter the name of the z,t,s data file.')
      read (5,116) ifile
      open (unit=9,file=ifile)
      end if
c
c
      do 50 j=1,nzmax
      if(mzts.eq.2) then
      write (6,876)
  876 format (1x,'Enter a z,t,s (end = z < -10).')
      read (5,*) zo(j),to(j),so(j)
      end if
c
      if(mzts.eq.3) then
      read(9,*,end=53) zo(j),to(j),so(j)
      end if
c
      if(zo(j).lt.-9.) go to 53
      nts = nts + 1
c     if(mzts.eq.3) write (6,503) zo(j),to(j),so(j)
c  503 format (1x,'Initial z, t, s are:', 3f10.2)
   50 continue
   53 continue
c
c  Compute the size of the arrays actually used.
c
      nzo = int(zo(nts)/dz)
      nz = nzo
      if(nz.gt.nzmax) nz = nzmax
c
c  Interpolate the initial data to get a profile at dz resolution.
c
      do 52 j=1,nz
      z(j) = float(j-1)*dz
      call intx(zo,to,nzs,nts,z(j),t(j))
      call intx(zo,so,nzs,nts,z(j),s(j))
      d(j) = sgt(t(j),s(j),gg)
c      write (6,54) j,z(j),t(j),s(j),d(j)
   54 format (1x,'Density prof.:',i4,2x,6f10.3)
   52 continue
c
c  Initialization of z, t, s, d is finished.
c
c
c
c  Section below allows for application of a simple "background"
c  diffusion to be applied to the profiles. this is not part of
c  the pwp model per se, but is included here for the hell of it.
c
      rkz = 0.
c
      rkzmax = (dz**2)/(2.*dt)
      write (6,3355) rkzmax
 3355 format (1x,//,1x
     x 'If you want to have a background diffusion, then',
     x /,1x,'enter Kz (m**2/sec) (default = 0; max =',e10.3,')')
      read (5,*) rkz
      dstab = dt*rkz/dz**2
      if(dstab.gt.0.5) then
      write (6,8433) dstab
 8433 format (1x,/,1x,'Warning, this value of kz will be unstable:',
     x /,1x,'dstab = ', e10.3)
      end if
c
c
      write (6,8899)
 8899 format (1x,/,1x,'Do you want a screen listing of data ?',/,
     x 1x,'(0 = no, n = every nth step (default = 2)')
      iwrt = 2
      read (5,*) iwrt
c
c  Section below stores some data onto a disk file for later
c  analysis or plotting.
c
      istor = 0
      write (6,3186)
 3186 format (1x,/,1x,'Do you want to store the data on disk ?',/,1x,
     x '(0 = no (default), 1 = yes)')
      read (5,*) istor
c
      if(istor.eq.1) then
      write (6,1188)
 1188 format (1x,/,1x,'Enter the name of the file to store data.')
      read (5,116) ifile
      open (unit=7,file=ifile)
c
      itfreq = 2
      izfreq = 5
c
      write (6,3187)
 3187 format (1x,/,1x,'Enter the decimation rate for time and depth.',
     x /,1x,'(default is 2 and 5)')
      read (5,*) itfreq,izfreq
      end if
c
c  At this point, we are ready to call the initialization
c  entry point in the pwp subroutine.
c
      call pwpint(beta1,beta2,rlat,udrag)
c
c
c  Time step the model for up to nnn steps.
c
      nnn = 5000
c
c  nnn is set to 5000 to avoid running forever
c  in case the limit timed > days is missed.
c
      do 40 m=1,nnn
c
c  Compute the solar insolation as a function of the time,
c  where timed is time since start in days.
c
c
      timed = float(m-1)*dtd
      if(timed.gt.days) go to 499
c
      if(metu.eq.1) then
      p2 = 3.141*2.
      tims = amod(timed,1.)
      tims = tims - 0.50
      qi = 0.
      if(cos(p2*tims).gt.0.) then
      qi = qimax*cos(tims*p2/pqfac)
      if(qi.lt.0.) qi = 0.
      end if
      emp = 0.
      end if
c
      if(metu.eq.2) then
c
      day = timed + day0
      call intx (daya,qia,nzs,nmet,day,qi)
      call intx (daya,qla,nzs,nmet,day,ql)
      call intx (daya,txa,nzs,nmet,day,tx)
      call intx (daya,tya,nzs,nmet,day,ty)
      call intx (daya,empa,nzs,nmet,day,emp)
c
      end if
c
c  nn is the number of time steps actually taken.
c
      nn = nn + 1
c
c  Time step the model by an increment of time, dt.
c
      call pwpgo(qi,ql,emp,tx,ty,dml,dtl)
c
c
c  Apply a "background" diffusion if rkz is non-zero.
c
      if(rkz.gt.0) then
c
      call diffus (rkz,nz,dz,dt,d)
      call diffus (rkz,nz,dz,dt,s)
      call diffus (rkz,nz,dz,dt,t)
      call diffus (rkz,nz,dz,dt,u)
      call diffus (rkz,nz,dz,dt,v)
c
      end if
c
c  Store the density profile if this is the first step.
c
      if(m.eq.1) then
      do 2278 j=1,nz
      do(j) = d(j)
 2278 continue
      end if
c
c
c  This is the place to compute diagnostics.
c
c  Find max/min values on the first day.
c
      if(m.eq.1) dmlmin = 100.
      if(m.eq.1) tmin = t(1)
      if(timed.lt.1.) then
      if(t(1).lt.tmin) tmin = t(1)
      if(t(1).gt.tmax) tmax = t(1)
      spd = sqrt(u(1)**2 + v(1)**2)
      if(spd.gt.spdmax) spdmax = spd
      if(dml.lt.dmlmin) dmlmin = dml
      end if
c
c
c  Write out a few things on every iwrtth time step.
c
      if(iwrt.lt.1) go to 1339
c
      if(m.eq.1) write (6,444)
  444 format (1x,/,1x,'model solution variables are:',/,1x,
     x '   m timed    qi     ql      tx   t(1)   s(1)   u(1) ',
     x '  v(1)  dml   dtl',/,1x)
c
      if(mod(m,iwrt).ne.0) go to 1339
      write (6,133) m,timed,qi,ql,tx,t(1),s(1),
     c u(1),v(1),dml,dtl
  133 format (1x,i4,f6.2,2f7.0,f7.2,4f7.2,2f6.0)
c
 1339 continue
c
c
c  Compute the net heat flux as a check on heat conservation.
c
      qnet = qnet + dt*(qi + ql)
c
c
c  Store data on disk, logical unit 7, if you told it to.
c
      if(istor.eq.1) then
      if(mod(m,itfreq).eq.0) then
      write (7,3188) timed,qi,ql,tx,t(1),s(1),u(1),v(1),
     x dml
 3188 format (1x,20f10.3)
      end if
      end if
c
   40 continue
  499 continue
c
c
      write (6,870) tmin,tmax,dmlmin,spdmax
  870 format (1x,/,1x,'tmin, tmax, dmlmin, spdmax are',4f8.2)
c
c
c  Compute heat and potential energy diagnostics.
c  dpe will be the change in potential energy over the
c  integration period, and heat is the change in heat
c  content. heat should nearly equal the time-integrated
c  surface heat flux, qnet, if heat has been conserved.
c
      dpe = 0.
      heat = 0.
c
      do 8376 j=1,nz
      call intx(zo,to,nzs,nts,z(j),ti)
      tanom = t(j) - ti
      heat = heat + tanom*dz
      if(j.eq.1) tanoms = tanom
c
      danom = d(j) - do(j)
      dpe = dpe - g*danom*z(j)*dz

c     write (6,4465) j,do(j),d(j),danom,dpe
 4465 format (1x,'do,d,danom,dpe',i4,3f10.3,e12.2)
 8376 continue
c
      qnet = qnet/(ro*cpw)
      write (6,3877) heat, qnet, dpe
 3877 format (1x,/,1x,'heat, qnet, dpe are', 3f9.2)
c
c  End of the diagnostics.
c
      end
c
c
      subroutine pwpint (beta1,beta2,rlat,udrag)
c
c
c  This subroutine is an implementation of the Price, Weller,
c  Pinkel upper ocean model described in JGR 91, C7 8411-8427
c  July 15, 1986 (PWP). This version was coded and documented by
c  Jim Price in April 1989.
c
c  Edited on 20 September 1993 by JFP to allow for a critical
c  gradient Richardson number other than 1/4, and to implement a
c  different and a priori better means of achieving convergence
c  of gradient ri mixing (see subroutine stir for details).
c  The major difference is that the revised scheme gives a more
c  smoothly varying mixed layer depth over a diurnal cycle.
c  Edited on 14 December 1998 by JFP to clarify the bulk Ri
c  relaxation.
c
c  This model also implements an energy budget form of an
c  entrainment parameterization that is very similar to that
c  described in Price, Mooers, Van Leer, JPO 8, 4, 582-599 (and
c  references therein). This part of the model should be
c  treated as developmental only, as there are several features
c  that are arbitrary to this model (i.e., the depth of the ml
c  during times of heating can be the grid interval, dz). To
c  use this parameterization set the bulk Richardson number to
c  zero, and set em1, or em2, or em3 to non-zero. The gradient
c  Richardson number can be zero or not.
c
c
c  Please direct questions and comments to Jim Price, WHOI,
c  Woods Hole, MA, 02543, MA, tel. 508-548-1400, x2526.
c
c  All units within the model are mks, except density, d,
c  which is in sigma units.
c
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cpw, rg, rb, em1, em2, em3
c
c
c  nz is the number of grid points in the vertical.
c  dz is the grid interval (meters).
c  beta1 and beta2 are the longwave and shortwave extinction
c   coefficients for solar insolation (meters).
c  rlat is the latitude (deg).
c  tr, sr are the reference values of temperature and
c   salinity used in the density equation (C, and ppt).
c  udrag is the e-folding time scale of current due to
c   unresolved processes (days)  (set to infinite if > 100).
c  rg is the critical gradient richardson number (= 1/4,
c   in the pwp model).
c  rb is the critical bulk richardson number (= 0.65,
c   in the pwp model).
c  em1, em2, em3 are coefficients that multiply energy
c   source terms in the turbulent kinetic energy budget:
c   buoyancy production, shear production, and ustar**3; all
c   are zero in the pwp model, but can be used here by setting
c   rb = 0, and then at least one of the emns to non-zero.
c  There are some peculiar features of any energy budget model
c  that arise when the ocean is heated, so be careful !
c
      save d2r, hcon, ucon, f, tr, sr, dr, alpha, beta, energy
c
c  Set a few constants that will not change during the run.
c
      d2r = 2.*3.14159/360.
      g = 9.8
      ro = 1.024e3
      cpw = 4183.3
      hcon = dz*ro*cpw
      ucon = 0.
      if(udrag.lt.100.) ucon = 1./(8.64e4*udrag)
      f = 2.*7.29e-5*sin(rlat*d2r)
c
c  Evaluate alpha and beta, the thermal and haline expansion
c  coefficients used in a linear equation of state.
c  dr is the reference density.
c
      tr = t(1)
      sr = s(1)
      dr = sgt(tr,sr,gg)
      alpha = sgt(tr+.5,sr,gg) - sgt(tr-.5,sr,gg)
      beta = sgt(tr,sr+.5,gg) - sgt(tr,sr-.5,gg)
c
c  Compute the absorption profile; absrb(j) is the fraction
c  of the solar insolation that will be absorbed within
c  the grid cell j.
c
      call absorb(beta1,beta2)
c
c  Finished with initialization.
c
c
      return
c
c
c  Come here to step ahead by an amount dt.
c
      entry pwpgo (qi,ql,emp,tx,ty,dml,dtl)
c
c  Input to the subroutine are the following:
c
c  qi and ql are the insolation and heat loss (qi > 0,
c  ql < 0 almost always)  (W/m**2).
c  emp is evaporation minus precipitation (m/sec)
c  (emp > if evaporation exceeds precipitation).
c  tx and ty are the east and north stress components (Pa).
c
c  Apply heat and fresh water fluxes to the top most grid cell.
c
      q1 = qi*absrb(1) + ql
      t(1) = t(1) + dt*q1/(dz*ro*cpw)
c
c  Absorb solar radiation at depth.
c
      do 70 j=2,nz
      t(j) = t(j) + qi*absrb(j)*dt/(dz*ro*cpw)
   70 continue
      s(1) = s(1) + s(1)*emp*dt/dz
c
c  Compute the density (sigma units), and relieve static
c  instability, if it occurs.
c
      do 71 j=1,nz
      d(j) = dr + (t(j) - tr)*alpha + (s(j) - sr)*beta
   71 continue
c
      call mldep(ds1)
      call si(ml,sipe)
      if(ml.gt.1) call mix5(ml)
      call mldep(ds2)
c
c  At this point the density proifile should be statically stable.
c
c  Time step the momentum equation.
c
c  Rotate the current throughout the water column through an
c  angle equal to inertial rotation for half a time step.
c
      ang = f*dt/2.
      sa = sin(ang)
      ca = cos(ang)
c
      do 32 j=1,nz
      call rot(u(j),v(j),sa,ca)
   32 continue
c
c  Apply the wind stress to the mixed layer as it now exists.
c
c  Find the ml depth.
c
      call mldep(dml)
      ml = int(dml/dz)
c
      du = (tx/(dml*ro))*dt
      dv = (ty/(dml*ro))*dt
      do 33 j=1,ml
      u(j) = u(j) + du
      v(j) = v(j) + dv
   33 continue
c
c  Apply drag to the current (this is a horrible parameterization of
c  inertial-internal wave dispersion).
c
      if(ucon.gt.1.e-10) then
      do 37 j = 1,nz
      u(j) = u(j)*(1. - dt*ucon)
      v(j) = v(j)*(1. - dt*ucon)
   37 continue
      end if
c
c  Rotate another half time step.
c
      do 34 j = 1,nz
      call rot(u(j),v(j),sa,ca)
   34 continue
c
c  Finished with the momentum equation for this time step.
c
c  Cause the mixed-layer to deepen.
c
c
      if(rb.le.0.00001) go to 61
c
c  Come here to do the bulk Richardson number instability
c  form of mixing (as in PWP).
c
      nzm = nz - 1
c
      rvc = rb
      do 80 j = ml,nzm
      delr = (d(j+1) - d(1))/ro                      
      ds2 = (u(j+1) - u(1))**2 + (v(j+1) - v(1))**2  
      ds2 = ds2 + 1.e-8
      h1 = float(j)*dz
      rv = g*delr*h1/ds2
      if(rv.gt.rvc) go to 81
c
      jp = j + 1
      call mix5(jp)
c
   80 continue
   81 continue
      go to 65
c
c
   61 continue
c
c
      if(em1.le.0..and.em2.le.0..and.em3.le.0.) go to 65
c
c  Come here to mix according to an energy balance closure;
c  this implementation follows Price, Mooers, Van Leer, JPO,
c  8, 582-599, July 1978. This is not part of the PWP model
c  per se, and has some rather unusual properties, so watch out !
c
c
      call mldep(dml)
      ml = dml/dz
      taumag = sqrt(tx**2 + ty**2)
      ustar = sqrt(taumag/ro)
      ustarc = taumag*ustar*dt
c
c  Compute the energy available to do entrainment.
c
      energy = energy + em3*ustarc + em1*sipe
c
      delkes = 0.
      penes = 0.
c
      nzm = nz - 1
      do 60 l=ml,nzm
c
c  Determine how much energy is required to entrain the next
c  level below the base of the mixed-layer.
c
      call pe(l+1,pene)
      if(energy.lt.pene) go to 65
      if(energy.gt.pene) then
c
c  Come here if sufficient energy is avaliable to entrain at
c  least one level into the mixed layer.
c
c  Compute the change in kinetic energy due to entrainment.
c
      eke1 = eke(l+1)
      call mix5(l+1)
      eke2 = eke(l+1)
      delke = eke1 - eke2
c
      penes = penes + pene
      delkes = delkes + delke
c
c  Add and subtract energy losses and gains due to entrainment.
c
      energy = energy + em2*delke - pene
c
c
      end if
   60 continue
c
c  End of the energy budget method for estimation entrainment.
c
   65 continue
c
c  Relieve gradient Richardson number instability if it occurs.
c
      if(rg.gt.0.) call rimix(nmix,kcd)
c
      call mldep(dml)
      dtl = dz*float(kcd)
c
      return
      end
c
      subroutine pe(m,pene)
c
c  Compute the energy required to entrain density level
c  d(m) into a mixed-layer above.
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, rg, rb, em1, em2, em3
c
      dr = d(m) - d(m-1)
      ho2 = dz*float(m)/2.
      pene = g*dz*ho2*dr
      return
      end
c
      subroutine rimix(nmix,kcd)
c
c  This subroutine performs the gradient Richardson number
c  relaxation by mixing adjacent cells just enough to bring
c  them to a new richardson number = rnew (defined in
c  subroutine stir). rg is the critical gradient Richardson number
c  at which mixing is presumed to begin. rg = 0.25 is a nominal
c  value.
c
c  All of u, v, d, t, s, dz, nz are exactly as in the pwpri subroutine.
c  nmix is the number of iterations required to achieve the relaxation,
c  kcd is the deepest grid level reached (the base of the transition
c  layer).
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cwp, rg, rb, em1, em2, em3
c
      dimension r(500)
c
      rc = rg
      nzm = nz - 1
      kcd = 0
      nmix = 0
c
      j1 = 1
      j2 = nzm
   10 continue
c
c  Compute the gradient Richardson number, taking care
c  to avoid dividing by zero in the mixed-layer. The numerical
c  values of the minimum allowable density and velocity differences
c  are entirely arbitary, and should not effect the calculations
c  (except that on some occasions thay evidently have!)
c
      do 1 j = j1,j2
      dd = d(j+1) - d(j)
      if(dd.lt.1.e-3) dd = 1.e-3
      dv = (u(j+1) - u(j))**2 + (v(j+1) - v(j))**2
      if(dv.lt.1.e-6) dv = 1.e-6
      r(j) = g*dz*dd/(dv*ro)
    1 continue
c
c  Find the smallest value of r in profile.
c
      rs = r(1)
      js = 1
      do 2 j=2,nzm
      if(r(j).lt.rs) go to 3
      go to 2
    3 continue
      rs = r(j)
      js = j
    2 continue
c
c  Check to see whether the smallest r is critical or not.
c
      if(rs.gt.rc) go to 99
c
c  Mix the cells js and js+1 that had the smallest Richardson number.
c
      if(js.ge.kcd) kcd = js + 1
      call stir(rc,rs,t,js)
      call stir(rc,rs,s,js)
      call stir(rc,rs,d,js)
      call stir(rc,rs,u,js)
      call stir(rc,rs,v,js)
      nmix = nmix + 1
c
c  Recompute the Richardson number over the part of the profile
c  that has changed.
c
      j1 = js - 2
      if(j1.lt.1) j1 = 1
      j2 = js + 2
      if(j2.gt.nzm) j2 = nzm
      go to 10
c
   99 continue
      return
      end
c
c
      subroutine stir (rc,r,a,j)
c
c
c  This subroutine mixes cells j and j+1 just enough so that
c  the Richardson number after the mixing is brought up to
c  the value rnew. In order to have this mixing process
c  converge, rnew must exceed the critical value of the
c  richardson number where mixing is presumed to start. if
c  r critical = rc = 0.25 (the nominal value), and r = 0.20, then
c  rnew = 0.3 would be reasonable. If r were smaller, then a
c  larger value of rnew - rc is used to hasten convergence.
c
c  This subroutine was modified by JFP in Sep 93 to allow for an
c  aribtrary rc and to achieve faster convergence.  
c
c  rc is the value of the critical gradient Richardson number,
c  r is the Richardson number before this mixing,
c  a is the array to be mixed,
c  j and j+1 define the cell (grid level) where r was found to
c   be critical.
c
      dimension a(500)
c
c  Set the convergence parameter.
c
      rcon = 0.02 + (rc - r)/2.
      rnew = rc + rcon/5.               !  an arbitrary change
c
      f = 1. - r/rnew
      da = (a(j+1) - a(j))*f/2.
      a(j+1) = a(j+1) - da
      a(j) = a(j) + da
      return
      end
c
c
c
      subroutine mldep(dml)
c
c  This subroutine scans through the density array d to find
c  the depth of the surface mixed-layer. The degree of density
c  homogeneity, deps, is arbitary and should not effect the
c  results.
c
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cpw, rg, rb, em1, em2, em3
c
      deps = 1.e-4
      nzm = nz - 1
      do 1 j=1,nzm
      dd = abs(d(j+1) - d(j))
      if(dd.gt.deps) go to 2
    1 continue
    2 continue
      dml = float(j)*dz
      return
      end
c
c
      subroutine mix1(b,k)
c
c  This subroutine homogenizes the array b down to level k.
c
      dimension b(500)
      bs = 0.
      do 1 j=1,k
      bs = bs + b(j)
    1 continue
      bs = bs/float(k)
      do 2 j=1,k
      b(j) = bs
    2 continue
      return
      end
c
c
      subroutine mix5(k)
c
c  This subroutine mixes arrays t, s, u, v, d down to level k.
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cpw, rg, rb, em1, em2, em3
c
      ts = 0.
      ss = 0.
      us = 0.
      vs = 0.
      ds = 0.
      do 1 j=1,k
      ts = ts + t(j)
      ss = ss + s(j)
      us = us + u(j)
      vs = vs + v(j)
      ds = ds + d(j)
    1 continue
      x = float(k)
      do 2 j=1,k
      u(j) = us/x
      v(j) = vs/x
      t(j) = ts/x
      s(j) = ss/x
      d(j) = ds/x
    2 continue
      return
      end
c
c
      subroutine rot(u,v,sa,ca)
c
c  This subroutine rotates the vector (u,v) through an
c  angle whose sine and cosine are sa and ca.
c
      u0 = u
      v0 = v
      u = u0*ca + v0*sa
      v = v0*ca - u0*sa
      return
      end
c
c
      subroutine si(ml,sipe)
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cpw, rg, rb, em1, em2, em3
c
      dimension di(500)
c
c  Find and relieve static instability that may occur in the
c  density array d. This simulates free convection.
c  ml is the depth of the surface mixed layer after adjustment,
c  sipe is the change in potential energy due to free convection.
c
      do 10 j=1,nz
      di(j) = d(j)
   10 continue
c
      mml = 1
      do 1 j=2,nz
      if(d(j).gt.d(j-1)) go to 2
      if(d(j).lt.d(j-1)) then
      mml = j
      call mix1(d,mml)
      end if
    1 continue
    2 continue
      ml = mml
c
      nj = mml + 3
      do 30 j=1,nj
   30 continue
c
c
      pesum = 0.
      if(ml.ge.2) then
c
c  Compute the change in potential energy.
c
      do 11 j= ml,1,-1
      z = float(j)*dz - dz/2.
      pesum = pesum + (d(j) - di(j))*g*z*dz
   11 continue
      end if
      sipe = pesum
c
      return
      end
c
c
      function eke(k)
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cpw, rg, rb, em1, em2, em3
c
c  Compute the kinetic energy in the u,v profiles from the surface
c  down to level k.
c
      ekes = 0.
      do 1 j=1,k
      ekes = ekes + u(j)**2 + v(j)**2
    1 continue
      eke = ekes*ro*dz/2.
      return
      end
c
c
      subroutine absorb(beta1,beta2)
c
      common t(500), s(500), u(500), v(500), d(500), absrb(500),
     1 dz, dt, nz, g, ro, cpw, rg, rb, em1, em2, em3
c
c  Compute solar radiation absorption profile. This
c  subroutine assumes two wavelengths, and a double
c  exponential depth dependence for absorption.
c
c  Subscript 1 is for red, non-penetrating light, and
c  2 is for blue, penetrating light. rs1 is the fraction
c  assumed to be red.
c
      abss = 0.
      rs1 = 0.6
      rs2 = 1.0 - rs1
c
      do 3 j=1,nz
      absrb(j) = 0.
    3 continue
c
      do 1 j=1,nz
      z1 = float(j-1)*dz
      z2 = z1 + dz
c
      z1b1 = z1/beta1
      z2b1 = z2/beta1
      z1b2 = z1/beta2
      z2b2 = z2/beta2
c
c  The checks below are to avoid math overflows.
c
      if(z2b1.lt.70.) absrb(j) = absrb(j) +
     x  rs1*(exp(-z1b1) - exp(-z2b1))
c
      if(z2b2.lt.70.) absrb(j) = absrb(j) +
     x  rs2*(exp(-z1b2) - exp(-z2b2))
c
c  Make sure that ab(z) integrates to 1 at large depth.
c
      abss = abss + absrb(j)
c      if(j.lt.20) write (6,2) j,z2,absrb(j),abss
c    2 format (1x,'absorption',i5,3f8.3)
    1 continue
      return
      end
c
c
      subroutine intx(r,s,nzs,n,ri,si)
c
c  This subroutine interploates the array s to find the value
c  at the point ri, where r is the independent variable.
c  The interpolation is linear, and assumes that r increases
c  montonically, and that ri is within the range of r. If
c  ri is not within the range of r, si is set equal to the
c  appropriate endpoint of s, and a warning is printed.

c
      dimension r(1000), s(1000)
c
c  Check for out of range ri.
c
      if(ri.lt.r(1)) then
      si = s(1)
      write (6,20) ri, r(1)
  20  format (1x,/,1x,'warning, ri was below r(1) in call to intx',/,
     c 'ri and r(1) were', 2e12.4)
      end if
c
c
      if(ri.gt.r(n)) then
      si = s(n)
      write (6,21) ri, r(n)
  21  format (1x,/,1x,'warning, ri was above r(n) in call to intx',/,
     c 'ri and r(n) were', 2e12.4)
      end if
c
c  OK, data are within bounds for an interpolation.
c
      nm = n - 1
      do 2 k=1,nm
      if(ri.ge.r(k).and.ri.le.r(k+1)) go to 1
    2 continue
c
      go to 9
c
    1 continue
      si = (s(k)*(r(k+1) - ri) + s(k+1)*(ri - r(k)))/
     x (r(k+1) - r(k))
c
c
    9 continue
      return
      end
c
c
c
      subroutine diffus (rkz,nz,dz,dt,a)
      dimension a(1000), work(1000)
c
c
c  This subroutine applies a simple diffusion
c  operation to the array a. It leaves the endpoints
c  unchanged (assumes nothing about the
c  boundary conditions).
c
c
      dconst = dt*rkz/dz**2
      nzm = nz - 1
c

      do 1 j=2,nzm
      work(j) = dconst*(a(j-1) + a(j+1) - 2.*a(j))
    1 continue
c
      do 2 j=2,nzm
    2 a(j) = a(j) + work(j)
c
      return
      end
c

c
      function sg0(s)
c
c  A sigma-0 subroutine neede by the sigma-t subroutine;
c  taken from seaprop.
c
c  sigma-0 knudsen
c
      sg0 = ((6.76786136e-6*s-4.8249614e-4)*s+0.814876577)*s
     x -0.0934458632
      return
      end
c
c
      function sgt(t,s,sg)
c
c  A sigma-t subroutine taken from seaprop;
c  sigma-t knudsen
c
      sg = sg0(s)
   20 sgt = ((((-1.43803061e-7*t-1.98248399e-3)*t-0.545939111)*t
     x +4.53168426)*t)/(t+67.26)+((((1.667e-8*t-8.164e-7)*t
     x +1.803e-5)*t)*sg+((-1.0843e-6*t+9.8185e-5)*t-4.7867e-3)*t
     x +1.0)*sg
      return
      end
