!-------------------------------------- LICENCE BEGIN ------------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer, 
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms 
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer 
!version 3 or (at your option) any later version that should be found at: 
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html 
!
!This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
!without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
!See the above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software; 
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec), 
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------
!*** S/P GWSPECTRUM
!

  SUBROUTINE gwspectrum ( kproma , kbdim  , klev   & 1,2
       &                 ,s      , sh     , sexpk  &
       &                 ,shexpk , pressg , th     &
       &                 ,ptm1   , pum1   , pvm1   &
       &                 ,ptte   , pvol            &
       &                 ,pvom   , g      , rd     &
       &                 ,tau    , rmscon , iheatcal)

    USE mo_gwspectrum,        ONLY: emiss_lev, kstar, naz

    IMPLICIT NONE

    ! scalar argument with intent(IN)
    INTEGER ,INTENT(in) ::  kproma, kbdim, klev, iheatcal

    !  Array arguments with intent(IN):
    ! Input 1D
    REAL*8 ,INTENT(IN) :: pressg(kproma)       ! Surface pressure (pascal)
    ! Input 2D
    REAL*8 ,INTENT(IN) :: th(kbdim,klev)       ! half level temperature
    ! Input constants
    REAL   ,INTENT(IN) :: g
    REAL   ,INTENT(IN) :: rd
    REAL   ,INTENT(IN) :: tau
    REAL   ,INTENT(IN) :: rmscon

    !  Array arguments with intent(InOut):
    ! - input/output 2d
    REAL*8 ,INTENT(INOUT) :: pum1(kbdim,klev)  ! zonal wind (t-dt)
    REAL*8 ,INTENT(INOUT) :: pvm1(kbdim,klev)  ! meridional wind (t-dt)
    REAL*8 ,INTENT(INOUT) :: ptm1(kbdim,klev)  ! temperature (t-dt)

    !  Array arguments with intent(Out):
    ! - output 2d
    REAL*8 ,INTENT(OUT) :: ptte(kbdim,klev)    ! tendency of temperature
    REAL*8 ,INTENT(OUT) :: pvol(kbdim,klev)    ! tendency of meridional wind
    REAL*8 ,INTENT(OUT) :: pvom(kbdim,klev)    ! tendency of zonal wind
    REAL*8              :: diffco(kbdim,klev)  ! turbulent diffusion coefficient
