Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/AdjointSSA/AdjointSSA_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 (LGGE, Grenoble,France)
26
! * Email: [email protected]
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! * Original Date:
30
! *
31
! *****************************************************************************
32
SUBROUTINE AdjointSSA_CostDiscSolver( Model,Solver,dt,TransientSimulation )
33
!------------------------------------------------------------------------------
34
!------------------------------------------------------------------------------
35
!Compute the Cost function of the SSA Adjoint inverse Problem as: SUM_1^Nobs (u-u^obs)2
36
! where u is evaluated at observation location
37
! Serial/Parallel 2D/3D
38
!
39
! OUTPUT are : J and DJDu (==Velocityb variable used as forcing of the SSA adjoint problem)
40
!
41
! !! Be careful this solver will reset the cost and DJDu to 0; so it has to
42
! be used as the first cost solver if regularistaion of flux divergence cost
43
! solvers are used in the simulation!!
44
!
45
!
46
! INPUT PARAMETERS are:
47
!
48
! In solver section:
49
! Problem Dimension = Integer (default = Coordinate system dimension)
50
! Cost Filename = File (default = 'CostOfT.dat')
51
! Cost Variable Name = String (default= 'CostValue')
52
! Lambda = Real (default= '1.0')
53
! Observed Variable Name = String
54
! Observation File Name = File
55
! Parallel observation Files = Logical
56
! Save use data = logical
57
!
58
! Variables
59
! Velocityb (forcing for the adjoint pb;DOFs== Pb dimension)
60
!
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
74
REAL(KIND=dp) :: dt
75
LOGICAL :: TransientSimulation
76
!
77
CHARACTER(LEN=MAX_NAME_LEN), PARAMETER :: DefaultCostFile = 'CostOfT.dat'
78
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName="Adjoint Solver"
79
CHARACTER(LEN=MAX_NAME_LEN) :: CostFile,UsedDataFile
80
CHARACTER(LEN=MAX_NAME_LEN) :: CostSolName,VariableName,ObsFileName
81
TYPE(Mesh_t),POINTER :: Mesh
82
TYPE(Element_t),POINTER :: Element
83
TYPE(Variable_t), POINTER :: TimeVar,CostVar
84
TYPE(Variable_t), POINTER :: VelocitybSol,Variable
85
TYPE(ValueList_t), POINTER :: SolverParams
86
TYPE(Nodes_t) :: ElementNodes
87
REAL(KIND=dp), POINTER :: Vb(:),Values(:)
88
INTEGER, POINTER :: NodeIndexes(:)
89
INTEGER, POINTER :: VbPerm(:),Perm(:)
90
Logical :: Firsttime=.true.,Found,Parallel,ParallelFile,stat,Gotit
91
integer :: i,j,k,l,s,t,n,NMAX,DIM,ierr,c,ok
92
real(kind=dp) :: Cost,Cost_S,Lambda
93
real(kind=dp) :: Coord(3),UVW(3),coeff,SqrtElementMetric,x
94
REAL(KIND=dp),ALLOCATABLE,SAVE :: Basis(:), dBasisdx(:,:)
95
REAL(KIND=dp) :: xmin,ymin,xmax,ymax
96
INTEGER,SAVE :: VDOFs
97
REAL(KIND=dp) :: V(3)
98
REAL(KIND=dp),ALLOCATABLE,SAVE :: xobs(:,:),Vobs(:,:)
99
REAL(KIND=dp),ALLOCATABLE :: xx(:),yy(:),ux(:,:),uy(:,:)
100
INTEGER,ALLOCATABLE,SAVE :: InElement(:)
101
INTEGER :: ElementIndex
102
INTEGER :: XMinIndex,XMaxIndex,YMinIndex,YMaxIndex,nx,ny
103
INTEGER,SAVE :: NTOT=-1,NTOT_S
104
integer,SAVE :: nobs
105
LOGICAL,SAVE :: FirstRound=.True.,SAVE_USED_DATA=.False.
106
CHARACTER*10 :: date,temps
107
INTEGER,PARAMETER :: IO=12
108
LOGICAL :: WarnActive
109
110
LOGICAL :: NETCDFFormat
111
INTEGER :: NetcdfStatus,varid,ncid
112
CHARACTER(LEN=MAX_NAME_LEN) :: Xdim,Ydim,VarName
113
REAL(KIND=dp):: UxFillv,UyFillv
114
REAL(KIND=dp):: NodalU,NodalV
115
116
save Firsttime,Parallel
117
save SolverName,CostSolName,CostFile,VariableName
118
save ElementNodes
119
120
CALL Info(SolverName,'***********************',level=0)
121
CALL Info(SolverName,' This solver has been replaced by:',level=0)
122
CALL Info(SolverName,' Adjoint_CostDiscSolver ',level=0)
123
CALL Info(SolverName,' See documentation under: ',level=0)
124
CALL Info(SolverName,' elmerice/Solvers/Documentation ',level=0)
125
CALL Info(SolverName,'***********************',level=0)
126
CALL FATAL(SolverName,' Use new solver !!')
127
128
SolverParams => GetSolverParams()
129
DIM=GetInteger(SolverParams ,'Problem Dimension',Found)
130
If (.NOT.Found) then
131
CALL WARN(SolverName,'Keyword >Problem Dimension< not found, assume DIM = CoordinateSystemDimension()')
132
DIM = CoordinateSystemDimension()
133
Endif
134
135
! Get min/max coordinates of current mesh
136
xmin=MINVAL(Solver%Mesh%Nodes%x(:))
137
xmax=MAXVAL(Solver%Mesh%Nodes%x(:))
138
IF (DIM.EQ.2) THEN
139
ymin=MINVAL(Solver%Mesh%Nodes%y(:))
140
ymax=MAXVAL(Solver%Mesh%Nodes%y(:))
141
ENDIF
142
143
Lambda = GetConstReal( SolverParams,'Lambda', Found)
144
IF(.NOT.Found) THEN
145
CALL WARN(SolverName,'Keyword >Lambda< not found in section >Solver<')
146
CALL WARN(SolverName,'Taking default value Lambda=1.0')
147
Lambda = 1.0_dp
148
CALL ListAddConstReal( SolverParams,'Lambda',Lambda)
149
End if
150
151
If (Firsttime) then
152
N = model % MaxElementNodes
153
allocate(ElementNodes % x(N), ElementNodes % y(N), ElementNodes % z(N))
154
allocate(Basis(N), dBasisdx(N,3))
155
156
!!!!!!! Check for parallel run
157
Parallel = .FALSE.
158
IF ( ASSOCIATED( Solver % Matrix % ParMatrix ) ) THEN
159
IF ( Solver % Matrix % ParMatrix % ParEnv % PEs > 1 ) THEN
160
Parallel = .TRUE.
161
END IF
162
END IF
163
164
WRITE(SolverName, '(A)') 'CostSolver_Adjoint'
165
166
!!!!!!!!!!! get Solver Variables
167
168
CostFile = ListGetString(Solver % Values,'Cost Filename',Found )
169
IF (.NOT. Found) CostFile = DefaultCostFile
170
CALL DATE_AND_TIME(date,temps)
171
If (Parallel) then
172
if (ParEnv % MyPe.EQ.0) then
173
OPEN (IO, FILE=CostFile)
174
write(IO,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)
175
write(IO,1001) Lambda
176
write(IO,'(A)') '# iter, Lambda*J0, rms'
177
CLOSE(IO)
178
End if
179
Else
180
OPEN (IO, FILE=CostFile)
181
write(IO,1000) date(5:6),date(7:8),date(1:4),temps(1:2),temps(3:4),temps(5:6)
182
write(IO,1001) Lambda
183
write(IO,*)'# iter, Lambda*J0, rms'
184
CLOSE(IO)
185
End if
186
187
CostSolName = GetString( SolverParams,'Cost Variable Name', Found)
188
IF(.NOT.Found) THEN
189
CALL WARN(SolverName,'Keyword >Cost Variable Name< not found in section >Solver<')
190
CALL WARN(SolverName,'Taking default value >CostValue<')
191
WRITE(CostSolName,'(A)') 'CostValue'
192
END IF
193
194
VariableName = ListGetString( SolverParams,'Observed Variable Name', UnFoundFatal=.TRUE.)
195
Variable => VariableGet( Solver % Mesh % Variables, Trim(VariableName) ,UnFoundFatal=.TRUE. )
196
VDOFs=Variable%DOFs
197
198
!! Get the obs
199
ObsFileName = ListGetString( SolverParams,'Observation File Name', UnFoundFatal=.TRUE.)
200
201
!! I the file netcf?
202
k = INDEX(ObsFileName ,'.nc' )
203
NETCDFFormat = ( k /= 0 )
204
205
IF (NETCDFFormat) then
206
207
#ifdef HAVE_NETCDF
208
209
IF (DIM.NE.2) CALL FATAL(Trim(SolverName),'Netcdf only supported for 2D')
210
211
CALL INFO(Trim(SolverName),'Data File is in netcdf format', Level=5)
212
213
NetCDFstatus = NF90_OPEN(trim(ObsFileName),NF90_NOWRITE,ncid)
214
IF ( NetCDFstatus /= NF90_NOERR ) &
215
CALL FATAL(Trim(SolverName), 'Unable to open NETCDF File')
216
217
Xdim=ListGetString( SolverParams,"X Dim Name", Found )
218
if (.NOT.Found) Xdim='x'
219
220
NetCDFstatus = nf90_inq_dimid(ncid, trim(Xdim) , varid)
221
IF ( NetCDFstatus /= NF90_NOERR ) &
222
CALL FATAL(Trim(SolverName),'Unable to get netcdf x-dim Id')
223
224
NetCDFstatus = nf90_inquire_dimension(ncid,varid,len=nx)
225
IF ( NetCDFstatus /= NF90_NOERR ) &
226
CALL FATAL(Trim(SolverName), 'Unable to get netcdf nx')
227
228
Ydim=ListGetString( SolverParams,"Y Dim Name", Found )
229
if (.NOT.Found) Ydim='y'
230
231
NetCDFstatus = nf90_inq_dimid(ncid, trim(Ydim) , varid)
232
IF ( NetCDFstatus /= NF90_NOERR ) &
233
CALL FATAL(Trim(SolverName),'Unable to get netcdf y-dim Id')
234
235
NetCDFstatus = nf90_inquire_dimension(ncid,varid,len=ny)
236
IF ( NetCDFstatus /= NF90_NOERR ) &
237
CALL FATAL(Trim(SolverName), 'Unable to get netcdf ny')
238
239
ALLOCATE(xx(nx),yy(ny))
240
241
!! Get X and Y variable
242
Xdim=ListGetString( SolverParams, "X Var Name", Found )
243
if (.NOT.Found) Xdim='x'
244
NetCDFstatus = nf90_inq_varid(ncid,trim(Xdim),varid)
245
IF ( NetCDFstatus /= NF90_NOERR ) &
246
CALL FATAL(Trim(SolverName),'Unable to get netcdf x-variable id')
247
248
NetCDFstatus = nf90_get_var(ncid, varid,xx)
249
IF ( NetCDFstatus /= NF90_NOERR ) &
250
CALL FATAL(Trim(SolverName), 'Unable to get netcdf x-variable ')
251
252
Ydim=ListGetString( SolverParams, "Y Var Name", Found )
253
if (.NOT.Found) Ydim='y'
254
NetCDFstatus = nf90_inq_varid(ncid,trim(Ydim),varid)
255
IF ( NetCDFstatus /= NF90_NOERR ) &
256
CALL FATAL(Trim(SolverName),'Unable to get netcdf x-variable id')
257
258
NetCDFstatus = nf90_get_var(ncid, varid,yy)
259
IF ( NetCDFstatus /= NF90_NOERR ) &
260
CALL FATAL(Trim(SolverName), 'Unable to get netcdf x-variable ')
261
262
!! Check that there is data within the domain
263
IF ((MAXVAL(xx).LT.xmin).OR.(MINVAL(xx).GT.xmax)&
264
.OR.(MAXVAL(yy).LT.ymin).OR.(MINVAL(yy).GT.ymax)) &
265
CALL Fatal(Trim(SolverName), &
266
'No data within model domain')
267
!!! get the index of values that are within the mesh bounding box
268
CALL MinMaxIndex(xx,nx,xmin,xmax,XMinIndex,XMaxIndex)
269
CALL MinMaxIndex(yy,ny,ymin,ymax,YMinIndex,YMaxIndex)
270
271
!! get ux and uy
272
nx=XMaxIndex-XMinIndex+1
273
ny=YMaxIndex-YMinIndex+1
274
ALLOCATE(ux(nx,ny),uy(nx,ny))
275
276
VarName=ListGetString( SolverParams, "Ux Var Name", Found )
277
if (.NOT.Found) VarName='vx'
278
NetCDFstatus = nf90_inq_varid(ncid,trim(VarName),varid)
279
IF ( NetCDFstatus /= NF90_NOERR ) &
280
CALL Fatal(Trim(SolverName),'Unable to get netcdf ux variable id')
281
NetCDFstatus = nf90_get_var(ncid, Varid, ux(:, :), &
282
start = (/ XMinIndex, YMinIndex /), &
283
count = (/ nx,ny/))
284
IF ( NetCDFstatus /= NF90_NOERR ) &
285
CALL Fatal(Trim(SolverName),'Unable to get netcdf ux variable')
286
NetCDFstatus = nf90_get_att(ncid, varid,"_FillValue",Uxfillv)
287
IF ( NetCDFstatus /= NF90_NOERR ) &
288
CALL FATAL(Trim(SolverName),'Ux has no attribute _FillValue')
289
290
VarName=ListGetString( SolverParams, "Uy Var Name", Found )
291
if (.NOT.Found) VarName='vy'
292
NetCDFstatus = nf90_inq_varid(ncid,trim(VarName),varid)
293
IF ( NetCDFstatus /= NF90_NOERR ) &
294
CALL Fatal(Trim(SolverName),'Unable to get netcdf uy variable id')
295
NetCDFstatus = nf90_get_var(ncid, Varid, uy(:, :), &
296
start = (/ XMinIndex, YMinIndex /), &
297
count = (/ nx,ny /))
298
IF ( NetCDFstatus /= NF90_NOERR ) &
299
CALL Fatal(Trim(SolverName),'Unable to get netcdf uy variable')
300
NetCDFstatus = nf90_get_att(ncid, varid,"_FillValue",Uyfillv)
301
IF ( NetCDFstatus /= NF90_NOERR ) &
302
CALL FATAL(Trim(SolverName),'Uy has no attribute _FillValue')
303
304
!! close netcdf
305
NetCDFstatus = nf90_close(ncid)
306
307
!!
308
ALLOCATE(xobs(nx*ny,3),Vobs(nx*ny,DIM))
309
xobs=0._dp
310
Vobs=0._dp
311
312
nobs=0
313
Do i=1,nx
314
Do j=1,ny
315
NodalU=ux(i,j)
316
NodalV=uy(i,j)
317
IF ((NodalU.EQ.Uxfillv).OR.(NodalV.EQ.Uyfillv)) CYCLE
318
nobs=nobs+1
319
xobs(nobs,1)=xx(XMinIndex+i-1)
320
xobs(nobs,2)=yy(YMinIndex+j-1)
321
Vobs(nobs,1)=NodalU
322
Vobs(nobs,2)=NodalV
323
End do
324
End do
325
326
DEALLOCATE(xx,yy,ux,uy)
327
328
#else
329
330
CALL FATAL(Trim(SolverName),'Elmer/Ice has not been installed with netcdf -convert your file to ASCII table--')
331
332
#endif
333
334
Else !.not.NETCDFFormat
335
336
ParallelFile = .False.
337
ParallelFile = GetLogical(SolverParams,'Parallel Observation Files', Found)
338
if (Parallel.AND.ParallelFile) &
339
write(ObsFileName,'(A,A,I0)') trim(ObsFileName),'.',ParEnv % MyPE
340
341
open(IO,file=trim(ObsFileName),status = 'old',iostat = ok)
342
if(ok /= 0) then
343
write(message,'(A,A)') 'Unable to open file ',TRIM(ObsFileName)
344
CALL Fatal(Trim(SolverName),Trim(message))
345
end if
346
nobs=0
347
do while(ok == 0)
348
read(io,*,iostat = ok)
349
if (ok == 0) nobs = nobs + 1
350
end do
351
close(IO)
352
353
ALLOCATE(xobs(nobs,3),Vobs(nobs,DIM))
354
355
Vobs=0.0_dp
356
xobs=0.0_dp
357
open(IO,file=trim(ObsFileName))
358
do i=1,nobs
359
read(IO,*) (xobs(i,j),j=1,DIM),(Vobs(i,j),j=1,DIM)
360
end do
361
close(IO)
362
ENDIF
363
364
ALLOCATE(InElement(nobs))
365
InElement(:)=-1
366
367
SAVE_USED_DATA = GetLogical(SolverParams,'Save used data', Found)
368
!!! End of First visit
369
Firsttime=.false.
370
Endif
371
372
! Get the variable solution
373
Variable => VariableGet( Solver % Mesh % Variables, Trim(VariableName), UnFoundFatal=.TRUE. )
374
Values => Variable % Values
375
Perm => Variable % Perm
376
377
! Get the adjoint
378
VelocitybSol => VariableGet( Solver % Mesh % Variables, 'Velocityb', UnFoundFatal=.TRUE. )
379
Vb => VelocitybSol % Values
380
VbPerm => VelocitybSol % Perm
381
Vb=0.0_dp
382
383
IF (VelocitybSol%DOFs.NE.Variable%DOFs) &
384
CALL FATAL(Trim(SolverName),'DOFs do not correspond')
385
!
386
Mesh => GetMesh()
387
388
! Temporary trick to disable Warnings as LocateParticleInMeshOctree
389
! will send a lot of warning for data points not found in the emsh
390
IF (FirstRound) THEN
391
WarnActive=OutputLevelMask(2)
392
OutputLevelMask(2)=.FALSE.
393
ENDIF
394
395
! Compute the cost
396
Cost=0._dp
397
398
Element => GetActiveElement(1)
399
ElementIndex = Element % ElementIndex
400
401
CALL StartAdvanceOutput(SolverName,'Compute cost')
402
Do s=1,nobs
403
404
CALL AdvanceOutput(s,nobs)
405
406
IF (FirstRound) then
407
!Need to find in which Element the data point resides
408
! First check that it is within the computation domain
409
Coord=0._dp
410
Coord(1:DIM)=xobs(s,1:DIM)
411
IF ((Coord(1).GT.xmax).OR.(Coord(1).LT.xmin)) CYCLE
412
IF (DIM.EQ.2) THEN
413
IF ((Coord(2).GT.ymax).OR.(Coord(2).LT.ymin)) CYCLE
414
END IF
415
416
IF (DIM.LT.CoordinateSystemDimension()) THEN
417
! we are in a lower dimension than the mesh
418
! => use brute force search
419
420
! first check in the current elmement
421
Element => Mesh % Elements(ElementIndex)
422
n = GetElementNOFNodes(Element)
423
NodeIndexes => Element % NodeIndexes
424
ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)
425
IF (DIM == 1) THEN
426
ElementNodes % y(1:n) = 0.0_dp
427
ElementNodes % z(1:n) = 0.0_dp
428
ELSE IF (DIM == 2) THEN
429
ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)
430
ElementNodes % z(1:n) = 0.0_dp
431
ENDIF
432
IF (PointInElement(Element,ElementNodes,Coord(:),UVW)) THEN
433
IF (.NOT.CheckPassiveElement(Element)) &
434
InElement(s)=ElementIndex
435
436
ELSE
437
! go through all elements
438
Do i=1,Solver%NumberOfActiveElements
439
Element => GetActiveElement(i)
440
n = GetElementNOFNodes(Element)
441
NodeIndexes => Element % NodeIndexes
442
ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)
443
IF (DIM == 1) THEN
444
ElementNodes % y(1:n) = 0.0_dp
445
ElementNodes % z(1:n) = 0.0_dp
446
ELSE IF (DIM == 2) THEN
447
ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)
448
ElementNodes % z(1:n) = 0.0_dp
449
ENDIF
450
IF (PointInElement(Element,ElementNodes,Coord(:),UVW)) THEN
451
IF (CheckPassiveElement(Element)) Exit
452
ElementIndex= Element % ElementIndex
453
InElement(s)=ElementIndex
454
Exit
455
END IF
456
End Do
457
END IF
458
459
ELSE
460
!> use particles meshoctree
461
ElementIndex=-1 ! don't know why but if i don't reset ElmentIndex it fails
462
CALL LocateParticleInMeshOctree( ElementIndex,Coord)
463
If (ElementIndex.NE.0) THEN
464
InElement(s)=ElementIndex
465
Element => Mesh % Elements(ElementIndex)
466
IF (CheckPassiveElement(Element).OR. &
467
(Element % PartIndex /= ParEnv % myPE)) THEN
468
InElement(s)=-1
469
END IF
470
END IF
471
472
END IF
473
ENDIF !End if FirstRound
474
475
476
! Data Point has been found in one element
477
IF (InElement(s)>0) THEN
478
Element => Mesh % Elements(InElement(s))
479
n = GetElementNOFNodes(Element)
480
NodeIndexes => Element % NodeIndexes
481
! set coords of highest occurring dimension to zero (to get correct path element)
482
!-------------------------------------------------------------------------------
483
ElementNodes % x(1:n) = Solver % Mesh % Nodes % x(NodeIndexes)
484
IF (DIM == 1) THEN !1D SSA
485
ElementNodes % y(1:n) = 0.0_dp
486
ElementNodes % z(1:n) = 0.0_dp
487
ELSE IF (DIM == 2) THEN !2D SSA
488
ElementNodes % y(1:n) = Solver % Mesh % Nodes % y(NodeIndexes)
489
ElementNodes % z(1:n) = 0.0_dp
490
ELSE
491
WRITE(Message,'(a,i1,a)')&
492
'It is not possible to compute SSA problems with DOFs=',&
493
DIM, ' . Aborting'
494
CALL Fatal( SolverName, Message)
495
END IF
496
497
IF (.NOT.PointInElement(Element,ElementNodes,xobs(s,1:3),UVW)) THEN
498
PRINT *,ParEnv%MyPE,'eindex',Element % ElementIndex
499
PRINT *,ParEnv%MyPE,'obs. coords',xobs(s,1:2)
500
PRINT *,ParEnv%MyPE,'node indexes',NodeIndexes(1:n)
501
PRINT *,ParEnv%MyPE,'nodex',ElementNodes % x(1:n)
502
PRINT *,ParEnv%MyPE,'nodey',ElementNodes % y(1:n)
503
504
CALL FATAL(SolverName,'Point was supposed to be found in this element')
505
ELSE
506
stat = ElementInfo( Element,ElementNodes,UVW(1),UVW(2),UVW(3),SqrtElementMetric, &
507
Basis,dBasisdx )
508
509
! Variable at obs point
510
Do i=1,DIM
511
V(i)=SUM(Values(VDOFs*(Perm(NodeIndexes(1:n))-1)+i)*basis(1:n))
512
End do
513
514
! Update cost
515
Do i=1,DIM
516
Cost=Cost+0.5*Lambda*(V(i)-Vobs(s,i))*(V(i)-Vobs(s,i))
517
End do
518
!PRINT *,V,Vobs
519
520
!Derivative of Cost at nodal Point
521
Do j=1,n
522
Do i=1,DIM
523
k=VDOFS*(VbPerm(NodeIndexes(j))-1)+i
524
Vb(k)=Vb(k)+Lambda*(V(i)-Vobs(s,i))*basis(j)
525
End do
526
End Do
527
528
END IF
529
530
ELSE
531
532
WRITE(Message,'(a,I0,a)')&
533
'Data Point',s,'found in no element'
534
CALL Info( SolverName, Message,level=15)
535
END IF
536
537
END DO !Do on s
538
539
540
if (NTOT < 0) NTOT=COUNT(InElement(:)>0)
541
!! Save Cost as a function of time
542
543
TimeVar => VariableGet( Solver % Mesh % Variables, 'Time' )
544
545
IF (Parallel) THEN
546
CALL MPI_ALLREDUCE(NTOT,NTOT_S,1,&
547
MPI_INTEGER,MPI_SUM,ELMER_COMM_WORLD,ierr)
548
CALL MPI_ALLREDUCE(Cost,Cost_S,1,&
549
MPI_DOUBLE_PRECISION,MPI_SUM,ELMER_COMM_WORLD,ierr)
550
CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )
551
IF (ASSOCIATED(CostVar)) THEN
552
CostVar % Values(1)=Cost_S
553
END IF
554
IF (Solver % Matrix % ParMatrix % ParEnv % MyPE == 0) then
555
OPEN (IO, FILE=CostFile,POSITION='APPEND')
556
write(IO,'(e13.5,2x,e15.8,2x,e15.8)') TimeVar % Values(1),Cost_S,sqrt(2.0*Cost_S/(NTOT_S*Lambda))
557
CLOSE(IO)
558
write(Message,'(A,A,I0)') trim(SolverName),'total number of data points:',NTOT_S
559
call INFO(SolverName,Message,level=3)
560
End if
561
ELSE
562
CostVar => VariableGet( Solver % Mesh % Variables, CostSolName )
563
IF (ASSOCIATED(CostVar)) THEN
564
CostVar % Values(1)=Cost
565
END IF
566
OPEN (IO, FILE=CostFile,POSITION='APPEND')
567
write(IO,'(e13.5,2x,e15.8,2x,e15.8)') TimeVar % Values(1),Cost,sqrt(2.0*Cost/(NTOT*Lambda))
568
close(IO)
569
write(Message,'(A,A,I0)') trim(SolverName),'total number of data points:',NTOT
570
call INFO(SolverName,Message,level=3)
571
END IF
572
573
If (FirstRound) THEN
574
IF (SAVE_USED_DATA) THEN
575
If (Parallel) then
576
write(UsedDataFile,'(A,A,I0)') trim(SolverName),'.useddata.',ParEnv % MyPE
577
Else
578
write(UsedDataFile,'(A,A)') trim(SolverName),'.useddata'
579
End if
580
581
open(IO,File=UsedDataFile)
582
Do s=1,nobs
583
If (InElement(s)>0) then
584
if (DIM.eq.1) Then
585
write(IO,'(e13.5,2x,e15.8)') (xobs(s,i),i=1,DIM),(Vobs(s,i),i=1,DIM)
586
Else if (DIM.eq.2) Then
587
write(IO,'(e15.8,2x,e15.8,2x,e15.8,2x,e15.8)') (xobs(s,i),i=1,DIM),(Vobs(s,i),i=1,DIM)
588
End if
589
End if
590
End do
591
close(IO)
592
END IF
593
End if
594
595
! Reset Warning level to previous value
596
IF (FirstRound) THEN
597
OutputLevelMask(2)=WarnActive
598
ENDIF
599
600
FirstRound=.False.
601
Return
602
603
1000 format('#date,time,',a1,'/',a1,'/',a4,',',a2,':',a2,':',a2)
604
1001 format('#lambda,',e15.8)
605
606
CONTAINS
607
! Find the min and max indexes of values within bBox
608
SUBROUTINE MinMaxIndex(x,n,minx,maxx,MinIndex,MaxIndex)
609
IMPLICIT NONE
610
REAL(KIND=dp),INTENT(IN) :: x(:),minx,maxx
611
INTEGER,INTENT(IN) :: n
612
INTEGER,INTENT(OUT) :: MinIndex,MaxIndex
613
614
! coordinates should be monotonically increasing or
615
! decreasing
616
IF ((x(2)>x(1)).AND.(x(n)>x(n-1))) THEN
617
MinIndex = MAXLOC(x, DIM=1,MASK=(x < minx))
618
MinIndex=MAX(MinIndex,1)
619
620
MaxIndex = MINLOC(x, DIM=1,MASK=(x > maxx))
621
IF (MaxIndex.LE.1) MaxIndex=n
622
ELSE IF ((x(2)<x(1)).AND.(x(n)<x(n-1))) THEN
623
MaxIndex = MAXLOC(x, DIM=1,MASK=(x < minx))
624
IF (MaxIndex.LE.1) MaxIndex=n
625
626
MinIndex = MINLOC(x, DIM=1,MASK=(x > maxx))
627
MinIndex=MAX(MinIndex,1)
628
ELSE
629
CALL FATAL(SolverName,'coordinate is neither monotonically increasing or decreasing')
630
ENDIF
631
632
IF (MaxIndex.LT.MinIndex) THEN
633
WRITE(message,*) 'Error Min Max Indexes ',MinIndex,MaxIndex
634
CALL WARN(SolverName,message)
635
WRITE(message,*) 'Min values ',MINVAL(x),minx
636
CALL WARN(SolverName,message)
637
WRITE(message,*) 'Max values ',MAXVAL(x),maxx
638
CALL WARN(SolverName,message)
639
CALL FATAL(SolverName,'This is a fatal error')
640
ENDIF
641
642
END SUBROUTINE MinMaxIndex
643
644
!------------------------------------------------------------------------------
645
END SUBROUTINE AdjointSSA_CostDiscSolver
646
!------------------------------------------------------------------------------
647
! *****************************************************************************
648
649