Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/Grid2DInterpolator.F90
3203 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:
26
! * Email:
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! * Original Date:
30
! *
31
! *****************************************************************************
32
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
33
!
34
! Interpolate data given on a regular 2D regular grid in an ASCII file (x y Value)
35
! in the mesh nodes using bilinear interpolation
36
! The data are ordered such that
37
! x1 y1 val11
38
! x2 y1 val21
39
! ...
40
! xn y1 valn1
41
! x1 y2 val12
42
! ...
43
! xn yn valnn
44
!
45
! The grid is described by giving:
46
! (x0, y0) the left-bottom corner coordinate
47
! (lx, ly) the x and y lengths of the covered domain
48
! (Nx, Ny) the number of cells in x and y directions
49
! No data are given by -9999 with a tolerance of 0.001
50
! These can be over-ridden in the sif by 'no data' and 'no data tol'
51
!
52
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
53
SUBROUTINE Grid2DInterpolator( Model,Solver,dt,TransientSimulation )
54
55
USE DefUtils
56
57
IMPLICIT NONE
58
TYPE(Solver_t), TARGET :: Solver
59
TYPE(Model_t) :: Model
60
REAL(KIND=dp) :: dt
61
LOGICAL :: TransientSimulation
62
63
TYPE(ValueList_t), POINTER :: Params
64
TYPE(Variable_t), POINTER :: Var
65
REAL(KIND=dp), POINTER :: Values(:)
66
INTEGER, POINTER :: Perm(:)
67
68
REAL(KIND=DP) :: Rmin, Rmax
69
REAL(KIND=DP) :: x, y, z, x0, y0, lx, ly, dx, dy
70
REAL(KIND=DP), ALLOCATABLE :: xb(:), yb(:), zb(:), xbaux(:), ybaux(:), zbaux(:)
71
REAL(KIND=dp) :: noDataVal, noDataTol, posTol
72
REAL(KIND=dp), PARAMETER :: noDataValDefault = -9999.0, noDataTolDefault = 0.001, posTolDefault= 1.0D-06
73
74
INTEGER,parameter :: io=20
75
INTEGER :: ok, Nx, Ny, Nb, Nbaux, OutNode
76
INTEGER :: i, j, k, l, kmin, NoVar
77
78
CHARACTER(LEN=MAX_NAME_LEN) :: VariableName, DataF
79
CHARACTER(LEN=MAX_NAME_LEN) :: Name, FName, ParaName
80
CHARACTER(LEN=MAX_NAME_LEN), PARAMETER :: SolverName='Grid2DInterpolator'
81
82
LOGICAL :: GotVar, Found, InvertOrder, FillIn, UnFoundFatal=.TRUE.
83
84
NULLIFY(Params,Var,Values,Perm)
85
86
Params => GetSolverParams()
87
88
! Read variable to initialize and Data
89
NoVar=0
90
GotVar=.True.
91
92
DO WHILE(GotVar)
93
NoVar = NoVar + 1
94
WRITE (Name,'(A,I0)') 'Variable ',NoVar
95
96
VariableName = ListGetString( Params, TRIM(Name), GotVar )
97
IF (.NOT.GotVar) EXIT
98
99
Var => VariableGet(Model % Mesh % Variables, VariableName,UnFoundFatal=UnFoundFatal )
100
Values => Var % Values
101
Perm => Var % Perm
102
103
WRITE (FName,'(A,I0,A)') 'Variable ',NoVar,' Data File'
104
DataF = ListGetString( Params, TRIM(FName), Found, UnFoundFatal )
105
106
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' x0'
107
x0 = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal)
108
109
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' y0'
110
y0 = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal )
111
112
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' lx'
113
lx = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal )
114
115
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' ly'
116
ly = ListGetConstReal( Params, TRIM(ParaName), Found,UnFoundFatal=UnFoundFatal )
117
118
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Nx'
119
Nx = ListGetInteger( Params, TRIM(ParaName), Found ,UnFoundFatal=UnFoundFatal)
120
121
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Ny'
122
Ny = ListGetInteger( Params, TRIM(ParaName), Found ,UnFoundFatal=UnFoundFatal)
123
124
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Invert'
125
InvertOrder = GetLogical( Params, TRIM(ParaName), Found )
126
IF (.NOT.Found) THEN
127
InvertOrder = .FALSE.
128
END IF
129
IF (InvertOrder) THEN
130
WRITE(message,'(A,A,I0)')'Inverting order (row major) for variable ', 'Variable ',NoVar
131
CALL INFO(Trim(SolverName),Trim(message),Level=1)
132
END IF
133
134
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' Fill'
135
FillIn = GetLogical( Params, TRIM(ParaName), Found )
136
IF (.NOT.Found) THEN
137
FillIn = .FALSE.
138
END IF
139
IF (FillIn) THEN
140
WRITE(message,'(A,A,I0)')'Filling empty entries for ', 'Variable ',NoVar
141
CALL INFO(Trim(SolverName),Trim(message),Level=1)
142
END IF
143
144
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' no data'
145
noDataVal = ListGetConstReal( Params, TRIM(ParaName), Found )
146
IF (.NOT.Found) then
147
noDataVal = noDataValDefault
148
WRITE(message,'(A,A,A,e14.8)')'Keyword <',Trim(ParaName), &
149
'> not found, using default ',noDataValDefault
150
CALL INFO(SolverName, Message, Level=3)
151
END IF
152
153
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' no data tol'
154
noDataTol = ListGetConstReal( Params, TRIM(ParaName), Found )
155
IF (.NOT.Found) then
156
noDataTol = noDataTolDefault
157
WRITE(message,'(A,A,A,e14.8)')'Keyword <',Trim(ParaName), &
158
'> not found, using default ',noDataTolDefault
159
CALL INFO(SolverName, Message, Level=3)
160
END IF
161
162
WRITE (ParaName,'(A,I0,A)') 'Variable ',NoVar,' position tol'
163
posTol = ListGetConstReal( Params, TRIM(ParaName), Found )
164
IF (.NOT.Found) then
165
posTol = posTolDefault
166
WRITE(message,'(A,A,A,e14.8)')'Keyword <',Trim(ParaName), &
167
'> not found, using default ',posTolDefault
168
CALL INFO(SolverName, Message, Level=3)
169
END IF
170
171
OPEN(unit = io, file = TRIM(DataF), status = 'old',iostat = ok)
172
173
IF (ok /= 0) THEN
174
WRITE(message,'(A,A)') 'Unable to open file ',TRIM(DataF)
175
CALL FATAL(Trim(SolverName),Trim(message))
176
END IF
177
178
Nb = Nx*Ny
179
180
ALLOCATE(xb(Nb), yb(Nb), zb(Nb), xbaux(Nb), ybaux(Nb), zbaux(Nb))
181
182
! read data
183
DO i = 1, Nb
184
READ(io,*,iostat = ok, end=100) xbaux(i), ybaux(i), zbaux(i)
185
END DO
186
100 Nbaux = Nb - i
187
IF (Nbaux > 0) THEN
188
WRITE(message,'(I0,A,I0,A,A)') Nbaux,' out of ',Nb,' datasets in file ', TRIM(DataF)
189
CALL INFO(Trim(SolverName),Trim(message))
190
END IF
191
CLOSE(io)
192
193
! Make some verifications and - in case - manipulation
194
!on the DEM structure
195
dx = lx / (Nx-1.0)
196
dy = ly / (Ny-1.0)
197
k = 0
198
l = 0
199
IF (.NOT.InvertOrder) THEN
200
DO j = 1, Ny
201
y = y0 + dy*(j-1)
202
DO i = 1, Nx
203
k = k + 1
204
x = x0 + dx*(i-1)
205
IF (.NOT.FillIn) THEN
206
xb(k) = xbaux(k)
207
yb(k) = ybaux(k)
208
zb(k) = zbaux(k)
209
IF ((ABS(x-xbaux(k))>posTol*dx).OR.(ABS(y-ybaux(k))>posTol*dy)) THEN
210
211
WRITE(Message,'(A,A)')'Structure of the DEM is not conforming to what is given in the sif for ',TRIM(FName)
212
CALL INFO(SolverName, Message, Level=1)
213
WRITE(Message,'(A,i4,A,i4,A,e14.8,2x,e14.8,A,e14.8,2x,e14.8,A)') &
214
'Variable', NoVar, ': Found that point ',k,&
215
' coordinate is (',xbaux(k),ybaux(k),&
216
'), whereas it should be (',x,y,')'
217
CALL FATAL(SolverName, Message)
218
END IF
219
ELSE
220
IF ((ABS(x-xbaux(l+1))>posTol*dx).OR.(ABS(y-ybaux(l+1))>posTol*dy)) THEN
221
xb(k) = x
222
yb(k) = y
223
zb(k) = noDataVal ! setting to NaN
224
ELSE
225
l=l+1
226
xb(k) = xbaux(l)
227
yb(k) = ybaux(l)
228
zb(k) = zbaux(l)
229
END IF
230
END IF
231
END DO
232
END DO
233
ELSE ! inverse order
234
DO i = 1, Nx
235
x = x0 + dx*(i-1)
236
DO j = 1, Ny
237
k = k + 1
238
y = y0 + dy*(j-1)
239
240
IF (.NOT.FillIn) THEN
241
xb((j-1)*Nx + i) = xbaux(k)
242
yb((j-1)*Nx + i) = ybaux(k)
243
zb((j-1)*Nx + i) = zbaux(k)
244
IF ((ABS(x-xb((j-1)*Nx + i))>posTol*dx).OR.(ABS(y-yb((j-1)*Nx + i))>posTol*dy)) THEN
245
246
WRITE(Message,'(A,A)')'Structure of the DEM is not conforming to what is given in the sif for ',TRIM(FName)
247
CALL INFO(SolverName, Message, Level=1)
248
WRITE(Message,'(A,i4,A,i4,A,e14.8,2x,e14.8,A,e14.8,2x,e14.8,A)') &
249
'Variable', NoVar, ':Found that point ',k,&
250
' coordinate is (',xb((j-1)*Nx),yb((j-1)*Nx + i),'),&
251
whereas 3 it should be (',x,y,')'
252
CALL FATAL(SolverName, Message)
253
END IF
254
ELSE
255
IF ((ABS(x-xbaux(l+1))>posTol*dx).OR.(ABS(y-ybaux(l+1))>posTol*dy)) THEN
256
xb((j-1)*Nx + i) = x
257
yb((j-1)*Nx + i) = y
258
zb((j-1)*Nx + i) = noDataVal ! setting to NaN
259
ELSE
260
l=l+1
261
xb((j-1)*Nx + i) = xbaux(l)
262
yb((j-1)*Nx + i) = ybaux(l)
263
zb((j-1)*Nx + i) = zbaux(l)
264
END IF
265
END IF
266
267
END DO
268
END DO
269
END IF
270
271
OutNode = 0
272
Rmax = 0.0
273
DO i=1,Model % Mesh % NumberOfNodes
274
x = Model % Mesh % Nodes % x(i)
275
y = Model % Mesh % Nodes % y(i)
276
Rmin = 0.0
277
CALL InterpolateDEM(x,y,xb,yb,zb,Nx,Ny,x0,y0,lx,ly,Rmin,z,noDataVal,noDataTol)
278
if ( perm(i) .eq. 0 ) CYCLE
279
Values(Perm(i)) = z
280
IF (Rmin > 0.0) THEN
281
OutNode = OutNode + 1
282
IF (Rmin > Rmax) Rmax = Rmin
283
END IF
284
END DO
285
286
! Give information on the number of Nodes which are outside of the
287
! DEM domain
288
IF (OutNode > 0) THEN
289
WRITE( Message, '(I0,A,A)' )OutNode,' nodes where found outside of &
290
the DEM domain in ',TRIM(DataF)
291
CALL Info( TRIM(SolverName), Message, Level=3 )
292
WRITE( Message, '(A,e14.8)' )'The farthest DEM point used to evaluate &
293
the nodal value was: ', Rmax
294
CALL Info( TRIM(SolverName), Message, Level=3 )
295
END IF
296
297
DEALLOCATE(xb, yb, zb, xbaux, ybaux, zbaux)
298
END DO
299
300
CALL INFO(Trim(SolverName), '----------ALL DONE----------',Level=5)
301
302
END SUBROUTINE Grid2DInterpolator
303
304
305
!!!!!!!!!!!!!!!!!!!
306
! Subroutine InterpolateDEM
307
!!------------------------------------------------------------------------------!!
308
SUBROUTINE InterpolateDEM (x, y, xb, yb, zb, Nbx, Nby, xb0, yb0, lbx, lby, Rmin, zbed, noDataVal, noDataTol)
309
USE DefUtils
310
IMPLICIT NONE
311
REAL(KIND=dp),INTENT(IN) :: noDataVal, noDataTol
312
INTEGER :: imin, Npt, t
313
INTEGER :: NMAX, i, j, Nb, Nbx, Nby, ib, ix, iy
314
REAL(KIND=dp) :: x, y, zbed, xb0, yb0, x1, x2, y1, y2, zi(2,2)
315
REAL(KIND=dp) :: R, Rmin, lbx, lby, dbx, dby
316
REAL(KIND=dp) :: xb(Nbx*Nby), yb(Nbx*Nby), zb(Nbx*Nby)
317
318
! Find zbed for that point from the Bedrock MNT
319
dbx = lbx / (Nbx-1.0)
320
dby = lby / (Nby-1.0)
321
Nb = Nbx*Nby
322
323
ix = INT((x-xb0)/dbx)+1
324
iy = INT((y-yb0)/dby)+1
325
ib = Nbx * (iy - 1) + ix
326
327
! if we are already at the end of the domain then collapse the 2 by 2 interpolation
328
! square to just 2 points at the end of the domain (else we get interpolation involving
329
! points at the beginning of the domain). This comment refers to the x direction.
330
IF (MOD(ib,Nbx) .eq. 0.0) THEN
331
zi(2,1) = noDataVal
332
zi(2,2) = noDataVal
333
ELSE
334
IF ( (ib+1).gt.size(zb) ) THEN
335
zi(2,1) = noDataVal
336
ELSE
337
zi(2,1) = zb(ib+1)
338
END IF
339
IF ( (ib+Nbx+1).gt.size(zb) ) THEN
340
zi(2,2) = noDataVal
341
ELSE
342
zi(2,2) = zb(ib + Nbx + 1)
343
END IF
344
END IF
345
346
x1 = xb(ib)
347
IF ( (ib+1).gt.size(xb) ) THEN
348
x2 = noDataVal
349
ELSE
350
x2 = xb(ib+1)
351
END IF
352
353
y1 = yb(ib)
354
IF ( (ib+Nbx).gt.size(yb) ) THEN
355
y2 = noDataVal
356
ELSE
357
y2 = yb(ib + Nbx)
358
END IF
359
360
IF ( (ib).gt.size(zb) ) THEN
361
zi(1,1) = noDataVal
362
ELSE
363
zi(1,1) = zb(ib)
364
END IF
365
IF ( (ib+Nbx).gt.size(zb) ) THEN
366
zi(1,2) = noDataVal
367
ELSE
368
zi(1,2) = zb(ib + Nbx)
369
END IF
370
371
IF ( (isNoData(zi(1,1))).OR. &
372
(isNoData(zi(1,2))).OR. &
373
(isNoData(zi(2,1))).OR. &
374
(isNoData(zi(2,2))) ) THEN
375
376
IF ( (isNoData(zi(1,1))).AND. &
377
(isNoData(zi(1,2))).AND. &
378
(isNoData(zi(2,1))).AND. &
379
(isNoData(zi(2,2))) ) THEN
380
381
! Find the nearest point available if all neighbouring points have noData
382
Rmin = 9999999.0
383
DO i=1, Nb
384
IF (.NOT.isNoData(zb(i))) THEN
385
R = SQRT((x-xb(i))**2.0+(y-yb(i))**2.0)
386
IF (R<Rmin) THEN
387
Rmin = R
388
imin = i
389
END IF
390
END IF
391
END DO
392
zbed = zb(imin)
393
394
ELSE
395
! Mean value over the available data if only some points have noData
396
zbed = 0.0
397
Npt = 0
398
DO i=1, 2
399
DO J=1, 2
400
IF (.NOT. isNoData(zi(i,j))) THEN
401
zbed = zbed + zi(i,j)
402
Npt = Npt + 1
403
END IF
404
END DO
405
END DO
406
zbed = zbed / Npt
407
END IF
408
ELSE
409
! linear interpolation is only carried out if all 4 neighbouring points have data.
410
zbed = (zi(1,1)*(x2-x)*(y2-y)+zi(2,1)*(x-x1)*(y2-y)+zi(1,2)*(x2-x)*(y-y1)+zi(2,2)*(x-x1)*(y-y1))/(dbx*dby)
411
END IF
412
413
414
CONTAINS
415
416
LOGICAL FUNCTION isNoData(val)
417
418
IMPLICIT NONE
419
REAL(KIND=dp),INTENT(IN) :: val
420
421
IF ((val .GT. noDataVal-noDataTol) .AND. (val .LT. noDataVal+noDataTol)) THEN
422
isNoData = .TRUE.
423
ELSE
424
isNoData = .FALSE.
425
END IF
426
427
RETURN
428
429
END FUNCTION isNoData
430
431
END SUBROUTINE InterpolateDEM
432
433
434