!
!Authors
!    
!   n. mcfarlane                cccma     may 1995
!   c. mclandress               ists      august 1995
!   m. charron                  mpi       2000-2001
!   e. manzini                  mpi       february 2002 (re-write, based on cccgwd)
!   th.schoenemeyer/h.schmidt   nec/mpi   july 2002 (optimized for vector architecture)
!   h. schmidt                  mpi       march 2003
!   m. charron                  rpn       june 2004
!
!
!Revision
! 001      L. Spacek (Sep 2008) - Density calulation uses th instead ptm1
!
!Object
! 
!   Hines parameterization from ccc/mam (Hines, 1997a,b):       
!   physical tendencies of the prognostic variables u,v 
!   due to vertical transports by a broad band spectrum
!   of gravity waves. 
!
!   Note that diffusion coefficient and  heating rate 
!   only calculated if iheatcal = 1.
!
!   *gwspectrum* is called from *physc*.
! 
!Arguments
! 
!            - Input/Ouput -
! pum1     zonal wind (t-dt)
! pvm1     meridional wind (t-dt)
! ptm1     temperature (t-dt)
!
!          - Output -
! utendgw  zonal tend, gravity wave spectrum (m/s^2)
! pvol     tendency of meridional wind
! pvom     tendency of zonal wind
! diffco   turbulent diffusion coefficient
!
!          - Input -
! pressg   surface pressure (pascal)
! th       half  level temperature
!
    !  Local arrays for ccc/mam hines gwd scheme:

    ! Important local parameter (passed to all subroutines):
    INTEGER, PARAMETER :: nazmth = 8  ! max azimuth array dimension size 

    ! * Vertical positioning arrays and work arrays:                       
    REAL*8, INTENT(in) :: s(kproma,klev), sh(kproma,klev), shexpk(kproma,klev), sexpk(kproma,klev)
    REAL*8 :: dttdsf,dttdzl

    REAL*8 :: utendgw(kproma,klev) ! zonal tend, gravity wave spectrum (m/s^2)
    REAL*8 :: vtendgw(kproma,klev) ! merid tend, gravity wave spectrum (m/s^2)
    REAL*8 :: ttendgw(kproma,klev) ! temperature tend, gravity wave spectrum (K/s)
    REAL*8 ::  flux_u(kproma,klev) ! zonal momentum flux (pascals)
    REAL*8 ::  flux_v(kproma,klev) ! meridional momentum flux (pascals) 

    REAL*8 :: uhs(kproma,klev)      ! zonal wind (m/s), input for hines param
    REAL*8 :: vhs(kproma,klev)      ! merid wind (m/s), input for hines param
    REAL*8 :: bvfreq(kproma,klev)   ! background brunt vassala frequency (rad/s)
    REAL*8 :: density(kproma,klev)  ! background density (kg/m^3)
    REAL*8 :: visc_mol(kproma,klev) ! molecular viscosity (m^2/s) 
    REAL*8 :: alt(kproma,klev)      ! background altitude (m)

    REAL*8 :: rmswind(kproma)        ! rms gravity wave  wind, lowest level (m/s) 
    REAL*8 :: anis(kproma,nazmth)    ! anisotropy factor (sum over azimuths = 1) 
    REAL*8 :: k_alpha(kproma,nazmth) ! horizontal wavenumber of each azimuth (1/m)
    LOGICAL :: lorms(kproma)       ! .true. for rmswind /=0 at launching level 

    REAL*8 :: m_alpha(kproma,klev,nazmth) ! cutoff vertical wavenumber (1/m)
    REAL*8 :: mmin_alpha(kproma,nazmth)   ! minumum value of m_alpha
    REAL*8 :: sigma_t(kproma,klev)        ! total rms gw wind (m/s)
    ! gw variances from orographic sources (for coupling to a orogwd)
    REAL*8 :: sigsqmcw(kproma,klev,nazmth), sigmatm(kproma,klev)

    !
    ! Local scalars:
    INTEGER  :: jk, jl
    INTEGER  :: levbot     ! gravity wave spectrum lowest level
    REAL*8     :: hscal, ratio


       !
       !--  Initialize the ccc/mam hines gwd scheme
       !

       utendgw(:,:) = 0.
       vtendgw(:,:) = 0.
       ttendgw(:,:) = 0.

       diffco(:,:) = 0

       flux_u(:,:) = 0.
       flux_v(:,:) = 0. 

       uhs(:,:) = 0.
       vhs(:,:) = 0.

       ! Wind variances form orographic gravity waves
       ! Note: the code is NOT fully implemeted for this case!

       sigsqmcw(:,:,:) = 0.
       sigmatm(:,:)    = 0.

