#include <misc.h>
#include <params.h>


subroutine linemsdyn(lat     ,ps      ,u3      ,u3m1    ,v3      , & 1,17
                     v3m1    ,t3      ,t3m1    ,q3      ,etadot  , &
                     etadotm1,etamid  ,ztodt   ,                   &
                     vcour   ,vmax    ,vmaxt   ,detam   , &
                     ed1     ,fu      ,fv      ,lnpssld ,prhssld , &
                     tarrsld ,parrsld ,t2      ,div     ,tl      , &
                     tm      ,ql      ,qm      ,dpsl    ,dpsm    , &
                     phis    ,phisl   ,phism   ,omga    , &
                     u3sld   ,v3sld   ,urhs    ,vrhs    , &
                     trhs    ,prhs    ,nlon    ,cwava   ,flx_net)
!-----------------------------------------------------------------------
!
! Purpose:
! Driver for non-linear dynamics computations (in grid-point space)
!
! Original version:  CCM1
!
!-----------------------------------------------------------------------
!
! $Id: linemsdyn.F90,v 1.17.2.3 2002/11/15 02:03:28 eaton Exp $
! $Author: eaton $
!
!-----------------------------------------------------------------------

  use shr_kind_mod, only: r8 => shr_kind_r8
  use pmgrid
  use constituents, only: pcnst, pnats
  use pspect
  use comslt
  use commap
  use history, only: outfld
  use dynconst, only: omega
  use time_manager, only: get_step_size, is_first_step

  implicit none

#include <comctl.h>
#include <comhyb.h>
#include <comlun.h>

!------------------------------Arguments--------------------------------
!
  integer , intent(in)   :: lat                    ! latitude index for S->N storage
  real(r8), intent(in)   :: ps      (plond)        ! surface pressure (time n)
  real(r8), intent(in)   :: u3      (plond,plev)   ! u-wind (time n)
  real(r8), intent(inout):: u3m1    (plond,plev)   ! u-wind (time n-1)
  real(r8), intent(in)   :: v3      (plond,plev)   ! v-wind (time n)
  real(r8), intent(inout):: v3m1    (plond,plev)   ! v-wind (time n-1)
  real(r8), intent(in)   :: t3      (plond,plev)   ! temperature (time n)
  real(r8), intent(inout):: t3m1    (plond,plev)   ! temperature (time n-1)
  real(r8), intent(in)   :: q3      (plond,plev,pcnst+pnats)! constituents
  real(r8), intent(inout):: etadot  (plond,plevp)  ! vertical motion (3-d used by slt)
  real(r8), intent(inout):: etadotm1(plond,plevp)  ! vertical motion (3-d used by slt)
  real(r8), intent(in)   :: etamid  (plev)         ! midpoint values of eta (a+b)
  real(r8), intent(in)   :: ztodt                  ! 2*timestep unless nstep = 0
  real(r8), intent(out)  :: vcour   (plev)         ! maximum Courant number in vert.
  real(r8), intent(out)  :: vmax    (plev)         ! maximum wind speed squared (m^2/s^2)
  real(r8), intent(out)  :: vmaxt   (plev)         ! maximum truncated wind speed (m^2/s^2)
  real(r8), intent(in)   :: detam   (plev)         ! intervals between vert.levels
  real(r8), intent(inout):: ed1     (plond,plev)   ! etadot*dp/deta (for SLD)
  real(r8), intent(inout):: fu      (plond,plev)   ! nonlinear term - u momentum eqn.
  real(r8), intent(inout):: fv      (plond,plev)   ! nonlinear term - v momentum eqn.
  real(r8), intent(inout):: lnpssld (plond,plev)   ! RHS Ps term for SLD
  real(r8), intent(inout):: prhssld (plond,plev)   ! RHS Ps term for SLD
  real(r8), intent(inout):: tarrsld (plond,plev)   ! T  at arr. pt. (SLD)
  real(r8), intent(inout):: parrsld (plond,plev)   ! Ps at arr. pt. (SLD)
  real(r8), intent(inout):: t2      (plond,plev)   ! nonlinear term - temperature
  real(r8), intent(in)   :: div     (plond,plev)   ! divergence (time n)
  real(r8), intent(in)   :: tl      (plond,plev)   ! long derivative of T (n)
  real(r8), intent(in)   :: tm      (plond,plev)   ! lat  derivative of T (n)
  real(r8), intent(in)   :: ql      (plond,plev)   ! long derivative of q (n)
  real(r8), intent(in)   :: qm      (plond,plev)   ! lat  derivative of q (n-1)
  real(r8), intent(in)   :: dpsl    (plond)        ! long derivative of lnps (n)
  real(r8), intent(in)   :: dpsm    (plond)        ! lat  derivative of lnps (n)
  real(r8), intent(in)   :: phis    (plond)        ! surface geopotential
  real(r8), intent(in)   :: phisl   (plond)        ! long derivative of phis
  real(r8), intent(in)   :: phism   (plond)        ! lat  derivative of phis
  real(r8), intent(in)   :: omga    (plond,plev)   ! vertical velocity
  real(r8), intent(inout):: u3sld   (plond,plev)   ! u-wind (time n) (used for advection)
  real(r8), intent(inout):: v3sld   (plond,plev)   ! v-wind (time n) (used for advection)
  real(r8), intent(inout):: urhs    (plond,plev)   ! RHS of U  eqn valid for mid-point
  real(r8), intent(inout):: vrhs    (plond,plev)   ! RHS of V  eqn valid for mid-point
  real(r8), intent(inout):: trhs    (plond,plev)   ! RHS of T  eqn valid for mid-point
  real(r8), intent(inout):: prhs    (plond,plev)   ! RHS of Ps eqn valid for mid-point
  integer , intent(in)   :: nlon                   ! number of longitudes for this lat
  real(r8), intent(in)   :: cwava                  ! weight for global water vapor int.
  real(r8), intent(in)   :: flx_net(plond)         ! net flux from physics
