Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/Covarianceutils/CovarianceUtils.F90
3206 views
1
!/*****************************************************************************/
2
! *
3
! * Elmer/Ice, a glaciological add-on to Elmer
4
! * http://elmerice.elmerfem.org
5
! *
6
! *
7
! * This program is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU General Public License
9
! * as published by the Free Software Foundation; either version 2
10
! * of the License, or (at your option) any later version.
11
! *
12
! * This program is distributed in the hope that it will be useful,
13
! * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
! * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
! * GNU General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU General Public License
18
! * along with this program (in file fem/GPL-2); if not, write to the
19
! * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20
! * Boston, MA 02110-1301, USA.
21
! *
22
! *****************************************************************************/
23
! ******************************************************************************
24
! ******************************************************************************
25
! *
26
! * Authors: F. Gillet-Chaulet
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! * Original Date: 24/06/2024
30
! *
31
! *****************************************************************************
32
!***********************************************************************************************
33
! Module to deal with covariances matrices
34
!***********************************************************************************************
35
MODULE CovarianceUtils
36
USE MainUtils
37
USE DefUtils
38
39
IMPLICIT NONE
40
41
INTERFACE SqrCovarianceVectorMultiply
42
MODULE PROCEDURE SqrCovarianceVectorMultiplyD,SqrCovarianceVectorMultiplyL
43
END INTERFACE
44
45
INTERFACE CovarianceVectorMultiply
46
MODULE PROCEDURE CovarianceVectorMultiplyD,CovarianceVectorMultiplyL
47
END INTERFACE
48
49
INTERFACE InvCovarianceVectorMultiply
50
MODULE PROCEDURE InvCovarianceVectorMultiplyD,InvCovarianceVectorMultiplyL
51
END INTERFACE
52
53
INTERFACE CovarianceInit
54
MODULE PROCEDURE CovarianceInitD,CovarianceInitL
55
END INTERFACE
56
57
CONTAINS
58
59
SUBROUTINE GetActiveNodesSet(Solver,n,ActiveNodes,InvPerm,PbDim)
60
TYPE(Solver_t) :: Solver
61
INTEGER, INTENT(OUT) :: n
62
INTEGER, ALLOCATABLE, INTENT(OUT) :: ActiveNodes(:),InvPerm(:)
63
INTEGER :: PbDim
64
65
INTEGER :: t
66
INTEGER :: counter
67
INTEGER,POINTER :: Perm(:)
68
LOGICAL :: BoundarySolver
69
70
IF (.NOT.ASSOCIATED(Solver % Matrix)) &
71
CALL FATAL("GetActiveNodesSet","Matrix must be associated")
72
Perm => Solver % Variable % Perm
73
74
n = Solver % Matrix % NumberOfRows
75
ALLOCATE(ActiveNodes(n),InvPerm(n))
76
77
counter = 0
78
DO t=1,Solver % Mesh % NumberOfNodes
79
IF (Perm(t).LT.1) CYCLE
80
counter = counter + 1
81
IF (counter.GT.n) &
82
CALL FATAL("GetActiveNodesSet","Problem detected...")
83
ActiveNodes(counter) = t
84
InvPerm(Perm(t)) = t
85
END DO
86
87
BoundarySolver = ( Solver % ActiveElements(1) > Solver % Mesh % NumberOfBulkElements )
88
IF (BoundarySolver) THEN
89
PbDim = CoordinateSystemDimension() - 1
90
ELSE
91
PbDim = CoordinateSystemDimension()
92
ENDIF
93
94
END SUBROUTINE GetActiveNodesSet
95
96
!############################################################################################
97
!##
98
!## standard matrix vector multiplication using lapack
99
!##
100
!############################################################################################
101
SUBROUTINE InvCovarianceVectorMultiplyL(Solver,n,aap,x,y)
102
INTEGER,INTENT(IN) :: n
103
TYPE(Solver_t) :: Solver
104
REAL(kind=dp),INTENT(IN) :: aap(:)
105
REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x
106
REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y
107
108
REAL(KIND=dp),DIMENSION(n) :: x1
109
TYPE(ValueList_t), POINTER :: SolverParams
110
character*1,parameter :: uplo='L'
111
REAL(KIND=dp) :: std
112
113
SolverParams => GetSolverParams(Solver)
114
115
std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)
116
117
! x1 = Sigma-1 x
118
x1(1:n)=x(1:n)/std
119
120
! y = C-1 . x1
121
call dspmv(uplo,n,1._dp,aap,x1,1,0._dp,y,1)
122
123
! y = Sigma-1 y
124
y(1:n)=y(1:n)/std
125
126
END SUBROUTINE InvCovarianceVectorMultiplyL
127
128
SUBROUTINE CovarianceVectorMultiplyL(Solver,n,aap,x,y)
129
INTEGER,INTENT(IN) :: n
130
TYPE(Solver_t) :: Solver
131
REAL(kind=dp),INTENT(IN) :: aap(:)
132
REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x
133
REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y
134
135
REAL(KIND=dp),DIMENSION(n) :: x1
136
TYPE(ValueList_t), POINTER :: SolverParams
137
character*1,parameter :: uplo='L'
138
REAL(KIND=dp) :: std
139
140
SolverParams => GetSolverParams(Solver)
141
142
std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)
143
144
! x1 = Sigma x
145
x1(1:n)=std*x(1:n)
146
147
! y = C . x1
148
call dspmv(uplo,n,1._dp,aap,x1,1,0._dp,y,1)
149
150
! y = Sigma y
151
y(1:n)=std*y(1:n)
152
153
END SUBROUTINE CovarianceVectorMultiplyL
154
155
SUBROUTINE SqrCovarianceVectorMultiplyL(Solver,n,aap,x,y)
156
INTEGER,INTENT(IN) :: n
157
TYPE(Solver_t) :: Solver
158
REAL(kind=dp),INTENT(IN) :: aap(:)
159
REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x
160
REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y
161
162
TYPE(ValueList_t), POINTER :: SolverParams
163
character*1,parameter :: uplo='L'
164
REAL(KIND=dp) :: std
165
166
SolverParams => GetSolverParams(Solver)
167
168
std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)
169
170
! y = L . x; matrix is lower triangular
171
call dtpmv(uplo,'N','N',n,aap,x,1)
172
173
! y = Sigma y
174
y(1:n)=std*x(1:n)
175
176
END SUBROUTINE SqrCovarianceVectorMultiplyL
177
178
!############################################################################################
179
!##
180
!## Matrix vector multiplications for the diffusion operator approach
181
!##
182
!############################################################################################
183
!-------------------------------------------------------------------------------------------
184
! Covariance product : y=C.x
185
!-------------------------------------------------------------------------------------------
186
SUBROUTINE CovarianceVectorMultiplyD(Solver,MSolver,KMSolver,n,x,y)
187
TYPE(Solver_t) :: Solver
188
TYPE(Solver_t), POINTER :: MSolver,KMSolver
189
INTEGER,INTENT(IN) :: n
190
REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x
191
REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y
192
193
TYPE(Matrix_t), POINTER :: KMMatrix, MMatrix
194
TYPE(ValueList_t), POINTER :: SolverParams
195
REAL(KIND=dp),DIMENSION(n) :: y2
196
REAL(KIND=dp) :: Crange,gamma,std
197
REAL(KIND=dp) :: Norm
198
INTEGER :: iter
199
INTEGER :: Cm
200
LOGICAL :: Parallel
201
202
Parallel=(ParEnv % PEs > 1)
203
204
SolverParams => GetSolverParams(Solver)
205
206
Cm = ListGetInteger(SolverParams,"Matern exponent m",UnFoundFatal=.TRUE.)
207
IF (Cm.LT.2) &
208
CALL FATAL("Covariance","<Matern exponent m> should be >=2")
209
Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)
210
std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)
211
gamma=sqrt(4*Pi*(Cm-1))*Crange
212
213
MMatrix => MSolver % Matrix
214
KMMatrix => KMSolver % Matrix
215
216
! Sigma x
217
y2(1:n)=std*x(1:n)
218
219
! y_0=Gamma . y2
220
y(1:n)=gamma*y2(1:n)
221
222
! L_M . M-1 . y0
223
! iter=1,m : (K+M) . y_i = (M) . y_{i-1}
224
DO iter=1,Cm
225
226
! First iter M.M-1; nothing to do
227
IF (iter.EQ.1) THEN
228
KMMatrix % RHS(1:n) = y(1:n)
229
ELSE
230
IF (Parallel) THEN
231
CALL ParallelInitSolve( MMatrix,y,MMatrix%RHS,KMMatrix % RHS )
232
CALL ParallelMatrixVector( MMatrix,y, KMMatrix % RHS ,.TRUE. )
233
ELSE
234
CALL MatrixVectorMultiply( MMatrix, y, KMMatrix % RHS )
235
END IF
236
END IF
237
! And finally, solve:
238
!--------------------
239
Norm = DefaultSolve(USolver=KMSolver)
240
y(1:n) = KMSolver % Variable % Values(1:n)
241
242
END DO
243
244
! Gamma . y
245
y2(1:n)=gamma*y(1:n)
246
247
! Sigma x
248
y(1:n)=std*y2(1:n)
249
250
END SUBROUTINE CovarianceVectorMultiplyD
251
!-------------------------------------------------------------------------------------------
252
! Square root: C=V.V^T => y = V.x
253
!-------------------------------------------------------------------------------------------
254
SUBROUTINE SqrCovarianceVectorMultiplyD(Solver,MSolver,KMSolver,n,x,y)
255
TYPE(Solver_t) :: Solver
256
TYPE(Solver_t), POINTER :: MSolver,KMSolver
257
INTEGER,INTENT(IN) :: n
258
REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x
259
REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y
260
261
TYPE(Matrix_t), POINTER :: KMMatrix, MMatrix
262
TYPE(ValueList_t), POINTER :: SolverParams
263
REAL(KIND=dp),DIMENSION(n) :: ML
264
REAL(KIND=dp),DIMENSION(n) :: y2
265
REAL(KIND=dp) :: Crange,gamma,std
266
REAL(KIND=dp) :: Norm
267
REAL(KIND=dp) :: msum
268
INTEGER :: iter
269
INTEGER :: Cm,kk
270
LOGICAL :: Parallel
271
INTEGER :: i,j
272
273
Parallel=(ParEnv % PEs > 1)
274
IF (Parallel) &
275
CALL FATAL("SqrCovarianceVector","not ready for parallel")
276
277
SolverParams => GetSolverParams(Solver)
278
279
Cm = ListGetInteger(SolverParams,"Matern exponent m",UnFoundFatal=.TRUE.)
280
IF (Cm.LT.2) &
281
CALL FATAL("Covariance","<Matern exponent m> should be >=2")
282
IF (mod(Cm,2).NE.0) &
283
CALL FATAL("SqrCovarianceVector","m should be even")
284
285
Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)
286
std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)
287
gamma=sqrt(4*Pi*(Cm-1))*Crange
288
289
MMatrix => MSolver % Matrix
290
KMMatrix => KMSolver % Matrix
291
292
! lumped mass matrix; this could be done only once..
293
DO i=1,n
294
msum = 0.0_dp
295
DO j=MMatrix%Rows(i),MMatrix % Rows(i+1)-1
296
msum = msum + MMatrix % Values(j)
297
END DO
298
ML(i) = msum
299
END DO
300
301
! M^-1/2.x
302
ML(1:n)=sqrt(ML(1:n))
303
y(1:n)=x(1:n)/ML(1:n)
304
305
kk=Cm/2
306
DO iter=1,kk
307
308
CALL MatrixVectorMultiply( MMatrix, y, KMMatrix % RHS )
309
310
! And finally, solve:
311
!--------------------
312
Norm = DefaultSolve(USolver=KMSolver)
313
y(1:n) = KMSolver % Variable % Values(1:n)
314
315
END DO
316
317
! Gamma . y
318
y2(1:n)=gamma*y(1:n)
319
320
! Sigma x
321
y(1:n)=std*y2(1:n)
322
323
324
END SUBROUTINE SqrCovarianceVectorMultiplyD
325
!-------------------------------------------------------------------------------------------
326
! InvCovariance : y = C^-1 x
327
!-------------------------------------------------------------------------------------------
328
SUBROUTINE InvCovarianceVectorMultiplyD(Solver,MSolver,KMSolver,n,x,y)
329
TYPE(Solver_t) :: Solver
330
TYPE(Solver_t), POINTER :: MSolver,KMSolver
331
INTEGER,INTENT(IN) :: n
332
REAL(KIND=dp),DIMENSION(n),INTENT(IN) :: x
333
REAL(KIND=dp),DIMENSION(n),INTENT(OUT) :: y
334
335
TYPE(Matrix_t), POINTER :: KMMatrix, MMatrix
336
TYPE(ValueList_t), POINTER :: SolverParams
337
REAL(KIND=dp),DIMENSION(n) :: y2
338
REAL(KIND=dp) :: Crange,gamma,std
339
REAL(KIND=dp) :: Norm
340
INTEGER :: iter
341
INTEGER :: Cm
342
LOGICAL :: Parallel
343
344
Parallel=(ParEnv % PEs > 1)
345
346
SolverParams => GetSolverParams(Solver)
347
348
Cm = ListGetInteger(SolverParams,"Matern exponent m",UnFoundFatal=.TRUE.)
349
IF (Cm.LT.2) &
350
CALL FATAL("Covariance","<Matern exponent m> should be >=2")
351
Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)
352
std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)
353
gamma=sqrt(4*Pi*(Cm-1))*Crange
354
355
MMatrix => MSolver % Matrix
356
KMMatrix => KMSolver % Matrix
357
358
! Sigma-1 x
359
y2(1:n)=x(1:n)/std
360
361
! y_0=Gamma^-1 . y2
362
y(1:n)=y2(1:n)/gamma
363
364
! L_M^-1 . y0
365
! iter=1,m : M . y_i = (M+K) . y_{i-1}
366
DO iter=1,Cm
367
368
IF (Parallel) THEN
369
CALL ParallelInitSolve( KMMatrix,y,KMMatrix%RHS,MMatrix % RHS )
370
CALL ParallelMatrixVector( KMMatrix,y, MMatrix % RHS ,.TRUE. )
371
ELSE
372
CALL MatrixVectorMultiply( KMMatrix, y, MMatrix % RHS )
373
END IF
374
! And finally, solve:
375
!--------------------
376
Norm = DefaultSolve(USolver=MSolver)
377
y(1:n) = MSolver % Variable % Values(1:n)
378
379
END DO
380
381
! y2=M . y_m
382
IF (Parallel) THEN
383
CALL ParallelInitSolve( MMatrix,y,MMatrix % RHS,y2)
384
CALL ParallelMatrixVector( MMatrix,y, y2,.TRUE.)
385
CALL ParallelSumVector( MMatrix, y2 )
386
ELSE
387
CALL MatrixVectorMultiply( MMatrix, y, y2 )
388
ENDIF
389
390
! Gamma-1 . y2
391
y(1:n)=y2(1:n)/gamma
392
393
! Sigma-1 . y
394
y(1:n)=y(1:n)/std
395
396
END SUBROUTINE InvCovarianceVectorMultiplyD
397
398
!############################################################################################
399
!##
400
!## CovarianceInit subroutines to initialise the correlation matrices
401
!##
402
!############################################################################################
403
!-------------------------------------------------------------------------------------------
404
! Using the diffusion operator approach; build the required matrices
405
!
406
!-------------------------------------------------------------------------------------------
407
SUBROUTINE CovarianceInitD(Solver,MSolver,KMSolver)
408
TYPE(Solver_t) :: Solver
409
TYPE(Solver_t), POINTER :: MSolver,KMSolver
410
411
TYPE(ValueList_t), POINTER :: SolverParams
412
TYPE(Element_t),POINTER :: Element
413
REAL(kind=dp) :: CRange
414
LOGICAL :: Parallel
415
INTEGER :: t,Active
416
INTEGER :: n
417
INTEGER :: ProjCoord
418
LOGICAL :: DoProj
419
420
Parallel=(ParEnv % PEs > 1)
421
422
SolverParams => GetSolverParams(Solver)
423
Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)
424
ProjCoord = ListGetInteger(SolverParams,"projection coordinate",DoProj)
425
426
MSolver => CreateChildSolver( Solver,TRIM(Solver%Variable%Name)//"_mvar",1 )
427
KMSolver => CreateChildSolver( Solver,TRIM(Solver%Variable%Name)//"_kmVar",1)
428
IF (Parallel) THEN
429
MSolver % Parallel = .TRUE.
430
KMSolver % Parallel = .TRUE.
431
END IF
432
MSolver % Variable % Output = .FALSE.
433
KMSolver % Variable % Output = .FALSE.
434
435
! System assembly:
436
!----------------
437
CALL DefaultInitialize(USolver=MSolver)
438
CALL DefaultInitialize(USolver=KMSolver)
439
Active = GetNOFActive(Solver)
440
DO t=1,Active
441
Element => GetActiveElement(t)
442
n = GetElementNOFNodes()
443
CALL LocalMatrix( Element, n, Crange)
444
END DO
445
446
CALL DefaultFinishBulkAssembly(Solver=MSolver)
447
CALL DefaultFinishBulkAssembly(Solver=KMSolver)
448
449
CALL DefaultFinishAssembly(Solver=MSolver)
450
CALL DefaultFinishAssembly(Solver=KMSolver)
451
452
CONTAINS
453
!------------------------------------------------------------------------------
454
SUBROUTINE LocalMatrix( Element, n, l)
455
!------------------------------------------------------------------------------
456
INTEGER :: n
457
TYPE(Element_t), POINTER :: Element
458
REAL(KIND=dp) :: l
459
INTEGER :: iter
460
!------------------------------------------------------------------------------
461
REAL(KIND=dp) :: Weight
462
REAL(KIND=dp) :: Basis(n),dBasisdx(n,3),DetJ
463
REAL(KIND=dp) :: MASS(n,n), STIFF(n,n), FORCE(n)
464
LOGICAL :: Stat
465
INTEGER :: t,p,q
466
TYPE(GaussIntegrationPoints_t) :: IP
467
TYPE(Nodes_t) :: Nodes
468
SAVE Nodes
469
!------------------------------------------------------------------------------
470
471
CALL GetElementNodes( Nodes )
472
473
IF (DoProj) THEN
474
SELECT CASE (ProjCoord)
475
CASE (1)
476
Nodes % x(:)=0._dp
477
CASE (2)
478
Nodes % y(:)=0._dp
479
CASE (3)
480
Nodes % z(:)=0._dp
481
CASE DEFAULT
482
CALL FATAL("CovarianceInitD", &
483
"Wrong projection coordinate"//I2S(ProjCoord))
484
485
END SELECT
486
END IF
487
488
MASS = 0._dp
489
STIFF = 0._dp
490
FORCE = 0._dp
491
492
! Numerical integration:
493
!-----------------------
494
IP = GaussPoints( Element )
495
DO t=1,IP % n
496
! Basis function values & derivatives at the integration point:
497
!--------------------------------------------------------------
498
stat = ElementInfo( Element, Nodes, IP % U(t), IP % V(t), &
499
IP % W(t), detJ, Basis, dBasisdx )
500
501
Weight = IP % s(t) * DetJ
502
503
! diffusion term (l**2*grad(u),grad(v)):
504
! -----------------------------------
505
STIFF(1:n,1:n) = STIFF(1:n,1:n) + Weight * &
506
l * l * MATMUL( dBasisdx, TRANSPOSE( dBasisdx ) )
507
508
DO p=1,n
509
DO q=1,n
510
! identity term (R*u,v)
511
! -----------------------------------
512
MASS(p,q) = MASS(p,q) + Weight * Basis(q) * Basis(p)
513
END DO
514
END DO
515
516
END DO
517
518
CALL DefaultUpdateEquations(STIFF+MASS,FORCE,USolver=KMSolver)
519
CALL DefaultUpdateEquations(MASS,FORCE,USolver=MSolver)
520
!------------------------------------------------------------------------------
521
END SUBROUTINE LocalMatrix
522
!------------------------------------------------------------------------------
523
END SUBROUTINE CovarianceInitD
524
525
!-------------------------------------------------------------------------------------------
526
! Initialisation of the full covariance matrix in lapack uplo format
527
! restricted to small 1D/2D serial cases....
528
!-------------------------------------------------------------------------------------------
529
SUBROUTINE CovarianceInitL(Solver,n,InvPerm,aap,Op,PbDim)
530
TYPE(Solver_t) :: Solver
531
INTEGER,INTENT(IN) :: n
532
INTEGER,INTENT(IN) :: InvPerm(n)
533
REAL(kind=dp),INTENT(OUT) :: aap(:)
534
INTEGER,INTENT(IN) :: Op !1: correlation matrix ; 2: Cholesky; 3: inverse
535
INTEGER,INTENT(IN) :: PbDim
536
537
TYPE(ValueList_t), POINTER :: SolverParams
538
REAL(kind=dp) :: x(n),y(n)
539
REAL(kind=dp) :: d,dx,dy
540
INTEGER :: i,j,kk
541
INTEGER :: infoo
542
543
CHARACTER(LEN=MAX_NAME_LEN) :: Ctype
544
REAL(KIND=dp) :: Crange
545
INTEGER :: p
546
547
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName="CovarianceInit"
548
character*1,parameter :: uplo='L'
549
550
LOGICAL :: Parallel
551
552
! Current restrictions:
553
! - serial
554
Parallel=(ParEnv % PEs > 1)
555
IF (Parallel) &
556
CALL FATAL(SolverName,'Sorry serial only!')
557
558
! Get parameter remated to the correlation function
559
SolverParams => GetSolverParams(Solver)
560
561
Ctype = ListGetString(SolverParams,"correlation type",UnFoundFatal=.TRUE.)
562
563
IF (Ctype == 'maternp') THEN
564
p = ListGetInteger(SolverParams,"MaternP polynomial order",UnFoundFatal=.TRUE.)
565
ELSE IF (Ctype == 'materni') THEN
566
p = ListGetInteger(SolverParams,"MaternI order",UnFoundFatal=.TRUE.)
567
ENDIF
568
569
Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)
570
571
! build the correlation matrix
572
CALL INFO(SolverName,"Computing correlation matrix",level=4)
573
574
DO i=1,n
575
d=0._dp
576
DO j=1,i
577
dx=Solver%Mesh%Nodes%x(InvPerm(i))-Solver%Mesh%Nodes%x(InvPerm(j))
578
d=dx**2
579
IF (PbDim.GE.2) THEN
580
dx=Solver%Mesh%Nodes%y(InvPerm(i))-Solver%Mesh%Nodes%y(InvPerm(j))
581
d=d+dx**2
582
IF (PbDim.EQ.3) THEN
583
dx=Solver%Mesh%Nodes%z(InvPerm(i))-Solver%Mesh%Nodes%z(InvPerm(j))
584
d=d+dx**2
585
END IF
586
END IF
587
d=sqrt(d)
588
aap(i + (j-1)*(2*n-j)/2) = correlation(d,Ctype,Crange,p)
589
END DO
590
END DO
591
592
IF ( Op == 1 ) RETURN
593
594
! get Cholesky decomposition A=LL^T
595
CALL INFO(SolverName,"Computing Cholesky",level=4)
596
call dpptrf(uplo,n,aap,infoo)
597
IF (infoo.NE.0) THEN
598
CALL FATAL(SolverName,'Cholesky Factorisation failed')
599
END IF
600
601
IF ( Op == 2 ) RETURN
602
603
! compute the inverse from Cholesky
604
CALL INFO(SolverName,"Computing Inverse",level=4)
605
call dpptri(uplo,n,aap,infoo)
606
607
IF (infoo.NE.0) THEN
608
CALL FATAL(SolverName,'Inversion failed')
609
END IF
610
611
END SUBROUTINE CovarianceInitL
612
613
614
!####################################################
615
!# Some classical analytical correlation functions
616
!####################################################
617
function correlation(d,Ctype,r,p) RESULT(c)
618
implicit none
619
real(kind=dp) :: c ! the correlation value
620
real(kind=dp) :: d ! the distance
621
real(kind=dp) :: r ! the range
622
integer :: p ! Matern polynomial order, for nu=p+1/2 for maternP
623
! or matern oder nu, for maternI
624
CHARACTER(LEN=MAX_NAME_LEN) :: Ctype ! corrlation function type:
625
626
SELECT CASE (Ctype)
627
628
CASE ('exponential')
629
c=exp(-d/r)
630
631
CASE ('gaussian')
632
c=exp(-d**2/(2*r**2))
633
634
! Matern case with integer order nu=p
635
CASE ('materni')
636
c=MaternI(p,d/r)
637
638
! Matern case with nu half integer p=nu-1/2
639
CASE ('maternp')
640
SELECT CASE (p)
641
CASE(1)
642
c=(1+d/r)*exp(-d/r)
643
CASE(2)
644
c=(1+d/r+d**2/(3*r**2))*exp(-d/r)
645
CASE DEFAULT
646
CALL FATAL('correlation',&
647
'Matern polynomial order not available')
648
END SELECT
649
650
651
CASE DEFAULT
652
CALL FATAL('correlation',&
653
'Correlation Type not known')
654
END SELECT
655
656
end function correlation
657
658
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
659
! The matern correlation function for nu=integer
660
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
661
FUNCTION MaternI(n,x) RESULT(c)
662
REAL(KIND=dp) :: c
663
REAL(kind=dp),INTENT(IN) :: x
664
INTEGER,INTENT(IN) :: n
665
real(kind=dp) :: Kn
666
667
if (n.lt.1) CALL FATAL("MaternI","n must be >=1")
668
! Bessel not defined for x=0; but c should be 1
669
if (x.lt.10*AEPS) THEN
670
c=1._dp
671
Return
672
endif
673
if (n.gt.1) then
674
Kn=BesselKn(n,x)
675
else
676
Kn=BesselK1(x)
677
endif
678
c=(2.0**(1-n))*((x)**n)*Kn/fact(n-1)
679
680
END
681
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
682
! Modified Bessel function of second kind Kn
683
! Computed from the recursion
684
! Kn+1 = 2*n/x Kn + Kn-1
685
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
686
FUNCTION BesselKn(n,x) RESULT(Kn)
687
REAL(kind=dp) :: Kn
688
INTEGER,INTENT(IN) :: n
689
REAL(kind=dp),INTENT(IN) :: x
690
691
INTEGER :: j
692
REAL(kind=dp) :: y
693
REAL(kind=dp) :: bjm,bj,bjp
694
695
IF (x.LT.AEPS) &
696
CALL FATAL("BesselKn","x is too small")
697
IF (n.lt.2) THEN
698
CALL FATAL("BesselKn","n must be >= 2")
699
END IF
700
701
y=2._dp/x
702
703
bjm=BesselK0(x)
704
bj=BesselK1(x)
705
706
DO j=1,n-1
707
bjp=bjm+j*y*bj
708
bjm=bj
709
bj=bjp
710
END DO
711
712
Kn=bj
713
714
RETURN
715
END
716
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
717
! Modified Bessel function of second kind of order 0, K0
718
! Polynomial approximation; cf
719
! https://www.advanpix.com/2015/11/25/rational-approximations-for-the-modified-bessel-function-of-the-second-kind-k0-for-computations-with-double-precision/
720
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
721
FUNCTION BesselK0(x) RESULT(K0)
722
REAL(KIND=dp) :: K0
723
REAL(KIND=dp), INTENT(IN) :: x
724
725
REAL(KIND=dp), Dimension(8),Parameter :: P7=(/ 1.1593151565841244842077226e-01,&
726
2.7898287891460317300886539e-01,&
727
2.5248929932161220559969776e-02,&
728
8.4603509072136578707676406e-04,&
729
1.4914719243067801775856150e-05,&
730
1.6271068931224552553548933e-07,&
731
1.2082660336282566759313543e-09,&
732
6.6117104672254184399933971e-12/)
733
734
REAL(KIND=dp), Dimension(7),Parameter :: P6=(/ 1.0000000000000000044974165e+00,&
735
2.4999999999999822316775454e-01,&
736
2.7777777777892149148858521e-02,&
737
1.7361111083544590676709592e-03,&
738
6.9444476047072424198677755e-05,&
739
1.9288265756466775034067979e-06,&
740
3.9908220583262192851839992e-08/)
741
742
REAL(KIND=dp), Dimension(3), Parameter :: Q2=(/ 8.5331186362410449871043129e-02,&
743
7.3477344946182065340442326e-01,&
744
1.4594189037511445958046540e+00/)
745
746
REAL(KIND=dp), Dimension(22), Parameter :: P21=(/1.0694678222191263215918328e-01,&
747
9.0753360415683846760792445e-01,&
748
1.7215172959695072045669045e+00,&
749
-1.7172089076875257095489749e-01,&
750
7.3154750356991229825958019e-02,&
751
-5.4975286232097852780866385e-02,&
752
5.7217703802970844746230694e-02,&
753
-7.2884177844363453190380429e-02,&
754
1.0443967655783544973080767e-01,&
755
-1.5741597553317349976818516e-01,&
756
2.3582486699296814538802637e-01,&
757
-3.3484166783257765115562496e-01,&
758
4.3328524890855568555069622e-01,&
759
-4.9470375304462431447923425e-01,&
760
4.8474122247422388055091847e-01,&
761
-3.9725799556374477699937953e-01,&
762
2.6507653322930767914034592e-01,&
763
-1.3951265948137254924254912e-01,&
764
5.5500667358490463548729700e-02,&
765
-1.5636955694760495736676521e-02,&
766
2.7741514506299244078981715e-03,&
767
-2.3261089001545715929104236e-04/)
768
769
REAL(KIND=dp) :: x2,y,y2,p,p1,I0
770
771
IF (x.lt.1._dp) THEN
772
x2=x*x
773
y=x/2.0_dp
774
y2=y*y
775
776
!P6[(x/2)^2]
777
p1=Polynomial(y2,P6,6)
778
!I0
779
I0=1._dp+y2*p1
780
781
!! P7(x2)
782
p=Polynomial(x2,P7,7)
783
784
K0=p-log(x)*I0
785
786
ELSE
787
788
y=1._dp/x
789
!P21(x^-1)
790
p=Polynomial(y,P21,21)
791
!Q2(x^-1)
792
p1=Polynomial(y,Q2,2)
793
K0=(p/p1)
794
K0=K0/(sqrt(x)*exp(x))
795
796
ENDIF
797
798
RETURN
799
END
800
801
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
802
! Modified Bessel function of second kind of order 1, K1
803
! Polynomial approximation; cf
804
! https://www.advanpix.com/2016/01/05/rational-approximations-for-the-modified-bessel-function-of-the-second-kind-k1-for-computations-with-double-precision/
805
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
806
FUNCTION BesselK1(x) RESULT(K1)
807
REAL(KIND=dp) :: K1
808
REAL(KIND=dp), INTENT(IN) :: x
809
810
REAL(KIND=dp), Dimension(6), Parameter :: P5=(/8.3333333333333325191635191e-02,&
811
6.9444444444467956461838830e-03,&
812
3.4722222211230452695165215e-04,&
813
1.1574075952009842696580084e-05,&
814
2.7555870002088181016676934e-07,&
815
4.9724386164128529514040614e-09/)
816
817
REAL(KIND=dp), Dimension(9), Parameter :: P8=(/-3.0796575782920622440538935e-01,&
818
-8.5370719728650778045782736e-02,&
819
-4.6421827664715603298154971e-03,&
820
-1.1253607036630425931072996e-04,&
821
-1.5592887702110907110292728e-06,&
822
-1.4030163679125934402498239e-08,&
823
-8.8718998640336832196558868e-11,&
824
-4.1614323580221539328960335e-13,&
825
-1.5261293392975541707230366e-15/)
826
827
REAL(KIND=dp), Dimension(23), Parameter :: P22=(/1.0234817795732426171122752e-01,&
828
9.4576473594736724815742878e-01,&
829
2.1876721356881381470401990e+00,&
830
6.0143447861316538915034873e-01,&
831
-1.3961391456741388991743381e-01,&
832
8.8229427272346799004782764e-02,&
833
-8.5494054051512748665954180e-02,&
834
1.0617946033429943924055318e-01,&
835
-1.5284482951051872048173726e-01,&
836
2.3707700686462639842005570e-01,&
837
-3.7345723872158017497895685e-01,&
838
5.6874783855986054797640277e-01,&
839
-8.0418742944483208700659463e-01,&
840
1.0215105768084562101457969e+00,&
841
-1.1342221242815914077805587e+00,&
842
1.0746932686976675016706662e+00,&
843
-8.4904532475797772009120500e-01,&
844
5.4542251056566299656460363e-01,&
845
-2.7630896752209862007904214e-01,&
846
1.0585982409547307546052147e-01,&
847
-2.8751691985417886721803220e-02,&
848
4.9233441525877381700355793e-03,&
849
-3.9900679319457222207987456e-04/)
850
851
REAL(KIND=dp), Dimension(3), Parameter :: Q2=(/ 8.1662031018453173425764707e-02,&
852
7.2398781933228355889996920e-01,&
853
1.4835841581744134589980018e+00/)
854
855
REAL(KIND=dp) :: y,y2,y4,x2,I1
856
REAL(KIND=dp) :: p,p1
857
858
IF (x.lt.1._dp) THEN
859
x2=x*x
860
y=x/2.0_dp
861
y2=y*y
862
y4=y2*y2
863
864
!P5[(x/2)^2]
865
p1=Polynomial(y2,P5,5)
866
!I1
867
I1=y*(1+y2/2+y4*p1)
868
869
!! P8(x2)
870
p=Polynomial(x2,P8,8)
871
872
K1=log(x)*I1+1/x+x*p
873
874
ELSE
875
876
y=1._dp/x
877
!P22(x^-1)
878
p=Polynomial(y,P22,22)
879
!Q2(x^-1)
880
p1=Polynomial(y,Q2,2)
881
K1=(p/p1)
882
K1=K1/(sqrt(x)*exp(x))
883
884
ENDIF
885
886
RETURN
887
END FUNCTION BesselK1
888
889
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
890
! Compute the value at x of a Polynom of order n
891
! Horner scheme
892
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
893
FUNCTION Polynomial(x,P,n) RESULT(y)
894
IMPLICIT NONE
895
REAL(KIND=dp) :: y
896
REAL(KIND=dp),INTENT(IN) :: P(n+1),x
897
INTEGER ,INTENT(IN) :: n
898
INTEGER :: i
899
900
y=P(n+1)
901
Do i=1,n
902
y=P(n+1-i)+y*x
903
End Do
904
905
RETURN
906
END
907
908
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
909
! Integer factorial
910
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
911
function fact(n)
912
implicit none
913
integer :: fact
914
integer, intent(IN) :: n
915
integer :: i
916
917
fact = 1
918
do i = 2, n
919
fact = fact * i
920
enddo
921
return
922
end function fact
923
924
925
END MODULE CovarianceUtils
926
927