!     * CALCULATE  B V FREQUENCY EVERYWHERE.

       DO jk=2,klev
         DO jl=1,kproma
           dttdsf=(th(jl,jk)/SHEXPK(jl,jk)-th(jl,jk-1)/SHEXPK(jl,jk-1)) &
                         /(SH(jl,jk)-SH(jl,jk-1))
           dttdsf=MIN(dttdsf, -5./S(jl,jk))
           dttdzl=-dttdsf*S(jl,jk)*g/(rd*ptm1(jl,jk))
           bvfreq(jl,jk)=SQRT(g*dttdzl*SEXPK(jl,jk)/ptm1(jl,jk))
         ENDDO
       ENDDO

       bvfreq(:,1)=bvfreq(:,2)

       DO jk=2,klev
         DO jl=1,kproma
           ratio=5.*LOG(S(jl,jk)/S(jl,jk-1))
           bvfreq(jl,jk) = (bvfreq(jl,jk-1) + ratio*bvfreq(jl,jk))/(1.+ratio)
         END DO
       END DO

       !     * altitude and density at bottom.

       alt(:,klev) = 0.

       DO jl=1,kproma
          hscal = rd * ptm1(jl,klev) / g
          density(jl,klev) = s(jl,klev) * pressg(jl) / (g*hscal)
       END DO

       !     * altitude and density at remaining levels.

       DO jk=klev-1,1,-1
          DO jl=1,kproma
             hscal = rd * th(jl,jk) / g
             alt(jl,jk) = alt(jl,jk+1) + hscal * LOG(s(jl,jk+1)/s(jl,jk))
             density(jl,jk) = s(jl,jk) * pressg(jl) / (rd * ptm1(jl,jk))
          END DO
       END DO

       !
       !     * set molecular viscosity to a very small value.
       !     * if the model top is greater than 100 km then the actual
       !     * viscosity coefficient could be specified here.


       DO jk=1,klev
          DO jl=1,kproma
             visc_mol(jl,jk) = 3.90E-7*ptm1(jl,jk)**.69 / density(jl,jk)
          ENDDO
       ENDDO

       ! use single value for azimuthal-dependent horizontal wavenumber:
       ! kstar = (old latitudinal dependence, introduce here if necessary)

       k_alpha(:,:) = kstar

       !     * defile bottom launch level (emission level of gws)

       levbot = klev-emiss_lev   

       !     * initialize switch for column calculation

       lorms(:) = .FALSE.

       !     * background wind minus value at bottom launch level.

       DO jk=1,levbot
         DO jl=1,kproma 
           uhs(jl,jk) = pum1(jl,jk) - pum1(jl,levbot)
           vhs(jl,jk) = pvm1(jl,jk) - pvm1(jl,levbot)
         END DO
       END DO

       !     * specify root mean square wind at bottom launch level.

       DO jl=1,kproma 
          rmswind(jl) = DBLE(rmscon)
          anis(jl,:)   = 1./FLOAT(naz)
       END DO

       DO jl=1,kproma 
          IF (rmswind(jl) .GT. 0.0) THEN
             lorms(jl) = .TRUE.
          ENDIF
       END DO

       !
       !     * calculate gw tendencies (note that diffusion coefficient and
       !     * heating rate only calculated if iheatcal = 1).
       !

       CALL hines_extro ( kproma, klev, nazmth,                          & 
            &             utendgw, vtendgw, ttendgw, diffco(1:kproma,:), &
            &             flux_u, flux_v,                                & 
            &             uhs, vhs, bvfreq, density, visc_mol, alt,      & 
            &             rmswind, anis, k_alpha, sigsqmcw,              &
            &             m_alpha,  mmin_alpha ,sigma_t, sigmatm,        & 
            &             levbot, lorms, iheatcal)

       DO jk=1, klev
          DO jl=1,kproma
             pum1(jl,jk)=pum1(jl,jk)+tau*utendgw(jl,jk)
             pvm1(jl,jk)=pvm1(jl,jk)+tau*vtendgw(jl,jk)
             ptm1(jl,jk)=ptm1(jl,jk)+tau*ttendgw(jl,jk)
          ENDDO
       ENDDO

       !   update tendencies: 
       !
       DO jk=1, klev
          DO jl=1,kproma
             pvom(jl,jk) = utendgw(jl,jk)
             pvol(jl,jk) = vtendgw(jl,jk)
             ptte(jl,jk) = ttendgw(jl,jk)
          END DO
       END DO
       !

    !     * end of hines calculations.

    !-----------------------------------------------------------------------
  END SUBROUTINE gwspectrum