Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/fem/src/InterpVarToVar.F90
3203 views
1
!/*****************************************************************************/
2
! *
3
! * Elmer, A Finite Element Software for Multiphysical Problems
4
! *
5
! * Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland
6
! *
7
! * This library is free software; you can redistribute it and/or
8
! * modify it under the terms of the GNU Lesser General Public
9
! * License as published by the Free Software Foundation; either
10
! * version 2.1 of the License, or (at your option) any later version.
11
! *
12
! * This library 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 GNU
15
! * Lesser General Public License for more details.
16
! *
17
! * You should have received a copy of the GNU Lesser General Public
18
! * License along with this library (in file ../LGPL-2.1); if not, write
19
! * to the Free Software Foundation, Inc., 51 Franklin Street,
20
! * Fifth Floor, Boston, MA 02110-1301 USA
21
! *
22
! *****************************************************************************/
23
!
24
! ******************************************************************************
25
! *
26
! * Authors: Peter RÃ¥back, Joe Todd
27
! * Email: [email protected]
28
! * Web: http://www.csc.fi/elmer
29
! * Address: CSC - IT Center for Science Ltd.
30
! * Keilaranta 14
31
! * 02101 Espoo, Finland
32
! *
33
! * Original Date: 19/10/2014
34
! *
35
! ****************************************************************************/
36
37
!InterpolateVarToVarReduced: Subroutine to interpolate variable values on a reduced
38
!dimension mesh. Either once or twice reduced (3D => line search, in the latter case)
39
40
! This subroutine is largely based on InterpolateMeshToMesh, with a few modifications
41
!
42
! The user specifies a variable 'HeightName' which is to be interpolated. This differs
43
! from InterpolateMeshToMesh, where all variables are interpolated. This is because
44
! this subroutine has been principally used for remeshing a glacier, and so only the
45
! height variable is required.
46
!
47
! Its also possible to specify a VariableList to get similar behaviour to
48
! InterpolateMeshToMesh. If a VariableList is specified which has regular
49
! field variables, OldNodeMask and NewNodeMask should be supplied to ensure
50
! only BC values are interpolated. Alternatively, one could create a perm
51
! of an internal layer of an extruded mesh.
52
!
53
! Care should be taken with supplying overly relaxed epsilon values:
54
! The subroutine will naively search elements in turn with the given epsilon
55
! values, and so if a neighbouring element which 'almost' contains the node
56
! is searched first, this will be accepted by the subroutine. If a more relaxed
57
! epsilon search is required, one should first call this subroutine with more
58
! stringent epsilon values, then call again, with more relaxed epsilon, and a mask
59
! specifying which nodes to look for (i.e. only those not found in the previous run)
60
!------------------------------------------------------------------------------
61
MODULE InterpVarToVar
62
63
USE DefUtils
64
USE Types
65
USE Interpolation
66
67
IMPLICIT NONE
68
69
CONTAINS
70
SUBROUTINE InterpolateVartoVarReduced( OldMesh, NewMesh, HeightName, HeightDimensions,&
71
UnfoundNodes, OldNodeMask, NewNodeMask, OldElemMask, Variables, GlobalEps, LocalEps, NumericalEps)
72
73
TYPE(Mesh_t), TARGET, INTENT(IN) :: OldMesh
74
TYPE(Mesh_t), TARGET, INTENT(INOUT) :: NewMesh
75
TYPE(Variable_t), POINTER, OPTIONAL :: Variables
76
CHARACTER(LEN=*) :: HeightName
77
INTEGER, POINTER :: HeightDimensions(:)
78
REAL(KIND=dp), OPTIONAL :: GlobalEps, LocalEps, NumericalEps
79
LOGICAL, POINTER, OPTIONAL :: UnfoundNodes(:), OldNodeMask(:), &
80
NewNodeMask(:), OldElemMask(:)
81
!------------------------------------------------------------------------------
82
TYPE(Variable_t), POINTER :: Var, nVar, OldVar
83
TYPE(Mesh_t), POINTER :: nMesh
84
REAL(KIND=dp), POINTER :: OldHeight(:), NewHeight(:), nReal(:)
85
INTEGER, POINTER :: OldPerm(:), NewPerm(:), nperm(:)
86
TYPE(Nodes_t) :: ElementNodes
87
INTEGER :: i, j, k, l, n, nvars, ierr, npart, nfound, proc, status(MPI_STATUS_SIZE), unfound
88
REAL(KIND=dp), DIMENSION(3) :: Point
89
INTEGER, POINTER :: NodeIndexes(:)
90
INTEGER, ALLOCATABLE :: perm(:), vperm(:)
91
REAL(KIND=dp), DIMENSION(3) :: LocalCoordinates
92
REAL(KIND=dp), POINTER :: ElementValues(:)
93
TYPE(Element_t),POINTER :: Element
94
REAL(KIND=dp), ALLOCATABLE, TARGET :: BB(:,:), nodes_x(:),nodes_y(:),nodes_z(:),vstore(:,:),&
95
astore(:), xpart(:), ypart(:), zpart(:), PointLocalDistance(:), &
96
SendLocalDistance(:), RecvLocalDistance(:), WorkReal(:)
97
REAL(KIND=dp) :: detJ, u,v,w,s, dn, NoData = -99999.0_dp
98
LOGICAL :: Found, Debug
99
REAL(KIND=dp) :: myBB(6), epsBB
100
LOGICAL, ALLOCATABLE :: FoundNodes(:), BetterFound(:)
101
102
!------------------------------------------------------------------------------
103
TYPE ProcRecv_t
104
INTEGER :: n = 0
105
REAL(KIND=dp), ALLOCATABLE :: nodes_x(:),nodes_y(:),nodes_z(:)
106
END TYPE ProcRecv_t
107
TYPE(ProcRecv_t), ALLOCATABLE, TARGET :: ProcRecv(:)
108
109
TYPE ProcSend_t
110
INTEGER :: n = 0
111
INTEGER, ALLOCATABLE :: perm(:)
112
END TYPE ProcSend_t
113
TYPE(ProcSend_t), ALLOCATABLE :: ProcSend(:)
114
!------------------------------------------------------------------------------
115
116
Debug = .FALSE.
117
118
ALLOCATE( FoundNodes(NewMesh % NumberOfNodes),&
119
PointLocalDistance(NewMesh % NumberOfNodes))
120
121
FoundNodes=.TRUE.
122
PointLocalDistance = 0.0_dp
123
124
IF(PRESENT(UnfoundNodes)) THEN
125
IF(ASSOCIATED(UnfoundNodes)) DEALLOCATE(UnfoundNodes)
126
ALLOCATE(UnfoundNodes(NewMesh % NumberOfNodes))
127
END IF
128
129
IF ( ParEnv % PEs<=1 ) THEN
130
CALL InterpolateVarToVarReducedQ( OldMesh, NewMesh, HeightName, HeightDimensions, &
131
FoundNodes=FoundNodes, OldNodeMask=OldNodeMask, NewNodeMask=NewNodeMask, &
132
OldElemMask=OldElemMask, Variables=Variables, GlobalEps=GlobalEps, &
133
LocalEps=LocalEps, NumericalEps=NumericalEps )
134
135
IF(PRESENT(UnfoundNodes)) UnfoundNodes = .NOT. FoundNodes
136
RETURN
137
END IF
138
139
CALL InterpolateVarToVarReducedQ( OldMesh, NewMesh, HeightName, HeightDimensions, &
140
FoundNodes, PointLocalDistance, OldNodeMask, NewNodeMask, &
141
OldElemMask, Variables, GlobalEps, LocalEps, NumericalEps )
142
CALL MPI_BARRIER(ParEnv % ActiveComm, ierr)
143
144
IF(PRESENT(UnfoundNodes)) UnfoundNodes = .NOT. FoundNodes
145
146
DO i=1,NewMesh % NumberOfNodes
147
IF(.NOT. FoundNodes(i)) THEN
148
!Mark huge to indicate that this wasn't found
149
PointLocalDistance(i) = HUGE(PointLocalDistance(i))
150
CYCLE
151
END IF
152
153
IF(PointLocalDistance(i) == 0.0_dp) CYCLE
154
IF(Debug) PRINT *,ParEnv % MyPE,'Debug, point ',&
155
i,' found with local dist: ',PointLocalDistance(i)
156
END DO
157
158
!Sum up unfound nodes, and those where point wasn't exactly in element
159
n = COUNT((.NOT. FoundNodes) .OR. (PointLocalDistance > 0.0_dp))
160
dn = n
161
IF(Debug) THEN
162
PRINT *, 'Partition ',ParEnv % MyPE,' could not find ',n,'points!'
163
END IF
164
CALL SParActiveSUM(dn,2)
165
166
!Special case: all found
167
!----------------------
168
IF ( dn==0 ) RETURN
169
170
171
! Exchange partition bounding boxes:
172
! ----------------------------------
173
myBB(1) = MINVAL(OldMesh % Nodes % x)
174
myBB(2) = MINVAL(OldMesh % Nodes % y)
175
myBB(3) = MINVAL(OldMesh % Nodes % z)
176
myBB(4) = MAXVAL(OldMesh % Nodes % x)
177
myBB(5) = MAXVAL(OldMesh % Nodes % y)
178
myBB(6) = MAXVAL(OldMesh % Nodes % z)
179
180
myBB(HeightDimensions) = 0.0_dp
181
myBB(HeightDimensions + 3) = 0.0_dp
182
183
!Possibly need to adjust this - is it necessary to be extending the
184
!bounding box by a factor of 0.1
185
epsBB = 0.1_dp * MAXVAL(myBB(4:6)-myBB(1:3))
186
myBB(1:3) = myBB(1:3) - epsBB
187
myBB(4:6) = myBB(4:6) + epsBB
188
189
ALLOCATE(BB(6,ParEnv % PEs))
190
DO i=1,ParEnv % PEs
191
IF ( Parenv % mype == i-1 .OR. .NOT. ParEnv % Active(i) ) CYCLE
192
proc = i-1
193
CALL MPI_BSEND( myBB, 6, MPI_DOUBLE_PRECISION, proc, &
194
1099, ELMER_COMM_WORLD, ierr )
195
END DO
196
DO i=1,COUNT(ParEnv % Active)-1
197
CALL MPI_RECV( myBB, 6, MPI_DOUBLE_PRECISION, MPI_ANY_SOURCE, &
198
1099, ELMER_COMM_WORLD, status, ierr )
199
proc = status(MPI_SOURCE)
200
BB(:,proc+1) = myBB
201
END DO
202
203
Sending:IF ( n==0 ) THEN
204
DEALLOCATE(FoundNodes, BB)
205
DO i=1,ParEnv % PEs
206
IF ( Parenv % mype == i-1 .OR. .NOT. ParEnv % Active(i) ) CYCLE
207
proc = i-1
208
CALL MPI_BSEND( n, 1, MPI_INTEGER, proc, &
209
1101, ELMER_COMM_WORLD, ierr )
210
END DO
211
ELSE
212
! Extract nodes that we didn't find from our own partition...
213
! ------------------------------------------------------------
214
ALLOCATE( Perm(n), nodes_x(n), nodes_y(n),nodes_z(n) ); Perm=0
215
j = 0
216
DO i=1,NewMesh % NumberOfNodes
217
IF ( FoundNodes(i) .AND. (PointLocalDistance(i) <= 0.0_dp) ) CYCLE
218
j = j + 1
219
perm(j) = i
220
nodes_x(j) = NewMesh % Nodes % x(i)
221
nodes_y(j) = NewMesh % Nodes % y(i)
222
nodes_z(j) = NewMesh % Nodes % z(i)
223
END DO
224
IF(ANY(HeightDimensions==1)) nodes_x = 0.0_dp
225
IF(ANY(HeightDimensions==2)) nodes_y = 0.0_dp
226
IF(ANY(HeightDimensions==3)) nodes_z = 0.0_dp
227
228
DEALLOCATE(FoundNodes)
229
230
! ...and ask those from others
231
! -------------------------------
232
233
ALLOCATE(ProcSend(ParEnv % PEs))
234
DO i=1,ParEnv % PEs
235
IF ( Parenv % mype == i-1 .OR. .NOT. ParEnv % Active(i) ) CYCLE
236
proc = i-1
237
! extract those of the missing nodes that are within the other
238
! partitions bounding box:
239
! --------------------------------------------------------
240
myBB = BB(:,i) !Actually theirBB, but saves var names...
241
npart = 0
242
DO j=1,n
243
IF ( nodes_x(j)<myBB(1) .OR. nodes_x(j)>myBB(4) .OR. &
244
nodes_y(j)<myBB(2) .OR. nodes_y(j)>myBB(5) .OR. &
245
nodes_z(j)<myBB(3) .OR. nodes_z(j)>myBB(6) ) CYCLE
246
npart = npart+1
247
END DO
248
ProcSend(proc+1) % n = npart
249
IF ( npart>0 ) THEN
250
ALLOCATE( xpart(npart),ypart(npart),zpart(npart),ProcSend(proc+1) % perm(npart) )
251
npart = 0
252
DO j=1,n
253
IF ( nodes_x(j)<myBB(1) .OR. nodes_x(j)>myBB(4) .OR. &
254
nodes_y(j)<myBB(2) .OR. nodes_y(j)>myBB(5) .OR. &
255
nodes_z(j)<myBB(3) .OR. nodes_z(j)>myBB(6) ) CYCLE
256
npart=npart+1
257
ProcSend(proc+1) % perm(npart)=j
258
xpart(npart) = Nodes_x(j)
259
ypart(npart) = Nodes_y(j)
260
zpart(npart) = Nodes_z(j)
261
END DO
262
END IF
263
! send count...
264
! -------------
265
CALL MPI_BSEND( npart, 1, MPI_INTEGER, proc, &
266
1101, ELMER_COMM_WORLD, ierr )
267
IF ( npart==0 ) CYCLE
268
! ...and points
269
! -------------
270
CALL MPI_BSEND( xpart, npart, MPI_DOUBLE_PRECISION, proc, &
271
1102, ELMER_COMM_WORLD, ierr )
272
CALL MPI_BSEND( ypart, npart, MPI_DOUBLE_PRECISION, proc, &
273
1103, ELMER_COMM_WORLD, ierr )
274
CALL MPI_BSEND( zpart, npart, MPI_DOUBLE_PRECISION, proc, &
275
1104, ELMER_COMM_WORLD, ierr )
276
277
DEALLOCATE(xpart,ypart,zpart)
278
END DO
279
DEALLOCATE(nodes_x,nodes_y,nodes_z,BB)
280
END IF Sending
281
282
! receive points from others:
283
! ----------------------------
284
ALLOCATE(ProcRecv(Parenv % Pes))
285
DO i=1,COUNT(ParEnv % Active)-1
286
CALL MPI_RECV( n, 1, MPI_INTEGER, MPI_ANY_SOURCE, &
287
1101, ELMER_COMM_WORLD, status, ierr )
288
289
proc = status(MPI_SOURCE)
290
ProcRecv(proc+1) % n = n
291
292
IF ( n<=0 ) CYCLE
293
294
ALLOCATE(ProcRecv(proc+1) % Nodes_x(n), &
295
ProcRecv(proc+1) % Nodes_y(n),ProcRecv(proc+1) % Nodes_z(n))
296
297
CALL MPI_RECV( ProcRecv(proc+1) % nodes_x, n, MPI_DOUBLE_PRECISION, proc, &
298
1102, ELMER_COMM_WORLD, status, ierr )
299
CALL MPI_RECV( ProcRecv(proc+1) % nodes_y, n, MPI_DOUBLE_PRECISION, proc, &
300
1103, ELMER_COMM_WORLD, status, ierr )
301
CALL MPI_RECV( ProcRecv(proc+1) % nodes_z, n, MPI_DOUBLE_PRECISION, proc, &
302
1104, ELMER_COMM_WORLD, status, ierr )
303
END DO
304
305
DO i=1,ParEnv % PEs
306
IF ( Parenv % mype == i-1 .OR. .NOT. ParEnv % Active(i) ) CYCLE
307
308
proc = i-1
309
n = ProcRecv(i) % n
310
311
IF ( n==0 ) THEN
312
CALL MPI_BSEND( n, 1, MPI_INTEGER, proc, &
313
2101, ELMER_COMM_WORLD, ierr )
314
CYCLE
315
END IF
316
317
! Construct temporary mesh structure for the received points:
318
! -----------------------------------------------------------
319
Nmesh => AllocateMesh()
320
Nmesh % Nodes % x => ProcRecv(i) % nodes_x
321
Nmesh % Nodes % y => ProcRecv(i) % nodes_y
322
Nmesh % Nodes % z => ProcRecv(i) % nodes_z
323
Nmesh % NumberOfNodes = n
324
325
ALLOCATE(nperm(n), nReal(n))
326
DO j=1,n
327
nPerm(j)=j
328
END DO
329
nReal = NoData
330
331
CALL VariableAdd( NMesh % Variables, NMesh, CurrentModel % Solver, &
332
HeightName, 1, nReal, nPerm )
333
334
NULLIFY(nReal, nPerm)
335
nvars = 1 !not 0, because we always have 'height' var
336
337
!-------------------------------------------------------------
338
! If we have a variable list to interpolate, add them to nMesh
339
!-------------------------------------------------------------
340
IF(PRESENT(Variables)) THEN
341
OldVar => Variables
342
DO WHILE(ASSOCIATED(OldVar))
343
344
!Is the variable valid?
345
IF((SIZE(OldVar % Values) == OldVar % DOFs) .OR. & !-global
346
(OldVar % DOFs > 1) .OR. & !-multi-dof
347
(OldVar % Name == HeightName) .OR. & !-already got
348
OldVar % Secondary) THEN !-secondary
349
OldVar => OldVar % Next
350
CYCLE
351
ELSE IF(LEN(OldVar % Name) >= 10) THEN
352
IF(OldVar % Name(1:10)=='coordinate') THEN !-coord var
353
OldVar => OldVar % Next
354
CYCLE
355
END IF
356
END IF
357
358
nvars = nvars + 1
359
360
ALLOCATE(nReal(n), nPerm(n))
361
DO j=1,n
362
nPerm(j)=j
363
END DO
364
nReal = NoData
365
366
CALL VariableAdd( NMesh % Variables, NMesh, CurrentModel % Solver, &
367
OldVar % Name, 1, nReal, nPerm)
368
NULLIFY(nReal, nPerm)
369
370
nVar => VariableGet(NMesh % Variables, OldVar % Name, .TRUE.)
371
IF(.NOT. ASSOCIATED(nVar)) CALL Fatal("InterpolateVarToVarReduced",&
372
"Error trying to add variable to temporary mesh")
373
374
375
IF ( ASSOCIATED(OldVar % PrevValues) ) THEN
376
j = SIZE(OldVar % PrevValues,2)
377
nvars = nvars+j
378
ALLOCATE(nVar % PrevValues(n,j))
379
nVar % PrevValues = 0._dp
380
END IF
381
382
OldVar => OldVar % Next
383
END DO
384
END IF
385
386
! try interpolating values for the points:
387
! ----------------------------------------
388
ALLOCATE( FoundNodes(n),&
389
SendLocalDistance(n))
390
391
FoundNodes=.FALSE.
392
SendLocalDistance = 0.0_dp
393
394
CALL InterpolateVarToVarReducedQ( OldMesh, nMesh, HeightName, HeightDimensions, &
395
FoundNodes, SendLocalDistance, OldNodeMask, &
396
OldElemMask=OldElemMask, Variables=Variables, GlobalEps=GlobalEps, &
397
LocalEps=LocalEps, NumericalEps=NumericalEps )
398
399
nfound = COUNT(FoundNodes)
400
401
CALL MPI_BSEND( nfound, 1, MPI_INTEGER, proc, &
402
2101, ELMER_COMM_WORLD, ierr )
403
404
unfound = n - nfound
405
IF(unfound > 0) THEN
406
PRINT *, 'InterpVarToVar','Parallel: Found ',nfound,&
407
' nodes but still cannot find ',unfound,' nodes!'
408
END IF
409
410
! send interpolated values back to the owner:
411
! -------------------------------------------
412
IF ( nfound>0 ) THEN
413
ALLOCATE(vstore(nfound, nvars), vperm(nfound), WorkReal(nfound))
414
vstore=0
415
416
k = 0
417
DO j=1,n
418
IF ( .NOT.FoundNodes(j)) CYCLE
419
k = k + 1
420
vperm(k) = j
421
WorkReal(k) = SendLocalDistance(j)
422
Nvar => VariableGet( Nmesh % Variables,HeightName,ThisOnly=.TRUE.)
423
nvars = 1
424
vstore(k,nvars)=Nvar % Values(j)
425
426
! send all variables if requested
427
!--------------------------------
428
IF(PRESENT(Variables)) THEN
429
OldVar => Variables
430
DO WHILE(ASSOCIATED(OldVar))
431
432
IF((SIZE(OldVar % Values) == OldVar % DOFs) .OR. & !-global
433
(OldVar % DOFs > 1) .OR. & !-multi-dof
434
(OldVar % Name == HeightName) .OR. & !-already got
435
OldVar % Secondary) THEN !-secondary
436
437
OldVar => OldVar % Next
438
CYCLE
439
ELSE IF(LEN(OldVar % Name) >= 10) THEN
440
IF(OldVar % Name(1:10)=='coordinate') THEN !-coord var
441
OldVar => OldVar % Next
442
CYCLE
443
END IF
444
END IF
445
nVar => VariableGet( Nmesh % Variables,OldVar % Name,ThisOnly=.TRUE.)
446
nvars = nvars+1
447
vstore(k,nvars)=nVar % Values(j)
448
449
IF ( ASSOCIATED(OldVar % PrevValues) ) THEN
450
DO l=1,SIZE(nVar % PrevValues,2)
451
nvars = nvars+1
452
vstore(k,nvars)=Nvar % PrevValues(j,l)
453
END DO
454
END IF
455
OldVar => OldVar % Next
456
END DO
457
END IF
458
459
IF(Debug) PRINT *,'Partition ',ParEnv % MyPE,' found point with value: ',vstore(k,1)
460
END DO
461
462
!Pack up Local Distance from interp for this partition pair
463
DEALLOCATE(SendLocalDistance)
464
ALLOCATE(SendLocalDistance(nfound))
465
SendLocalDistance = WorkReal
466
DEALLOCATE(WorkReal)
467
468
CALL MPI_BSEND( SendLocalDistance, nfound, MPI_DOUBLE_PRECISION, proc, &
469
2100, ELMER_COMM_WORLD, ierr )
470
471
CALL MPI_BSEND( vperm, nfound, MPI_INTEGER, proc, &
472
2102, ELMER_COMM_WORLD, ierr )
473
474
DO j=1,nvars
475
CALL MPI_BSEND( vstore(:,j), nfound, MPI_DOUBLE_PRECISION, proc, &
476
2103+j, ELMER_COMM_WORLD, ierr )
477
END DO
478
479
DEALLOCATE(vstore, vperm)
480
END IF
481
482
!These deallocations could be done with fewer lines,
483
!but this way is more transparent (Nmesh % nodes point to procrecv)
484
DEALLOCATE(ProcRecv(i) % Nodes_x, ProcRecv(i) % Nodes_y,&
485
ProcRecv(i) % Nodes_z)
486
NULLIFY(Nmesh % Nodes % x, Nmesh % Nodes % y, Nmesh % Nodes % z)
487
CALL ReleaseMesh(Nmesh)
488
DEALLOCATE(foundnodes, SendLocalDistance, nMesh)
489
END DO
490
DEALLOCATE(ProcRecv)
491
492
! Receive interpolated values:
493
! ----------------------------
494
DO i=1,COUNT(ParEnv % Active)-1
495
496
! recv count:
497
! -----------
498
CALL MPI_RECV( n, 1, MPI_INTEGER, MPI_ANY_SOURCE, &
499
2101, ELMER_COMM_WORLD, status, ierr )
500
501
proc = status(MPI_SOURCE)
502
IF ( n<=0 ) THEN
503
IF ( ALLOCATED(ProcSend) ) THEN
504
IF ( ALLOCATED(ProcSend(proc+1) % Perm)) &
505
DEALLOCATE(ProcSend(proc+1) % Perm)
506
END IF
507
CYCLE
508
END IF
509
510
ALLOCATE(astore(n),vperm(n), RecvLocalDistance(n))
511
512
! recv permutation (where in the original array the
513
! points the partition found are):
514
! --------------------------------------------------
515
CALL MPI_RECV( vperm, n, MPI_INTEGER, proc, &
516
2102, ELMER_COMM_WORLD, status, ierr )
517
518
CALL MPI_RECV( RecvLocalDistance, n, MPI_DOUBLE_PRECISION, proc, &
519
2100, ELMER_COMM_WORLD, status, ierr )
520
521
! recv values and store:
522
! ----------------------
523
!FIX HERE, INC MPI SEND ID
524
CALL MPI_RECV( astore, n, MPI_DOUBLE_PRECISION, proc, &
525
2103+1, ELMER_COMM_WORLD, status, ierr )
526
527
Nvar => VariableGet( NewMesh % Variables,HeightName,ThisOnly=.TRUE.)
528
IF(.NOT. ASSOCIATED(Nvar)) CALL Fatal("InterpVarToVar","Could not get variable from &
529
&temporary mesh!")
530
531
!Ddetermine which nodes were found BETTER than previously
532
!i.e. compare RecvLocalDistance to PointLocalDistance.
533
!In case the node previously wasn't found, BetterFound=.TRUE.,
534
!because PointLocalDistance = HUGE()
535
ALLOCATE(BetterFound(n))
536
BetterFound = .FALSE.
537
DO j=1,n
538
k=perm(ProcSend(proc+1) % Perm(vperm(j)))
539
IF(RecvLocalDistance(j) < PointLocalDistance(k)) THEN
540
BetterFound(j) = .TRUE.
541
542
IF(Debug .AND. (PointLocalDistance(k) /= HUGE(PointLocalDistance(k)))) &
543
PRINT *,ParEnv % MyPE,' better find node: ',k,' local dist new, old:',&
544
RecvLocalDistance(j), PointLocalDistance(k)
545
546
PointLocalDistance(k) = RecvLocalDistance(j)
547
END IF
548
END DO
549
550
DO j=1,n
551
IF(.NOT. BetterFound(j)) CYCLE
552
k=perm(ProcSend(proc+1) % Perm(vperm(j)))
553
IF ( Nvar % perm(k)>0 ) THEN
554
Nvar % Values(Nvar % Perm(k)) = astore(j)
555
IF(PRESENT(UnfoundNodes)) UnfoundNodes(k) = .FALSE.
556
END IF
557
END DO
558
559
IF(PRESENT(Variables)) THEN
560
OldVar => Variables
561
nvars = 1
562
563
DO WHILE(ASSOCIATED(OldVar))
564
IF((SIZE(OldVar % Values) == OldVar % DOFs) .OR. & !-global
565
(OldVar % DOFs > 1) .OR. & !-multi-dof
566
(OldVar % Name == HeightName) .OR. & !-already got
567
OldVar % Secondary) THEN !-secondary
568
569
OldVar => OldVar % Next
570
CYCLE
571
ELSE IF(LEN(OldVar % Name) >= 10) THEN
572
IF(OldVar % Name(1:10)=='coordinate') THEN !-coord var
573
OldVar => OldVar % Next
574
CYCLE
575
END IF
576
END IF
577
578
nvars = nvars + 1
579
CALL MPI_RECV( astore, n, MPI_DOUBLE_PRECISION, proc, &
580
2103+nvars, ELMER_COMM_WORLD, status, ierr )
581
582
nVar => VariableGet( NewMesh % Variables,OldVar % Name,ThisOnly=.TRUE.)
583
584
IF (ASSOCIATED(nVar) ) THEN
585
DO j=1,n
586
IF(.NOT. BetterFound(j)) CYCLE
587
k=perm(ProcSend(proc+1) % Perm(vperm(j)))
588
IF(ABS(astore(j) - NoData) < EPSILON(astore(j))) CYCLE !point found but not this specific var
589
IF ( Nvar % perm(k)>0 ) &
590
Nvar % Values(Nvar % Perm(k)) = astore(j)
591
END DO
592
END IF
593
594
IF ( ASSOCIATED(OldVar % PrevValues) ) THEN
595
DO l=1,SIZE(OldVar % PrevValues,2)
596
nvars=nvars+1
597
CALL MPI_RECV( astore, n, MPI_DOUBLE_PRECISION, proc, &
598
2103+nvars, ELMER_COMM_WORLD, status, ierr )
599
IF(ASSOCIATED(Nvar)) THEN
600
DO j=1,n
601
IF(.NOT. BetterFound(j)) CYCLE
602
k=perm(ProcSend(proc+1) % Perm(vperm(j)))
603
IF ( Nvar % perm(k)>0 ) &
604
Nvar % PrevValues(Nvar % Perm(k),l) = astore(j)
605
END DO
606
END IF
607
END DO
608
END IF
609
610
OldVar => OldVar % Next
611
END DO
612
END IF
613
614
DEALLOCATE(astore,vperm,RecvLocalDistance, BetterFound, ProcSend(proc+1) % perm)
615
616
END DO
617
618
DEALLOCATE(PointLocalDistance)
619
IF ( ALLOCATED(Perm) ) DEALLOCATE(Perm,ProcSend)
620
621
!------------------------------------------------------------------------------
622
END SUBROUTINE InterpolateVarToVarReduced
623
624
!------------------------------------------------------------------------------
625
SUBROUTINE InterpolateVarToVarReducedQ( OldMesh, NewMesh,HeightName,HeightDimensions, &
626
FoundNodes, LocalDistances, OldNodeMask, NewNodeMask, OldElemMask, &
627
Variables, GlobalEps, LocalEps, NumericalEps)
628
!This subroutine takes each boundary node on the specified boundary of the new mesh and finds its height (y coord in 2D) by performing (DIM - 1) interpolaton through boundary elements of the old mesh.
629
630
!-------------------------------------------------------------------------------
631
TYPE(Mesh_t), TARGET, INTENT(IN) :: OldMesh
632
TYPE(Mesh_t), TARGET, INTENT(INOUT) :: NewMesh
633
TYPE(Variable_t), POINTER, OPTIONAL :: Variables
634
CHARACTER(LEN=*) :: HeightName
635
INTEGER, POINTER :: HeightDimensions(:)
636
LOGICAL, POINTER, OPTIONAL :: OldNodeMask(:), &
637
NewNodeMask(:), OldElemMask(:)
638
LOGICAL, ALLOCATABLE, OPTIONAL :: FoundNodes(:)
639
REAL(KIND=dp), OPTIONAL :: GlobalEps, LocalEps, NumericalEps
640
REAL(KIND=dp), ALLOCATABLE, OPTIONAL :: LocalDistances(:)
641
!------------------------------------------------------------------------------
642
TYPE(Variable_t), POINTER :: Var, VarOld, OldVar, NewVar, PermVar, WorkVar
643
TYPE(Element_t),POINTER :: Element
644
TYPE(Nodes_t) :: ElementNodes
645
REAL(KIND=dp), POINTER :: OldHeight(:), NewHeight(:)
646
INTEGER, POINTER :: OldPerm(:), NewPerm(:)
647
INTEGER :: i, j, k, l, n, ierr
648
REAL(KIND=dp), DIMENSION(3) :: Point
649
INTEGER, POINTER :: NodeIndexes(:)
650
INTEGER, ALLOCATABLE :: DefaultPerm(:)
651
REAL(KIND=dp), DIMENSION(3) :: LocalCoordinates
652
REAL(KIND=dp), POINTER :: ElementValues(:)
653
REAL(KIND=dp) :: detJ, u,v,w,s, LocalDist
654
LOGICAL :: Found, Debug, FirstTime=.TRUE.,GMUnfound=.FALSE.
655
REAL(KIND=dp) :: eps_global_limit, eps_local_limit,&
656
eps_global_init, eps_local_init, eps_global, eps_local, eps_numeric
657
658
SAVE DefaultPerm, FirstTime
659
!------------------------------------------------------------------------------
660
661
!========================================
662
! Variables and parameter initializations
663
!========================================
664
665
Debug = .FALSE.
666
667
!For hydromesh calving purposes
668
IF(HeightName == 'temp residual') THEN
669
GMUnfound = .TRUE.
670
ELSE
671
GMUnfound = .FALSE.
672
END IF
673
674
IF(Debug) THEN
675
PRINT *, 'Debug, present(OldNodeMask)', PRESENT(OldNodeMask)
676
IF(PRESENT(OldNodeMask)) THEN
677
PRINT *, 'Size OldNodeMask ', SIZE(OldNodeMask)
678
PRINT *, 'count true: ', COUNT(OldNodeMask)
679
END IF
680
END IF
681
682
! Get the height variable
683
!---------------------------------------
684
VarOld => VariableGet( OldMesh % Variables, HeightName, ThisOnly = .TRUE. )
685
OldHeight => VarOld % Values
686
OldPerm => VarOld % Perm
687
688
! If the target variable does not exist, create it
689
!----------------------------------------------------------
690
Var => VariableGet( NewMesh % Variables, HeightName, ThisOnly = .TRUE. )
691
IF( .NOT. ASSOCIATED(Var) ) THEN
692
! This for when mesh connectivity isn't the same...
693
! Only actually for if new mesh has bigger perm than old mesh
694
! Which crashes on result output
695
! If inequality other way round, standard routine works fine
696
IF(NewMesh % NumberOfNodes /= OldMesh % NumberOfNodes .OR. NewMesh % MeshDim /= OldMesh % MeshDim) THEN
697
!Special case for my calvinghydrointerp stuff
698
PermVar => VariableGet( NewMesh % Variables, 'hydroweights', ThisOnly = .TRUE. )
699
!On the assumption you'll have some velocity
700
IF(.NOT. ASSOCIATED(PermVar)) THEN
701
PermVar => VariableGet( NewMesh % Variables, 'velocity 1', ThisOnly = .TRUE. )
702
END IF
703
!And if you don't, you'll probably have this one
704
IF(.NOT. ASSOCIATED(PermVar)) THEN
705
PermVar => VariableGet( NewMesh % Variables, 'hydraulic potential', ThisOnly = .TRUE. )
706
END IF
707
ALLOCATE( NewHeight(SIZE(PermVar % Values)))
708
NewHeight = 0.0_dp
709
ALLOCATE( NewPerm(SIZE(PermVar % Perm)) )
710
NewPerm = PermVar % Perm
711
NULLIFY(PermVar)
712
! This assumes that the mesh connectivity is the same...
713
ELSE
714
ALLOCATE( NewHeight(SIZE(OldHeight) ) )
715
NewHeight = 0.0_dp
716
ALLOCATE( NewPerm(SIZE(OldPerm) ) )
717
NewPerm = OldPerm
718
END IF
719
CALL VariableAdd( NewMesh % Variables, NewMesh, CurrentModel % Solver, &
720
HeightName, 1, NewHeight, NewPerm )
721
Var => VariableGet( NewMesh % Variables, HeightName, ThisOnly = .TRUE. )
722
IF(.NOT. ASSOCIATED(Var)) CALL Fatal("InterpolateVarToVarReduced",&
723
"Error adding the height variable to the new mesh.")
724
END IF
725
NewHeight => Var % Values
726
NewPerm => Var % Perm
727
728
729
! Get epsilon values if specified
730
!------------------------------------------------------------
731
eps_global_init = 2.0e-10_dp
732
eps_local_init = 1.0e-10_dp
733
eps_numeric = 1.0e-10_dp
734
735
IF(PRESENT(GlobalEps)) THEN
736
eps_global_limit = GlobalEps
737
ELSE
738
eps_global_limit = ListGetConstReal( CurrentModel % Simulation, &
739
'Interpolation Global Epsilon', Found)
740
IF(.NOT. Found) eps_global_limit = 1.0e-10
741
END IF
742
743
IF(PRESENT(LocalEps)) THEN
744
eps_local_limit = LocalEps
745
ELSE
746
eps_local_limit = ListGetConstReal( CurrentModel % Simulation, &
747
'Interpolation Local Epsilon', Found )
748
IF(.NOT. Found) eps_local_limit = 1.0e-10
749
END IF
750
751
IF(PRESENT(NumericalEps)) THEN
752
eps_numeric = NumericalEps
753
ELSE
754
eps_numeric = ListGetConstReal( CurrentModel % Simulation, &
755
'Interpolation Numerical Epsilon', Found )
756
IF(.NOT. Found) eps_numeric = EPSILON(eps_numeric)
757
END IF
758
759
!------------------------------------------------------------------------------
760
n = OldMesh % MaxElementNodes
761
ALLOCATE( ElementNodes % x(n), ElementNodes % y(n), &
762
ElementNodes % z(n), ElementValues(n) )
763
ElementNodes % x = 0.0_dp
764
ElementNodes % y = 0.0_dp
765
ElementNodes % z = 0.0_dp
766
767
!========================================
768
! Action
769
!========================================
770
771
!------------------------------------------------------------------------------
772
! Loop over all nodes in the new mesh
773
!------------------------------------------------------------------------------
774
DO i=1,NewMesh % NumberOfNodes
775
!------------------------------------------------------------------------------
776
777
Found = .FALSE.
778
779
IF( PRESENT(NewNodeMask)) THEN
780
IF(NewNodeMask(i)) CYCLE
781
END IF
782
IF( NewPerm(i) == 0 ) CYCLE
783
784
Point(1) = NewMesh % Nodes % x(i)
785
Point(2) = NewMesh % Nodes % y(i)
786
Point(3) = NewMesh % Nodes % z(i)
787
Point(HeightDimensions) = 0.0_dp
788
789
IF(Debug) PRINT *, 'Debug point no: ',i,' Perm: ',NewPerm(i), Point(1),Point(2),Point(3)
790
!------------------------------------------------------------------------------
791
! Go through all old mesh boundary elements
792
!------------------------------------------------------------------------------
793
eps_global = eps_global_init
794
eps_local = eps_local_init
795
796
DO WHILE(.TRUE.)
797
DO k=1, OldMesh % NumberOfBulkElements + OldMesh % NumberOfBoundaryElements
798
799
Element => OldMesh % Elements(k)
800
n = Element % TYPE % NumberOfNodes
801
NodeIndexes => Element % NodeIndexes
802
803
IF(Element % TYPE % DIMENSION > (3-SIZE(HeightDimensions))) CYCLE
804
805
IF( ANY( OldPerm( NodeIndexes ) == 0 ) ) CYCLE
806
807
IF(PRESENT(OldElemMask)) THEN
808
IF(OldElemMask(k)) CYCLE
809
END IF
810
IF(PRESENT(OldNodeMask)) THEN
811
IF( ANY( OldNodeMask( NodeIndexes ))) CYCLE
812
END IF
813
814
ElementNodes % x = 0.0_dp
815
ElementNodes % y = 0.0_dp
816
ElementNodes % z = 0.0_dp
817
818
IF( ALL(HeightDimensions /= 1) ) &
819
ElementNodes % x(1:n) = OldMesh % Nodes % x(NodeIndexes)
820
821
IF( ALL(HeightDimensions /= 2) ) &
822
ElementNodes % y(1:n) = OldMesh % Nodes % y(NodeIndexes)
823
824
IF( ALL(HeightDimensions /= 3) ) &
825
ElementNodes % z(1:n) = OldMesh % Nodes % z(NodeIndexes)
826
827
IF(Debug .AND. .FALSE.) THEN
828
PRINT *, 'Debug element coords: '
829
DO l=1,n
830
PRINT *, ElementNodes % x(l),ElementNodes % y(l),ElementNodes % z(l)
831
END DO
832
END IF
833
834
Found = PointInElement( Element, ElementNodes, &
835
Point, LocalCoordinates, eps_global, eps_local, eps_numeric,&
836
LocalDistance=LocalDist)
837
IF( Found ) EXIT
838
END DO
839
IF( Found ) EXIT
840
841
eps_global = eps_global * 10.0_dp
842
eps_local = eps_local * 10.0_dp
843
IF(eps_global > eps_global_limit) EXIT
844
IF(eps_local > eps_local_limit) EXIT
845
846
END DO
847
848
IF (.NOT.Found) THEN
849
!CHANGE
850
!Need to define value for groundedmask on unfound nodes if
851
!interpolating between ice mesh and larger footprint hydrological mesh
852
IF(GMUnfound) THEN
853
WorkVar => VariableGet(NewMesh % Variables, "groundedmask", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
854
IF(ASSOCIATED(WorkVar)) THEN
855
WorkVar % Values(WorkVar % Perm(i)) = -1.0
856
END IF
857
NULLIFY(WorkVar)
858
WorkVar => VariableGet(NewMesh % Variables, "basalmeltrate", ThisOnly=.TRUE., UnfoundFatal=.FALSE.)
859
IF(ASSOCIATED(WorkVar)) THEN
860
WorkVar % Values(WorkVar % Perm(i)) = 0.0
861
END IF
862
END IF
863
NULLIFY(Element, WorkVar)
864
IF(PRESENT(FoundNodes)) FoundNodes(i) = .FALSE.
865
CYCLE
866
END IF
867
868
IF(PRESENT(FoundNodes)) FoundNodes(i) = .TRUE.
869
870
ElementValues(1:n) = OldHeight( OldPerm(NodeIndexes) )
871
NewHeight(NewPerm(i)) = InterpolateInElement( &
872
Element, ElementValues, LocalCoordinates(1), &
873
LocalCoordinates(2), LocalCoordinates(3) )
874
875
!Return element distances if requested.
876
IF(PRESENT(LocalDistances)) LocalDistances(i) = LocalDist
877
878
879
!-------------------------------------------------------
880
! Interpolate full variable list if requested
881
!-------------------------------------------------------
882
!For variables without perm (see change below)
883
IF(FirstTime) THEN
884
FirstTime = .FALSE.
885
ALLOCATE(DefaultPerm(OldMesh % NumberOfNodes))
886
DO j=1,OldMesh % NumberOfNodes
887
DefaultPerm(j) = j
888
END DO
889
END IF
890
891
IF(PRESENT(Variables)) THEN
892
OldVar => Variables
893
DO WHILE(ASSOCIATED(OldVar))
894
895
IF((SIZE(OldVar % Values) == OldVar % DOFs) .OR. & !-global
896
(OldVar % DOFs > 1) .OR. & !-multi-dof
897
(OldVar % Name == HeightName) .OR. & !-already got
898
OldVar % Secondary) THEN !-secondary
899
900
OldVar => OldVar % Next
901
CYCLE
902
ELSE IF(LEN(OldVar % Name) >= 10) THEN
903
IF(OldVar % Name(1:10)=='coordinate') THEN !-coord var
904
OldVar => OldVar % Next
905
CYCLE
906
END IF
907
END IF
908
909
!For variables which don't have a perm for some reason
910
IF(.NOT.(ASSOCIATED(OldVar % Perm))) THEN
911
ALLOCATE(OldVar % Perm(OldMesh % NumberOfNodes))
912
OldVar % Perm(1:SIZE(OldVar % Perm)) = DefaultPerm(1:SIZE(OldVar % Perm))
913
END IF
914
915
NewVar => VariableGet(NewMesh % Variables, OldVar % Name, .TRUE.)
916
IF(.NOT. ASSOCIATED(NewVar)) THEN
917
OldVar => OldVar % Next
918
CYCLE
919
END IF
920
921
IF((NewVar % Perm(i) == 0) .OR. ANY(OldVar % Perm(NodeIndexes)==0)) THEN
922
! PRINT *, 'Debug interpvartovar, skipping ',OldVar % Name,' because of zero perm'
923
OldVar => OldVar % Next
924
CYCLE
925
END IF
926
927
ElementValues(1:n) = OldVar % Values( OldVar % Perm(NodeIndexes) )
928
NewVar % Values(NewVar % Perm(i)) = InterpolateInElement( &
929
Element, ElementValues, LocalCoordinates(1), &
930
LocalCoordinates(2), LocalCoordinates(3) )
931
932
IF ( ASSOCIATED( OldVar % PrevValues ) ) THEN
933
DO j=1,SIZE(NewVar % PrevValues,2) !NewVar, not OldVar, to prevent error
934
ElementValues(1:n) = & !if sizes differ
935
OldVar % PrevValues(OldVar % Perm(NodeIndexes),j)
936
NewVar % PrevValues(NewVar % Perm(i),j) = &
937
InterpolateInElement( Element, ElementValues, &
938
LocalCoordinates(1), &
939
LocalCoordinates(2), LocalCoordinates(3) )
940
END DO
941
END IF
942
943
OldVar => OldVar % Next
944
END DO
945
END IF
946
947
END DO
948
949
DEALLOCATE( ElementNodes % x, ElementNodes % y, &
950
ElementNodes % z, ElementValues )
951
952
953
!------------------------------------------------------------------------------
954
END SUBROUTINE InterpolateVarToVarReducedQ
955
956
!Subroutine designed to interpolate single missing points which sometimes
957
!occur on the base and top interpolation, from surrounding nodes of the same mesh.
958
SUBROUTINE InterpolateUnfoundPoint( NodeNumber, Mesh, HeightName, HeightDimensions,&
959
ElemMask, NodeMask, Variables, UnfoundDOFS, Found )
960
961
! reworked
962
! search for suppnodes
963
! calculate vars present on each supp node
964
! interp variables and assign
965
966
TYPE(Mesh_t), TARGET, INTENT(INOUT) :: Mesh
967
TYPE(Variable_t), POINTER, OPTIONAL :: Variables
968
CHARACTER(LEN=*) :: HeightName
969
INTEGER :: NodeNumber
970
INTEGER, POINTER :: HeightDimensions(:)
971
LOGICAL, POINTER, OPTIONAL :: ElemMask(:),NodeMask(:)
972
INTEGER, ALLOCATABLE, OPTIONAL :: UnfoundDOFS(:)
973
LOGICAL, OPTIONAL :: Found
974
!------------------------------------------------------------------------------
975
TYPE(Variable_t), POINTER :: HeightVar, Var
976
TYPE(Element_t),POINTER :: Element
977
LOGICAL :: Parallel, Debug, HasNeighbours
978
LOGICAL, ALLOCATABLE :: ValidNode(:), SuppNodeMask(:,:), SuppNodePMask(:,:)
979
REAL(KIND=dp) :: Point(3), SuppPoint(3), weight, Exponent, distance
980
REAL(KIND=dp), ALLOCATABLE :: interpedValue(:), SuppNodeWeights(:),SumWeights(:),&
981
InterpedPValue(:), PSumWeights(:)
982
INTEGER :: i,j,n,idx,NoNeighbours,NoSuppNodes, MaskCount, PMaskCount
983
INTEGER, ALLOCATABLE :: WorkInt(:), SuppNodes(:)
984
INTEGER, POINTER :: Neighbours(:)
985
986
Debug = .TRUE.
987
Parallel = ParEnv % PEs > 1
988
989
HeightVar => VariableGet( Mesh % Variables, HeightName, &
990
ThisOnly = .TRUE., UnfoundFatal = .TRUE. )
991
992
!The sought point
993
Point(1) = Mesh % Nodes % x(NodeNumber)
994
Point(2) = Mesh % Nodes % y(NodeNumber)
995
Point(3) = Mesh % Nodes % z(NodeNumber)
996
Point(HeightDimensions) = 0.0_dp
997
998
!IDW exponent
999
Exponent = 1.0
1000
1001
!Is another partition also contributing to this
1002
NoNeighbours = SIZE(Mesh % ParallelInfo % &
1003
NeighbourList(NodeNumber) % Neighbours) - 1
1004
HasNeighbours = NoNeighbours > 0
1005
1006
!Create list of neighbour partitions (this will almost always be 0 :( )
1007
IF(HasNeighbours) THEN
1008
! given the complexity of shared point problems put in separate subroutine
1009
CALL FATAL('InterpolateUnfoundPoint', 'Use InterpolateUnfoundsharedPoint for shared nodes!')
1010
END IF
1011
1012
!Count this partition's relevant nodes
1013
ALLOCATE(ValidNode(Mesh % NumberOfNodes))
1014
ValidNode = .FALSE.
1015
1016
!Start by marking .TRUE. based on ElemMask if present
1017
IF(PRESENT(ElemMask)) THEN
1018
DO i=1,SIZE(ElemMask)
1019
IF(ElemMask(i)) CYCLE
1020
n = Mesh % Elements(i) % TYPE % NumberOfNodes
1021
ValidNode(Mesh % Elements(i) % NodeIndexes(1:n)) = .TRUE.
1022
END DO
1023
ELSE
1024
ValidNode = .TRUE.
1025
END IF
1026
1027
!Knock down by node mask if present
1028
IF(PRESENT(NodeMask)) THEN
1029
DO i=1,SIZE(NodeMask)
1030
IF(NodeMask(i)) ValidNode(i) = .FALSE.
1031
END DO
1032
END IF
1033
1034
!Knock down nodes with 0 perm
1035
DO i=1,Mesh % NumberOfNodes
1036
IF(HeightVar % Perm(i) > 0) CYCLE
1037
ValidNode(i) = .FALSE.
1038
END DO
1039
1040
IF(Debug) PRINT *,ParEnv % MyPE,'Debug, seeking nn: ',NodeNumber,' found ',&
1041
COUNT(ValidNode),' valid nodes.'
1042
1043
ALLOCATE(WorkInt(100))
1044
WorkInt = 0
1045
1046
!Cycle elements containing our node, adding other nodes to list
1047
NoSuppNodes = 0
1048
DO i=Mesh % NumberOfBulkElements+1,Mesh % NumberOfBulkElements &
1049
+ Mesh % NumberOfBoundaryElements
1050
Element => Mesh % Elements(i)
1051
n = Element % TYPE % NumberOfNodes
1052
1053
!Doesn't contain our point
1054
IF(.NOT. ANY(Element % NodeIndexes(1:n)==NodeNumber)) CYCLE
1055
1056
!Cycle element nodes
1057
DO j=1,n
1058
idx = Element % NodeIndexes(j)
1059
IF(idx == NodeNumber) CYCLE !sought node
1060
IF(ANY(WorkInt == idx)) CYCLE !already got
1061
IF(.NOT. ValidNode(idx)) CYCLE !invalid
1062
! do not include nodes that has yet to be interped
1063
! nodes are interped in GDOF order so if this unfoundnode has a lower
1064
! GDOF then the SuppNode has yet to be interped
1065
IF(PRESENT(UnfoundDOFs)) THEN
1066
IF(ANY(UnfoundDOFS == Mesh % ParallelInfo % GlobalDOFs(idx)) .AND. &
1067
Mesh % ParallelInfo % GlobalDOFs(NodeNumber) < Mesh % ParallelInfo % GlobalDOFs(idx)) CYCLE
1068
END IF
1069
1070
NoSuppNodes = NoSuppNodes + 1
1071
WorkInt(NoSuppNodes) = idx
1072
END DO
1073
END DO
1074
1075
ALLOCATE(SuppNodes(NoSuppNodes))
1076
SuppNodes = WorkInt(:NoSuppNodes)
1077
1078
IF(Debug) PRINT *,ParEnv % MyPE,'Debug, seeking nn: ',NodeNumber,' found ',&
1079
NoSuppNodes,' supporting nodes.'
1080
1081
IF(PRESENT(Found)) THEN
1082
Found = .TRUE.
1083
IF(NoSuppNodes == 0) THEN
1084
Found = .FALSE.
1085
RETURN
1086
END IF
1087
END IF
1088
1089
! calculate maskcount and pmaskcount
1090
IF(PRESENT(Variables)) THEN
1091
MaskCount = 0 ! zero since no variables already
1092
PMaskCount = 0
1093
Var => Variables
1094
DO WHILE(ASSOCIATED(Var))
1095
MaskCount = MaskCount + 1
1096
IF(ASSOCIATED(Var % PrevValues)) &
1097
PMaskCount = PMaskCount + SIZE(Var % PrevValues,2)
1098
Var => Var % Next
1099
END DO
1100
END IF
1101
1102
!create suppnode mask and get node values
1103
! get node weights too
1104
ALLOCATE(SuppNodeMask(NoSuppNodes, MaskCount), &
1105
SuppNodePMask(NoSuppNodes, PMaskCount), &
1106
InterpedValue(MaskCount), InterpedPValue(PMaskCount), &
1107
SuppNodeWeights(NoSuppNodes))
1108
SuppNodeMask = .FALSE.; SuppNodePMask = .FALSE.
1109
interpedValue = 0.0_dp; InterpedPValue = 0.0_dp
1110
DO i=1, NoSuppNodes
1111
! SuppNodes for interp
1112
SuppPoint(1) = Mesh % Nodes % x(SuppNodes(i))
1113
SuppPoint(2) = Mesh % Nodes % y(SuppNodes(i))
1114
SuppPoint(3) = Mesh % Nodes % z(SuppNodes(i))
1115
SuppPoint(HeightDimensions) = 0.0_dp
1116
1117
distance = 0.0_dp
1118
DO j=1,3
1119
distance = distance + (Point(j) - SuppPoint(j))**2.0_dp
1120
END DO
1121
distance = distance**0.5_dp
1122
1123
weight = distance**(-exponent)
1124
SuppNodeWeights(i) = weight
1125
1126
interpedValue(1) = interpedValue(1) + &
1127
weight * HeightVar % Values(HeightVar % Perm(SuppNodes(i)))
1128
SuppNodeMask(i, 1) = .TRUE.
1129
1130
IF(ASSOCIATED(HeightVar % PrevValues)) THEN
1131
DO j=1, SIZE(HeightVar % PrevValues,2)
1132
interpedPValue(j) = interpedPValue(j) + &
1133
weight * HeightVar % PrevValues(HeightVar % Perm(SuppNodes(i)),j)
1134
SuppNodePMask(i, j) = .TRUE.
1135
END DO
1136
END IF
1137
1138
IF(PRESENT(Variables)) THEN
1139
MaskCount = 1; PMaskCount = SIZE(HeightVar % PrevValues,2)
1140
Var => Variables
1141
DO WHILE(ASSOCIATED(Var))
1142
MaskCount = MaskCount + 1
1143
IF(ASSOCIATED(Var % PrevValues)) &
1144
PMaskCount = PMaskCount + SIZE(Var % PrevValues,2)
1145
IF((SIZE(Var % Values) == Var % DOFs) .OR. & !-global
1146
(Var % DOFs > 1) .OR. & !-multi-dof
1147
Var % Secondary) THEN !-secondary
1148
Var => Var % Next
1149
CYCLE
1150
ELSEIF(Var % Name == HeightName) THEN !-already got
1151
MaskCount = MaskCount - 1
1152
PMaskCount = PMaskCount - SIZE(Var % PrevValues,2)
1153
Var => Var % Next
1154
CYCLE
1155
ELSE IF(LEN(Var % Name) >= 10) THEN
1156
IF(Var % Name(1:10)=='coordinate') THEN !-coord var
1157
Var => Var % Next
1158
CYCLE
1159
END IF
1160
END IF
1161
IF(Var % Perm(SuppNodes(i)) <= 0 .OR. &
1162
(Var % Perm(NodeNumber) <= 0)) THEN !-not fully defined here
1163
Var => Var % Next
1164
CYCLE
1165
END IF
1166
1167
SuppNodeMask(i, MaskCount) = .TRUE.
1168
InterpedValue(MaskCount) = interpedvalue(MaskCount) + &
1169
weight * Var % Values(Var % Perm(SuppNodes(i)))
1170
1171
!PrevValues
1172
IF(ASSOCIATED(Var % PrevValues)) THEN
1173
SuppNodePMask(i, PMaskCount) = .TRUE.
1174
DO j=1, SIZE(Var % PrevValues, 2)
1175
n = PMaskCount + j - SIZE(Var % PrevValues, 2)
1176
InterpedPValue(n) = InterpedPValue(n) +&
1177
weight * Var % PrevValues(Var % Perm(SuppNodes(i)), j)
1178
END DO
1179
END IF
1180
1181
Var => Var % Next
1182
END DO
1183
END IF
1184
END DO
1185
1186
!Calculate weights
1187
ALLOCATE(SumWeights(MaskCount), PSumWeights(PMaskCount))
1188
SumWeights = 0.0_dp; PSumWeights = 0.0_dp
1189
DO i=1, NoSuppNodes
1190
DO j=1, MaskCount
1191
!var exists on that node
1192
IF(SuppNodeMask(i,j)) &
1193
SumWeights(j) = SumWeights(j) + SuppNodeWeights(i)
1194
END DO
1195
DO j=1, PMaskCount
1196
IF(SuppNodePMask(i,j)) &
1197
PSumWeights(j) = PSumWeights(j) + SuppNodeWeights(i)
1198
END DO
1199
END DO
1200
1201
interpedValue = interpedValue/SumWeights
1202
InterpedPValue = InterpedPValue/PSumWeights
1203
1204
!Finally, put the interped values in their place
1205
HeightVar % Values(HeightVar % Perm(NodeNumber)) = interpedValue(1)
1206
1207
IF(ASSOCIATED(HeightVar % PrevValues)) THEN
1208
DO j=1, SIZE(HeightVar % PrevValues,2)
1209
HeightVar % PrevValues(HeightVar % Perm(NodeNumber), j) = interpedPValue(j)
1210
END DO
1211
END IF
1212
1213
IF(PRESENT(Variables)) THEN
1214
MaskCount = 1; PMaskCount = SIZE(HeightVar % PrevValues,2)
1215
Var => Variables
1216
DO WHILE(ASSOCIATED(Var))
1217
MaskCount = MaskCount + 1
1218
IF(ASSOCIATED(Var % PrevValues)) &
1219
PMaskCount = PMaskCount + SIZE(Var % PrevValues,2)
1220
IF((SIZE(Var % Values) == Var % DOFs) .OR. & !-global
1221
(Var % DOFs > 1) .OR. & !-multi-dof
1222
Var % Secondary) THEN !-secondary
1223
Var => Var % Next
1224
CYCLE
1225
ELSEIF(Var % Name == HeightName) THEN !-already got
1226
MaskCount = MaskCount - 1
1227
PMaskCount = PMaskCount - SIZE(Var % PrevValues,2)
1228
Var => Var % Next
1229
CYCLE
1230
ELSE IF(LEN(Var % Name) >= 10) THEN
1231
IF(Var % Name(1:10)=='coordinate') THEN !-coord var
1232
Var => Var % Next
1233
CYCLE
1234
END IF
1235
END IF
1236
IF(Var % Perm(NodeNumber) <= 0) THEN !-not fully defined here
1237
Var => Var % Next
1238
CYCLE
1239
END IF
1240
1241
!if any suppnode had variable
1242
IF(ANY(SuppNodeMask(:,MaskCount))) THEN
1243
Var % Values(Var % Perm(NodeNumber)) = interpedValue(MaskCount)
1244
END IF
1245
1246
IF(ASSOCIATED(Var % PrevValues)) THEN
1247
DO j=1, SIZE(Var % PrevValues,2)
1248
n = PMaskCount + j - SIZE(Var % PrevValues, 2)
1249
IF(ANY(SuppNodePMask(:,n))) THEN ! defined at suppnodes
1250
Var % PrevValues(Var % Perm(NodeNumber),j) = InterpedPValue(n)
1251
ELSE
1252
CALL WARN('InterpolateUnfoundPoint', &
1253
'PrevValues not found on Supp Nodes but defined on node so setting to zero')
1254
Var % PrevValues(Var % Perm(NodeNumber),j) = 0.0_dp
1255
END IF
1256
END DO
1257
END IF
1258
1259
Var => Var % Next
1260
END DO
1261
END IF
1262
1263
END SUBROUTINE InterpolateUnfoundPoint
1264
1265
SUBROUTINE InterpolateUnfoundSharedPoint( NodeNumber, Mesh, HeightName, HeightDimensions,&
1266
ElemMask, NodeMask, Variables, UnfoundDOFS, Found )
1267
1268
! similar process to InterpolateUnfoundPont but includes parallel communication
1269
!! new method
1270
!! share NoSuppNodes
1271
!! share SuppNodeMask
1272
!! share SuppNodeValues
1273
!! Share SuppNodeWeights
1274
!! calculate interpedvalue and assign
1275
1276
TYPE(Mesh_t), TARGET, INTENT(INOUT) :: Mesh
1277
TYPE(Variable_t), POINTER, OPTIONAL :: Variables
1278
CHARACTER(LEN=*) :: HeightName
1279
INTEGER :: NodeNumber
1280
INTEGER, POINTER :: HeightDimensions(:)
1281
LOGICAL, POINTER, OPTIONAL :: ElemMask(:),NodeMask(:)
1282
INTEGER, ALLOCATABLE, OPTIONAL :: UnfoundDOFS(:)
1283
LOGICAL, OPTIONAL :: Found
1284
!------------------------------------------------------------------------------
1285
TYPE(Variable_t), POINTER :: HeightVar, Var
1286
TYPE(Element_t),POINTER :: Element
1287
LOGICAL :: Parallel, Debug, HasNeighbours
1288
LOGICAL, ALLOCATABLE :: ValidNode(:), SuppNodeMask(:,:), PartSuppNodeMask(:,:,:), &
1289
UseProc(:),SuppNodePMask(:,:), PartSuppNodePMask(:,:,:)
1290
REAL(KIND=dp) :: Point(3), SuppPoint(3), weight, Exponent, distance
1291
REAL(KIND=dp), ALLOCATABLE :: interpedValue(:), PartInterpedValues(:,:), &
1292
SuppNodeWeights(:), PartSuppNodeWeights(:,:), SumWeights(:),&
1293
FinalInterpedValues(:), InterpedPValue(:), PartInterpedPValues(:,:), &
1294
FinalInterpedPValues(:), PSumWeights(:)
1295
INTEGER :: i,j,k,n,idx,NoNeighbours,NoSuppNodes,NoUsedNeighbours,&
1296
proc,status(MPI_STATUS_SIZE), counter, ierr, MaskCount, PMaskCount
1297
INTEGER, ALLOCATABLE :: NeighbourParts(:), WorkInt(:), SuppNodes(:), PartNoSuppNodes(:), WorkInt2(:), &
1298
GDOFs(:), PartGDOFs(:), GDOFLoc(:)
1299
INTEGER, POINTER :: Neighbours(:)
1300
Debug = .TRUE.
1301
Parallel = ParEnv % PEs > 1
1302
1303
HeightVar => VariableGet( Mesh % Variables, HeightName, &
1304
ThisOnly = .TRUE., UnfoundFatal = .TRUE. )
1305
1306
!The sought point
1307
Point(1) = Mesh % Nodes % x(NodeNumber)
1308
Point(2) = Mesh % Nodes % y(NodeNumber)
1309
Point(3) = Mesh % Nodes % z(NodeNumber)
1310
Point(HeightDimensions) = 0.0_dp
1311
1312
!IDW exponent
1313
Exponent = 1.0
1314
1315
!Is another partition also contributing to this
1316
NoNeighbours = SIZE(Mesh % ParallelInfo % &
1317
NeighbourList(NodeNumber) % Neighbours) - 1
1318
HasNeighbours = NoNeighbours > 0
1319
1320
!Count this partition's relevant nodes
1321
ALLOCATE(ValidNode(Mesh % NumberOfNodes))
1322
ValidNode = .FALSE.
1323
!Start by marking .TRUE. based on ElemMask if present
1324
IF(PRESENT(ElemMask)) THEN
1325
DO i=1,SIZE(ElemMask)
1326
IF(ElemMask(i)) CYCLE
1327
n = Mesh % Elements(i) % TYPE % NumberOfNodes
1328
ValidNode(Mesh % Elements(i) % NodeIndexes(1:n)) = .TRUE.
1329
END DO
1330
ELSE
1331
ValidNode = .TRUE.
1332
END IF
1333
!Knock down by node mask if present
1334
IF(PRESENT(NodeMask)) THEN
1335
DO i=1,SIZE(NodeMask)
1336
IF(NodeMask(i)) ValidNode(i) = .FALSE.
1337
END DO
1338
END IF
1339
1340
!Knock down nodes with 0 perm
1341
DO i=1,Mesh % NumberOfNodes
1342
IF(HeightVar % Perm(i) > 0) CYCLE
1343
ValidNode(i) = .FALSE.
1344
END DO
1345
IF(Debug) PRINT *,ParEnv % MyPE,'Debug, seeking nn: ',NodeNumber,' found ',&
1346
COUNT(ValidNode),' valid nodes.'
1347
1348
ALLOCATE(WorkInt(100), WorkInt2(100))
1349
WorkInt = 0; WorkInt2 = 0
1350
1351
!Cycle elements containing our node, adding other nodes to list
1352
NoSuppNodes = 0
1353
DO i=Mesh % NumberOfBulkElements+1,Mesh % NumberOfBulkElements &
1354
+ Mesh % NumberOfBoundaryElements
1355
Element => Mesh % Elements(i)
1356
n = Element % TYPE % NumberOfNodes
1357
1358
!Doesn't contain our point
1359
IF(.NOT. ANY(Element % NodeIndexes(1:n)==NodeNumber)) CYCLE
1360
!Cycle element nodes
1361
DO j=1,n
1362
idx = Element % NodeIndexes(j)
1363
IF(idx == NodeNumber) CYCLE
1364
IF(ANY(WorkInt == idx)) CYCLE !already got
1365
IF(.NOT. ValidNode(idx)) CYCLE !invalid
1366
! do not include nodes that has yet to be interped
1367
! nodes are interped in GDOF order so if this unfoundnode has a lower
1368
! GDOF then the SuppNode has yet to be interped
1369
IF(PRESENT(UnfoundDOFS)) THEN
1370
IF(ANY(UnfoundDOFS == Mesh % ParallelInfo % GlobalDOFs(idx)) .AND. &
1371
Mesh % ParallelInfo % GlobalDOFs(NodeNumber) < Mesh % ParallelInfo % GlobalDOFs(idx)) CYCLE
1372
END IF
1373
1374
NoSuppNodes = NoSuppNodes + 1
1375
WorkInt(NoSuppNodes) = idx
1376
WorkInt2(NoSuppNodes) = Mesh % ParallelInfo % GlobalDOFs(idx)
1377
END DO
1378
END DO
1379
1380
ALLOCATE(SuppNodes(NoSuppNodes), GDOFs(NoSuppNodes))
1381
SuppNodes = WorkInt(:NoSuppNodes)
1382
GDOFs = WorkInt2(:NoSuppNodes)
1383
1384
!Create list of neighbour partitions
1385
ALLOCATE(NeighbourParts(NoNeighbours))
1386
counter = 0
1387
DO i=1,NoNeighbours+1
1388
IF(Mesh % ParallelInfo % NeighbourList(NodeNumber) % &
1389
Neighbours(i) == ParEnv % MyPE) CYCLE
1390
counter = counter + 1
1391
NeighbourParts(counter) = Mesh % ParallelInfo &
1392
% NeighbourList(NodeNumber) % Neighbours(i)
1393
END DO
1394
1395
! share number of supp nodes
1396
ALLOCATE(PartNoSuppNodes(NoNeighbours+1))
1397
PartNoSuppNodes(1) = NoSuppNodes
1398
DO i=1, NoNeighbours
1399
proc = NeighbourParts(i)
1400
CALL MPI_BSEND( NoSuppNodes, 1, MPI_INTEGER, proc, &
1401
3998, ELMER_COMM_WORLD,ierr )
1402
CALL MPI_RECV( PartNoSuppNodes(i+1) , 1, MPI_INTEGER, proc, &
1403
3998, ELMER_COMM_WORLD, status, ierr )
1404
END DO
1405
1406
! is the proc used?
1407
NoUsedNeighbours=NoNeighbours
1408
ALLOCATE(UseProc(NoNeighbours+1))
1409
UseProc = .TRUE. ! default is to use proc
1410
IF(ANY(PartNoSuppNodes == 0)) THEN
1411
DO i=1, NoNeighbours+1
1412
IF(PartNoSuppNodes(i) == 0) UseProc(i) = .FALSE.
1413
END DO
1414
!reassign noneighbours to neighbours with suppnodes
1415
NoUsedNeighbours = COUNT(UseProc(2:NoNeighbours+1))
1416
END IF
1417
1418
! change of strategy here. previously supp nodes dropped if a larger
1419
! neighbour present. However this doesn't work for complex geometries often
1420
! resulting from repartitioning. Instead gather global indexes and remove supp
1421
! node if global index present on higher partition
1422
ALLOCATE(PartGDOFs(SUM(PartNoSuppNodes)))
1423
counter = 0
1424
IF(NoSuppNodes /= 0) THEN
1425
PartGDOFs(1:NoSuppNodes) = GDOFs
1426
counter=NoSuppNodes
1427
END IF
1428
DO i=1, NoNeighbours
1429
proc = NeighbourParts(i)
1430
IF(UseProc(1)) THEN ! if this proc has supp nodes send
1431
CALL MPI_BSEND( GDOFs, NoSuppNodes, MPI_INTEGER, proc, &
1432
3999, ELMER_COMM_WORLD,ierr )
1433
END IF
1434
IF(UseProc(i+1)) THEN !neighouring proc has supp nodes
1435
CALL MPI_RECV( PartGDOFs(counter+1:counter+PartNoSuppNodes(i+1)), &
1436
PartNoSuppNodes(i+1), MPI_INTEGER, proc, &
1437
3999, ELMER_COMM_WORLD, status, ierr )
1438
counter=counter+PartNoSuppNodes(i+1)
1439
END IF
1440
END DO
1441
1442
!create list of GDOFS parts
1443
ALLOCATE(GDOFLoc(SUM(PartNoSuppNodes)))
1444
counter=0
1445
DO i=1, NoNeighbours+1
1446
IF(PartNoSuppNodes(i) == 0) CYCLE
1447
IF(i==1) THEN
1448
GDOFLoc(counter+1:counter+PartNoSuppNodes(i)) = ParEnv % MyPE
1449
ELSE
1450
GDOFLoc(counter+1:counter+PartNoSuppNodes(i)) = NeighbourParts(i-1)
1451
END IF
1452
counter = counter + PartNoSuppNodes(i)
1453
END DO
1454
1455
! is global index present on higher part?
1456
DO i=1, NoSuppNodes
1457
DO j=NoSuppNodes+1, SUM(PartNoSuppNodes)
1458
IF(GDOFs(i) == PartGDOFs(j)) THEN
1459
IF(GDOFLoc(j) > ParEnv % MyPE) THEN
1460
WorkInt(i) = 0
1461
END IF
1462
END IF
1463
END DO
1464
END DO
1465
1466
NoSuppNodes = COUNT(WorkInt > 0)
1467
IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, seeking ',NodeNumber,&
1468
' higher partition has node, so deleting...'
1469
1470
DEALLOCATE(SuppNodes)
1471
ALLOCATE(SuppNodes(NoSuppNodes))
1472
SuppNodes = PACK(WorkInt, WorkInt > 0)
1473
DEALLOCATE(WorkInt)
1474
1475
IF(NoSuppNodes == 0) THEN
1476
WRITE(Message, '(i0,A,i0)') ParEnv % MyPE, ' NoSuppNodes = ',NoSuppNodes
1477
CALL WARN('InterpVarToVar', Message)
1478
END IF
1479
1480
!share NoSuppNodes
1481
PartNoSuppNodes(1) = NoSuppNodes
1482
DO i=1, NoNeighbours
1483
proc = NeighbourParts(i)
1484
CALL MPI_BSEND( NoSuppNodes, 1, MPI_INTEGER, proc, &
1485
4000, ELMER_COMM_WORLD,ierr )
1486
CALL MPI_RECV( PartNoSuppNodes(i+1) , 1, MPI_INTEGER, proc, &
1487
4000, ELMER_COMM_WORLD, status, ierr )
1488
END DO
1489
1490
IF(PRESENT(Found)) THEN
1491
Found = .TRUE.
1492
IF(SUM(PartNoSuppNodes) == 0) THEN
1493
Found = .FALSE.
1494
RETURN
1495
END IF
1496
END IF
1497
1498
! an mpi_error can occur if one proc has zero supp nodes
1499
! if proc has zero supp nodes it needs to receive mpi info but cannot send any
1500
! therefore neighbours need to allocate less space to avoid nans
1501
NoUsedNeighbours=NoNeighbours
1502
UseProc = .TRUE. ! default is to use proc
1503
IF(ANY(PartNoSuppNodes == 0)) THEN
1504
DO i=1, NoNeighbours+1
1505
IF(PartNoSuppNodes(i) == 0) UseProc(i) = .FALSE.
1506
END DO
1507
!reassign noneighbours to neighbours with suppnodes
1508
NoUsedNeighbours = COUNT(UseProc(2:NoNeighbours+1))
1509
END IF
1510
1511
! calculate maskcount and pmaskcount
1512
IF(PRESENT(Variables)) THEN
1513
MaskCount = 0 ! zero since no variables already
1514
PMaskCount = 0
1515
Var => Variables
1516
DO WHILE(ASSOCIATED(Var))
1517
MaskCount = MaskCount + 1
1518
IF(ASSOCIATED(Var % PrevValues)) &
1519
PMaskCount = PMaskCount + SIZE(Var % PrevValues,2)
1520
1521
Var => Var % Next
1522
END DO
1523
END IF
1524
1525
!create suppnode mask and get node values
1526
! get node weights too
1527
ALLOCATE(SuppNodeMask(NoSuppNodes, MaskCount), &
1528
SuppNodePMask(NoSuppNodes, PMaskCount), &
1529
InterpedValue(MaskCount), InterpedPValue(PMaskCount), &
1530
SuppNodeWeights(NoSuppNodes))
1531
SuppNodeMask = .FALSE.; SuppNodePMask = .FALSE.
1532
interpedValue = 0.0_dp; InterpedPValue = 0.0_dp
1533
DO i=1, NoSuppNodes
1534
! SuppNodes for interp
1535
SuppPoint(1) = Mesh % Nodes % x(SuppNodes(i))
1536
SuppPoint(2) = Mesh % Nodes % y(SuppNodes(i))
1537
SuppPoint(3) = Mesh % Nodes % z(SuppNodes(i))
1538
SuppPoint(HeightDimensions) = 0.0_dp
1539
1540
distance = 0.0_dp
1541
DO j=1,3
1542
distance = distance + (Point(j) - SuppPoint(j))**2.0_dp
1543
END DO
1544
distance = distance**0.5_dp
1545
1546
weight = distance**(-exponent)
1547
SuppNodeWeights(i) = weight
1548
1549
interpedValue(1) = interpedValue(1) + &
1550
weight * HeightVar % Values(HeightVar % Perm(SuppNodes(i)))
1551
SuppNodeMask(i, 1) = .TRUE.
1552
1553
IF(ASSOCIATED(HeightVar % PrevValues)) THEN
1554
DO j=1, SIZE(HeightVar % PrevValues,2)
1555
interpedPValue(j) = interpedPValue(j) + &
1556
weight * HeightVar % PrevValues(HeightVar % Perm(SuppNodes(i)),j)
1557
SuppNodePMask(i, j) = .TRUE.
1558
END DO
1559
END IF
1560
1561
IF(PRESENT(Variables)) THEN
1562
MaskCount = 1; PMaskCount = SIZE(HeightVar % PrevValues,2)
1563
Var => Variables
1564
DO WHILE(ASSOCIATED(Var))
1565
MaskCount = MaskCount + 1
1566
IF(ASSOCIATED(Var % PrevValues)) &
1567
PMaskCount = PMaskCount + SIZE(Var % PrevValues,2)
1568
1569
IF((SIZE(Var % Values) == Var % DOFs) .OR. & !-global
1570
(Var % DOFs > 1) .OR. & !-multi-dof
1571
Var % Secondary) THEN !-secondary
1572
Var => Var % Next
1573
CYCLE
1574
ELSEIF(Var % Name == HeightName) THEN !-already got
1575
MaskCount = MaskCount - 1
1576
PMaskCount = PMaskCount - SIZE(Var % PrevValues,2)
1577
Var => Var % Next
1578
CYCLE
1579
ELSE IF(LEN(Var % Name) >= 10) THEN
1580
IF(Var % Name(1:10)=='coordinate') THEN !-coord var
1581
Var => Var % Next
1582
CYCLE
1583
END IF
1584
END IF
1585
IF(Var % Perm(SuppNodes(i)) <= 0 .OR. &
1586
(Var % Perm(NodeNumber) <= 0)) THEN !-not fully defined here
1587
Var => Var % Next
1588
CYCLE
1589
END IF
1590
1591
SuppNodeMask(i, MaskCount) = .TRUE.
1592
InterpedValue(MaskCount) = InterpedValue(MaskCount) + &
1593
weight * Var % Values(Var % Perm(SuppNodes(i)))
1594
1595
!PrevValues
1596
IF(ASSOCIATED(Var % PrevValues)) THEN
1597
SuppNodePMask(i, PMaskCount) = .TRUE.
1598
DO j=1, SIZE(Var % PrevValues, 2)
1599
n = PMaskCount + j - SIZE(Var % PrevValues, 2)
1600
InterpedPValue(n) = InterpedPValue(n) +&
1601
weight * Var % PrevValues(Var % Perm(SuppNodes(i)), j)
1602
END DO
1603
END IF
1604
1605
Var => Var % Next
1606
END DO
1607
END IF
1608
END DO
1609
1610
! all parallel communication changed to use NoUsedNeighbours so neighbouring procs
1611
! of those with zero suppnodes (no info) do not over allocate (eg allocate nans)
1612
!share SuppNodeMask
1613
ALLOCATE(PartSuppNodeMask(NoUsedNeighbours+1, 25, MaskCount))
1614
PartSuppNodeMask = .FALSE.
1615
PartSuppNodeMask(1,:NoSuppNodes,:) = SuppNodeMask
1616
counter=0
1617
DO i=1, NoNeighbours
1618
proc = NeighbourParts(i)
1619
IF(UseProc(1)) THEN ! if this proc has supp nodes send
1620
CALL MPI_BSEND( SuppNodeMask, NoSuppNodes*MaskCount, MPI_LOGICAL, proc, &
1621
4001, ELMER_COMM_WORLD,ierr )
1622
END IF
1623
IF(UseProc(i+1)) THEN !neighbouring proc has supp nodes
1624
counter=counter+1
1625
CALL MPI_RECV( PartSuppNodeMask(counter+1,:PartNoSuppNodes(i+1),: ) , &
1626
PartNoSuppNodes(i+1)*MaskCount, MPI_LOGICAL, proc, &
1627
4001, ELMER_COMM_WORLD, status, ierr )
1628
END If
1629
END DO
1630
1631
!share SuppNodePMask for prevvalues
1632
ALLOCATE(PartSuppNodePMask(NoUsedNeighbours+1, 25, PMaskCount))
1633
PartSuppNodePMask = .FALSE.
1634
PartSuppNodePMask(1,:NoSuppNodes,:) = SuppNodePMask
1635
counter=0
1636
DO i=1, NoNeighbours
1637
proc = NeighbourParts(i)
1638
IF(UseProc(1)) THEN ! if this proc has supp nodes send
1639
CALL MPI_BSEND( SuppNodePMask, NoSuppNodes*PMaskCount, MPI_LOGICAL, proc, &
1640
4011, ELMER_COMM_WORLD,ierr )
1641
END IF
1642
IF(UseProc(i+1)) THEN !neighouring proc has supp nodes
1643
counter=counter+1
1644
CALL MPI_RECV( PartSuppNodePMask(counter+1,:PartNoSuppNodes(i+1),: ) , &
1645
PartNoSuppNodes(i+1)*PMaskCount, MPI_LOGICAL, proc, &
1646
4011, ELMER_COMM_WORLD, status, ierr )
1647
END If
1648
END DO
1649
1650
!share interped value
1651
ALLOCATE(PartInterpedValues(NoUsedNeighbours+1, MaskCount))
1652
PartInterpedValues(1,1:MaskCount) = InterpedValue
1653
counter=0
1654
DO i=1, NoNeighbours
1655
proc = NeighbourParts(i)
1656
IF(UseProc(1)) THEN ! if this proc has supp nodes send
1657
CALL MPI_BSEND( InterpedValue, MaskCount, MPI_DOUBLE_PRECISION, proc, &
1658
4002, ELMER_COMM_WORLD,ierr )
1659
END IF
1660
IF(UseProc(i+1)) THEN !neighbouring prco has supp nodes
1661
counter=counter+1
1662
CALL MPI_RECV( PartInterpedValues(counter+1,:), MaskCount, MPI_DOUBLE_PRECISION, proc, &
1663
4002, ELMER_COMM_WORLD, status, ierr )
1664
END IF
1665
END DO
1666
1667
!share interped prevvalue
1668
ALLOCATE(PartInterpedPValues(NoUsedNeighbours+1, PMaskCount))
1669
PartInterpedPValues(1,1:PMaskCount) = InterpedPValue
1670
counter=0
1671
DO i=1, NoNeighbours
1672
proc = NeighbourParts(i)
1673
IF(UseProc(1)) THEN ! if this proc has supp nodes send
1674
CALL MPI_BSEND( InterpedPValue, PMaskCount, MPI_DOUBLE_PRECISION, proc, &
1675
4012, ELMER_COMM_WORLD,ierr )
1676
END IF
1677
IF(UseProc(i+1)) THEN !neighouring prco has supp nodes
1678
counter=counter+1
1679
CALL MPI_RECV( PartInterpedPValues(counter+1,:), PMaskCount, MPI_DOUBLE_PRECISION, proc, &
1680
4012, ELMER_COMM_WORLD, status, ierr )
1681
END IF
1682
END DO
1683
1684
!share suppnode weights
1685
ALLOCATE(PartSuppNodeWeights(NoUsedNeighbours+1, 25))
1686
PartSuppNodeWeights=0.0_dp
1687
PartSuppNodeWeights(1,1:NoSuppNodes) = SuppNodeWeights
1688
counter=0
1689
DO i=1, NoNeighbours
1690
proc = NeighbourParts(i)
1691
IF(UseProc(1)) THEN ! if this proc has supp nodes send
1692
CALL MPI_BSEND( SuppNodeWeights, NoSuppNodes, MPI_DOUBLE_PRECISION, proc, &
1693
4003, ELMER_COMM_WORLD,ierr )
1694
END IF
1695
IF(UseProc(i+1)) THEN !neighbouring prco has supp nodes
1696
counter=counter+1
1697
CALL MPI_RECV( PartSuppNodeWeights(counter+1,1:PartNoSuppNodes(i+1)), &
1698
PartNoSuppNodes(i+1), MPI_DOUBLE_PRECISION, proc, &
1699
4003, ELMER_COMM_WORLD, status, ierr )
1700
END IF
1701
END DO
1702
1703
!calculate interped values
1704
ALLOCATE(FinalInterpedValues(MaskCount), FinalInterpedPValues(PMaskCount))
1705
FinalInterpedValues = 0.0_dp; FinalInterpedPValues = 0.0_dp
1706
! add up interpedvalues
1707
DO i=1, NoUsedNeighbours+1
1708
FinalInterpedValues = FinalInterpedValues + PartInterpedValues(i, :)
1709
FinalInterpedPValues = FinalInterpedPValues + PartInterpedPValues(i, :)
1710
END DO
1711
1712
! convert PartNoSuppNodes to only used procs
1713
ALLOCATE(WorkInt(NoNeighbours+1))
1714
WorkInt=PartNoSuppNodes
1715
DEALLOCATE(PartNoSuppNodes)
1716
ALLOCATE(PartNoSuppNodes(NoUsedNeighbours+1))
1717
counter=0
1718
DO i=1, NoNeighbours+1
1719
IF(i/=1 .AND. .NOT. UseProc(i)) CYCLE
1720
counter=counter+1
1721
PartNoSuppNodes(counter) = WorkInt(i)
1722
END DO
1723
DEALLOCATE(WorkInt)
1724
1725
! calculate weight for each var
1726
ALLOCATE(SumWeights(MaskCount), PSumWeights(PMaskCount))
1727
SumWeights = 0.0_dp; PSumWeights = 0.0_dp
1728
DO i=1, NoUsedNeighbours+1
1729
! loop through procs suppnodes
1730
DO j=1, PartNoSuppNodes(i)
1731
DO k=1, MaskCount
1732
!var exists on that node
1733
IF(PartSuppNodeMask(i,j,k)) THEN
1734
SumWeights(k) = SumWeights(k) + PartSuppNodeWeights(i,j)
1735
END IF
1736
END DO
1737
DO k=1, PMaskCount
1738
!var exists on that node
1739
IF(PartSuppNodePMask(i,j,k)) THEN
1740
PSumWeights(k) = PSumWeights(k) + PartSuppNodeWeights(i,j)
1741
END IF
1742
END DO
1743
END DO
1744
END DO
1745
1746
!interpedvalue/sumweights
1747
FinalInterpedValues = FinalInterpedValues/sumweights
1748
FinalInterpedPValues = FinalInterpedPValues/PSumWeights
1749
1750
!Finally, put the interped values in their place
1751
HeightVar % Values(HeightVar % Perm(NodeNumber)) = interpedValue(1)
1752
1753
IF(ASSOCIATED(HeightVar % PrevValues)) THEN
1754
DO j=1, SIZE(HeightVar % PrevValues,2)
1755
HeightVar % PrevValues(HeightVar % Perm(NodeNumber), j) = interpedPValue(j)
1756
END DO
1757
END IF
1758
1759
!return values
1760
IF(PRESENT(Variables)) THEN
1761
MaskCount = 1; PMaskCount = SIZE(HeightVar % PrevValues,2)
1762
Var => Variables
1763
DO WHILE(ASSOCIATED(Var))
1764
MaskCount = MaskCount + 1
1765
IF(ASSOCIATED(Var % PrevValues)) &
1766
PMaskCount = PMaskCount + SIZE(Var % PrevValues,2)
1767
1768
!Is the variable valid?
1769
IF((SIZE(Var % Values) == Var % DOFs) .OR. & !-global
1770
(Var % DOFs > 1) .OR. & !-multi-dof
1771
Var % Secondary) THEN !-secondary
1772
Var => Var % Next
1773
CYCLE
1774
ELSE IF(Var % Name == HeightName) THEN !-already got
1775
MaskCount = MaskCount - 1
1776
PMaskCount = PMaskCount - SIZE(Var % PrevValues,2)
1777
Var => Var % Next
1778
CYCLE
1779
ELSE IF(LEN(Var % Name) >= 10) THEN
1780
IF(Var % Name(1:10)=='coordinate') THEN !-coord var
1781
Var => Var % Next
1782
CYCLE
1783
END IF
1784
END IF
1785
IF(Var % Perm(NodeNumber) <= 0) THEN !-not fully defined here
1786
Var => Var % Next
1787
CYCLE
1788
END IF
1789
1790
!if any suppnode from any proc has var
1791
IF(ANY(PartSuppNodeMask(:,:,MaskCount))) THEN
1792
Var % Values(Var % Perm(NodeNumber)) = FinalInterpedValues(MaskCount)
1793
END IF
1794
1795
IF(ASSOCIATED(Var % PrevValues)) THEN
1796
DO j=1, SIZE(Var % PrevValues,2)
1797
n = PMaskCount + j - SIZE(Var % PrevValues, 2)
1798
IF(ANY(PartSuppNodePMask(:,:,n))) THEN ! defined at suppnodes
1799
Var % PrevValues(Var % Perm(NodeNumber),j) = FinalInterpedPValues(n)
1800
ELSE
1801
CALL WARN('InterpolateUnfoundSharedPoint', &
1802
'PrevValues not found on Supp Nodes but defined on node so setting to zero')
1803
Var % PrevValues(Var % Perm(NodeNumber),j) = 0.0_dp
1804
END IF
1805
END DO
1806
END IF
1807
1808
Var => Var % Next
1809
END DO
1810
END IF
1811
1812
END SUBROUTINE InterpolateUnfoundSharedPoint
1813
1814
END MODULE InterpVarToVar
1815
1816