!-------------------------------------- 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 HINES_WAVNUM

  SUBROUTINE hines_wavnum ( m_alpha, sigma_t, sigma_alpha, ak_alpha,     & 1,9
       &                    mmin_alpha, losigma_t,                       &
       &                    v_alpha, visc_mol, density, densb,           &
       &                    bvfreq, bvfb, rms_wind, anis, lorms,         &
       &                    sigsqmcw, sigmatm,                           &
       &                    il1, il2, levtop, levbot, nlons, nlevs, nazmth)

    USE mo_doctor,       ONLY: nerr
    USE mo_exception,    ONLY: finish 
    USE mo_gwspectrum,   ONLY: kstar, m_min, slope, f1, f2, f3, naz

    IMPLICIT NONE

    INTEGER :: il1, il2, levtop, levbot, nlons, nlevs, nazmth
    REAL*8    :: m_alpha(nlons,nlevs,nazmth)
    REAL*8    :: sigma_alpha(nlons,nlevs,nazmth)
    REAL*8    :: sigalpmc(nlons,nlevs,nazmth)
    REAL*8    :: sigsqh_alpha(nlons,nlevs,nazmth)
    REAL*8    :: sigma_t(nlons,nlevs)
    REAL*8    :: sigmatm(nlons,nlevs)
    REAL*8    :: sigsqmcw(nlons,nlevs,nazmth)
    REAL*8    :: ak_alpha(nlons,nazmth)
    REAL*8    :: v_alpha(nlons,nlevs,nazmth)
    REAL*8    :: visc_mol(nlons,nlevs)
    REAL*8    :: f2mod(nlons,nlevs)
    REAL*8    :: density(nlons,nlevs),  densb(nlons)
    REAL*8    :: bvfreq(nlons,nlevs),   bvfb(nlons),  rms_wind(nlons)
    REAL*8    :: anis(nlons,nazmth) 
    REAL*8    :: i_alpha(nlons,nazmth), mmin_alpha(nlons,nazmth)

    LOGICAL :: lorms(nlons), losigma_t(nlons,nlevs), do_alpha(nlons,nazmth)
