375 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Fortran
		
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Fortran
		
	
	
	
| !
 | |
| !=======================================================================
 | |
| !
 | |
| MODULE CONFLUENT_HYPGEOM_REAL 
 | |
| !
 | |
| !  This module provides several subroutines to compute 
 | |
| !        the Gauss hypergeometric function 
 | |
| !
 | |
| !                      2F1(a,b,c;x)
 | |
| !
 | |
| !
 | |
| !                 -->            <--
 | |
| !                 -->   x real   <--
 | |
| !                 -->            <--
 | |
| !
 | |
| !
 | |
| !
 | |
| !   1)  SUBROUTINE HYGFX(A,B,C,X,HF)  
 | |
| !
 | |
| !   2)  SUBROUTINE HYP(Z,A,B,C,RE,IM)    
 | |
| !
 | |
| !
 | |
| !
 | |
|       USE ACCURACY_REAL
 | |
| !
 | |
| CONTAINS
 | |
| !
 | |
| !=======================================================================
 | |
| !
 | |
|       SUBROUTINE HYGFX(A,B,C,X,HF)
 | |
| !
 | |
| !  HYGFX computes the hypergeometric function F(a,b,c,x).
 | |
| !
 | |
| !  Licensing:
 | |
| !
 | |
| !    This routine is copyrighted by Shanjie Zhang and Jianming Jin.  However, 
 | |
| !    they give permission to incorporate this routine into a user program 
 | |
| !    provided that the copyright is acknowledged.
 | |
| !
 | |
| !  Modified:
 | |
| !
 | |
| !    04 April 2012
 | |
| !
 | |
| !  Author:
 | |
| !
 | |
| !    Shanjie Zhang, Jianming Jin
 | |
| !
 | |
| !  Reference:
 | |
| !
 | |
| !    Shanjie Zhang, Jianming Jin,
 | |
| !    Computation of Special Functions,
 | |
| !    Wiley, 1996,
 | |
| !    ISBN: 0-471-11963-6,
 | |
| !    LC: QA351.C45.
 | |
| ! 
 | |
| !  ==========================================================
 | |
| !
 | |
| !       Purpose: Compute hypergeometric function F(a,b,c,x)
 | |
| !
 | |
| !       Input :  A --- Parameter
 | |
| !                B --- Parameter
 | |
| !                C --- Parameter, C <> 0,-1,-2,...
 | |
| !                X --- Argument   (X < 1)
 | |
| !
 | |
| !       Output:  HF --- F(A,B,C,X)
 | |
| !
 | |
| !       Routines called:
 | |
| !            (1) GAMMA for computing gamma function
 | |
| !            (2) PSI for computing psi function
 | |
| !
 | |
| !  ==========================================================
 | |
| !
 | |
| !
 | |
| !                                     Last modified (DS) :  1 Sep 2020
 | |
| !
 | |
| !
 | |
|       USE REAL_NUMBERS,     ONLY : ZERO,ONE,TWO,HALF
 | |
|       USE PI_ETC,           ONLY : PI
 | |
|       USE GAMMA_FUNCTION,   ONLY : GAMMA
 | |
|       USE DIGAMMA_FUNCTION, ONLY : PSI
 | |
| !
 | |
|       IMPLICIT NONE
 | |
| !
 | |
|       INTEGER                ::  J,K,M,NM
 | |
| !
 | |
|       REAL (WP), INTENT(IN)  ::  C
 | |
|       REAL (WP)              ::  A,B,X
 | |
|       REAL (WP), INTENT(OUT) ::  HF
 | |
| !
 | |
|       REAL (WP)              ::  C0
 | |
|       REAL (WP)              ::  EPS
 | |
|       REAL (WP)              ::  G0,G1,G2,G3
 | |
|       REAL (WP)              ::  GC,R
 | |
|       REAL (WP)              ::  A0,AA,BB,C1
 | |
|       REAL (WP)              ::  F0,F1
 | |
|       REAL (WP)              ::  GA,GABC,GAM,GB,GBM,GCA,GCAB,GCB,GM
 | |
|       REAL (WP)              ::  HW
 | |
|       REAL (WP)              ::  PA,PB,R1,RM,RP
 | |
|       REAL (WP)              ::  SM,SP,SP0
 | |
|       REAL (WP)              ::  R0,X1
 | |
| !
 | |
|       REAL, PARAMETER        ::  EL = 0.5772156649015329E+00_WP
 | |
| !
 | |
|       LOGICAL                ::  L0,L1,L2,L3,L4,L5
 | |
| !
 | |
|       L0 = C == INT(C) .AND. C < ZERO                               !
 | |
|       L1 = ONE - X < 1.0E-15_WP .AND. C - A - B <= ZERO             !
 | |
|       L2 = A == INT(A) .AND. A < ZERO                               !
 | |
