MODULE NUMERICS use LAKE_DATATYPES, only : ireals, iintegers use NUMERIC_PARAMS, only : vector_length contains SUBROUTINE MATRIXSUM(a,b,c,k) implicit none !MATRIXES: C=A+B real(kind=ireals), dimension (vector_length,2,2)::a,b,c integer(kind=iintegers) k,j,i do j=1,2 do i=1,2 c(k,i,j)=a(k,i,j)+b(k,i,j) enddo enddo END SUBROUTINE MATRIXSUM SUBROUTINE MATRIXMULT(a,b,c,k) implicit none !MATRIXES: C=A*B real(kind=ireals), dimension (vector_length,2,2)::a,b,c integer(kind=iintegers) k c(k,1,1)=a(k,1,1)*b(k,1,1)+a(k,1,2)*b(k,2,1) c(k,1,2)=a(k,1,1)*b(k,1,2)+a(k,1,2)*b(k,2,2) c(k,2,1)=a(k,2,1)*b(k,1,1)+a(k,2,2)*b(k,2,1) c(k,2,2)=a(k,2,1)*b(k,1,2)+a(k,2,2)*b(k,2,2) END SUBROUTINE MATRIXMULT SUBROUTINE MATRIXMULTVECTOR(a,g,f,k) implicit none !MATRIX A, VECTORS g, f: Ag=f real(kind=ireals) a(vector_length,2,2),f(vector_length,2), & & g(vector_length,2) integer(kind=iintegers) k f(k,1)=a(k,1,1)*g(k,1)+a(k,1,2)*g(k,2) f(k,2)=a(k,2,1)*g(k,1)+a(k,2,2)*g(k,2) return END SUBROUTINE MATRIXMULTVECTOR SUBROUTINE VECTORSUM(a,b,c,k) implicit none !VECTORS: C=A+B real(kind=ireals), dimension(vector_length,2)::a,b,c integer(kind=iintegers) k c(k,1)=a(k,1)+b(k,1) c(k,2)=a(k,2)+b(k,2) END SUBROUTINE VECTORSUM SUBROUTINE INVERSMATRIX(a,a1,k) implicit none !MATRIXES: A1=A*(-1) real(kind=ireals), dimension(vector_length,2,2)::a,a1 integer(kind=iintegers) k a1(k,1,1)=a(k,2,2)/(a(k,1,1)*a(k,2,2)-a(k,1,2)*a(k,2,1)) a1(k,1,2)=-a(k,1,2)/(a(k,1,1)*a(k,2,2)-a(k,1,2)*a(k,2,1)) a1(k,2,1)=-a(k,2,1)/(a(k,1,1)*a(k,2,2)-a(k,1,2)*a(k,2,1)) a1(k,2,2)=a(k,1,1)/(a(k,1,1)*a(k,2,2)-a(k,1,2)*a(k,2,1)) END SUBROUTINE INVERSMATRIX SUBROUTINE MATRIXPROGONKA(a,b,c,d,y,N) !MATRIXPROGONKA solves the set of MATRIX three-point diference equations implicit none real(kind=ireals), dimension(vector_length,2,2):: a,b,c,x3,x32,x31,x4,alpha real(kind=ireals), dimension(vector_length,2):: y,d,x2,beta,x21 integer(kind=iintegers) N,i,j,k call INVERSMATRIX(c,x32,1) call MATRIXMULT(x32,b,x3,1) do j = 1, 2 do i = 1, 2 alpha(2,i,j) = x3(1,i,j) enddo enddo call MATRIXMULTVECTOR(x32,d,x2,1) do i = 1, 2 beta(2,i) = x2(1,i) enddo do k = 3, N CALL MATRIXMULT(A,ALPHA,X3,k-1) X4(k-1,1:2,1:2) = - X3(k-1,1:2,1:2) CALL MATRIXSUM(C,X4,X31,k-1) CALL INVERSMATRIX(X31,X32,k-1) CALL MATRIXMULT(X32,B,X3,k-1) do j = 1, 2 do i = 1, 2 alpha(k,i,j) = X3(k-1,i,j) enddo enddo !call matrixmult(x3,x31,x33,k-1) !call matrixsum(-b,x33,x3,k-1) CALL MATRIXMULTVECTOR(A,BETA,X2,K-1) CALL VECTORSUM(D,X2,X21,K-1) CALL MATRIXMULTVECTOR(X32,X21,X2,K-1) do i = 1, 2 beta(k,i) = X2(k-1,i) enddo enddo CALL MATRIXMULT(A,ALPHA,X3,N) X4(N,1:2,1:2) = - X3(N,1:2,1:2) CALL MATRIXSUM(C,X4,X31,N) CALL INVERSMATRIX(X31,X32,N) CALL MATRIXMULTVECTOR(A,BETA,X2,N) CALL VECTORSUM(D,X2,X21,N) CALL MATRIXMULTVECTOR(X32,X21,X2,N) do i = 1, 2 Y(N,i) = X2(N,i) enddo do k = N-1, 1, -1 CALL MATRIXMULTVECTOR(ALPHA,Y,X2,K+1) CALL VECTORSUM(X2,BETA,X21,K+1) Y(K,1) = X21(K+1,1) Y(K,2) = X21(K+1,2) enddo return END SUBROUTINE MATRIXPROGONKA real(kind=ireals) FUNCTION KRON(i,j) implicit none integer(kind=iintegers) i,j kron=0. if(i==j) kron=1. END FUNCTION SUBROUTINE IND_STAB_FACT_DB (a,b,c,N,M,ind_stab,ind_bound) implicit none real(kind=ireals), dimension(1:vector_length):: a,b,c integer(kind=iintegers) M,i,N logical ind_stab, ind_bound SAVE ind_stab=.true. if (ind_bound .eqv. .true.) then if (abs(b(N))>=abs(c(N)).or.abs(a(M))>=abs(c(M))) then ind_stab=.false. RETURN endif endif do i=N+1,M-1 if (abs(a(i))+abs(b(i))>=abs(c(i))) then ind_stab=.false. RETURN endif enddo END SUBROUTINE IND_STAB_FACT_DB LOGICAL FUNCTION CHECK_PROGONKA(N,a,b,c,d,y) !Function CHECK_PROGONKA checks the accuracy !of tridiagonal matrix system solution implicit none integer(kind=iintegers), intent(in):: N real(kind=ireals), intent(in):: a(1:N) real(kind=ireals), intent(in):: b(1:N) real(kind=ireals), intent(in):: c(1:N) real(kind=ireals), intent(in):: d(1:N) real(kind=ireals), intent(in):: y(1:N) real(kind=ireals), parameter:: del0 = 1.0d-13 real(kind=ireals) del integer(kind=iintegers) i del = 0.d0 del = max(c(1)*y(1)-b(1)*y(2)-d(1),del) del = max(c(N)*y(N)-a(N)*y(N-1)-d(N),del) do i = 2, N-1 del = max(-a(i)*y(i-1)+c(i)*y(i)-b(i)*y(i+1)-d(i),del) enddo CHECK_PROGONKA = del < del0 END FUNCTION CHECK_PROGONKA SUBROUTINE PROGONKA(a, b, c, f, y, K, N) implicit none !FACTORIZATION METHOD FOR THE FOLLOWING SYSTEM OF LINEAR EQUATIONS: !-a(i)*y(i-1)+c(i)*y(i)-b(i)*y(i+1)=f(i) i=K+1,N-1 ! c(K)*y(K)-b(K)*y(K+1)=f(K) !-a(N)*y(N-1)+c(N)*y(N)=f(N) ! integer(kind=iintegers), intent(in) :: K, N real(kind=ireals), intent(in) :: a(vector_length), b(vector_length), & & c(vector_length), f(vector_length) real(kind=ireals), intent(out) :: y(vector_length) real(kind=ireals) :: alpha(vector_length+2), beta(vector_length+2) integer(kind=iintegers) :: i SAVE alpha(K+1) = b(K)/c(K) beta(K+1) = f(K)/c(K) do i = K+2, N+1 alpha(i) = b(i-1)/(c(i-1)-a(i-1)*alpha(i-1)) beta(i) = (f(i-1)+a(i-1)*beta(i-1))/ & & (c(i-1)-a(i-1)*alpha(i-1)) end do y(N) = beta(N+1) do i = N-1, K, -1 y(i) = alpha(i+1)*y(i+1)+beta(i+1) end do END SUBROUTINE PROGONKA FUNCTION STEP(x) ! Heavyside (step) function of x implicit none real(kind=ireals) :: STEP real(kind=ireals), intent(in) :: x STEP = 0.5*(sign(1._ireals,x) + 1.) END FUNCTION STEP !>Function ACCUMSUM updates an accumulated mean FUNCTION ACCUMM(n,sum_nm1,xn) implicit none real(kind=ireals), intent(in) :: sum_nm1 !> mean over n-1 values real(kind=ireals), intent(in) :: xn !> n-th value of time series integer(kind=iintegers), intent(in) :: n real(kind=ireals) :: ACCUMM ACCUMM = ((n-1)*sum_nm1 + xn)/real(n) END FUNCTION ACCUMM REAL FUNCTION FindDet(matrix, n) IMPLICIT NONE REAL, DIMENSION(n,n) :: matrix INTEGER, INTENT(IN) :: n REAL :: m, temp INTEGER :: i, j, k, l LOGICAL :: DetExists = .TRUE. l = 1 !Convert to upper triangular form DO k = 1, n-1 IF (matrix(k,k) == 0) THEN DetExists = .FALSE. DO i = k+1, n IF (matrix(i,k) /= 0) THEN DO j = 1, n temp = matrix(i,j) matrix(i,j)= matrix(k,j) matrix(k,j) = temp END DO DetExists = .TRUE. l=-l EXIT ENDIF END DO IF (DetExists .EQV. .FALSE.) THEN FindDet = 0 return END IF ENDIF DO j = k+1, n m = matrix(j,k)/matrix(k,k) DO i = k+1, n matrix(j,i) = matrix(j,i) - m*matrix(k,i) END DO END DO END DO !Calculate determinant by finding product of diagonal elements FindDet = l DO i = 1, n FindDet = FindDet * matrix(i,i) END DO END FUNCTION FindDet !> Conservative second-order smoothing after Vreman, 2004 SUBROUTINE SMOOTHER_CONSERV(y,dx,N) implicit none !Input/output variables integer, intent(in) :: N real(kind=8), intent(inout) :: y(1:N) real(kind=8), intent(in) :: dx(0:N) !Local variables integer :: i real(kind=8), parameter :: gamma = 0.99 real(kind=8), allocatable :: x(:) real(kind=8) :: dxi, dxii, xx allocate(x(1:N)) dxi = 0.5*(dx(0) + dx(1)) dxii = 0.5*(dx(1) + dx(2)) xx = 0.5*(1-gamma)/dxi x(1) = xx*dx(1)*y(2) + (1. - xx*dx(1))*y(1) do i = 2, N-1 dxi = 0.5*(dx(i-1) + dx(i)) xx = 0.5*(1-gamma)/dxi x(i) = xx*dx(i-1)*y(i-1) + gamma*y(i) + xx*dx(i)*y(i+1) enddo dxi = 0.5*(dx(N-1) + dx(N)) dxii = 0.5*(dx(N-2) + dx(N-1)) xx = 0.5*(1-gamma)/dxi x(N) = xx*dx(N-1)*y(N-1) + (1.-xx*dx(N-1))*y(N) y(1:N) = x(1:N) deallocate(x) END SUBROUTINE SMOOTHER_CONSERV !************************************************************************ !* * !* Program to calculate the first kind modified Bessel function of * !* integer order N, for any REAL X, using the function BESSI(N,X). * !* * !* -------------------------------------------------------------------- * !* * !* SAMPLE RUN: * !* * !* (Calculate Bessel function for N=2, X=0.75). * !* * !* Bessel function of order 2 for X = 0.7500: * !* * !* Y = 0.73666878E-01 * !* * !* -------------------------------------------------------------------- * !* Reference: From Numath Library By Tuan Dang Trong in Fortran 77. * !* * !* F90 Release 1.2 By J-P Moreau, Paris. * !* (www.jpmoreau.fr) * !* * !* Version 1.1: corected value of P4 in BESSIO (P4=1.2067492 and not * !* 1.2067429) Aug. 2011. * !* Version 2: all variables are declared. * !************************************************************************ !PROGRAM TBESSI ! ! IMPLICIT NONE ! REAL*8 BESSI, X, Y ! INTEGER N ! ! N=2 ! X=0.75D0 ! ! Y = BESSI(N,X) ! ! write(*,10) N, X ! write(*,20) Y ! ! stop ! !10 format (/' Bessel Function of order ',I2,' for X=',F8.4,':') !20 format(/' Y = ',E15.8/) ! !END ! ---------------------------------------------------------------------- ! Auxiliary Bessel functions for N=0, N=1 FUNCTION BESSI0(X) IMPLICIT NONE REAL *8 X,BESSI0,Y,P1,P2,P3,P4,P5,P6,P7, & & Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9,AX,BX DATA P1,P2,P3,P4,P5,P6,P7/1.D0,3.5156229D0,3.0899424D0,1.2067492D0, & & 0.2659732D0,0.360768D-1,0.45813D-2/ DATA Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9/0.39894228D0,0.1328592D-1, & & 0.225319D-2,-0.157565D-2,0.916281D-2,-0.2057706D-1, & & 0.2635537D-1,-0.1647633D-1,0.392377D-2/ IF(ABS(X).LT.3.75D0) THEN Y=(X/3.75D0)**2 BESSI0=P1+Y*(P2+Y*(P3+Y*(P4+Y*(P5+Y*(P6+Y*P7))))) ELSE AX=ABS(X) Y=3.75D0/AX BX=EXP(AX)/SQRT(AX) AX=Q1+Y*(Q2+Y*(Q3+Y*(Q4+Y*(Q5+Y*(Q6+Y*(Q7+Y*(Q8+Y*Q9))))))) BESSI0=AX*BX ENDIF RETURN END ! ---------------------------------------------------------------------- FUNCTION BESSI1(X) IMPLICIT NONE REAL *8 X,BESSI1,Y,P1,P2,P3,P4,P5,P6,P7, & & Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9,AX,BX DATA P1,P2,P3,P4,P5,P6,P7/0.5D0,0.87890594D0,0.51498869D0, & & 0.15084934D0,0.2658733D-1,0.301532D-2,0.32411D-3/ DATA Q1,Q2,Q3,Q4,Q5,Q6,Q7,Q8,Q9/0.39894228D0,-0.3988024D-1, & & -0.362018D-2,0.163801D-2,-0.1031555D-1,0.2282967D-1, & & -0.2895312D-1,0.1787654D-1,-0.420059D-2/ IF(ABS(X).LT.3.75D0) THEN Y=(X/3.75D0)**2 BESSI1=X*(P1+Y*(P2+Y*(P3+Y*(P4+Y*(P5+Y*(P6+Y*P7)))))) ELSE AX=ABS(X) Y=3.75D0/AX BX=EXP(AX)/SQRT(AX) AX=Q1+Y*(Q2+Y*(Q3+Y*(Q4+Y*(Q5+Y*(Q6+Y*(Q7+Y*(Q8+Y*Q9))))))) BESSI1=AX*BX ENDIF RETURN END ! ---------------------------------------------------------------------- ! ---------------------------------------------------------------------- FUNCTION BESSI(N,X) ! ! This subroutine calculates the first kind modified Bessel function ! of integer order N, for any REAL X. We use here the classical ! recursion formula, when X > N. For X < N, the Miller's algorithm ! is used to avoid overflows. ! REFERENCE: ! C.W.CLENSHAW, CHEBYSHEV SERIES FOR MATHEMATICAL FUNCTIONS, ! MATHEMATICAL TABLES, VOL.5, 1962. ! IMPLICIT NONE INTEGER, PARAMETER :: IACC = 40 REAL*8, PARAMETER :: BIGNO = 1.D10, BIGNI = 1.D-10 INTEGER N, M, J REAL *8 X,BESSI,TOX,BIM,BI,BIP !,BESSI0,BESSI1 IF (N.EQ.0) THEN BESSI = BESSI0(X) RETURN ENDIF IF (N.EQ.1) THEN BESSI = BESSI1(X) RETURN ENDIF IF(X.EQ.0.D0) THEN BESSI=0.D0 RETURN ENDIF TOX = 2.D0/X BIP = 0.D0 BI = 1.D0 BESSI = 0.D0 M = 2*((N+INT(SQRT(FLOAT(IACC*N))))) DO 12 J = M,1,-1 BIM = BIP+DFLOAT(J)*TOX*BI BIP = BI BI = BIM IF (ABS(BI).GT.BIGNO) THEN BI = BI*BIGNI BIP = BIP*BIGNI BESSI = BESSI*BIGNI ENDIF IF (J.EQ.N) BESSI = BIP 12 CONTINUE BESSI = BESSI*BESSI0(X)/BI RETURN END END MODULE NUMERICS