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

  SUBROUTINE hines_intgrl (i_alpha,                                     & 1,3
       &                   v_alpha, m_alpha, bvfb, m_min, slope, naz,   &
       &                   lev, il1, il2, nlons, nlevs, nazmth,         &
       &                   lorms, do_alpha)

    USE mo_doctor,     ONLY: nout, nerr
    USE mo_exception,  ONLY: finish 


    IMPLICIT NONE

    INTEGER  lev, naz, il1, il2, nlons, nlevs, nazmth
    REAL*8  i_alpha(nlons,nazmth)
    REAL*8  v_alpha(nlons,nlevs,nazmth)
    REAL*8  m_alpha(nlons,nlevs,nazmth)
    REAL*8  bvfb(nlons), rbvfb(nlons), slope, m_min

    LOGICAL lorms(nlons), do_alpha(nlons,nazmth)
    LOGICAL lerror(nlons)
!
!Authors
!
!  aug. 8/95 - c. mclandress
!  2001      - m. charron
!  2003      - l. kornblueh
!
!Revision
!
!Modules
!
! mo_doctor
! mo_exception
!
!Object
!
!  This routine calculates the vertical wavenumber integral
!  for a single vertical level at each azimuth on a longitude grid
!  for the hines' doppler spread gwd parameterization scheme.
!  note: (1) only spectral slopes of 1, 1.5 or 2 are permitted.
!        (2) the integral is written in terms of the product qm
!            which by construction is always less than 1. series
!            solutions are used for small |qm| and analytical solutions
!            for remaining values.
!
!           - Output -
! i_alpha   hines' integral.
!
!           - Input -
! v_alpha   azimuthal wind component (m/s). 
! m_alpha   azimuthal cutoff vertical wavenumber (1/m).
! bvfb      background brunt vassala frequency at model bottom.
! m_min     minimum allowable cutoff vertical wavenumber (1/m)
!           for spectral slope of one.
! slope     slope of initial vertical wavenumber spectrum 
!           (must use slope = 1., 1.5 or 2.)
! naz       actual number of horizontal azimuths used.
! lev       altitude level to process.
! 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).
! lorms     .true. for drag computation (column selector)
!
!  constants in data statements:
!
! qmin = minimum value of q_alpha (avoids indeterminant form of integral)
! qm_min = minimum value of q_alpha * m_alpha (used to avoid numerical
!          problems).
!

    !
    !  internal variables.
    !
    INTEGER  i, n
    REAL*8  q_alpha, qm, qmm, sqrtqm, q_min, qm_min
    REAL*8  zero

    !  variables for sparse vector optimization
    INTEGER ic, ixi(nlons*nazmth), ix, ixnaz(nlons*nazmth)

    !-----------------------------------------------------------------------
    !
    !  initialize local scalar and arrays

    zero=0.
    q_min = 1.0 
    qm_min = 0.01 

    DO i = il1,il2
      rbvfb(i)=1.0/bvfb(i)
    ENDDO
    !
    !  for integer value slope = 1.
    !
    IF ( ABS(slope-1.) < EPSILON(1.) )  THEN
       ic = 0
       DO n = 1,naz
          DO i = il1,il2
             IF (lorms(i)) THEN
                ! 
                IF (m_alpha(i,lev,n) > m_min) THEN
                   q_alpha = v_alpha(i,lev,n) * rbvfb(i)
                   qm      = q_alpha * m_alpha(i,lev,n)
                   qmm     = q_alpha * m_min
                   !
                   !  if |qm| is small then use first 4 terms series of taylor
                   !  series expansion of integral in order to avoid 
                   !  indeterminate form of integral,
                   !  otherwise use analytical form of integral.
                   !
                   IF ( ABS(q_alpha) .LT. q_min .OR. ABS(qm).LT. qm_min)  THEN
                      ! taylor series expansion is a very rare event.
                      ! do sparse processing separately
                      ic = ic+1
                      ixi(ic) = i
                      ixnaz(ic) = n
                   ELSE
                      i_alpha(i,n) = - ( LOG(1.-qm) - LOG(1.-qmm) + qm - qmm) / q_alpha**2
                   END IF
                   !
                   !  If i_alpha negative due to round off error, set it to zero
                   !
                   i_alpha(i,n) = MAX( i_alpha(i,n) , zero )
                ELSE
                   i_alpha(i,n) = 0.
                   do_alpha(i,n) = .FALSE.
                ENDIF
                !
             ENDIF
          END DO
       END DO
       ! taylor series expansion is a very rare event.
       ! do sparse processing here separately 
       DO ix =1, ic
          n = ixnaz(ix)
          i = ixi(ix)
          q_alpha = v_alpha(i,lev,n) * rbvfb(i)
          qm      = q_alpha * m_alpha(i,lev,n)
          qmm     = q_alpha * m_min
          IF ( ABS(q_alpha) < EPSILON(1.) )  THEN
             i_alpha(i,n) = ( m_alpha(i,lev,n)**2  - m_min**2 ) / 2.
          ELSE
             i_alpha(i,n) = ( qm**2/2.  + qm**3/3.  + qm**4/4.  + qm**5/5.    &
                 - qmm**2/2. - qmm**3/3. - qmm**4/4. - qmm**5/5. ) &
                 / q_alpha**2
          END IF
          i_alpha(i,n) = MAX( i_alpha(i,n) , zero )
       END DO
    END IF
    !
    !  for integer value slope = 2.
    !
    IF ( ABS(slope-2.) < EPSILON(1.) )  THEN
       ic = 0
       DO n = 1,naz
          DO i = il1,il2
             IF ( lorms(i) ) THEN
                !
                q_alpha = v_alpha(i,lev,n) * rbvfb(i)
                qm = q_alpha * m_alpha(i,lev,n)
                !
                !  if |qm| is small then use first 4 terms series of taylor 
                !  series expansion of integral in order to avoid 
                !  indeterminate form of integral,
                !  otherwise use analytical form of integral.
                !
                IF ( ABS(q_alpha) .LT. q_min .OR. ABS(qm) .LT. qm_min)  THEN  
                   ! taylor series expansion is a very rare event.
                   ! do sparse processing separately
                   ic = ic+1
                   ixi(ic) = i
                   ixnaz(ic) = n
                ELSE
                   i_alpha(i,n) = - ( LOG(1.-qm) + qm + qm**2/2.)    &
                        / q_alpha**3
                ENDIF
                !
             ENDIF
          END DO
       END DO
       ! taylor series expansion is a very rare event.
       ! do sparse processing here separately 
       DO ix = 1, ic
          n = ixnaz(ix)
          i = ixi(ix)
          q_alpha = v_alpha(i,lev,n) * rbvfb(i)
          qm = q_alpha * m_alpha(i,lev,n)
          IF ( ABS(q_alpha) < EPSILON(1.) )  THEN
             i_alpha(i,n) = m_alpha(i,lev,n)**3 / 3.
          ELSE
             i_alpha(i,n) = ( qm**3/3. + qm**4/4. + qm**5/5.    &
               + qm**6/6. ) / q_alpha**3
           END IF
       END DO
    END IF
    !
    !  for real value slope = 1.5
    !
    IF ( ABS(slope-1.5) < EPSILON(1.) )  THEN
       ic = 0 
       DO n = 1,naz
          DO i = il1,il2
             IF ( lorms(i) ) THEN
                !
                q_alpha = v_alpha(i,lev,n) * rbvfb(i)
                qm = q_alpha * m_alpha(i,lev,n)       
                !
                !  if |qm| is small then use first 4 terms series of taylor 
                !  series expansion of integral in order to avoid 
                !  indeterminate form of integral,
                !  otherwise use analytical form of integral.
                !
                IF (ABS(q_alpha) .LT. q_min .OR. ABS(qm) .LT. qm_min)  THEN  
                   ! taylor series expansion is a very rare event.
                   ! do sparse processing separately
                   ic = ic+1
                   ixi(ic) = i
                   ixnaz(ic) = n
                ELSE
                   qm     = ABS(qm)
                   sqrtqm = SQRT(qm)
                   IF (q_alpha .GE. 0.)  THEN
                      i_alpha(i,n) = ( LOG( (1.+sqrtqm)/(1.-sqrtqm) )  &
                           &                          -2.*sqrtqm*(1.+qm/3.) ) / q_alpha**2.5
                   ELSE
                      i_alpha(i,n) = 2. * ( ATAN(sqrtqm) + sqrtqm*(qm/3.-1.) ) &
                           &                          / ABS(q_alpha)**2.5
                   ENDIF
                ENDIF
                !
             ENDIF
          END DO
       END DO
       ! taylor series expansion is a very rare event.
       ! do sparse processing here separately 
       DO ix = 1, ic
          n = ixnaz(ix)
          i = ixi(ix)
          q_alpha = v_alpha(i,lev,n) * rbvfb(i)
          qm = q_alpha * m_alpha(i,lev,n)   
          IF ( ABS(q_alpha) < EPSILON(1.) )  THEN
             i_alpha(i,n) = m_alpha(i,lev,n)**2.5 / 2.5
          ELSE
             i_alpha(i,n) = ( qm/2.5 + qm**2/3.5   &
                  + qm**3/4.5 + qm**4/5.5 )   &
                  * m_alpha(i,lev,n)**1.5 / q_alpha
          END IF
       ENDDO
    END IF
    !
    !  if integral is negative (which in principal should not happen) then
    !  print a message and some info since execution will abort when calculating
    !  the variances.
    !
    DO n = 1,naz
       lerror(:) = .FALSE.
       DO i = il1, il2
          IF (i_alpha(i,n) < 0.)  THEN
             lerror(i) = .TRUE.
             EXIT 
          END IF
       END DO

       IF (ANY(lerror)) THEN
          WRITE (nout,*) 
          WRITE (nout,*) '******************************'
          WRITE (nout,*) 'hines integral i_alpha < 0 '
          WRITE (nout,*) '  longitude i=',i
          WRITE (nout,*) '  azimuth   n=',n
          WRITE (nout,*) '  level   lev=',lev
          WRITE (nout,*) '  i_alpha =',i_alpha(i,n)
          WRITE (nout,*) '  v_alpha =',v_alpha(i,lev,n)
          WRITE (nout,*) '  m_alpha =',m_alpha(i,lev,n)
          WRITE (nout,*) '  q_alpha =',v_alpha(i,lev,n)*rbvfb(i)
          WRITE (nout,*) '  qm      =',v_alpha(i,lev,n)*rbvfb(i)*m_alpha(i,lev,n)
          WRITE (nout,*) '******************************'
          WRITE (nerr,*) ' Error: Hines i_alpha integral is negative  '
          CALL finish(' hines_intgrl','Run terminated')
       END IF
  
    END DO

    RETURN
    !-----------------------------------------------------------------------
  END SUBROUTINE hines_intgrl