|       L3 = B == INT(B) .AND. B < ZERO                               !
 | |
|       L4 = C - A == INT(C - A) .AND. C - A <= ZERO                  !
 | |
|       L5 = C - B == INT(C - B) .AND. C - B <= ZERO                  !
 | |
| !
 | |
|       IF(L0 .OR. L1) THEN                                           !
 | |
|         WRITE(6,110)                                                !
 | |
|         WRITE(6,111)                                                !
 | |
|         WRITE(6,112)                                                !
 | |
|         STOP                                                        !
 | |
|       END IF                                                        !
 | |
| !
 | |
|       IF(0.95E+00_WP < X) THEN                                      !
 | |
|         EPS = 1.0E-08_WP                                            !
 | |
|       ELSE                                                          !
 | |
|         EPS = 1.0E-15_WP                                            !
 | |
|       END IF                                                        !
 | |
| !
 | |
|       IF(X == ZERO .OR. A == ZERO .OR. B == ZERO) THEN              !
 | |
|         HF = ONE                                                    !
 | |
|         RETURN                                                      !
 | |
|       ELSE IF(ONE - X == EPS .AND. ZERO < C - A - B) THEN           !
 | |
|         CALL GAMMA(C, GC)                                           !
 | |
|         CALL GAMMA(C - A - B, GCAB)                                 !
 | |
|         CALL GAMMA(C - A, GCA)                                      !
 | |
|         CALL GAMMA(C - B, GCB)                                      !
 | |
|         HF = GC * GCAB / (GCA * GCB)                                !
 | |
|         RETURN                                                      !
 | |
|       ELSE IF(ONE + X <= EPS .AND.                                & !
 | |
|               DABS(C - A + B -ONE) <= EPS) THEN                     !
 | |
|         G0 = DSQRT(PI) * TWO ** (- A)                               !
 | |
|         CALL GAMMA(C, G1)                                           !
 | |
|         CALL GAMMA(ONE + A / TWO - B, G2)                           !
 | |
|         CALL GAMMA(HALF + HALF * A, G3)                             !
 | |
|         HF = G0 * G1 / (G2 * G3)                                    !
 | |
|         RETURN                                                      !
 | |
|       ELSE IF(L2 .OR. L3) THEN                                      !
 | |
|         IF(L2) THEN                                                 !
 | |
|           NM = INT(DABS(A))                                         !
 | |
|         END IF                                                      !
 | |
|         IF(L3) THEN                                                 !
 | |
|           NM = INT(DABS(B))                                         !
 | |
|         END IF                                                      !
 | |
|         HF = ONE                                                    !
 | |
|         R  = ONE                                                    !
 | |
|         DO K = 1, NM                                                !
 | |
|           R = R * (A + K - ONE) * (B + K - ONE) /                 & !
 | |
|              (K * (C + K - ONE)) * X                                !
 | |
|           HF = HF + R                                               !
 | |
|         END DO                                                      !
 | |
|         RETURN                                                      !
 | |
|       ELSE IF(L4 .OR. L5) THEN                                      !
 | |
|         IF(L4) THEN                                                 !
 | |
|           NM = INT(DABS(C - A))                                     !
 | |
|         END IF                                                      !
 | |
|         IF(L5) THEN                                                 !
 | |
|           NM = INT(DABS(C - B))                                     !
 | |
|         END IF                                                      !
 | |
|         HF = ONE                                                    !
 | |
|         R  = ONE                                                    !
 | |
|         DO K = 1, NM                                                !
 | |
|           R = R * (C - A + K - ONE) * (C - B + K - ONE) /         & !
 | |
|              (K * (C + K - ONE)) * X                                !
 | |
|           HF = HF + R                                               !
 | |
|         END DO                                                      !
 | |
|         HF = (ONE - X) ** (C - A - B) * HF                          !
 | |
|         RETURN                                                      !
 | |
|       END IF                                                        !
 | |
| !
 | |
|       AA = A                                                        !
 | |
|       BB = B                                                        !
 | |
|       X1 = X                                                        !
 | |
| !
 | |
|       IF(X < ZERO) THEN                                             !
 | |
|         X = X / (X - ONE)                                           !
 | |
|         IF(A < C .AND. B < A .AND. ZERO < B) THEN                   !
 | |
|           A = BB                                                    !
 | |
|           B = AA                                                    !
 | |
|         END IF                                                      !
 | |
|         B = C - B                                                   !
 | |
|       END IF                                                        !
 | |
| !
 | |
|       IF(0.75E+00_WP <= X) THEN                                     !
 | |
|         GM = ZERO                                                   !
 | |
|         IF(DABS(C - A - B - INT(C - A - B)) < 1.0E-15_WP) THEN      !
 | |
|           M = INT(C - A - B)                                        !
 | |
|           CALL GAMMA(A, GA)                                         !
 | |
