!
!=======================================================================
!
MODULE SPECIFIC_INT_8
!
!  This module provides integrals to compute the real part 
!    of the dielectric function
!
!
      USE ACCURACY_REAL
      USE ACCURACY_INTEGER
      USE MINMAX_VALUES
!
CONTAINS
!
!=======================================================================
!
      SUBROUTINE INT_ARB(X,A,B,INTG)
!
!  This subroutine computes an integral often used 
!   to compute the real part of the dielectric function
!
!
!  Reference: (1) N. R. Arista and W. Brandt, Phys. Rev. A 29,
!                     1471-1480 (1984)
!             (2) M. D. Barriga-Carrasco, Phys. Rev. E 76, 016405 (2007)
!
! 
!
!  Input parameters:
!
!       * X        : dimensionless parameter
!       * A        : parameter of the exponential
!       * B        : parameter of the exponential
!
!  Output parameters:
!
!       * INTG     : integral 1
!
!
!
!
!                / INF
!               |            y                  | x + y |
!  INTG    =    |      -------------------  Log |-------|  dy
!               |       exp(A y^2 - B) + 1      | x - y | 
!              / 0
!
!
!
!  Warning: the integrand becomes infinite when y = x. We correct 
!           this problem by making a linear interpolation at this value
!
!  Warning: the exponential can come quickly too large or too small 
!           to be represented. We need to test it exponent against 
!           MAX_EXP and MIN_EXP which represents the limits of the 
!           representation of e^x for real numbers of kind WP
!
!
!  Note: If x < 0, then INTG (x) = - INTG (-x)
!        so, we compute the integral only for z = |x|
! 
!
!
!   Author :  D. Sébilleau
!
!                                           Last modified :  9 Nov 2020
!
!
      USE REAL_NUMBERS,             ONLY : ZERO,ONE,TWO,HALF,SMALL,LARGE,TTINY,INF,MIC
      USE INTEGRATION,              ONLY : INTEGR_L
!
      IMPLICIT NONE
!
      INTEGER (IW), PARAMETER ::  N_I = 1000            ! number of integration steps
!
      INTEGER (IW)            ::  I                     ! loop index
      INTEGER (IW)            ::  I0                    ! pathological index
      INTEGER (IW)            ::  ID                    ! integration variable
      INTEGER (IW)            ::  ISGN                  ! sign of X
!
      REAL (WP), INTENT(IN)   ::  X,A,B
      REAL (WP), INTENT(OUT)  ::  INTG
!
      REAL (WP)               ::  MAX_EXP,MIN_EXP
      REAL (WP)               ::  Z
      REAL (WP)               ::  Y_MIN,Y_MAX,Y_STEP
      REAL (WP)               ::  Y,Y2
      REAL (WP)               ::  F(N_I)
      REAL (WP)               ::  INTGR
      REAL (WP)               ::  AYB,LN,DEN,LNN
!
      REAL (WP)               ::  FLOAT,LOG,ABS,EXP
!
!  Computing the max and min value of the exponent of e^x
!
      CALL MINMAX_EXP(MAX_EXP,MIN_EXP)                              !
!
      ID = 1                                                        ! integrand = 0 at 0
!
      I0 = 0                                                        ! counter for pathological case
!
      IF(X < ZERO) THEN                                             !
        Z    = - X                                                  !
        ISGN = - 1                                                  !
      ELSE                                                          !
        Z    =   X                                                  !
        ISGN =   1                                                  !
      END IF                                                        !
!
      Y_MIN  = 0.010E0_WP                                           !
      Y_MAX  = 4.0E0_WP                                             !
      Y_STEP = (Y_MAX - Y_MIN) / FLOAT(N_I - 1)                     !
!
!  Initialization of integrand function
!
      DO I = 1, N_I                                                 !
        F(I) = TTINY                                                !
      END DO                                                        !
!
!  Computing the integrand function
!
      DO I = 1, N_I                                                 !
!
        Y  = Y_MIN + FLOAT(I - 1) * Y_STEP                          !
        Y2 = Y * Y                                                  !
!
        AYB = A * Y2 - B                                            ! exponent of denominator
!
!  Evaluation of the denominator
!
        IF(AYB >= ZERO) THEN                                        !
          IF(AYB < MAX_EXP) THEN                                    !
            DEN = EXP(AYB) + ONE                                    !
          ELSE                                                      !
            DEN = LARGE                                             ! <-- e^{ayb} too large for being represented
          END IF                                                    !
        ELSE                                                        !
          IF(AYB > MIN_EXP) THEN                                    !
            DEN = EXP(AYB) + ONE                                    !
          ELSE                                                      !
            DEN = ONE                                               ! <-- e^{ayb} too small for being represented
          END IF                                                    !
        END IF                                                      !
!        
!  Evaluation of the logarithm (note: z always >= 0)
!
        IF(ABS(Z - Y) <= SMALL) THEN                                !
          LN = LARGE                                                ! <-- logarithm infinite
        ELSE                                                        !
          LN = LOG( ABS( (Z + Y) / (Z - Y) ) )                      !
        END IF                                                      !
!
!  Case where calculation is not done 
!
        IF(LN == INF) THEN                                          !
          F(I) = LARGE                                              !
          I0   = I                                                  !
          GO TO 10                                                  !
        END IF                                                      !
!
        IF(DEN == INF) THEN                                         !
          F(I) = TTINY                                              !
        ELSE                                                        !
!
!  Checking if LN/DEN can be represented
!
!
          LNN = LOG(LN) - LOG(DEN)                                  !
          IF(LNN >= ZERO) THEN                                      !
            IF(LNN < MAX_EXP / Y2) THEN                             !
              F(I) = Y * LN / DEN                                   !
            ELSE                                                    !
              F(I) = LARGE                                          !
            END IF                                                  !
          ELSE                                                      !          
            IF(LNN > MIN_EXP / Y2) THEN                             !
              F(I) = Y * LN / DEN                                   !
            ELSE                                                    !
              F(I)= TTINY                                           !
            END IF                                                  !
          END IF
!
        END IF                                                      !
!
  10    CONTINUE
!
      END DO                                                        !
!
!  Correcting the pathological values
!      through linear interpolation
!
      IF(I0 /= 0) THEN                                              !
        IF(I0 == 1) THEN                                            !
          F(I0) = TWO * F(I0+1) - F(I0+2)                           !
        ELSE IF (I0 == N_I) THEN                                    !
          F(I0) = TWO * F(I0-1) - F(I0-2)                           !
        ELSE                                                        !
          F(I0) = HALF * (F(I0-1) + F(I0+1))                        !
        END IF                                                      !
      END IF                                                        !
!
!  Computing the integral
!
      CALL INTEGR_L(F,Y_STEP,N_I,N_I,INTGR,ID)                      !  
!
!  Final result
!
      IF(ISGN == 1) THEN                                            !
        INTG =   INTGR                                              !
      ELSE                                                          !
        INTG = - INTGR                                              !
      END IF                                                        !
!
      END SUBROUTINE INT_ARB
!
END MODULE SPECIFIC_INT_8