!
!Author
!
!  aug. 10/95 - c. mclandress
!  2000-2001  - m. charron
!  2002       - e. manzini
!
!Revision
!
!Modules
!
! mo_doctor
! mo_exception
! mo_gwspectrum
!
!Object
!
!  This routine calculates the cutoff vertical wavenumber and velocity
!  variances on a longitude by altitude grid for the hines' doppler 
!  spread gravity wave drag parameterization scheme.
!  note: (1) only values of four or eight can be used for # azimuths (naz).
!        (2) only values of 1.0, 1.5 or 2.0 can be used for slope (slope). 
!        (3) if m_min not zero, only slope=1. can be used. 
!
!Arguments
!
!              - Output
! m_alpha      cutoff wavenumber at each azimuth (1/m).
! sigma_t      total rms horizontal wind (m/s).
! sigma_alpha  total rms wind in each azimuth (m/s).
! ak_alpha     spectral amplitude factor at each azimuth 
!              (i.e.,{ajkj}) in m^4/s^2.
! losigma_t    .true. for total sigma not zero
! mmin_alpha   minimum value of cutoff wavenumber.
!
!              - Input -
! v_alpha      wind component at each azimuth (m/s). 
! visc_mol     molecular viscosity (m^2/s)
! density      background density (kg/m^3).
! densb        background density at model bottom (kg/m^3).
! bvfreq       background brunt vassala frequency (radians/sec).
! bvfb         background brunt vassala frequency at model bottom.
! rms_wind     root mean square gravity wave wind at lowest level (m/s).
! anis         anisotropy factor (sum over azimuths is one)
! lorms        .true. for drag computation at lowest level 
! levbot       index of lowest vertical level.
! levtop       index of highest vertical level 
!              (note: if levtop < levbot then level index 
!              increases from top down).
! il1          first longitudinal index to use (il1 >= 1).
! il2          last longitudinal index to use (il1 <= il2 <= nlons).
! nlons        number of longitudes.
! nlevs        number of vertical levels.
! nazmth       azimuthal array dimension (nazmth >= naz).
!
!             - work arrays -
! i_alpha      hines' integral at a single level.
! do_alpha     .true. for the azimuths and longitudes for
!                   which to continue to compute the drag above  
!                   the lowest level
    !
    ! internal variables.
    !
    INTEGER :: i, l, n, istart, lend, lincr, lbelow

    REAL*8    :: m_sub_m_turb, m_sub_m_mol, m_trial, mmsq
    REAL*8    :: visc, visc_min, sp1, f2mfac

    REAL*8    :: n_over_m(nlons), sigfac(nlons)

    !-----------------------------------------------------------------------     
    !

    visc_min = 1.e-10 

    sp1 = slope + 1.
    mmsq = m_min**2

    !
    !  indices of levels to process.
    !
    IF (levbot > levtop)  THEN
       istart = levbot - 1     
       lend   = levtop         
       lincr  = -1
    ELSE
       WRITE (nerr,*) ' Error: level index not increasing downward '
       CALL finish('hines_wavnum','Run terminated')
    END IF


    !   initialize logical flags and arrays
    DO l=1,nlevs
       losigma_t(:,l) = lorms(:)
    ENDDO
    DO n=1,nazmth
       do_alpha(:,n) = lorms(:)
    ENDDO

    sigsqh_alpha(:,:,:) = 0
    i_alpha(:,:) = 0.0

    !
    ! calculate azimuthal variances at bottom level using anisotropy factor
    !
    DO n = 1,naz
       DO i = il1,il2
          sigsqh_alpha(i,levbot,n) = anis(i,n)* rms_wind(i)**2
       END DO
    END DO
    !
    !  velocity variances at bottom level.
    !
    CALL hines_sigma ( sigma_t, sigma_alpha,     &
         &                   sigsqh_alpha, naz, levbot,     &
         &                   il1, il2, nlons, nlevs, nazmth)

    CALL hines_sigma ( sigmatm, sigalpmc,     &
         &                   sigsqmcw, naz, levbot,     &
         &                   il1, il2, nlons, nlevs, nazmth)
    !
    !  calculate cutoff wavenumber and spectral amplitude factor 
    !  at bottom level where it is assumed that background winds vanish
    !  and also initialize minimum value of cutoff wavnumber.
    !
    IF ( ABS(slope-1.) < EPSILON(1.) ) THEN
       DO n = 1,naz
          DO i = il1,il2
             IF (lorms(i)) THEN
                m_alpha(i,levbot,n) =  bvfb(i) /    &
                     &                             ( f1 * sigma_alpha(i,levbot,n)    &
                     &                             + f2 * sigma_t(i,levbot) )
                ak_alpha(i,n)   = 2. * sigsqh_alpha(i,levbot,n)    &
                     &                        / ( m_alpha(i,levbot,n)**2 - mmsq )
                mmin_alpha(i,n) = m_alpha(i,levbot,n)
             ENDIF
          END DO
       END DO
    ELSE
       DO n = 1,naz
          DO i = il1,il2
             IF (lorms(i)) THEN
                m_alpha(i,levbot,n) =  bvfb(i) /    & 
                     &                           ( f1 * sigma_alpha(i,levbot,n)    & 
                     &                           + f2 * sigma_t(i,levbot) )
                ak_alpha(i,n)   = sigsqh_alpha(i,levbot,n)    & 
                     &                      / ( m_alpha(i,levbot,n)**sp1 / sp1 )
                mmin_alpha(i,n) = m_alpha(i,levbot,n)
             ENDIF
          END DO
       END DO
    ENDIF
    !
    !  calculate quantities from the bottom upwards, 
    !  starting one level above bottom.
    !

    DO l = istart,lend,lincr
       !
       !  level beneath present level.
       !
       lbelow = l - lincr 
       !
       !  calculate n/m_m where m_m is maximum permissible value of the vertical
       !  wavenumber (i.e., m > m_m are obliterated) and n is buoyancy frequency.
       !  m_m is taken as the smaller of the instability-induced 
       !  wavenumber (m_sub_m_turb) and that imposed by molecular viscosity
       !  (m_sub_m_mol). since variance at this level is not yet known
       !  use value at level below.
       !

       DO i = il1,il2
          IF (losigma_t(i,lbelow))   THEN

             f2mfac=sigmatm(i,lbelow)**2
             f2mod(i,lbelow) =1.+ 2.*f2mfac  &
                  &                      / ( f2mfac+sigma_t(i,lbelow)**2 )

             visc = MAX ( visc_mol(i,l), visc_min )
             m_sub_m_turb = bvfreq(i,l)   &
                  &                 / ( f2 *f2mod(i,lbelow)*sigma_t(i,lbelow))
             m_sub_m_mol = (bvfreq(i,l)*kstar/visc)**0.33333333/f3

             IF (m_sub_m_turb < m_sub_m_mol)  THEN
                n_over_m(i) = f2 *f2mod(i,lbelow)*sigma_t(i,lbelow)
             ELSE
                n_over_m(i) = bvfreq(i,l) / m_sub_m_mol 
             END IF

          ENDIF
       END DO

       !
       !  calculate cutoff wavenumber at this level.
       !
       DO n = 1,naz
          DO i = il1,il2
             IF ( do_alpha(i,n) .AND. losigma_t(i,lbelow) ) THEN
                !
                !  calculate trial value (variance at this level is not yet known:
                !  use value at level below). if trial value negative or larger 
                !  minimum value (not permitted) then set it to minimum value. 
                !                                                                      
                m_trial = bvfb(i) / ( f1 * ( sigma_alpha(i,lbelow,n)+   & 
                     &       sigalpmc(i,lbelow,n)) + n_over_m(i) + v_alpha(i,l,n) )

                IF (m_trial <= 0. .OR. m_trial > mmin_alpha(i,n))  THEN
                   m_trial = mmin_alpha(i,n)
                END IF
                m_alpha(i,l,n) = m_trial

                !  do not permit cutoff wavenumber to be less than minimum  value.

                IF (m_alpha(i,l,n) < m_min) THEN
                   m_alpha(i,l,n) = m_min
                ENDIF
                !
                !  reset minimum value of cutoff wavenumber if necessary.
                !
                IF (m_alpha(i,l,n) < mmin_alpha(i,n))  THEN
                   mmin_alpha(i,n) = m_alpha(i,l,n)
                END IF
             ELSE

                m_alpha(i,l,n) = m_min

             ENDIF
          END DO
       END DO
       !
       !  calculate the hines integral at this level.
       !
       CALL hines_intgrl ( i_alpha,                                     &
            &              v_alpha, m_alpha, bvfb, m_min, slope, naz,   &
            &              l, il1, il2, nlons, nlevs, nazmth,           &
            &              lorms, do_alpha )

       !
       !  calculate the velocity variances at this level.
       !
       DO i = il1,il2
          sigfac(i) = densb(i) / density(i,l) * bvfreq(i,l) / bvfb(i) 
       END DO
       DO n = 1,naz
          DO i = il1,il2
             sigsqh_alpha(i,l,n) = sigfac(i) * ak_alpha(i,n) * i_alpha(i,n)
          END DO
       END DO
       CALL hines_sigma ( sigma_t, sigma_alpha, sigsqh_alpha, naz, l, &
            &                    il1, il2, nlons, nlevs, nazmth )

       CALL hines_sigma ( sigmatm, sigalpmc, sigsqmcw, naz, l,   &
            &                     il1, il2, nlons, nlevs, nazmth )

       !
       !  if total rms wind zero (no more drag) then set drag to false
       !
       DO i=il1,il2
          IF ( sigma_t(i,l) < EPSILON(1.) ) THEN
             losigma_t(i,l) = .FALSE.
          ENDIF
       ENDDO
       !
       !  end of level loop.
       !
    END DO
    !
    RETURN
    !-----------------------------------------------------------------------
  END SUBROUTINE hines_wavnum