|           CALL GAMMA(B, GB)                                         !
 | |
|           CALL GAMMA(C, GC)                                         !
 | |
|           CALL GAMMA(A + M, GAM)                                    !
 | |
|           CALL GAMMA(B + M, GBM)                                    !
 | |
|           CALL PSI(A, PA)                                           !
 | |
|           CALL PSI(B, PB)                                           !
 | |
|           IF(M .NE. 0) THEN                                         !
 | |
|             GM = ONE                                                !
 | |
|           END IF                                                    !
 | |
|           DO J = 1, ABS (M) - 1                                     !
 | |
|             GM = GM * J                                             !
 | |
|           END DO                                                    !
 | |
|           RM = ONE                                                  !
 | |
|           DO J = 1, ABS (M)                                         !
 | |
|             RM = RM * J                                             !
 | |
|           END DO                                                    !
 | |
|           F0  = ONE                                                 !
 | |
|           R0  = ONE                                                 !
 | |
|           R1  = ONE                                                 !
 | |
|           SP0 = ZERO                                                !
 | |
|           SP  = ZERO                                                !
 | |
|           IF(0 <= M) THEN                                           !
 | |
|             C0 = GM * GC / (GAM * GBM)                              !
 | |
|             C1 = - GC * (X - ONE) ** M / (GA * GB * RM)             !
 | |
|             DO K = 1, M - 1                                         !
 | |
|               R0 = R0 * (A + K - ONE) * (B + K - ONE) /           & !
 | |
|                   (K * (K - M)) * (ONE - X)                         !
 | |
|               F0 = F0 + R0                                          !
 | |
|             END DO                                                  !
 | |
| !
 | |
|             DO K = 1, M                                             !
 | |
|               SP0 = SP0 + ONE / (A + K - ONE) +                   & !
 | |
|                     ONE / (B + K - ONE) - ONE / K                   !
 | |
|             END DO                                                  !
 | |
| !
 | |
|             F1 = PA + PB + SP0 + TWO * EL + DLOG(ONE - X)           !
 | |
| !
 | |
|             DO K = 1, 250                                           !
 | |
|               SP = SP + (ONE - A) / (K * (A + K - ONE)) +         & !
 | |
|                   (ONE - B) / (K * (B + K - ONE))                   !
 | |
|               SM = ZERO                                             !
 | |
|               DO J = 1,M                                            !
 | |
|                 SM = SM + (ONE - A) / ((J + K) *                  & !
 | |
|                      (A + J + K - ONE)) + ONE /                   & !
 | |
|                      (B + J + K - ONE)                              !
 | |
|               END DO                                                !
 | |
|               RP = PA + PB + TWO * EL + SP + SM + DLOG(ONE - X)     !
 | |
|               R1 = R1 * (A + M + K - ONE) * (B + M + K - ONE) /   & !
 | |
|                         (K * (M + K)) * (ONE - X)                   !
 | |
|               F1 = F1 + R1 * RP                                     !
 | |
|               IF(DABS(F1 - HW) < DABS(F1) * EPS) THEN               !
 | |
|                 GO TO 10                                            ! 
 | |
|               END IF                                                !
 | |
|               HW = F1                                               !
 | |
|             END DO                                                  !
 | |
| !
 | |
|   10        CONTINUE
 | |
| !
 | |
|             HF = F0  *C0 + F1 * C1                                  !
 | |
| !
 | |
|           ELSE IF(M < 0) THEN                                       !
 | |
| !
 | |
|             M  = - M                                                !
 | |
|             C0 = GM * GC / (GA * GB * (ONE - X)**M)                 !
 | |
|             C1 = - (-1)**M * GC / (GAM * GBM * RM)                  !
 | |
| !
 | |
|                  DO K = 1,M-1                                       !
 | |
|                     R0 = R0 * (A - M + K - ONE) *                 & !
 | |
|                               (B - M + K - ONE) /                 & !
 | |
|                               (K * (K - M)) * (ONE - X)             !
 | |
|                     F0 = F0 + R0                                    !
 | |
|                  END DO                                             !
 | |
| !
 | |
|                  DO K = 1,M                                         !
 | |
|                    SP0 = SP0 + ONE / K                              !
 | |
|                  END DO                                             !
 | |
|                  F1 = PA + PB - SP0 + TWO * EL + DLOG(ONE - X)      !
 | |
|                  DO K = 1,250                                       !
 | |
|                     SP = SP + (ONE - A) / (K * (A + K - ONE)) +   & !
 | |
|                               (ONE - B) / (K * (B + K - ONE))       !
 | |
|                     SM = ZERO                                       !
 | |
|                     DO J = 1,M                                      !
 | |
|                       SM = SM+ ONE /(J + K)                         !
 | |
|                     END DO                                          !
 | |
|                     RP = PA + PB + TWO * EL + SP - SM +           & !
 | |
