Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/Covarianceutils/BackgroundErrorCostSolver.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
! Compute a cost function from a background as Cost=0.5 * (x-x^b). B^-1 .(x-x^b)
34
! x is the optimized variable; x^b the background
35
! B^1 is the background error covariance matrix:
36
! here B= S . C . S
37
! with:
38
! - S is a diagonal matrix with the standard deviation (assumed constant for now)
39
! - C is a correlation matrix
40
! Available choices for C "Covariance type = String ..."
41
! - diagonal; i.e. C=I and B=S^2 is diagonal with the variances
42
! - "full matrix" : C is computed from standard correlation
43
! functions and inverted using Lapack routines
44
! - "diffusion operator" : C is approximated with the diffusion operator approach
45
! Current limitations :
46
! - Serial for the full-matrix approach
47
!
48
! Rq.
49
! - IF x has DOFs > 1 we apply independently the same B^-1
50
! - IF 2 instances of the same solver are used in the same .sif make a
51
! copy of the lib as things are initialized and saved....
52
!
53
! TODO:
54
! - add mandatory keywords at init, e.g. variable, ...
55
!
56
!***********************************************************************************************
57
SUBROUTINE BackgroundErrorCostSolver( Model,Solver,dt,TransientSimulation )
58
!***********************************************************************************************
59
USE GeneralUtils
60
USE CovarianceUtils
61
IMPLICIT NONE
62
!------------------------------------------------------------------------------
63
TYPE(Solver_t) :: Solver
64
65
TYPE(Model_t) :: Model
66
REAL(KIND=dp) :: dt
67
LOGICAL :: TransientSimulation
68
69
TYPE(ValueList_t), POINTER :: SolverParams
70
71
TYPE(Variable_t), POINTER :: Var,Var_b,DJDVariable,CostVar
72
REAL(KIND=dp), POINTER :: Values(:), Values_b(:),DJDValues(:)
73
INTEGER, POINTER :: Perm(:),Perm_b(:),DJDPerm(:)
74
CHARACTER(LEN=MAX_NAME_LEN) :: Varname,VarbName,GradVarName,CostName
75
INTEGER :: DOFs
76
77
INTEGER :: i,j,k,l,t
78
INTEGER :: ierr
79
INTEGER :: MeshDim
80
81
TYPE(Solver_t), POINTER, SAVE :: MSolver,KMSolver
82
REAL(kind=dp),allocatable,save :: aap(:) ! matrix in packed format
83
REAL(kind=dp),allocatable,save :: x(:),y(:)
84
REAL(kind=dp),allocatable,save :: One(:)
85
REAL(kind=dp) :: Cost,Cost_S
86
87
INTEGER,SAVE :: nn
88
INTEGER, ALLOCATABLE, SAVE :: ActiveNodes(:),InvPerm(:)
89
INTEGER,SAVE :: PbDim
90
91
CHARACTER(LEN=MAX_NAME_LEN),SAVE :: CovType
92
REAL(kind=dp),SAVE :: std
93
CHARACTER(LEN=MAX_NAME_LEN) :: Ctype
94
REAL(kind=dp) :: CRange,Cm
95
INTEGER :: p
96
REAL(kind=dp) :: sigma2
97
INTEGER :: Op
98
99
LOGICAL, SAVE :: Firsttime=.TRUE.
100
LOGICAL :: Reset
101
LOGICAL :: Found
102
Logical :: Parallel
103
104
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName="CostCov"
105
CHARACTER(LEN=MAX_NAME_LEN) :: CostFile
106
107
! check Parallel/Serial
108
Parallel=(ParEnv % PEs > 1)
109
110
111
SolverParams => GetSolverParams()
112
113
VarName = ListGetString(SolverParams,"Variable name",UnFoundFatal=.TRUE.)
114
GradVarName = ListGetString(SolverParams,"Gradient Variable name",UnFoundFatal=.TRUE.)
115
VarbName = ListGetString(SolverParams,"Background Variable name",UnFoundFatal=.TRUE.)
116
CostName = ListGetString(SolverParams,"Cost Variable name",UnFoundFatal=.TRUE.)
117
118
CostFile = ListGetString(SolverParams,'Cost Filename',UnFoundFatal=.TRUE. )
119
120
! get handles on the variables
121
Reset = GetLogical( SolverParams,'Reset Cost Value', Found)
122
IF(.NOT.Found) Reset=.True.
123
124
Var => VariableGet( Solver % Mesh % Variables,TRIM(VarName), UnFoundFatal=.TRUE. )
125
Values => Var % Values
126
Perm => Var % Perm
127
DOFs = Var % DOFs
128
129
Var_b => VariableGet(Solver % Mesh % Variables,TRIM(VarbName),UnFoundFatal=.TRUE.)
130
Values_b => Var_b % Values
131
Perm_b => Var_b % Perm
132
IF (Var_b % DOFs .NE. DOFs) &
133
CALL FATAL(SolverName,"Var and Var_b have different dofs")
134
135
DJDVariable => VariableGet( Solver % Mesh % Variables,TRIM(GradVarName), UnFoundFatal=.TRUE. )
136
DJDValues => DJDVariable % Values
137
DJDPerm => DJDVariable % Perm
138
IF (DJDVariable % DOFs .NE. DOFs) &
139
CALL FATAL(SolverName,"Var and grad have different dofs")
140
IF (Reset) DJDValues=0.0_dp
141
142
CostVar => VariableGet( Solver % Mesh % Variables,TRIM(CostName),UnFoundFatal=.TRUE.)
143
IF (Reset) CostVar % Values=0.0_dp
144
145
!! some initialisation
146
IF (Firsttime) THEN
147
CALL GetActiveNodesSet(Solver,nn,ActiveNodes,InvPerm,PbDim)
148
149
!! The covariance type
150
CovType = ListGetString(SolverParams,"Covariance type",UnFoundFatal=.TRUE.)
151
152
std = ListGetConstReal(SolverParams,"standard deviation",UnFoundFatal=.TRUE.)
153
154
IF (ParEnv%MyPE.EQ.0) THEN
155
open(10,file=TRIM(CostFile))
156
write(10,*) '# Covariance type: ',TRIM(CovType)
157
write(10,*) '# standard deviation: ',std
158
END IF
159
160
SELECT CASE (CovType)
161
162
CASE('diagonal')
163
CALL INFO(SolverName,"Using diagonal covariance",level=3)
164
165
CASE('full matrix')
166
CALL INFO(SolverName,"Using full matrix covariance",level=3)
167
168
Op=3
169
ALLOCATE(aap(nn*(nn+1)/2))
170
CALL CovarianceInit(Solver,nn,InvPerm,aap,Op,PbDim)
171
172
Ctype = ListGetString(SolverParams,"correlation type",UnFoundFatal=.TRUE.)
173
IF (ParEnv%MyPE.EQ.0) &
174
write(10,*) '# Correlation type: ',TRIM(Ctype)
175
176
Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)
177
178
IF (Ctype == 'maternp') THEN
179
p = ListGetInteger(SolverParams,"MaternP polynomial order",UnFoundFatal=.TRUE.)
180
IF (ParEnv%MyPE.EQ.0) &
181
write(10,*) '# range, exponent: ',Crange,p
182
ELSE IF (Ctype == 'materni') THEN
183
p = ListGetInteger(SolverParams,"MaternI order",UnFoundFatal=.TRUE.)
184
IF (ParEnv%MyPE.EQ.0) &
185
write(10,*) '# range, exponent: ',Crange,p
186
ELSE
187
IF (ParEnv%MyPE.EQ.0) &
188
write(10,*) '# range:',Crange
189
END IF
190
191
CASE('diffusion operator')
192
CALL INFO(SolverName,"Using diffusion operator covariance",level=3)
193
194
CALL CovarianceInit(Solver,MSolver,KMSolver)
195
196
Cm = ListGetInteger(SolverParams,"Matern exponent m",UnFoundFatal=.TRUE.)
197
Crange = ListGetConstReal(SolverParams,"correlation range", UnFoundFatal=.TRUE.)
198
199
IF (ParEnv%MyPE.EQ.0) &
200
write(10,*) '# range, exponent: ',Crange,Cm
201
202
CASE DEFAULT
203
CALL FATAL(SolverName,"Covariance type not known")
204
205
END SELECT
206
207
IF (ParEnv%MyPE.EQ.0) &
208
close(10)
209
210
allocate(x(nn),y(nn),One(nn))
211
! normalisation vector; usefull for parallel
212
One=1._dp
213
IF (Parallel) CALL ParallelSumVector(Solver%Matrix, One)
214
215
Firsttime=.FALSE.
216
END IF
217
218
Cost=0._dp
219
DO i=1,DOFS
220
221
!(x-x_b)
222
x(Solver%Variable%Perm(ActiveNodes(1:nn))) = Values(DOFs*(Perm(ActiveNodes(1:nn))-1)+i)- &
223
Values_b(DOFs*(Perm_b(ActiveNodes(1:nn))-1)+i)
224
225
SELECT CASE (CovType)
226
227
CASE('diagonal')
228
sigma2=std**2
229
y(1:nn) = x(1:nn)/sigma2
230
231
CASE('full matrix')
232
CALL InvCovarianceVectorMultiply(Solver,nn,aap,x,y)
233
234
CASE('diffusion operator')
235
! y = SIGMA^1 C^1 SIGMA^1 . (x-x_b)
236
CALL InvCovarianceVectorMultiply(Solver,MSolver,KMSolver,nn,x,y)
237
238
END SELECT
239
240
! gradient = SIGMA^1 C^1 SIGMA^1 . (x-x_b)
241
! gradients are gathered in the optimisation step; so also normalize by One.
242
DJDValues(DOFS*(DJDPerm(ActiveNodes(1:nn))-1)+i)=DJDValues(DOFS*(DJDPerm(ActiveNodes(1:nn))-1)+i)+ &
243
y(Solver%Variable%Perm(ActiveNodes(1:nn)))/One(Solver%Variable%Perm(ActiveNodes(1:nn)))
244
245
246
! 1/2 (x-x_b) . SIGMA^1 C^1 SIGMA^1 . (x-x_b)
247
! normalisation by one insure that shared nodes are not counted twice...
248
Cost=Cost+0.5*SUM(x(1:nn)*y(1:nn)/One(1:nn))
249
250
END DO
251
252
IF (Parallel) THEN
253
CALL MPI_ALLREDUCE(Cost,Cost_S,1,&
254
MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)
255
CostVar % Values(1)=CostVar % Values(1)+Cost_S
256
IF (ParEnv % MyPE == 0) then
257
OPEN (10, FILE=CostFile,POSITION='APPEND')
258
write(10,'(2(ES20.11E3))') GetTime(),Cost_S
259
CLOSE(10)
260
End if
261
ELSE
262
CostVar % Values(1)=CostVar % Values(1)+Cost
263
open(10,file=TRIM(CostFile),position='append')
264
write(10,'(2(ES20.11E3))') GetTime(),Cost
265
close(10)
266
END IF
267
268
END SUBROUTINE BackgroundErrorCostSolver
269
270