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


subroutine tfilt_massfix (ztodt   ,lat     ,u3m1    ,v3m1    ,t3m1    , & 1,14
                          q3      ,q3m1    ,ps      ,cwava   ,alpha   , &
                          etamid  ,qfcst   ,div     ,phis    ,omga    , &
                          dpsl    ,dpsm    ,nlon    ,t3      ,beta )
!-----------------------------------------------------------------------
!
! Purpose:
! Atmosphere and constituent mass fixer
!
! Author:  J. Olson
!
!-----------------------------------------------------------------------

  use shr_kind_mod, only: r8 => shr_kind_r8
  use pmgrid
  use pspect
  use commap
  use history, only: outfld
  use constituents, only: pcnst, pnats, qmin
!  use constituents, only: tottnam, cnst_get_type_byind
  use constituents, only: cnst_get_type_byind
  use physconst, only: cpair, gravit

  implicit none

#include <comctl.h>
#include <comlun.h>
#include <comqfl.h>
#include <comtfc.h>
!
!------------------------------Arguments--------------------------------
!
  real(r8), intent(in)   :: ztodt                          ! timestep
  integer , intent(in)   :: lat                            ! latitude index
  real(r8), intent(in)   :: u3m1    (plond,plev)             ! u
  real(r8), intent(in)   :: v3m1    (plond,plev)             ! v
  real(r8), intent(inout):: t3m1    (plond,plev)             ! T
  real(r8), intent(inout)   :: q3      (plond,plev,pcnst+pnats) ! q + consts (time level n-1)
  real(r8), intent(inout):: q3m1    (plond,plev,pcnst+pnats) ! q + consts (time level n  )
  real(r8), intent(inout):: ps    (plond)                  ! Ps
  real(r8), intent(in)   :: cwava                          ! weight for global integrals
  real(r8), intent(in)   :: alpha (pcnst)                  ! slt fixer coefficient
  real(r8), intent(in)   :: etamid(plev)                   ! vertical coords at midpoints 
  real(r8), intent(in)   :: qfcst (plond,plev,pcnst)       ! slt moisture forecast
  real(r8), intent(in)   :: div   (plond,plev)             ! divergence
  real(r8), intent(in)   :: phis  (plond)                  ! Geopotential field
  real(r8), intent(out)  :: omga  (plond,plev)             ! vertical motion
  real(r8), intent(in)   :: dpsl  (plond)                  ! long comp of grad ln(ps)
  real(r8), intent(in)   :: dpsm  (plond)                  ! lat comp  of grad ln(ps)
  integer , intent(in)   :: nlon                           ! number of longitudes
  real(r8), intent(in)   :: t3(plond,plev) ! temperature
  real(r8), intent(in)   :: beta                           ! energy fixer coefficient
!
!---------------------------Local workspace-----------------------------
!
  integer ifcnt                     ! Counter
  real(r8) qfcst1(plond,plev,pcnst) ! slt moisture forecast temporary
  real(r8) engycorr(plond,plev)   ! energy equivalent to T correction
  real(r8) rpmid (plond,plev)       ! 1./pmid
  real(r8) pdel  (plond,plev)       ! pdel(k)   = pint  (k+1)-pint  (k)
  real(r8) pint  (plond,plevp)      ! pressure at model interfaces (n  )
  real(r8) pmid  (plond,plev)       ! pressure at model levels (time n)
! real(r8) utend (plond,plev)       ! du/dt
! real(r8) vtend (plond,plev)       ! dv/dt
! real(r8) ttend (plond,plev)       ! dT/dt
! real(r8) qtend (plond,plev,pcnst) ! dq/dt
! real(r8) pstend(plond)            ! d(ps)/dt
  real(r8) psl   (plond)            ! sea level pressure
  real(r8) corm                     ! fixer limit
  real(r8) wm                       ! accumulator 
  real(r8) absf                     ! absolute value of fixer
  real(r8) worst                    ! largest fixer contribution at each model level
  logical lfixlim                   ! flag to turn on fixer limiter

  real(r8) ta    (plond,plev,pcnst) ! total advection of constituents
  real(r8) dqfx3 (plond,plev,pcnst) ! q tendency due to mass adjustment
  real(r8) coslat                   ! cosine(latitude)
  real(r8) rcoslat(plond)           ! 1./cosine(latitude)
! real(r8) engt                     ! Thermal   energy integral
! real(r8) engk                     ! Kinetic   energy integral
! real(r8) engp                     ! Potential energy integral

  integer i, k, m                   ! indices
!
!-----------------------------------------------------------------------
  qfcst1(1:nlon,:,:) = qfcst(i1:nlon+i1-1,:,:)
!
  coslat  = cos(clat(lat))
  do i=1,nlon
     rcoslat(i) = 1./coslat
  enddo
  lfixlim = .true.