!
!---------------------------Local workspace-----------------------------
!
  real(r8) :: dtime             ! timestep size
  real(r8) pmid  (plond,plev)   ! pressure at model levels (time n)
  real(r8) rpmid (plond,plev)   ! 1./pmid
  real(r8) pint  (plond,plevp)  ! pressure at model interfaces (n  )
  real(r8) pdel  (plond,plev)   ! pdel(k)   = pint  (k+1)-pint  (k)
  real(r8) logps (plond)        ! log(ps)
  real(r8) lvcour               ! local vertical courant number
  real(r8) dtdz                 ! dt/detam(k)

  real(r8) dpslat(plond,plev)   ! Pressure gradient term 
  real(r8) dpslon(plond,plev)   ! Pressure gradient term 
  real(r8) coslat               ! cosine(latitude)
  real(r8) rcoslat              ! 1./cosine(latitude)
  real(r8) coriol               ! Coriolis term
  real(r8) wind                 ! u**2 + v**2 (m/s)
  real(r8) utfac                ! asymmetric truncation factor for courant calculation
  real(r8) vtfac                ! asymmetric truncation factor for courant calculation
  real(r8) engy                 ! accumulator
  integer i,k                   ! indices
!
!----------------------------------------------------------------------
!
! Compute maximum wind speed this latitude (used in Courant number
! estimate)
!
  if (ptrm .lt. ptrn) then
     utfac = float(ptrm)/float(ptrn)
     vtfac = 1.
  else if (ptrn .lt. ptrm) then
     utfac = 1.
     vtfac = float(ptrn)/float(ptrm) 
  else if (ptrn .eq. ptrm) then
     utfac = 1.
     vtfac = 1.
  end if
  do k=1,plev
     vmax(k) = 0.
     vmaxt(k) = 0.
     do i=1,nlon
        wind = u3(i,k)**2 + v3(i,k)**2
        vmax(k) = max(wind,vmax(k))
!
! Change to Courant limiter for non-triangular truncations.
!
        wind = utfac*u3(i,k)**2 + vtfac*v3(i,k)**2
        vmaxt(k) = max(wind,vmaxt(k))
     end do
  end do
!
  coslat = cos(clat(lat))
  rcoslat = 1./coslat
  coriol  = 2.0*omega*sin(clat(lat))
!
! Set current time pressure arrays for model levels etc.
!
  call plevs0 (nlon    ,plond   ,plev    ,ps      ,pint    ,pmid    ,pdel)
  do k=1,plev
     do i=1,nlon
        rpmid(i,k) = 1./pmid(i,k)
     end do
  end do
!
! Accumulate statistics for diagnostic print
!
  call stats(lat     ,pint    ,pdel    ,ps      , &
             div     ,t3      ,q3(:,:,1),nlon   )
!     
! Compute log(surface pressure) for use by grmult and when adding
! tendency.
!     
  do i=1,nlon
     logps  (i) = log(ps  (i))
  end do

  if (adiabatic) t2     (:nlon,:)=0.
!     
! Compute (1/ps)etadot(dp/deta)
!     
  if (.not. is_first_step()) then
     call etadtn (lat   ,nlon    ,div     ,parrsld ,ed1     )
  end if
!     
! Compute integrals
!     
  call engy_te (cwava,w(lat),t3  ,u3  ,v3 ,phis    ,pdel, engy ,nlon)
  engy1lat(lat) = engy
!
! Include top/bottom flux integral to energy integral
!
  call flxint  (w(lat) ,flx_net ,engy ,nlon )
  engy1lat(lat) = engy1lat(lat) + engy*ztodt
!     
! Calculate non-linear terms in tendencies
!     
  call grmult(ztodt   ,rcoslat ,coslat  ,coriol  ,div     , &
              q3(1,1,1),t3     ,u3      ,v3      ,u3sld   , &
              v3sld   ,ed1     ,ql      ,qm      ,tl      , &
              tm      ,phis    ,phisl   ,phism   ,dpsl    , &
              dpsm    ,omga    ,pmid    ,pdel    ,ps      , &
              logps   ,rpmid   ,etamid  ,fu      ,fv      , &
              t2      ,t3m1    ,u3m1    ,v3m1    ,etadot  , &
              dpslon  ,dpslat  ,urhs    ,vrhs    ,trhs    , &
              prhs    ,etadotm1,lnpssld ,prhssld ,tarrsld , &
              parrsld ,nlon    )
  call outfld('ETADOT  ',etadot(1,1),plond,lat)
!     
! Compute maximum vertical Courant number this latitude.
!     
  dtime = get_step_size()
  vcour(:) = 0.
  do k=2,plev
     dtdz = dtime/detam(k-1)
     do i=1,nlon
        lvcour = abs(etadot(i,k))*dtdz
        vcour(k) = max(lvcour,vcour(k))
     end do
  end do

  return
end subroutine linemsdyn