Path: blob/devel/elmerice/Solvers/Covarianceutils/CovarianceUtils.F90
3206 views
!/*****************************************************************************/1! *2! * Elmer/Ice, a glaciological add-on to Elmer3! * http://elmerice.elmerfem.org4! *5! *6! * This program is free software; you can redistribute it and/or7! * modify it under the terms of the GNU General Public License8! * as published by the Free Software Foundation; either version 29! * of the License, or (at your option) any later version.10! *11! * This program is distributed in the hope that it will be useful,12! * but WITHOUT ANY WARRANTY; without even the implied warranty of13! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14! * GNU General Public License for more details.15! *16! * You should have received a copy of the GNU General Public License17! * along with this program (in file fem/GPL-2); if not, write to the18! * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,19! * Boston, MA 02110-1301, USA.20! *21! *****************************************************************************/22! ******************************************************************************23! ******************************************************************************24! *25! * Authors: F. Gillet-Chaulet26! * Web: http://elmerice.elmerfem.org27! *28! * Original Date: 24/06/202429! *30! *****************************************************************************31!***********************************************************************************************32! Module to deal with covariances matrices33!***********************************************************************************************34MODULE CovarianceUtils35USE MainUtils36USE DefUtils3738IMPLICIT NONE3940INTERFACE SqrCovarianceVectorMultiply41MODULE PROCEDURE SqrCovarianceVectorMultiplyD,SqrCovarianceVectorMultiplyL42END INTERFACE4344INTERFACE CovarianceVectorMultiply45MODULE PROCEDURE CovarianceVectorMultiplyD,CovarianceVectorMultiplyL46END INTERFACE4748INTERFACE InvCovarianceVectorMultiply49MODULE PROCEDURE InvCovarianceVectorMultiplyD,InvCovarianceVectorMultiplyL50END INTERFACE5152INTERFACE CovarianceInit53MODULE PROCEDURE CovarianceInitD,CovarianceInitL54END INTERFACE5556CONTAINS5758SUBROUTINE GetActiveNodesSet(Solver,n,ActiveNodes,InvPerm,PbDim)59TYPE(Solver_t) :: Solver60INTEGER, INTENT(OUT) :: n61INTEGER, ALLOCATABLE, INTENT(OUT) :: ActiveNodes(:),InvPerm(:)62INTEGER :: PbDim6364INTEGER :: t65INTEGER :: counter66INTEGER,POINTER :: Perm(:)67LOGICAL :: BoundarySolver6869IF (.NOT.ASSOCIATED(Solver % Matrix)) &70CALL FATAL("GetActiveNodesSet","Matrix must be associated")71Perm => Solver % Variable % Perm7273n = Solver % Matrix % NumberOfRows74ALLOCATE(ActiveNodes(n),InvPerm(n))7576counter = 077DO t=1,Solver % Mesh % NumberOfNodes78IF (Perm(t).LT.1) CYCLE79counter = counter + 180IF (counter.GT.n) &81CALL FATAL("GetActiveNodesSet","Problem detected...")82ActiveNodes(counter) = t83InvPerm(Perm(t)) = t84END DO8586BoundarySolver = ( Solver % ActiveElements(1) > Solver % Mesh % NumberOfBulkElements )87IF (BoundarySolver) THEN88PbDim = CoordinateSystemDimension() - 189ELSE90PbDim = CoordinateSystemDimension()91ENDIF9293END SUBROUTINE GetActiveNodesSet9495!############################################################################################96!##97!## standard matrix vector multiplication using lapack98!##99!############################################################################################100SUBROUTINE InvCovarianceVectorMultiplyL(Solver,n,aap,x,y)101INTEGER,INTENT(IN) :: n102TYPE(Solver_t) :: Solver103REAL(kind=dp),INTENT(IN) :: aap(:)104REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x105REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y106107REAL(KIND=dp),DIMENSION(n) :: x1108TYPE(ValueList_t), POINTER :: SolverParams109character*1,parameter :: uplo='L'110REAL(KIND=dp) :: std111112SolverParams => GetSolverParams(Solver)113114std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)115116! x1 = Sigma-1 x117x1(1:n)=x(1:n)/std118119! y = C-1 . x1120call dspmv(uplo,n,1._dp,aap,x1,1,0._dp,y,1)121122! y = Sigma-1 y123y(1:n)=y(1:n)/std124125END SUBROUTINE InvCovarianceVectorMultiplyL126127SUBROUTINE CovarianceVectorMultiplyL(Solver,n,aap,x,y)128INTEGER,INTENT(IN) :: n129TYPE(Solver_t) :: Solver130REAL(kind=dp),INTENT(IN) :: aap(:)131REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x132REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y133134REAL(KIND=dp),DIMENSION(n) :: x1135TYPE(ValueList_t), POINTER :: SolverParams136character*1,parameter :: uplo='L'137REAL(KIND=dp) :: std138139SolverParams => GetSolverParams(Solver)140141std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)142143! x1 = Sigma x144x1(1:n)=std*x(1:n)145146! y = C . x1147call dspmv(uplo,n,1._dp,aap,x1,1,0._dp,y,1)148149! y = Sigma y150y(1:n)=std*y(1:n)151152END SUBROUTINE CovarianceVectorMultiplyL153154SUBROUTINE SqrCovarianceVectorMultiplyL(Solver,n,aap,x,y)155INTEGER,INTENT(IN) :: n156TYPE(Solver_t) :: Solver157REAL(kind=dp),INTENT(IN) :: aap(:)158REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x159REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y160161TYPE(ValueList_t), POINTER :: SolverParams162character*1,parameter :: uplo='L'163REAL(KIND=dp) :: std164165SolverParams => GetSolverParams(Solver)166167std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)168169! y = L . x; matrix is lower triangular170call dtpmv(uplo,'N','N',n,aap,x,1)171172! y = Sigma y173y(1:n)=std*x(1:n)174175END SUBROUTINE SqrCovarianceVectorMultiplyL176177!############################################################################################178!##179!## Matrix vector multiplications for the diffusion operator approach180!##181!############################################################################################182!-------------------------------------------------------------------------------------------183! Covariance product : y=C.x184!-------------------------------------------------------------------------------------------185SUBROUTINE CovarianceVectorMultiplyD(Solver,MSolver,KMSolver,n,x,y)186TYPE(Solver_t) :: Solver187TYPE(Solver_t), POINTER :: MSolver,KMSolver188INTEGER,INTENT(IN) :: n189REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x190REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y191192TYPE(Matrix_t), POINTER :: KMMatrix, MMatrix193TYPE(ValueList_t), POINTER :: SolverParams194REAL(KIND=dp),DIMENSION(n) :: y2195REAL(KIND=dp) :: Crange,gamma,std196REAL(KIND=dp) :: Norm197INTEGER :: iter198INTEGER :: Cm199LOGICAL :: Parallel200201Parallel=(ParEnv % PEs > 1)202203SolverParams => GetSolverParams(Solver)204205Cm = ListGetInteger(SolverParams,"Matern exponent m",UnFoundFatal=.TRUE.)206IF (Cm.LT.2) &207CALL FATAL("Covariance","<Matern exponent m> should be >=2")208Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)209std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)210gamma=sqrt(4*Pi*(Cm-1))*Crange211212MMatrix => MSolver % Matrix213KMMatrix => KMSolver % Matrix214215! Sigma x216y2(1:n)=std*x(1:n)217218! y_0=Gamma . y2219y(1:n)=gamma*y2(1:n)220221! L_M . M-1 . y0222! iter=1,m : (K+M) . y_i = (M) . y_{i-1}223DO iter=1,Cm224225! First iter M.M-1; nothing to do226IF (iter.EQ.1) THEN227KMMatrix % RHS(1:n) = y(1:n)228ELSE229IF (Parallel) THEN230CALL ParallelInitSolve( MMatrix,y,MMatrix%RHS,KMMatrix % RHS )231CALL ParallelMatrixVector( MMatrix,y, KMMatrix % RHS ,.TRUE. )232ELSE233CALL MatrixVectorMultiply( MMatrix, y, KMMatrix % RHS )234END IF235END IF236! And finally, solve:237!--------------------238Norm = DefaultSolve(USolver=KMSolver)239y(1:n) = KMSolver % Variable % Values(1:n)240241END DO242243! Gamma . y244y2(1:n)=gamma*y(1:n)245246! Sigma x247y(1:n)=std*y2(1:n)248249END SUBROUTINE CovarianceVectorMultiplyD250!-------------------------------------------------------------------------------------------251! Square root: C=V.V^T => y = V.x252!-------------------------------------------------------------------------------------------253SUBROUTINE SqrCovarianceVectorMultiplyD(Solver,MSolver,KMSolver,n,x,y)254TYPE(Solver_t) :: Solver255TYPE(Solver_t), POINTER :: MSolver,KMSolver256INTEGER,INTENT(IN) :: n257REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x258REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y259260TYPE(Matrix_t), POINTER :: KMMatrix, MMatrix261TYPE(ValueList_t), POINTER :: SolverParams262REAL(KIND=dp),DIMENSION(n) :: ML263REAL(KIND=dp),DIMENSION(n) :: y2264REAL(KIND=dp) :: Crange,gamma,std265REAL(KIND=dp) :: Norm266REAL(KIND=dp) :: msum267INTEGER :: iter268INTEGER :: Cm,kk269LOGICAL :: Parallel270INTEGER :: i,j271272Parallel=(ParEnv % PEs > 1)273IF (Parallel) &274CALL FATAL("SqrCovarianceVector","not ready for parallel")275276SolverParams => GetSolverParams(Solver)277278Cm = ListGetInteger(SolverParams,"Matern exponent m",UnFoundFatal=.TRUE.)279IF (Cm.LT.2) &280CALL FATAL("Covariance","<Matern exponent m> should be >=2")281IF (mod(Cm,2).NE.0) &282CALL FATAL("SqrCovarianceVector","m should be even")283284Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)285std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)286gamma=sqrt(4*Pi*(Cm-1))*Crange287288MMatrix => MSolver % Matrix289KMMatrix => KMSolver % Matrix290291! lumped mass matrix; this could be done only once..292DO i=1,n293msum = 0.0_dp294DO j=MMatrix%Rows(i),MMatrix % Rows(i+1)-1295msum = msum + MMatrix % Values(j)296END DO297ML(i) = msum298END DO299300! M^-1/2.x301ML(1:n)=sqrt(ML(1:n))302y(1:n)=x(1:n)/ML(1:n)303304kk=Cm/2305DO iter=1,kk306307CALL MatrixVectorMultiply( MMatrix, y, KMMatrix % RHS )308309! And finally, solve:310!--------------------311Norm = DefaultSolve(USolver=KMSolver)312y(1:n) = KMSolver % Variable % Values(1:n)313314END DO315316! Gamma . y317y2(1:n)=gamma*y(1:n)318319! Sigma x320y(1:n)=std*y2(1:n)321322323END SUBROUTINE SqrCovarianceVectorMultiplyD324!-------------------------------------------------------------------------------------------325! InvCovariance : y = C^-1 x326!-------------------------------------------------------------------------------------------327SUBROUTINE InvCovarianceVectorMultiplyD(Solver,MSolver,KMSolver,n,x,y)328TYPE(Solver_t) :: Solver329TYPE(Solver_t), POINTER :: MSolver,KMSolver330INTEGER,INTENT(IN) :: n331REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x332REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y333334TYPE(Matrix_t), POINTER :: KMMatrix, MMatrix335TYPE(ValueList_t), POINTER :: SolverParams336REAL(KIND=dp),DIMENSION(n) :: y2337REAL(KIND=dp) :: Crange,gamma,std338REAL(KIND=dp) :: Norm339INTEGER :: iter340INTEGER :: Cm341LOGICAL :: Parallel342343Parallel=(ParEnv % PEs > 1)344345SolverParams => GetSolverParams(Solver)346347Cm = ListGetInteger(SolverParams,"Matern exponent m",UnFoundFatal=.TRUE.)348IF (Cm.LT.2) &349CALL FATAL("Covariance","<Matern exponent m> should be >=2")350Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)351std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)352gamma=sqrt(4*Pi*(Cm-1))*Crange353354MMatrix => MSolver % Matrix355KMMatrix => KMSolver % Matrix356357! Sigma-1 x358y2(1:n)=x(1:n)/std359360! y_0=Gamma^-1 . y2361y(1:n)=y2(1:n)/gamma362363! L_M^-1 . y0364! iter=1,m : M . y_i = (M+K) . y_{i-1}365DO iter=1,Cm366367IF (Parallel) THEN368CALL ParallelInitSolve( KMMatrix,y,KMMatrix%RHS,MMatrix % RHS )369CALL ParallelMatrixVector( KMMatrix,y, MMatrix % RHS ,.TRUE. )370ELSE371CALL MatrixVectorMultiply( KMMatrix, y, MMatrix % RHS )372END IF373! And finally, solve:374!--------------------375Norm = DefaultSolve(USolver=MSolver)376y(1:n) = MSolver % Variable % Values(1:n)377378END DO379380! y2=M . y_m381IF (Parallel) THEN382CALL ParallelInitSolve( MMatrix,y,MMatrix % RHS,y2)383CALL ParallelMatrixVector( MMatrix,y, y2,.TRUE.)384CALL ParallelSumVector( MMatrix, y2 )385ELSE386CALL MatrixVectorMultiply( MMatrix, y, y2 )387ENDIF388389! Gamma-1 . y2390y(1:n)=y2(1:n)/gamma391392! Sigma-1 . y393y(1:n)=y(1:n)/std394395END SUBROUTINE InvCovarianceVectorMultiplyD396397!############################################################################################398!##399!## CovarianceInit subroutines to initialise the correlation matrices400!##401!############################################################################################402!-------------------------------------------------------------------------------------------403! Using the diffusion operator approach; build the required matrices404!405!-------------------------------------------------------------------------------------------406SUBROUTINE CovarianceInitD(Solver,MSolver,KMSolver)407TYPE(Solver_t) :: Solver408TYPE(Solver_t), POINTER :: MSolver,KMSolver409410TYPE(ValueList_t), POINTER :: SolverParams411TYPE(Element_t),POINTER :: Element412REAL(kind=dp) :: CRange413LOGICAL :: Parallel414INTEGER :: t,Active415INTEGER :: n416INTEGER :: ProjCoord417LOGICAL :: DoProj418419Parallel=(ParEnv % PEs > 1)420421SolverParams => GetSolverParams(Solver)422Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)423ProjCoord = ListGetInteger(SolverParams,"projection coordinate",DoProj)424425MSolver => CreateChildSolver( Solver,TRIM(Solver%Variable%Name)//"_mvar",1 )426KMSolver => CreateChildSolver( Solver,TRIM(Solver%Variable%Name)//"_kmVar",1)427IF (Parallel) THEN428MSolver % Parallel = .TRUE.429KMSolver % Parallel = .TRUE.430END IF431MSolver % Variable % Output = .FALSE.432KMSolver % Variable % Output = .FALSE.433434! System assembly:435!----------------436CALL DefaultInitialize(USolver=MSolver)437CALL DefaultInitialize(USolver=KMSolver)438Active = GetNOFActive(Solver)439DO t=1,Active440Element => GetActiveElement(t)441n = GetElementNOFNodes()442CALL LocalMatrix( Element, n, Crange)443END DO444445CALL DefaultFinishBulkAssembly(Solver=MSolver)446CALL DefaultFinishBulkAssembly(Solver=KMSolver)447448CALL DefaultFinishAssembly(Solver=MSolver)449CALL DefaultFinishAssembly(Solver=KMSolver)450451CONTAINS452!------------------------------------------------------------------------------453SUBROUTINE LocalMatrix( Element, n, l)454!------------------------------------------------------------------------------455INTEGER :: n456TYPE(Element_t), POINTER :: Element457REAL(KIND=dp) :: l458INTEGER :: iter459!------------------------------------------------------------------------------460REAL(KIND=dp) :: Weight461REAL(KIND=dp) :: Basis(n),dBasisdx(n,3),DetJ462REAL(KIND=dp) :: MASS(n,n), STIFF(n,n), FORCE(n)463LOGICAL :: Stat464INTEGER :: t,p,q465TYPE(GaussIntegrationPoints_t) :: IP466TYPE(Nodes_t) :: Nodes467SAVE Nodes468!------------------------------------------------------------------------------469470CALL GetElementNodes( Nodes )471472IF (DoProj) THEN473SELECT CASE (ProjCoord)474CASE (1)475Nodes % x(:)=0._dp476CASE (2)477Nodes % y(:)=0._dp478CASE (3)479Nodes % z(:)=0._dp480CASE DEFAULT481CALL FATAL("CovarianceInitD", &482"Wrong projection coordinate"//I2S(ProjCoord))483484END SELECT485END IF486487MASS = 0._dp488STIFF = 0._dp489FORCE = 0._dp490491! Numerical integration:492!-----------------------493IP = GaussPoints( Element )494DO t=1,IP % n495! Basis function values & derivatives at the integration point:496!--------------------------------------------------------------497stat = ElementInfo( Element, Nodes, IP % U(t), IP % V(t), &498IP % W(t), detJ, Basis, dBasisdx )499500Weight = IP % s(t) * DetJ501502! diffusion term (l**2*grad(u),grad(v)):503! -----------------------------------504STIFF(1:n,1:n) = STIFF(1:n,1:n) + Weight * &505l * l * MATMUL( dBasisdx, TRANSPOSE( dBasisdx ) )506507DO p=1,n508DO q=1,n509! identity term (R*u,v)510! -----------------------------------511MASS(p,q) = MASS(p,q) + Weight * Basis(q) * Basis(p)512END DO513END DO514515END DO516517CALL DefaultUpdateEquations(STIFF+MASS,FORCE,USolver=KMSolver)518CALL DefaultUpdateEquations(MASS,FORCE,USolver=MSolver)519!------------------------------------------------------------------------------520END SUBROUTINE LocalMatrix521!------------------------------------------------------------------------------522END SUBROUTINE CovarianceInitD523524!-------------------------------------------------------------------------------------------525! Initialisation of the full covariance matrix in lapack uplo format526! restricted to small 1D/2D serial cases....527!-------------------------------------------------------------------------------------------528SUBROUTINE CovarianceInitL(Solver,n,InvPerm,aap,Op,PbDim)529TYPE(Solver_t) :: Solver530INTEGER,INTENT(IN) :: n531INTEGER,INTENT(IN) :: InvPerm(n)532REAL(kind=dp),INTENT(OUT) :: aap(:)533INTEGER,INTENT(IN) :: Op !1: correlation matrix ; 2: Cholesky; 3: inverse534INTEGER,INTENT(IN) :: PbDim535536TYPE(ValueList_t), POINTER :: SolverParams537REAL(kind=dp) :: x(n),y(n)538REAL(kind=dp) :: d,dx,dy539INTEGER :: i,j,kk540INTEGER :: infoo541542CHARACTER(LEN=MAX_NAME_LEN) :: Ctype543REAL(KIND=dp) :: Crange544INTEGER :: p545546CHARACTER(LEN=MAX_NAME_LEN) :: SolverName="CovarianceInit"547character*1,parameter :: uplo='L'548549LOGICAL :: Parallel550551! Current restrictions:552! - serial553Parallel=(ParEnv % PEs > 1)554IF (Parallel) &555CALL FATAL(SolverName,'Sorry serial only!')556557! Get parameter remated to the correlation function558SolverParams => GetSolverParams(Solver)559560Ctype = ListGetString(SolverParams,"correlation type",UnFoundFatal=.TRUE.)561562IF (Ctype == 'maternp') THEN563p = ListGetInteger(SolverParams,"MaternP polynomial order",UnFoundFatal=.TRUE.)564ELSE IF (Ctype == 'materni') THEN565p = ListGetInteger(SolverParams,"MaternI order",UnFoundFatal=.TRUE.)566ENDIF567568Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)569570! build the correlation matrix571CALL INFO(SolverName,"Computing correlation matrix",level=4)572573DO i=1,n574d=0._dp575DO j=1,i576dx=Solver%Mesh%Nodes%x(InvPerm(i))-Solver%Mesh%Nodes%x(InvPerm(j))577d=dx**2578IF (PbDim.GE.2) THEN579dx=Solver%Mesh%Nodes%y(InvPerm(i))-Solver%Mesh%Nodes%y(InvPerm(j))580d=d+dx**2581IF (PbDim.EQ.3) THEN582dx=Solver%Mesh%Nodes%z(InvPerm(i))-Solver%Mesh%Nodes%z(InvPerm(j))583d=d+dx**2584END IF585END IF586d=sqrt(d)587aap(i + (j-1)*(2*n-j)/2) = correlation(d,Ctype,Crange,p)588END DO589END DO590591IF ( Op == 1 ) RETURN592593! get Cholesky decomposition A=LL^T594CALL INFO(SolverName,"Computing Cholesky",level=4)595call dpptrf(uplo,n,aap,infoo)596IF (infoo.NE.0) THEN597CALL FATAL(SolverName,'Cholesky Factorisation failed')598END IF599600IF ( Op == 2 ) RETURN601602! compute the inverse from Cholesky603CALL INFO(SolverName,"Computing Inverse",level=4)604call dpptri(uplo,n,aap,infoo)605606IF (infoo.NE.0) THEN607CALL FATAL(SolverName,'Inversion failed')608END IF609610END SUBROUTINE CovarianceInitL611612613!####################################################614!# Some classical analytical correlation functions615!####################################################616function correlation(d,Ctype,r,p) RESULT(c)617implicit none618real(kind=dp) :: c ! the correlation value619real(kind=dp) :: d ! the distance620real(kind=dp) :: r ! the range621integer :: p ! Matern polynomial order, for nu=p+1/2 for maternP622! or matern oder nu, for maternI623CHARACTER(LEN=MAX_NAME_LEN) :: Ctype ! corrlation function type:624625SELECT CASE (Ctype)626627CASE ('exponential')628c=exp(-d/r)629630CASE ('gaussian')631c=exp(-d**2/(2*r**2))632633! Matern case with integer order nu=p634CASE ('materni')635c=MaternI(p,d/r)636637! Matern case with nu half integer p=nu-1/2638CASE ('maternp')639SELECT CASE (p)640CASE(1)641c=(1+d/r)*exp(-d/r)642CASE(2)643c=(1+d/r+d**2/(3*r**2))*exp(-d/r)644CASE DEFAULT645CALL FATAL('correlation',&646'Matern polynomial order not available')647END SELECT648649650CASE DEFAULT651CALL FATAL('correlation',&652'Correlation Type not known')653END SELECT654655end function correlation656657!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!658! The matern correlation function for nu=integer659!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!660FUNCTION MaternI(n,x) RESULT(c)661REAL(KIND=dp) :: c662REAL(kind=dp),INTENT(IN) :: x663INTEGER,INTENT(IN) :: n664real(kind=dp) :: Kn665666if (n.lt.1) CALL FATAL("MaternI","n must be >=1")667! Bessel not defined for x=0; but c should be 1668if (x.lt.10*AEPS) THEN669c=1._dp670Return671endif672if (n.gt.1) then673Kn=BesselKn(n,x)674else675Kn=BesselK1(x)676endif677c=(2.0**(1-n))*((x)**n)*Kn/fact(n-1)678679END680!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!681! Modified Bessel function of second kind Kn682! Computed from the recursion683! Kn+1 = 2*n/x Kn + Kn-1684!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!685FUNCTION BesselKn(n,x) RESULT(Kn)686REAL(kind=dp) :: Kn687INTEGER,INTENT(IN) :: n688REAL(kind=dp),INTENT(IN) :: x689690INTEGER :: j691REAL(kind=dp) :: y692REAL(kind=dp) :: bjm,bj,bjp693694IF (x.LT.AEPS) &695CALL FATAL("BesselKn","x is too small")696IF (n.lt.2) THEN697CALL FATAL("BesselKn","n must be >= 2")698END IF699700y=2._dp/x701702bjm=BesselK0(x)703bj=BesselK1(x)704705DO j=1,n-1706bjp=bjm+j*y*bj707bjm=bj708bj=bjp709END DO710711Kn=bj712713RETURN714END715!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!716! Modified Bessel function of second kind of order 0, K0717! Polynomial approximation; cf718! https://www.advanpix.com/2015/11/25/rational-approximations-for-the-modified-bessel-function-of-the-second-kind-k0-for-computations-with-double-precision/719!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!720FUNCTION BesselK0(x) RESULT(K0)721REAL(KIND=dp) :: K0722REAL(KIND=dp), INTENT(IN) :: x723724REAL(KIND=dp), Dimension(8),Parameter :: P7=(/ 1.1593151565841244842077226e-01,&7252.7898287891460317300886539e-01,&7262.5248929932161220559969776e-02,&7278.4603509072136578707676406e-04,&7281.4914719243067801775856150e-05,&7291.6271068931224552553548933e-07,&7301.2082660336282566759313543e-09,&7316.6117104672254184399933971e-12/)732733REAL(KIND=dp), Dimension(7),Parameter :: P6=(/ 1.0000000000000000044974165e+00,&7342.4999999999999822316775454e-01,&7352.7777777777892149148858521e-02,&7361.7361111083544590676709592e-03,&7376.9444476047072424198677755e-05,&7381.9288265756466775034067979e-06,&7393.9908220583262192851839992e-08/)740741REAL(KIND=dp), Dimension(3), Parameter :: Q2=(/ 8.5331186362410449871043129e-02,&7427.3477344946182065340442326e-01,&7431.4594189037511445958046540e+00/)744745REAL(KIND=dp), Dimension(22), Parameter :: P21=(/1.0694678222191263215918328e-01,&7469.0753360415683846760792445e-01,&7471.7215172959695072045669045e+00,&748-1.7172089076875257095489749e-01,&7497.3154750356991229825958019e-02,&750-5.4975286232097852780866385e-02,&7515.7217703802970844746230694e-02,&752-7.2884177844363453190380429e-02,&7531.0443967655783544973080767e-01,&754-1.5741597553317349976818516e-01,&7552.3582486699296814538802637e-01,&756-3.3484166783257765115562496e-01,&7574.3328524890855568555069622e-01,&758-4.9470375304462431447923425e-01,&7594.8474122247422388055091847e-01,&760-3.9725799556374477699937953e-01,&7612.6507653322930767914034592e-01,&762-1.3951265948137254924254912e-01,&7635.5500667358490463548729700e-02,&764-1.5636955694760495736676521e-02,&7652.7741514506299244078981715e-03,&766-2.3261089001545715929104236e-04/)767768REAL(KIND=dp) :: x2,y,y2,p,p1,I0769770IF (x.lt.1._dp) THEN771x2=x*x772y=x/2.0_dp773y2=y*y774775!P6[(x/2)^2]776p1=Polynomial(y2,P6,6)777!I0778I0=1._dp+y2*p1779780!! P7(x2)781p=Polynomial(x2,P7,7)782783K0=p-log(x)*I0784785ELSE786787y=1._dp/x788!P21(x^-1)789p=Polynomial(y,P21,21)790!Q2(x^-1)791p1=Polynomial(y,Q2,2)792K0=(p/p1)793K0=K0/(sqrt(x)*exp(x))794795ENDIF796797RETURN798END799800!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!801! Modified Bessel function of second kind of order 1, K1802! Polynomial approximation; cf803! https://www.advanpix.com/2016/01/05/rational-approximations-for-the-modified-bessel-function-of-the-second-kind-k1-for-computations-with-double-precision/804!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!805FUNCTION BesselK1(x) RESULT(K1)806REAL(KIND=dp) :: K1807REAL(KIND=dp), INTENT(IN) :: x808809REAL(KIND=dp), Dimension(6), Parameter :: P5=(/8.3333333333333325191635191e-02,&8106.9444444444467956461838830e-03,&8113.4722222211230452695165215e-04,&8121.1574075952009842696580084e-05,&8132.7555870002088181016676934e-07,&8144.9724386164128529514040614e-09/)815816REAL(KIND=dp), Dimension(9), Parameter :: P8=(/-3.0796575782920622440538935e-01,&817-8.5370719728650778045782736e-02,&818-4.6421827664715603298154971e-03,&819-1.1253607036630425931072996e-04,&820-1.5592887702110907110292728e-06,&821-1.4030163679125934402498239e-08,&822-8.8718998640336832196558868e-11,&823-4.1614323580221539328960335e-13,&824-1.5261293392975541707230366e-15/)825826REAL(KIND=dp), Dimension(23), Parameter :: P22=(/1.0234817795732426171122752e-01,&8279.4576473594736724815742878e-01,&8282.1876721356881381470401990e+00,&8296.0143447861316538915034873e-01,&830-1.3961391456741388991743381e-01,&8318.8229427272346799004782764e-02,&832-8.5494054051512748665954180e-02,&8331.0617946033429943924055318e-01,&834-1.5284482951051872048173726e-01,&8352.3707700686462639842005570e-01,&836-3.7345723872158017497895685e-01,&8375.6874783855986054797640277e-01,&838-8.0418742944483208700659463e-01,&8391.0215105768084562101457969e+00,&840-1.1342221242815914077805587e+00,&8411.0746932686976675016706662e+00,&842-8.4904532475797772009120500e-01,&8435.4542251056566299656460363e-01,&844-2.7630896752209862007904214e-01,&8451.0585982409547307546052147e-01,&846-2.8751691985417886721803220e-02,&8474.9233441525877381700355793e-03,&848-3.9900679319457222207987456e-04/)849850REAL(KIND=dp), Dimension(3), Parameter :: Q2=(/ 8.1662031018453173425764707e-02,&8517.2398781933228355889996920e-01,&8521.4835841581744134589980018e+00/)853854REAL(KIND=dp) :: y,y2,y4,x2,I1855REAL(KIND=dp) :: p,p1856857IF (x.lt.1._dp) THEN858x2=x*x859y=x/2.0_dp860y2=y*y861y4=y2*y2862863!P5[(x/2)^2]864p1=Polynomial(y2,P5,5)865!I1866I1=y*(1+y2/2+y4*p1)867868!! P8(x2)869p=Polynomial(x2,P8,8)870871K1=log(x)*I1+1/x+x*p872873ELSE874875y=1._dp/x876!P22(x^-1)877p=Polynomial(y,P22,22)878!Q2(x^-1)879p1=Polynomial(y,Q2,2)880K1=(p/p1)881K1=K1/(sqrt(x)*exp(x))882883ENDIF884885RETURN886END FUNCTION BesselK1887888!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!889! Compute the value at x of a Polynom of order n890! Horner scheme891!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!892FUNCTION Polynomial(x,P,n) RESULT(y)893IMPLICIT NONE894REAL(KIND=dp) :: y895REAL(KIND=dp),INTENT(IN) :: P(n+1),x896INTEGER ,INTENT(IN) :: n897INTEGER :: i898899y=P(n+1)900Do i=1,n901y=P(n+1-i)+y*x902End Do903904RETURN905END906907!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!908! Integer factorial909!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!910function fact(n)911implicit none912integer :: fact913integer, intent(IN) :: n914integer :: i915916fact = 1917do i = 2, n918fact = fact * i919enddo920return921end function fact922923924END MODULE CovarianceUtils925926927