Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/Adjoint/Adjoint_CostDiscSolver.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
! * Authors: f. Gillet-Chaulet (IGE, Grenoble,France)
26
! * Email:
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! * Original Date:
30
! *
31
! *****************************************************************************
32
SUBROUTINE Adjoint_CostDiscSolver_init0(Model,Solver,dt,TransientSimulation )
33
!------------------------------------------------------------------------------
34
USE DefUtils
35
IMPLICIT NONE
36
!------------------------------------------------------------------------------
37
TYPE(Solver_t), TARGET :: Solver
38
TYPE(Model_t) :: Model
39
REAL(KIND=dp) :: dt
40
LOGICAL :: TransientSimulation
41
!------------------------------------------------------------------------------
42
! Local variables
43
!------------------------------------------------------------------------------
44
CHARACTER(LEN=MAX_NAME_LEN) :: Name
45
46
Name = ListGetString( Solver % Values, 'Equation',UnFoundFatal=.TRUE.)
47
CALL ListAddNewString( Solver % Values,'Variable',&
48
'-nooutput '//TRIM(Name)//'_var')
49
CALL ListAddLogical(Solver % Values, 'Optimize Bandwidth',.FALSE.)
50
51
CALL ListAddInteger(Solver % Values, 'Nonlinear System Norm Degree',0)
52
53
END SUBROUTINE Adjoint_CostDiscSolver_init0
54
!------------------------------------------------------------------------------
55
!------------------------------------------------------------------------------
56
SUBROUTINE Adjoint_CostDiscSolver( Model,Solver,dt,TransientSimulation )
57
!------------------------------------------------------------------------------
58
!------------------------------------------------------------------------------
59
! Discrete cost function evaluated as a sum of the differences at observations points
60
! See documentation under ELMER_SRC/elmerice/Solvers/Documentation/Adjoint_CostDiscSolver.md
61
!******************************************************************************
62
USE ParticleUtils
63
USE GeneralUtils
64
USE DefUtils
65
USE Interpolation
66
#ifdef HAVE_NETCDF
67
USE Netcdf
68
#endif
69
IMPLICIT NONE
70
!------------------------------------------------------------------------------
71
TYPE(Solver_t) :: Solver
72
TYPE(Model_t) :: Model
73
REAL(KIND=dp) :: dt
74
LOGICAL :: TransientSimulation
75
!
76
TYPE(Mesh_t),POINTER :: Mesh
77
TYPE(ValueList_t), POINTER :: SolverParams
78
79
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName="Adjoint_CostDiscSolver"
80
CHARACTER(LEN=MAX_NAME_LEN),SAVE :: CostSolName,VariableName
81
CHARACTER(LEN=MAX_NAME_LEN) :: FVarName
82
CHARACTER(LEN=MAX_NAME_LEN):: ObsFileName
83
CHARACTER(LEN=MAX_NAME_LEN):: SideFile,SideParFile
84
CHARACTER(LEN=MAX_NAME_LEN),SAVE :: CostFile
85
CHARACTER(:), ALLOCATABLE :: OutPutDirectory
86
CHARACTER(*), PARAMETER :: DefaultCostFile = 'CostOfT.dat'
87
88
TYPE(Variable_t), POINTER :: TimeVar ! Time
89
TYPE(Variable_t), POINTER :: CostVar ! Cost Value
90
TYPE(Variable_t), POINTER :: Variable ! Active variable
91
TYPE(Variable_t), POINTER :: VbSol ! The sensitivity
92
REAL(KIND=dp), POINTER :: Vb(:),Values(:)
93
INTEGER, POINTER :: VbPerm(:),Perm(:)
94
INTEGER,SAVE :: VDOFs
95
96
! Variable related to elements
97
TYPE(Element_t),POINTER :: Element
98
TYPE(Nodes_t),SAVE :: ElementNodes
99
INTEGER :: ElementIndex
100
INTEGER, POINTER :: NodeIndexes(:)
101
REAL(KIND=dp),ALLOCATABLE,SAVE :: Basis(:), dBasisdx(:,:)
102
REAL(KIND=dp) :: SqrtElementMetric
103
INTEGER :: n
104
LOGICAL :: stat
105
106
LOGICAL,SAVE :: Firsttime=.true.,Parallel
107
LOGICAL,SAVE :: FirstRound=.True.
108
LOGICAL,SAVE :: SAVE_USED_DATA=.False.
109
LOGICAL,SAVE :: HaveSTD=.FALSE.
110
LOGICAL,SAVE :: CompNorm=.FALSE.
111
LOGICAL :: Found
112
LOGICAL :: ParallelFile,ProcessedFile,ActiveNumbering
113
114
INTEGER :: CoordDIM ! Coordinate system dimension for the observations points
115
INTEGER,SAVE :: VarDIM ! Dimension of the observed Variable
116
REAL(KIND=dp),SAVE :: Lambda
117
118
integer :: i,j,s
119
INTEGER :: k
120
real(kind=dp) :: StdMin
121
real(kind=dp) :: Cost,Cost_S
122
real(kind=dp) :: rms,rms_s
123
real(kind=dp) :: misfit
124
REAL(Kind=dp) :: VmNorm,VoNorm,StdNorm,VmNormb,um,umb
125
real(kind=dp) :: Coord(3),UVW(3)
126
REAL(KIND=dp) :: V(3)
127
INTEGER,SAVE :: NTOT=-1,NTOT_S
128
INTEGER :: AI
129
CHARACTER*10 :: date,temps
130
INTEGER,PARAMETER :: IO=12
131
INTEGER :: ok
132
LOGICAL :: WarnActive
133
LOGICAL :: BoundarySolver
134
135
! Variables with obs.
136
REAL(KIND=dp),ALLOCATABLE,SAVE :: xobs(:,:),Vobs(:,:),StdObs(:,:)
137
INTEGER,ALLOCATABLE,SAVE :: InElement(:)
138
INTEGER,SAVE :: nobs
139
140
! Variables related to netcdf
141
CHARACTER(LEN=MAX_NAME_LEN) :: Xdim,Ydim,VarName
142
REAL(KIND=dp),ALLOCATABLE :: Fillv(:)
143
REAL(KIND=dp),ALLOCATABLE :: xx(:),yy(:),ObsArray(:,:,:),StdObsArray(:,:,:)
144
INTEGER :: XMinIndex,XMaxIndex,YMinIndex,YMaxIndex,nx,ny
145
INTEGER :: NetcdfStatus,varid,ncid,ierr
146
LOGICAL :: NETCDFFormat
147
REAL(KIND=dp) :: xmin,ymin,xmax,ymax
148
149
150
SolverParams => GetSolverParams()
151
152
!! check if we are on a boundary or in the bulk
153
BoundarySolver = ( Solver % ActiveElements(1) > Model % Mesh % NumberOfBulkElements )
154
IF (BoundarySolver) THEN
155
CoordDIM = CoordinateSystemDimension() - 1
156
ELSE
157
CoordDIM = CoordinateSystemDimension()
158
ENDIF
159
160
! Get min/max coordinates of current mesh
161
xmin=MINVAL(Solver%Mesh%Nodes%x(:))
162
xmax=MAXVAL(Solver%Mesh%Nodes%x(:))
163
IF (CoordDIM.GE.2) THEN
164
ymin=MINVAL(Solver%Mesh%Nodes%y(:))
165
ymax=MAXVAL(Solver%Mesh%Nodes%y(:))
166
ENDIF
167
168
169
If (Firsttime) then
170
N = model % MaxElementNodes
171
allocate(ElementNodes % x(N), ElementNodes % y(N), ElementNodes % z(N))
172
allocate(Basis(N), dBasisdx(N,3))
173
174
!!!!!!! Check for parallel run
175
Parallel = .FALSE.
176
IF ( ASSOCIATED( Solver % Matrix % ParMatrix ) ) THEN
177
IF ( Solver % Matrix % ParMatrix % ParEnv % PEs > 1 ) THEN
178
Parallel = .TRUE.
179
END IF
180
END IF
181
182
Lambda = GetConstReal( SolverParams,'Lambda', Found)
183
IF(.NOT.Found) THEN
184
CALL WARN(SolverName,'Keyword >Lambda< not found in section >Solver<')
185
CALL WARN(SolverName,'Taking default value Lambda=1.0')
186
Lambda = 1.0_dp
187
CALL ListAddConstReal( SolverParams,'Lambda',Lambda)
188
End if
189
190
! error is the difference of the norm?
191
CompNorm = ListGetLogical(SolverParams,'Compute norm difference', Found)
192
IF(.NOT.Found) CompNorm=.FALSE.
193
194
!! Give information about standard error
195
HaveSTD=ListGetLogical(SolverParams,'Use standard error',Found)
196
IF (.NOT.Found) HaveSTD=.False.
197
IF (HaveSTD) THEN
198
StdMin=ListGetConstReal(SolverParams,'standard error Min Value',Found)
199
IF (.NOT.Found) StdMin=100*AEPS
200
END IF
201
202
!!!!!!!!!!! get Solver Variables
203
204
CostFile = ListGetString(Solver % Values,'Cost Filename',Found )
205
IF (.NOT. Found) CostFile = DefaultCostFile
206
CALL DATE_AND_TIME(date,temps)
207
If (Parallel) then
208
if (ParEnv % MyPe.EQ.0) then
209
OPEN (IO, FILE=CostFile)
210
write(IO,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)
211
write(IO,1001) Lambda
212
IF (HaveSTD) THEN
213
write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs),rms'
214
ELSE
215
write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs)'
216
END IF
217
CLOSE(IO)
218
End if
219
Else
220
OPEN (IO, FILE=CostFile)
221
write(IO,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)
222
write(IO,1001) Lambda
223
IF (HaveSTD) THEN
224
write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs),rms'
225
ELSE
226
write(IO,'(A)') '# iter, Lambda*J0, sqrt(2*J0/Nobs)'
227
END IF
228
CLOSE(IO)
229
End if
230
231
CostSolName = GetString( SolverParams,'Cost Variable Name', Found)
232
IF(.NOT.Found) THEN
233
CALL WARN(SolverName,'Keyword >Cost Variable Name< not found in section >Solver<')
234
CALL WARN(SolverName,'Taking default value >CostValue<')
235
WRITE(CostSolName,'(A)') 'CostValue'
236
END IF
237
238
VariableName = ListGetString( SolverParams,'Observed Variable Name', UnFoundFatal=.TRUE.)
239
Variable => VariableGet( Solver % Mesh % Variables, Trim(VariableName) ,UnFoundFatal=.TRUE. )
240
VDOFs=Variable%DOFs
241
242
VarDIM=GetInteger(SolverParams ,'Observed Variable Dimension',Found)
243
IF (.NOT.Found) THEN
244
VarDIM=MIN(VDOFs,CoordDIM)
245
WRITE(message,*) 'Keyword >Observed Variable Dimension< not found, assume VarDIM = ',VarDIM
246
CALL WARN(SolverName,message)
247
ENDIF
248
249
!! Get the obs
250
ObsFileName = ListGetString( SolverParams,'Observation File Name', UnFoundFatal=.TRUE.)
251
252
!! I the file netcf?
253
k = INDEX(ObsFileName ,'.nc' )
254
NETCDFFormat = ( k /= 0 )
255
256
IF (NETCDFFormat) then
257
258
#ifdef HAVE_NETCDF
259
260
IF (CoordDIM.NE.2) CALL FATAL(Trim(SolverName),'Netcdf only supported for 2D')
261
262
CALL INFO(Trim(SolverName),'Data File is in netcdf format', Level=5)
263
264
NetCDFstatus = NF90_OPEN(trim(ObsFileName),NF90_NOWRITE,ncid)
265
IF ( NetCDFstatus /= NF90_NOERR ) &
266
CALL FATAL(Trim(SolverName), 'Unable to open NETCDF File')
267
268
Xdim=ListGetString( SolverParams,"X Dim Name", Found )
269
if (.NOT.Found) Xdim='x'
270
271
NetCDFstatus = nf90_inq_dimid(ncid, trim(Xdim) , varid)
272
IF ( NetCDFstatus /= NF90_NOERR ) &
273
CALL FATAL(Trim(SolverName),'Unable to get netcdf x-dim Id')
274
275
NetCDFstatus = nf90_inquire_dimension(ncid,varid,len=nx)
276
IF ( NetCDFstatus /= NF90_NOERR ) &
277
CALL FATAL(Trim(SolverName), 'Unable to get netcdf nx')
278
279
Ydim=ListGetString( SolverParams,"Y Dim Name", Found )
280
if (.NOT.Found) Ydim='y'
281
282
NetCDFstatus = nf90_inq_dimid(ncid, trim(Ydim) , varid)
283
IF ( NetCDFstatus /= NF90_NOERR ) &
284
CALL FATAL(Trim(SolverName),'Unable to get netcdf y-dim Id')
285
286
NetCDFstatus = nf90_inquire_dimension(ncid,varid,len=ny)
287
IF ( NetCDFstatus /= NF90_NOERR ) &
288
CALL FATAL(Trim(SolverName), 'Unable to get netcdf ny')
289
290
ALLOCATE(xx(nx),yy(ny))
291
292
!! Get X and Y variable
293
Xdim=ListGetString( SolverParams, "X Var Name", Found )
294
if (.NOT.Found) Xdim='x'
295
NetCDFstatus = nf90_inq_varid(ncid,trim(Xdim),varid)
296
IF ( NetCDFstatus /= NF90_NOERR ) &
297
CALL FATAL(Trim(SolverName),'Unable to get netcdf x-variable id')
298
299
NetCDFstatus = nf90_get_var(ncid, varid,xx)
300
IF ( NetCDFstatus /= NF90_NOERR ) &
301
CALL FATAL(Trim(SolverName), 'Unable to get netcdf x-variable ')
302
303
Ydim=ListGetString( SolverParams, "Y Var Name", Found )
304
if (.NOT.Found) Ydim='y'
305
NetCDFstatus = nf90_inq_varid(ncid,trim(Ydim),varid)
306
IF ( NetCDFstatus /= NF90_NOERR ) &
307
CALL FATAL(Trim(SolverName),'Unable to get netcdf x-variable id')
308
309
NetCDFstatus = nf90_get_var(ncid, varid,yy)
310
IF ( NetCDFstatus /= NF90_NOERR ) &
311
CALL FATAL(Trim(SolverName), 'Unable to get netcdf x-variable ')
312
313
!! Check that there is data within the domain
314
IF ((MAXVAL(xx).LT.xmin).OR.(MINVAL(xx).GT.xmax)&
315
.OR.(MAXVAL(yy).LT.ymin).OR.(MINVAL(yy).GT.ymax)) &
316
CALL Fatal(Trim(SolverName), &
317
'No data within model domain')
318
!!! get the index of values that are within the mesh bounding box
319
CALL MinMaxIndex(xx,nx,xmin,xmax,XMinIndex,XMaxIndex)
320
CALL MinMaxIndex(yy,ny,ymin,ymax,YMinIndex,YMaxIndex)
321
322
323
!! get ux and uy
324
nx=XMaxIndex-XMinIndex+1
325
ny=YMaxIndex-YMinIndex+1
326
ALLOCATE(ObsArray(nx,ny,VarDIM),fillv(VarDIM))
327
IF (HaveSTD) ALLOCATE(StdObsArray(nx,ny,VarDIM))
328
329
DO k=1,VarDIM
330
IF (VarDIM==1) THEN
331
VarName=ListGetString( SolverParams, "Netcdf Var Name", Found )
332
IF (.NOT.Found) VarName=TRIM(VariableName)
333
ELSE
334
VarName=ListGetString( SolverParams, TRIM(ComponentName("Netcdf Var",k)) // " Name", Found )
335
IF (.NOT.Found) THEN
336
CALL WARN(SolverName,'keyword <' // &
337
TRIM(ComponentName("Netcdf Var",k)) // " Name" // ' not found, taking default')
338
select case (k)
339
case (1)
340
VarName='vx'
341
case (2)
342
VarName='vy'
343
end select
344
ENDIF
345
ENDIF
346
NetCDFstatus = nf90_inq_varid(ncid,trim(VarName),varid)
347
IF ( NetCDFstatus /= NF90_NOERR ) &
348
CALL Fatal(Trim(SolverName),'Unable to get netcdf variable id for ' // TRIM(VarName))
349
NetCDFstatus = nf90_get_var(ncid, Varid, ObsArray(:, :,k), &
350
start = (/ XMinIndex, YMinIndex /), &
351
count = (/ nx,ny/))
352
IF ( NetCDFstatus /= NF90_NOERR ) &
353
CALL Fatal(Trim(SolverName),'Unable to get netcdf variable' // TRIM(VarName))
354
NetCDFstatus = nf90_get_att(ncid, varid,"_FillValue",fillv(k))
355
IF ( NetCDFstatus /= NF90_NOERR ) &
356
CALL FATAL(Trim(SolverName),TRIM(VarName) // 'has no attribute _FillValue')
357
END DO
358
359
IF (HaveSTD) THEN
360
DO k=1,VarDIM
361
IF (VarDIM==1) THEN
362
VarName=ListGetString( SolverParams, "Netcdf Std Var Name", UnFoundFatal=.True. )
363
ELSE
364
VarName=ListGetString( SolverParams, TRIM(ComponentName("Netcdf Std Var",k)) // " Name", Found )
365
IF (.NOT.Found) THEN
366
CALL WARN(SolverName,'keyword <' // &
367
TRIM(ComponentName("Netcdf Std Var",k)) // " Name" // ' not found, taking default')
368
select case (k)
369
case (1)
370
VarName='ex'
371
case (2)
372
VarName='ey'
373
end select
374
ENDIF
375
ENDIF
376
NetCDFstatus = nf90_inq_varid(ncid,trim(VarName),varid)
377
IF ( NetCDFstatus /= NF90_NOERR ) &
378
CALL Fatal(Trim(SolverName),'Unable to get netcdf variable id for ' // TRIM(VarName))
379
NetCDFstatus = nf90_get_var(ncid, Varid, StdObsArray(:, :,k), &
380
start = (/ XMinIndex, YMinIndex /), &
381
count = (/ nx,ny/))
382
IF ( NetCDFstatus /= NF90_NOERR ) &
383
CALL Fatal(Trim(SolverName),'Unable to get netcdf variable' // TRIM(VarName))
384
END DO
385
END IF
386
387
!! close netcdf
388
NetCDFstatus = nf90_close(ncid)
389
390
!!
391
ALLOCATE(xobs(nx*ny,3),Vobs(nx*ny,VarDIM))
392
IF (HaveSTD) ALLOCATE(StdObs(nx*ny,VarDIM))
393
394
ALLOCATE(InElement(nx*ny))
395
InElement(:)=-1
396
xobs=0._dp
397
Vobs=0._dp
398
399
nobs=0
400
Do i=1,nx
401
Do j=1,ny
402
IF (ANY(abs(ObsArray(i,j,:)-fillv(:)).LT.AEPS)) CYCLE
403
nobs=nobs+1
404
xobs(nobs,1)=xx(XMinIndex+i-1)
405
xobs(nobs,2)=yy(YMinIndex+j-1)
406
Do k=1,VarDIM
407
Vobs(nobs,k)=ObsArray(i,j,k)
408
IF (HaveSTD) &
409
StdObs(nobs,k)=max(StdObsArray(i,j,k),StdMin)
410
END DO
411
End do
412
End do
413
414
DEALLOCATE(xx,yy,ObsArray,fillv)
415
IF (HaveSTD) DEALLOCATE(StdObsArray)
416
417
#else
418
419
CALL FATAL(Trim(SolverName),'Elmer/Ice has not been installed with netcdf -convert your file to ASCII table--')
420
421
#endif
422
423
Else !.not.NETCDFFormat
424
425
ParallelFile = .False.
426
ParallelFile = GetLogical(SolverParams,'Parallel Observation Files', Found)
427
if (Parallel.AND.ParallelFile) THEN
428
SideParFile = AddFilenameParSuffix(ObsFileName,'dat',Parallel,ParEnv % MyPe)
429
ELSE
430
SideParFile = trim(ObsFileName)
431
ENDIF
432
433
ProcessedFile = ListGetLogical(SolverParams,'Pre-Processed File')
434
IF (ProcessedFile) THEN
435
ActiveNumbering=ListGetLogical(SolverParams,"Element Number is Active Number")
436
ENDIF
437
438
open(IO,file=trim(SideParFile),status = 'old',iostat = ok)
439
if(ok /= 0) then
440
write(message,'(A,A)') 'Unable to open file ',TRIM(ObsFileName)
441
CALL Fatal(Trim(SolverName),Trim(message))
442
end if
443
nobs=0
444
do while(ok == 0)
445
read(io,*,iostat = ok)
446
if (ok == 0) nobs = nobs + 1
447
end do
448
close(IO)
449
450
ALLOCATE(xobs(nobs,3),Vobs(nobs,VarDIM))
451
IF (HaveSTD) ALLOCATE(StdObs(nobs,VarDIM))
452
ALLOCATE(InElement(nobs))
453
InElement(:)=-1
454
455
Vobs=0.0_dp
456
xobs=0.0_dp
457
open(IO,file=trim(SideParFile))
458
do i=1,nobs
459
IF (ProcessedFile) THEN
460
IF (HaveSTD) THEN
461
read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM),(StdObs(i,j),j=1,VarDIM),AI
462
ELSE
463
read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM),AI
464
END IF
465
466
IF (ActiveNumbering) THEN
467
Element => GetActiveElement(AI)
468
IF (.NOT.ASSOCIATED(Element)) &
469
CALL FATAL(SolverName,'No Active Element')
470
InElement(i) = Element % ElementIndex
471
ELSE
472
InElement(i) = AI
473
ENDIF
474
ELSE
475
IF (HaveSTD) THEN
476
read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM),(StdObs(i,j),j=1,VarDIM)
477
ELSE
478
read(IO,*) (xobs(i,j),j=1,CoordDIM),(Vobs(i,j),j=1,VarDIM)
479
ENDIF
480
ENDIF
481
end do
482
close(IO)
483
ENDIF
484
485
SAVE_USED_DATA = GetLogical(SolverParams,'Save used data', Found)
486
IF (SAVE_USED_DATA) THEN
487
SideFile =ListGetString(SolverParams,"output data file name",UnfoundFatal=.TRUE.)
488
CALL SolverOutputDirectory( Solver, SideFile, OutputDirectory )
489
SideFile = TRIM(OutputDirectory)// '/' //TRIM(SideFile)
490
SideParFile = AddFilenameParSuffix(SideFile,'dat',Parallel,ParEnv % MyPe)
491
END IF
492
493
!!! End of First visit
494
Firsttime=.false.
495
Endif
496
497
! Get the variable solution
498
Variable => VariableGet( Solver % Mesh % Variables, Trim(VariableName), UnFoundFatal=.TRUE. )
499
Values => Variable % Values
500
Perm => Variable % Perm
501
502
! Get the sensitivity variable
503
IF ( SEQL(TRIM(VariableName),'flow solution').OR.SEQL(TRIM(VariableName),'ssavelocity')) THEN
504
FVarName = 'Velocityb'
505
ELSE
506
FVarName = TRIM(VariableName) // 'b'
507
ENDIF
508
VbSol => VariableGet( Solver % Mesh % Variables,TRIM(FVarName), UnFoundFatal=.TRUE. )
509
Vb => VbSol % Values
510
VbPerm => VbSol % Perm
511
Vb=0.0_dp
512
513
IF (VbSol%DOFs.NE.Variable%DOFs) &
514
CALL FATAL(Trim(SolverName),'DOFs do not correspond')
515
IF (VarDIM.GT.Variable%DOFs) &
516
CALL FATAL(Trim(SolverName),'Observed Variable DIM too large')
517
!
518
Mesh => GetMesh()
519
520
! Temporary trick to disable Warnings as LocateParticleInMeshOctree
521
! will send a lot of warning for data points not found in the emsh
522
IF (FirstRound) THEN
523
WarnActive=OutputLevelMask(2)
524
OutputLevelMask(2)=.FALSE.
525
ENDIF
526
527
! Compute the cost
528
Cost=0._dp
529
rms=0._dp
530
531
Element => GetActiveElement(1)
532
ElementIndex = Element % ElementIndex
533
534
CALL StartAdvanceOutput(SolverName,'Compute cost')
535
Do s=1,nobs
536
537
CALL AdvanceOutput(s,nobs)
538
539
IF (FirstRound.AND.(InElement(s)<0)) then
540
!Need to find in which Element the data point resides
541
! First check that it is within the computation domain
542
Coord=0._dp
543
Coord(1:CoordDIM)=xobs(s,1:CoordDIM)
544
IF ((Coord(1).GT.xmax).OR.(Coord(1).LT.xmin)) CYCLE
545
IF (CoordDIM.GE.2) THEN
546
IF ((Coord(2).GT.ymax).OR.(Coord(2).LT.ymin)) CYCLE
547
END IF
548
549
IF (CoordDIM.LT.CoordinateSystemDimension()) THEN
550
! we are in a lower dimension than the mesh
551
! => use brute force search
552
553
! first check in the current elmement
554
Element => Mesh % Elements(ElementIndex)
555
n = GetElementNOFNodes(Element)
556
NodeIndexes => Element % NodeIndexes
557
ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)
558
IF (CoordDIM == 1) THEN
559
ElementNodes % y(1:n) = 0.0_dp
560
ElementNodes % z(1:n) = 0.0_dp
561
ELSE IF (CoordDIM == 2) THEN
562
ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)
563
ElementNodes % z(1:n) = 0.0_dp
564
ENDIF
565
IF (PointInElement(Element,ElementNodes,Coord(:),UVW)) THEN
566
IF (.NOT.CheckPassiveElement(Element)) &
567
InElement(s)=ElementIndex
568
569
ELSE
570
! go through all elements
571
Do i=1,Solver%NumberOfActiveElements
572
Element => GetActiveElement(i)
573
n = GetElementNOFNodes(Element)
574
NodeIndexes => Element % NodeIndexes
575
ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)
576
IF (CoordDIM == 1) THEN
577
ElementNodes % y(1:n) = 0.0_dp
578
ElementNodes % z(1:n) = 0.0_dp
579
ELSE IF (CoordDIM == 2) THEN
580
ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)
581
ElementNodes % z(1:n) = 0.0_dp
582
ENDIF
583
IF (PointInElement(Element,ElementNodes,Coord(:),UVW)) THEN
584
IF (CheckPassiveElement(Element)) Exit
585
ElementIndex= Element % ElementIndex
586
InElement(s)=ElementIndex
587
Exit
588
END IF
589
End Do
590
END IF
591
592
ELSE
593
!> use particles meshoctree
594
ElementIndex=-1 ! don't know why but if i don't reset ElmentIndex it fails
595
CALL LocateParticleInMeshOctree( ElementIndex,Coord)
596
If (ElementIndex.NE.0) THEN
597
InElement(s)=ElementIndex
598
Element => Mesh % Elements(ElementIndex)
599
IF (CheckPassiveElement(Element).OR. &
600
(Element % PartIndex /= ParEnv % myPE)) THEN
601
InElement(s)=-1
602
END IF
603
END IF
604
605
END IF
606
ENDIF !End if FirstRound
607
608
609
! Data Point has been found in one element
610
IF (InElement(s)>0) THEN
611
Element => Mesh % Elements(InElement(s))
612
n = GetElementNOFNodes(Element)
613
NodeIndexes => Element % NodeIndexes
614
! set coords of highest occurring dimension to zero (to get correct path element)
615
!-------------------------------------------------------------------------------
616
ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)
617
IF (CoordDIM == 1) THEN
618
ElementNodes % y(1:n) = 0.0_dp
619
ElementNodes % z(1:n) = 0.0_dp
620
ELSE IF (CoordDIM == 2) THEN
621
ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)
622
ElementNodes % z(1:n) = 0.0_dp
623
ELSE IF (CoordDIM == 3) THEN
624
ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)
625
ElementNodes % z(1:n) = Solver % Mesh % Nodes % z(NodeIndexes)
626
END IF
627
628
IF (.NOT.PointInElement(Element,ElementNodes,xobs(s,1:3),UVW)) THEN
629
PRINT *,ParEnv%MyPE,'eindex',Element % ElementIndex
630
PRINT *,ParEnv%MyPE,'obs. coords',xobs(s,1:2)
631
PRINT *,ParEnv%MyPE,'node indexes',NodeIndexes(1:n)
632
PRINT *,ParEnv%MyPE,'nodex',ElementNodes % x(1:n)
633
PRINT *,ParEnv%MyPE,'nodey',ElementNodes % y(1:n)
634
635
CALL FATAL(SolverName,'Point was supposed to be found in this element')
636
ELSE
637
stat = ElementInfo( Element,ElementNodes,UVW(1),UVW(2),UVW(3),SqrtElementMetric, &
638
Basis,dBasisdx )
639
640
IF (CompNorm) THEN
641
VmNorm=0._dp
642
VoNorm=0._dp
643
StdNorm=0._dp
644
Do i=1,VarDIM
645
um=SUM(Values(VDOFs*(Perm(NodeIndexes(1:n))-1)+i)*basis(1:n))
646
VmNorm=VmNorm+um**2
647
VoNorm=VoNorm+Vobs(s,i)**2
648
IF (HaveSTD) &
649
StdNorm=StdNorm+StdObs(s,i)**2
650
END DO
651
misfit=sqrt(VmNorm)-sqrt(VoNorm)
652
IF (HaveSTD) then
653
rms=rms+misfit**2
654
misfit=misfit/sqrt(StdNorm)
655
ENDIF
656
Cost = Cost + 0.5*Lambda*misfit**2
657
VmNormb=Lambda*misfit
658
IF (HaveSTD) &
659
VmNormb=VmNormb/sqrt(StdNorm)
660
IF (VmNorm.GT.10*AEPS) THEN
661
VmNormb=0.5*VmNormb*VmNorm**(-0.5)
662
ELSE
663
VmNormb=0._dp
664
END IF
665
666
Do i=1,VarDIM
667
um=SUM(Values(VDOFs*(Perm(NodeIndexes(1:n))-1)+i)*basis(1:n))
668
umb=2*um*VmNormb
669
Do j=1,n
670
k=VDOFS*(VbPerm(NodeIndexes(j))-1)+i
671
Vb(k)=Vb(k)+umb*basis(j)
672
End do
673
END DO
674
675
676
ELSE
677
! Update cost
678
Do i=1,VarDIM
679
V(i)=SUM(Values(VDOFs*(Perm(NodeIndexes(1:n))-1)+i)*basis(1:n))
680
misfit=(V(i)-Vobs(s,i))
681
IF (HaveSTD) then
682
rms=rms+misfit**2
683
misfit=misfit/StdObs(s,i)
684
END IF
685
Cost=Cost+0.5*Lambda*misfit**2
686
End do
687
688
!Derivative of Cost at nodal Point
689
! derivative of (V(i)-Vobs(s,i))**2/std**2=
690
! 2*(V(i)-Vobs(s,i))/std**2 * (dV(i)/Vnodal)
691
Do j=1,n
692
Do i=1,VarDIM
693
k=VDOFS*(VbPerm(NodeIndexes(j))-1)+i
694
misfit=(V(i)-Vobs(s,i))
695
IF (HaveSTD) misfit=misfit/StdObs(s,i)**2
696
Vb(k)=Vb(k)+Lambda*misfit*basis(j)
697
End do
698
End Do
699
700
ENDIF
701
702
END IF
703
704
ELSE
705
706
WRITE(Message,'(a,I0,ES20.11E3,ES20.11E3,ES20.11E3,a)')&
707
'Data Point ',s,xobs(s,1:3),' found in no element'
708
CALL Info( SolverName, Message,level=15)
709
END IF
710
711
END DO !Do on s
712
713
714
if (NTOT < 0) NTOT=COUNT(InElement(:)>0)
715
!! Save Cost as a function of time
716
717
TimeVar => VariableGet( Solver % Mesh % Variables, 'Time' )
718
719
IF (Parallel) THEN
720
CALL MPI_ALLREDUCE(NTOT,NTOT_S,1,&
721
MPI_INTEGER,MPI_SUM,ELMER_COMM_WORLD,ierr)
722
CALL MPI_ALLREDUCE(Cost,Cost_S,1,&
723
MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)
724
IF (HaveSTD) &
725
CALL MPI_ALLREDUCE(rms,rms_S,1,&
726
MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)
727
CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )
728
IF (ASSOCIATED(CostVar)) THEN
729
CostVar % Values(1)=Cost_S
730
END IF
731
IF (Solver % Matrix % ParMatrix % ParEnv % MyPE == 0) then
732
OPEN (IO, FILE=CostFile,POSITION='APPEND')
733
IF (HaveSTD) THEN
734
write(IO,'(4(ES20.11E3))') TimeVar % Values(1),Cost_S,&
735
sqrt(2.0*Cost_S/(NTOT_S*Lambda)),sqrt(rms_S/NTOT_S)
736
ELSE
737
write(IO,'(3(ES20.11E3))') TimeVar % Values(1),Cost_S,sqrt(2.0*Cost_S/(NTOT_S*Lambda))
738
END IF
739
CLOSE(IO)
740
write(Message,'(A,A,I0)') trim(SolverName),'total number of data points:',NTOT_S
741
call INFO(SolverName,Message,level=3)
742
End if
743
ELSE
744
CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )
745
IF (ASSOCIATED(CostVar)) THEN
746
CostVar % Values(1)=Cost
747
END IF
748
OPEN (IO, FILE=CostFile,POSITION='APPEND')
749
IF (HaveSTD) THEN
750
write(IO,'(4(ES20.11E3))') TimeVar % Values(1),Cost,&
751
sqrt(2.0*Cost/(NTOT*Lambda)),sqrt(rms/NTOT)
752
ELSE
753
write(IO,'(3(ES20.11E3))') TimeVar % Values(1),Cost,sqrt(2.0*Cost/(NTOT*Lambda))
754
END IF
755
close(IO)
756
write(Message,'(A,A,I0)') trim(SolverName),'total number of data points:',NTOT
757
call INFO(SolverName,Message,level=3)
758
Cost_S=Cost
759
END IF
760
761
Solver % Variable % Values(1)=Cost_S
762
763
If (FirstRound.AND.SAVE_USED_DATA) THEN
764
765
766
open(IO,File=SideParFile)
767
Do s=1,nobs
768
If (InElement(s)>0) then
769
DO i=1,CoordDIM
770
write(IO,'(ES20.11E3)',ADVANCE='NO') xobs(s,i)
771
END DO
772
DO i=1,VarDIM
773
write(IO,'(ES20.11E3)',ADVANCE='NO') Vobs(s,i)
774
END DO
775
IF (HaveSTD) THEN
776
DO i=1,VarDIM
777
write(IO,'(ES20.11E3)',ADVANCE='NO') StdObs(s,i)
778
END DO
779
END IF
780
write(IO,'(x,I0)') InElement(s)
781
End if
782
End do
783
close(IO)
784
785
END IF
786
787
! Reset Warning level to previous value
788
IF (FirstRound) THEN
789
OutputLevelMask(2)=WarnActive
790
ENDIF
791
792
FirstRound=.False.
793
Return
794
795
1000 format('#date,time,',a2,'/',a2,'/',a4,',',a2,':',a2,':',a2)
796
1001 format('#lambda,',e15.8)
797
798
CONTAINS
799
! Find the min and max indexes of values within bBox
800
SUBROUTINE MinMaxIndex(x,n,minx,maxx,MinIndex,MaxIndex)
801
IMPLICIT NONE
802
REAL(KIND=dp),INTENT(IN) :: x(:),minx,maxx
803
INTEGER,INTENT(IN) :: n
804
INTEGER,INTENT(OUT) :: MinIndex,MaxIndex
805
806
IF (n.EQ.1) THEN
807
MinIndex=1
808
MaxIndex=1
809
Return
810
ENDIF
811
812
! coordinates should be monotonically increasing or
813
! decreasing
814
IF ((x(2)>x(1)).AND.(x(n)>x(n-1))) THEN
815
MinIndex = MAXLOC(x, DIM=1,MASK=(x < minx))
816
MinIndex=MAX(MinIndex,1)
817
818
MaxIndex = MINLOC(x, DIM=1,MASK=(x > maxx))
819
IF (MaxIndex.LE.1) MaxIndex=n
820
ELSE IF ((x(2)<x(1)).AND.(x(n)<x(n-1))) THEN
821
MaxIndex = MAXLOC(x, DIM=1,MASK=(x < minx))
822
IF (MaxIndex.LE.1) MaxIndex=n
823
824
MinIndex = MINLOC(x, DIM=1,MASK=(x > maxx))
825
MinIndex=MAX(MinIndex,1)
826
ELSE
827
CALL FATAL(SolverName,'coordinate is neither monotonically increasing or decreasing')
828
ENDIF
829
830
IF (MaxIndex.LT.MinIndex) THEN
831
WRITE(message,*) 'Error Min Max Indexes ',MinIndex,MaxIndex
832
CALL WARN(SolverName,message)
833
WRITE(message,*) 'Min values ',MINVAL(x),minx
834
CALL WARN(SolverName,message)
835
WRITE(message,*) 'Max values ',MAXVAL(x),maxx
836
CALL WARN(SolverName,message)
837
CALL FATAL(SolverName,'This is a fatal error')
838
ENDIF
839
840
END SUBROUTINE MinMaxIndex
841
842
!------------------------------------------------------------------------------
843
END SUBROUTINE Adjoint_CostDiscSolver
844
!------------------------------------------------------------------------------
845
! *****************************************************************************
846
847