!
! Set average dry mass to specified constant preserving horizontal
! gradients of ln(ps). Proportionality factor was calculated in STEPON
! for nstep=0 or SCAN2 otherwise from integrals calculated in INIDAT
! and SCAN2 respectively.
! Set p*.
!
  do i=1,nlon
     ps(i) = ps(i)*fixmas
  end do
!
! Set current time pressure arrays for model levels etc.
!
  call plevs0(nlon    ,plond   ,plev    ,ps      ,pint    ,pmid    ,pdel)
!
  rpmid(:nlon,:plev) = 1./pmid(:nlon,:plev)
!
! Add temperature correction for energy conservation
!
  do k=1,plev
    do i=1,nlon
      engycorr(i,k) = (cpair/gravit)*beta*pdel(i,k)/ztodt
      t3m1    (i,k) = t3m1(i,k) + beta
    end do
  end do
!
! Output Energy correction term
!
  call outfld('ENGYCORR',engycorr ,plond   ,lat     )
!
! Compute q tendency due to mass adjustment
! If LFIXLIM = .T., then:
! Check to see if fixer is exceeding a desired fractional limit of the
! constituent mixing ratio ("corm").  If so, then limit the fixer to
! that specified limit.
!
  do m=1,pcnst
      if (cnst_get_type_byind(m).eq.'dry' ) then
         corm    = 1.e36
      else
         corm    = 0.1
      end if

     do k=1,plev
        do i=1,nlon
           dqfx3(i,k,m) = alpha(m)*etamid(k)*abs(qfcst1(i,k,m) - q3(i,k,m))
        end do

        if (lfixlim) then
           ifcnt = 0
           worst = 0.
           wm    = 0.
           do i = 1,nlon
              absf = abs(dqfx3(i,k,m))
              if (absf.gt.corm) then
                 ifcnt = ifcnt + 1
                 worst = max(absf,worst)
                 wm = wm + absf
                 dqfx3(i,k,m) = sign(corm,dqfx3(i,k,m))
              endif
           end do
           if (ifcnt.gt.0) then
              wm = wm/float(ifcnt)
              write (6,1000) m,corm,ifcnt,k,lat,wm,worst
           endif
        endif

        do i=1,nlon
           dqfx3(i,k,m) = qfcst1(i,k,m)*dqfx3(i,k,m)/ztodt
#ifdef HADVTEST
           q3m1(i,k,m) = qfcst1(i,k,m)
#else
           q3m1(i,k,m) = qfcst1(i,k,m) + ztodt*dqfx3(i,k,m)
#endif
           ta(i,k,m) = (q3m1(i,k,m) - q3(i,k,m))/ztodt
        end do
     end do
  end do

  ! stuff current water vapor into unused field so we can use it for 
  ! fixer next time step
  q3(:nlon,:,1) = q3m1(:nlon,:,1)

!
! Check for and correct invalid constituents
!
  call qneg3('TFILT_MASSFIX',lat   ,nlon    ,plond   ,plev    , &
             pcnst+pnats,qmin ,q3m1(1,1,1))
!
! Send slt tendencies to the history tape
!
!  do m=1,pcnst
!     call outfld(tottnam(m),ta(1,1,m)   ,plond   ,lat     )
!  end do
!
! Calculate vertical motion field
!
  call omcalc(rcoslat ,div     ,u3m1    ,v3m1    ,dpsl    , &
              dpsm    ,pmid    ,pdel    ,rpmid   ,pint(1,plevp), &
              omga    ,nlon    )

  call plevs0(nlon    ,plond   ,plev    ,ps      ,pint    ,pmid    ,pdel)
!
! Compute time tendencies:comment out since currently not on h-t
!
!      do k=1,plev
!        do i=1,nlon
!          ttend(i,k) = (t3m1(i,k)-tm2(i,k))/ztodt
!          utend(i,k) = (u3m1(i,k)-um2(i,k))/ztodt
!          vtend(i,k) = (v3m1(i,k)-vm2(i,k))/ztodt
!        end do  
!      end do  
!      do m=1,pcnst
!        do k=1,plev
!          do i=1,nlon
!            qtend(i,k,m) = (q3m1(i,k,m) - qm2(i,k,m))/ztodt
!          end do
!        end do
!      end do
!      do i=1,nlon
!        pstend(i) = (ps(i) - psm2(i))/ztodt
!      end do

!
! do m=1,pcnst
!    call outfld(tendnam(m),qtend(1,1,m),plond   ,lat     )
! end do
! call outfld('UTEND   ',utend   ,plond   ,lat     )
! call outfld('VTEND   ',vtend   ,plond   ,lat     )
! call outfld('TTEND   ',ttend   ,plond   ,lat     )
! call outfld('LPSTEN  ',pstend  ,plond   ,lat     )

  call plevs0(nlon    ,plond   ,plev    ,ps      ,pint    ,pmid    ,pdel)

  return
1000 format(' TIMEFILTER: WARNING: fixer for tracer ',i3,' exceeded ', &
            f8.5,' for ',i5,' points at k,lat = ',2i4,' Avg/Worst = ',1p2e10.2)
end subroutine tfilt_massfix