|                          DLOG(ONE - X)                              !
 | |
|                     R1 = R1 * (A + K - ONE) * (B + K - ONE) /     & !
 | |
|                               (K * (M + K)) * (ONE - X)             !
 | |
|                     F1 = F1 + R1 * RP                               !
 | |
|                     IF(DABS(F1 - HW) < DABS(F1) * EPS) THEN         !
 | |
|                       GO TO 20                                      !
 | |
|                     END IF                                          !
 | |
|                     HW = F1                                         !
 | |
|                  END DO                                             !
 | |
| !
 | |
|   20             CONTINUE                                           !
 | |
| !
 | |
|                  HF = F0 * C0 + F1 * C1                             !
 | |
|               END IF                                                !
 | |
|            ELSE                                                     !
 | |
|               CALL GAMMA(A,GA)                                      !
 | |
|               CALL GAMMA(B,GB)                                      !
 | |
|               CALL GAMMA(C,GC)                                      !
 | |
|               CALL GAMMA(C-A,GCA)                                   !
 | |
|               CALL GAMMA(C-B,GCB)                                   !
 | |
|               CALL GAMMA(C-A-B,GCAB)                                !
 | |
|               CALL GAMMA(A+B-C,GABC)                                !
 | |
|               C0 = GC * GCAB / (GCA * GCB)                          !
 | |
|               C1 = GC * GABC / (GA * GB) * (ONE - X)**(C - A - B)   !
 | |
|               HF = ZERO                                             !
 | |
|               R0 = C0                                               !
 | |
|               R1 = C1                                               !
 | |
|               DO K = 1,250                                          !
 | |
|                  R0 = R0 * (A + K - ONE) * (B + K - ONE) /        & !
 | |
|                            (K * (A + B - C + K)) * (ONE - X)        !
 | |
|                  R1 = R1 * (C - A + K - ONE) * (C - B + K - ONE) /& !
 | |
|                            (K * (C - A - B + K)) * (ONE - X)        !
 | |
|                  HF = HF + R0 + R1                                  !
 | |
|                  IF(DABS(HF - HW) < DABS(HF) * EPS) THEN            !
 | |
|                    GO TO 30                                         !
 | |
|                  END IF                                             !
 | |
|                  HW = HF                                            !
 | |
|               END DO                                                !
 | |
| !
 | |
|   30          CONTINUE                                              !
 | |
| !
 | |
|               HF = HF + C0 + C1                                     !
 | |
| !
 | |
|            END IF                                                   !
 | |
|         ELSE                                                        !
 | |
|            A0 = ONE                                                 !
 | |
|            IF(C > A .AND. C < TWO * A .AND.                       & !
 | |
|               C > B .AND. C < TWO*B) THEN                           !
 | |
|               A0 = (ONE - X) ** (C - A - B)                         !
 | |
|               A  = C - A                                            !
 | |
|               B  = C - B                                            !
 | |
|            END IF                                                   !
 | |
|            HF = ONE                                                 !
 | |
|            R  = ONE                                                 !
 | |
|            DO K = 1,250                                             !
 | |
|               R  = R *(A + K - ONE) * (B + K - ONE) /             & !
 | |
|                       (K * (C + K - ONE)) * X                       !
 | |
|               HF = HF + R                                           !
 | |
|               IF(DABS(HF - HW) <= DABS(HF) * EPS) THEN              !
 | |
|                 GO TO 40                                            !
 | |
|               END IF                                                !
 | |
|               HW = HF                                               !
 | |
|            END DO                                                   !
 | |
| !
 | |
|   40       CONTINUE                                                 !
 | |
| !
 | |
|            HF = A0 * HF                                             !
 | |
| !
 | |
|       END IF                                                        !
 | |
| !
 | |
|       IF(X1 < ZERO) THEN                                            !
 | |
|         X = X1                                                      !
 | |
|         C0 = ONE / (ONE - X) ** AA                                  !
 | |
|         HF = C0 * HF                                                !
 | |
|       END IF
 | |
| !
 | |
|       A = AA                                                        !
 | |
|       B = BB                                                        !
 | |
| !
 | |
|       IF(120 < K) THEN                                              !
 | |
|         WRITE(*,115)                                                !
 | |
|       END IF                                                        !
 | |
| !
 | |
| !  Formats:
 | |
| !
 | |
|  110  FORMAT(' ')
 | |
|  111  FORMAT('HYGFX - Fatal error!')
 | |
|  112  FORMAT('The hypergeometric series is divergent.')
 | |
|  115    FORMAT('Warning! You should check the accuracy')
 | |
| !
 | |
|       RETURN                                                        !
 | |
| !
 | |
|       END SUBROUTINE HYGFX
 | |
| !
 | |
| END MODULE CONFLUENT_HYPGEOM_REAL
 |