Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/CalvingFrontAdvance3D.F90
3204 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: Joe Todd
26
! * Email:
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! *
30
! *****************************************************************************
31
32
!A routine for getting frontal advance in 3D, given velocity and melt
33
34
SUBROUTINE FrontAdvance3D ( Model, Solver, dt, TransientSimulation )
35
36
USE CalvingGeometry
37
USE DefUtils
38
IMPLICIT NONE
39
40
!-----------------------------------------------
41
TYPE(Model_t) :: Model
42
TYPE(Solver_t), TARGET :: Solver
43
REAL(KIND=dp) :: dt
44
LOGICAL :: TransientSimulation
45
!-----------------------------------------------
46
TYPE(Mesh_t), POINTER :: Mesh
47
TYPE(Nodes_t), TARGET :: FrontNodes, ColumnNodes
48
TYPE(ValueList_t), POINTER :: Params
49
TYPE(Variable_t), POINTER :: Var, VeloVar, MeltVar, NormalVar, TangledVar
50
INTEGER :: i, j, k, m, n, DOFs, TotalNodes, NodesPerLevel, ExtrudedLevels,&
51
FaceNodeCount, DummyInt, col, hits, ierr, FrontLineCount, county,&
52
ShiftIdx, ShiftToIdx, NoTangledGroups, PivotIdx, CornerIdx, &
53
SecondIdx, FirstTangleIdx, LastTangleIdx
54
INTEGER, POINTER :: Perm(:), FrontPerm(:)=>NULL(), TopPerm(:)=>NULL(), &
55
FrontNodeNums(:)=>NULL()
56
INTEGER, ALLOCATABLE :: FNColumns(:), FrontColumnList(:), FrontLocalNodeNumbers(:), &
57
NodeNumbers(:), TangledGroup(:), TangledPivotIdx(:), UpdatedDirection(:)
58
REAL(KIND=dp) :: FrontOrientation(3),RotationMatrix(3,3),&
59
NodeVelo(3), NodeMelt(3), NodeNormal(3), ColumnNormal(3), CornerDirection(2),&
60
MeltRate, Displace(3), NodeHolder(3), DangerGrad, ShiftTo, direction, &
61
ShiftDist, y_coord(2), epsShift, ShiftToY, LongRangeLimit, MaxDisplacement, LimitZ, &
62
p1(2),p2(2),q1(2),q2(2),intersect(2), LeftY, RightY, EpsTangle,thisEps,Shift, thisY
63
REAL(KIND=dp), POINTER :: Advance(:)
64
REAL(KIND=dp), ALLOCATABLE :: Rot_y_coords(:,:), Rot_z_coords(:,:), ColumnNormals(:,:), &
65
TangledShiftTo(:)
66
#ifdef ELMER_BROKEN_MPI_IN_PLACE
67
REAL(KIND=dp) :: buffer
68
#endif
69
LOGICAL :: Found, Debug, Parallel, Boss, ShiftLeft, LeftToRight, MovedOne, ShiftSecond, &
70
Protrusion, SqueezeLeft, SqueezeRight, FirstTime=.TRUE., intersect_flag, FrontMelting, &
71
IgnoreVelo
72
LOGICAL, ALLOCATABLE :: DangerZone(:), WorkLogical(:), UpdatedColumn(:),&
73
Tangled(:), DontMove(:)
74
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName, VeloVarName, MeltVarName, &
75
NormalVarName, FrontMaskName, TopMaskName, TangledVarName
76
77
SAVE :: FirstTime
78
79
!-----------------------------------------------
80
! Initialisation
81
!-----------------------------------------------
82
83
Debug = .FALSE.
84
Parallel = (ParEnv % PEs > 1)
85
Boss = ParEnv % MyPE == 0
86
87
SolverName = "FrontAdvance3D"
88
Params => Solver % Values
89
Mesh => Solver % Mesh
90
91
!The main solver var contains the magnitude of front advance
92
Var => Solver % Variable
93
Advance => Var % Values
94
Perm => Var % Perm
95
DOFs = Var % DOFs
96
IF(Var % DOFs /= 3) CALL Fatal(SolverName, "Variable should have 3 DOFs...")
97
98
IgnoreVelo = ListGetLogical(Params, "Ignore Velocity", Found)
99
IF(.NOT. Found) THEN
100
IgnoreVelo = .FALSE.
101
ELSE
102
CALL Info(SolverName, "Ignoring velocity (melt undercutting only)")
103
END IF
104
105
IF(.NOT. IgnoreVelo) THEN
106
!Get the flow solution
107
VeloVarName = ListGetString(Params, "Flow Solution Variable Name", Found)
108
IF(.NOT. Found) THEN
109
CALL Info(SolverName, "Flow Solution Variable Name not found, assuming 'Flow Solution'")
110
VeloVarName = "Flow Solution"
111
END IF
112
VeloVar => VariableGet(Mesh % Variables, VeloVarName, .TRUE., UnfoundFatal=.TRUE.)
113
END IF
114
115
!Get melt rate
116
MeltVarName = ListGetString(Params, "Melt Variable Name", Found)
117
IF(.NOT. Found) THEN
118
CALL Info(SolverName, "Melt Variable Name not found, assuming no frontal melting")
119
FrontMelting = .FALSE.
120
ELSE
121
FrontMelting = .TRUE.
122
MeltVar => VariableGet(Mesh % Variables, MeltVarName, .TRUE., UnfoundFatal=.TRUE.)
123
END IF
124
125
TangledVarName = "Tangled"
126
TangledVar => VariableGet(Mesh % Variables, TangledVarName, .TRUE., UnfoundFatal=.TRUE.)
127
TangledVar % Values = 0.0_dp
128
129
!Get front normal vector
130
NormalVarName = ListGetString(Params, "Normal Vector Variable Name", UnfoundFatal=.TRUE.)
131
NormalVar => VariableGet(Mesh % Variables, NormalVarName, .TRUE., UnfoundFatal=.TRUE.)
132
133
!Get the orientation of the calving front, compute rotation matrix
134
!TODO: generalize and link
135
FrontOrientation = GetFrontOrientation(Model)
136
RotationMatrix = ComputeRotationMatrix(FrontOrientation)
137
138
DangerGrad = ListGetConstReal(Params, "Front Gradient Threshold", Found)
139
IF(.NOT.Found) THEN
140
CALL Info(SolverName, "'Front Gradient Threshold' not found, setting to 5.0")
141
DangerGrad = 5.0
142
END IF
143
144
!When correcting for unprojectability, to prevent interp problems,
145
!ensure that it is SLIGHTLY beyond beyond parallel, by adding this
146
!value (metres) to the displacement
147
epsShift = ListGetConstReal(Params, "Front Projectability Epsilon", Found)
148
IF(.NOT.Found) THEN
149
CALL Info(SolverName, "'Front Projectability Epsilon' not found, setting to 1.0")
150
epsShift = 1.0
151
END IF
152
153
epsTangle = ListGetConstReal(Params, "Front Tangle Epsilon", Found)
154
IF(.NOT.Found) THEN
155
CALL Info(SolverName, "'Front Tangle Epsilon' not found, setting to 1.0")
156
epsTangle = 1.0
157
END IF
158
159
LongRangeLimit = ListGetConstReal(Params, "Column Max Longitudinal Range", Found)
160
IF(.NOT.Found) THEN
161
CALL Info(SolverName, "'Column Max Longitudinal Range' not found, setting to 300.0")
162
LongRangeLimit = 300.0_dp
163
END IF
164
165
MaxDisplacement = ListGetConstReal(Params, "Maximum Node Displacement", Found)
166
IF(.NOT.Found) THEN
167
CALL Info(SolverName, "'Maximum Node Displacement' not found, setting to 1.0E4.")
168
MaxDisplacement = 1.0E4_dp
169
END IF
170
171
!-------------------------------------------
172
! Find FNColumns
173
CALL MPI_AllReduce(MAXVAL(Mesh % ParallelInfo % GlobalDOFs), TotalNodes, &
174
1, MPI_INTEGER, MPI_MAX, ELMER_COMM_WORLD,ierr)
175
176
ExtrudedLevels = ListGetInteger(CurrentModel % Simulation,'Extruded Mesh Levels',Found)
177
IF(.NOT. Found) ExtrudedLevels = &
178
ListGetInteger(CurrentModel % Simulation,'Remesh Extruded Mesh Levels',Found)
179
IF(.NOT. Found) CALL Fatal(SolverName,&
180
"Unable to find 'Extruded Mesh Levels' or 'Remesh Extruded Mesh Levels'")
181
NodesPerLevel = TotalNodes / ExtrudedLevels
182
183
ALLOCATE(FNColumns(Mesh % NumberOfNodes))
184
FNColumns = MOD(Mesh % ParallelInfo % GlobalDOFs, NodesPerLevel)
185
186
!Get the front line
187
FrontMaskName = "Calving Front Mask"
188
TopMaskName = "Top Surface Mask"
189
190
CALL MakePermUsingMask( Model, Solver, Mesh, TopMaskName, &
191
.FALSE., TopPerm, dummyint)
192
193
CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, &
194
.FALSE., FrontPerm, FaceNodeCount)
195
196
CALL GetDomainEdge(Model, Mesh, TopPerm, FrontNodes, &
197
FrontNodeNums, Parallel, FrontMaskName, Simplify=.FALSE.)
198
199
!Pass FrontNodeNums to all CPUs
200
IF(Boss) FrontLineCount = SIZE(FrontNodeNums)
201
CALL MPI_BCAST(FrontLineCount , 1, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
202
203
!Determine whether front columns are arranged
204
!left to right, and reorder if not
205
IF(Boss) THEN
206
207
NodeHolder(1) = FrontNodes % x(1)
208
NodeHolder(2) = FrontNodes % y(1)
209
NodeHolder(3) = FrontNodes % z(1)
210
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
211
y_coord(1) = NodeHolder(2)
212
213
NodeHolder(1) = FrontNodes % x(FrontLineCount)
214
NodeHolder(2) = FrontNodes % y(FrontLineCount)
215
NodeHolder(3) = FrontNodes % z(FrontLineCount)
216
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
217
y_coord(2) = NodeHolder(2)
218
219
LeftToRight = y_coord(2) > y_coord(1)
220
221
IF(.NOT. LeftToRight) THEN
222
IF(Debug) PRINT *,'Debug, switching to LeftToRight'
223
FrontNodeNums = FrontNodeNums(FrontLineCount:1:-1)
224
FrontNodes % x = FrontNodes % x(FrontLineCount:1:-1)
225
FrontNodes % y = FrontNodes % y(FrontLineCount:1:-1)
226
FrontNodes % z = FrontNodes % z(FrontLineCount:1:-1)
227
END IF
228
END IF
229
230
IF(.NOT. Boss) ALLOCATE(FrontNodeNums(FrontLineCount))
231
CALL MPI_BCAST(FrontNodeNums , FrontLineCount, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
232
233
!FrontNodeNums is the GlobalDOFs of the nodes on the front
234
!So this can be easily converted into a FNColumn like list
235
ALLOCATE(FrontColumnList(FrontLineCount), &
236
FrontLocalNodeNumbers(FrontLineCount), &
237
DangerZone(FrontLineCount), &
238
ColumnNormals(FrontLineCount,3))
239
240
FrontColumnList = MOD(FrontNodeNums, NodesPerLevel)
241
FrontLocalNodeNumbers = -1
242
DangerZone = .FALSE.
243
ColumnNormals = 0.0_dp
244
245
DO i=1,FrontLineCount
246
n = FrontNodeNums(i)
247
DO j=1,Mesh % NumberOfNodes
248
IF(Mesh % ParallelInfo % GlobalDOFs(j) == n) THEN
249
FrontLocalNodeNumbers(i) = j
250
END IF
251
END DO
252
END DO
253
254
!--------------------------------------
255
! Action: Compute lagrangian displacement for all nodes
256
! This is the main function of the Solver.
257
! Everything following this DO loop is taking care of
258
! unprojectability/high gradient etc
259
!--------------------------------------
260
261
DO i=1,Mesh % NumberOfNodes
262
IF(Perm(i) <= 0) CYCLE
263
264
IF(FrontMelting) THEN
265
IF(MeltVar % Perm(i) <= 0) &
266
CALL Fatal(SolverName, "Permutation error on front node!")
267
268
269
!Scalar melt value from Plume solver
270
MeltRate = MeltVar % Values(MeltVar % Perm(i))
271
272
NodeNormal(1) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 1)
273
NodeNormal(2) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 2)
274
NodeNormal(3) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 3)
275
276
NodeMelt = NodeNormal * MeltRate
277
ELSE
278
NodeMelt = 0.0_dp
279
END IF
280
281
IF(IgnoreVelo) THEN
282
NodeVelo = 0.0
283
ELSE
284
!Compute front normal component of velocity
285
NodeVelo(1) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 1)
286
NodeVelo(2) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 2)
287
NodeVelo(3) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 3)
288
END IF
289
290
Displace = 0.0
291
292
Displace(1) = NodeVelo(1) - NodeMelt(1)
293
Displace(2) = NodeVelo(2) - NodeMelt(2)
294
Displace(3) = NodeVelo(3) - NodeMelt(3)
295
296
Displace = Displace * dt
297
298
IF(MAXVAL(Displace) > MaxDisplacement) THEN
299
WRITE(Message,'(A,i0,A)') "Maximum allowable front displacement exceeded for node ",i,". Limiting..."
300
CALL Warn(SolverName, Message)
301
Displace = Displace * (MaxDisplacement/MAXVAL(Displace))
302
END IF
303
304
Advance((Perm(i)-1)*DOFs + 1) = Displace(1)
305
Advance((Perm(i)-1)*DOFs + 2) = Displace(2)
306
Advance((Perm(i)-1)*DOFs + 3) = Displace(3)
307
308
!First and last (i.e. lateral margin) columns don't move
309
IF((FNColumns(i) == FrontColumnList(1)) .OR. &
310
(FNColumns(i) == FrontColumnList(FrontLineCount))) THEN
311
Advance((Perm(i)-1)*DOFs + 1) = 0.0_dp
312
Advance((Perm(i)-1)*DOFs + 2) = 0.0_dp
313
Advance((Perm(i)-1)*DOFs + 3) = 0.0_dp
314
END IF
315
END DO
316
317
318
!----------------------------------------------------------
319
! Now we need to look for and limit regions on the
320
! where high gradient + 'straightness' makes
321
! remeshing into vertical columns troublesome.
322
!----------------------------------------------------------
323
!
324
! Five things:
325
! - Limit horizontal range (otherwise, Remesh will smear a column of nodes
326
! all over the place)
327
! - Limit undercut range (longitudinal range) to prevent mesh degeneracy
328
! - Prevent retreat at node near lateral margins
329
! - Check for 'tangled' regions, where fixing unprojectability one way
330
! causes unprojectability the other way.
331
! - Prevent Unprojectability - requires knowledge of neighbouring columns
332
!----------------------------------------------------------
333
334
!-------------------------------------------
335
! Cycle columns, looking at average normal for the column
336
!-------------------------------------------
337
! Normal vector is limited by projectability, so if average is high,
338
! all are high
339
!
340
! Note that we are cycling the parallel gathered line, so each part
341
! will only have a few columns (if any)
342
! So, mark troublesome columns where present, then communicate
343
!-------------------------------------------
344
345
DO i=1,FrontLineCount
346
col = FrontColumnList(i)
347
348
hits = COUNT(FNColumns == col)
349
IF(hits == 0) CYCLE
350
351
ColumnNormal = 0.0_dp
352
353
!Gather normal vector
354
DO j=1,Mesh % NumberOfNodes
355
IF(FNColumns(j) == col) THEN
356
ColumnNormal(1) = ColumnNormal(1) + &
357
NormalVar % Values(((NormalVar % Perm(j)-1)*NormalVar % DOFs) + 1)
358
ColumnNormal(2) = ColumnNormal(2) + &
359
NormalVar % Values(((NormalVar % Perm(j)-1)*NormalVar % DOFs) + 2)
360
ColumnNormal(3) = ColumnNormal(3) + &
361
NormalVar % Values(((NormalVar % Perm(j)-1)*NormalVar % DOFs) + 3)
362
END IF
363
END DO
364
365
!unit vector
366
ColumnNormal = ColumnNormal / hits
367
!Convert to front coordinate system
368
ColumnNormal = MATMUL( RotationMatrix, ColumnNormal )
369
!Save for later
370
ColumnNormals(i,1:3) = ColumnNormal(1:3)
371
372
!We're concerned with the lateral (rather than vertical) component
373
IF( ABS(ColumnNormal(2) / ColumnNormal(3)) > DangerGrad ) THEN
374
DangerZone(i) = .TRUE.
375
END IF
376
END DO
377
378
!Communicate between partitions
379
!This is an 'OR' condition insofar as only one partition
380
!will have actually computed the gradient
381
IF(Parallel) THEN
382
DO i=1,FrontLineCount
383
CALL SParIterAllReduceOR(DangerZone(i))
384
END DO
385
END IF
386
387
!Mark before and after dangerzone too
388
ALLOCATE(WorkLogical(FrontLineCount))
389
WorkLogical = .FALSE.
390
391
DO i=1,FrontLineCount
392
IF(DangerZone(i)) WorkLogical(i) = .TRUE.
393
394
IF(i > 1) THEN
395
IF(DangerZone(i-1)) WorkLogical(i) = .TRUE.
396
END IF
397
398
IF(i < FrontLineCount) THEN
399
IF(DangerZone(i+1)) WorkLogical(i) = .TRUE.
400
END IF
401
END DO
402
403
DangerZone = WorkLogical
404
DEALLOCATE(WorkLogical)
405
406
!Find and store leftmost and rightmost (rotated) coordinate of
407
!each column for checking projectability later
408
!Rot_y_coords(:,1) is leftmost, and (:,2) is right most y coord of
409
!each column's nodes, and Rot_z_coords(:,:) is the min(1)/max(2) z
410
ALLOCATE(Rot_y_coords(FrontLineCount,2),&
411
Rot_z_coords(FrontLineCount,2))
412
Rot_y_coords(:,1) = HUGE(0.0_dp)
413
Rot_y_coords(:,2) = -HUGE(0.0_dp)
414
Rot_z_coords(:,1) = HUGE(0.0_dp)
415
Rot_z_coords(:,2) = -HUGE(0.0_dp)
416
417
DO i=1,FrontLineCount
418
col = FrontColumnList(i)
419
IF(COUNT(FNColumns == col) == 0) CYCLE
420
421
DO j=1,Mesh % NumberOfNodes
422
IF(FNColumns(j) /= col) CYCLE
423
424
NodeHolder(1) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1)
425
NodeHolder(2) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2)
426
NodeHolder(3) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3)
427
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
428
429
Rot_y_coords(i,1) = MIN(Rot_y_coords(i,1), NodeHolder(2))
430
Rot_y_coords(i,2) = MAX(Rot_y_coords(i,2), NodeHolder(2))
431
432
Rot_z_coords(i,1) = MIN(Rot_z_coords(i,1), NodeHolder(3))
433
Rot_z_coords(i,2) = MAX(Rot_z_coords(i,2), NodeHolder(3))
434
END DO
435
END DO
436
437
!-----------------------------------
438
! Limit lateral range (to 0) in DangerZone
439
!-----------------------------------
440
! The physical interpretation of this is that, when melt undercutting occurs
441
! in a region of high gradient, the unmelted parts of that column also shift
442
! with the melt.
443
! This is a minor limitation, but better than Free Surface Equation!
444
445
DO i=1,FrontLineCount
446
IF(.NOT. DangerZone(i)) CYCLE
447
448
col = FrontColumnList(i)
449
hits = COUNT(FNColumns == col)
450
451
IF(hits == 0) CYCLE
452
453
ALLOCATE(NodeNumbers(hits), &
454
ColumnNodes % x(hits),&
455
ColumnNodes % y(hits),&
456
ColumnNodes % z(hits))
457
458
ColumnNodes % NumberOfNodes = hits
459
460
!Gather nodenumbers in column
461
county = 0
462
DO j=1,Mesh % NumberOfNodes
463
IF(FNColumns(j) /= col) CYCLE
464
county = county + 1
465
466
NodeNumbers(county) = j
467
ColumnNodes % x(county) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1)
468
ColumnNodes % y(county) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2)
469
ColumnNodes % z(county) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3)
470
END DO
471
472
!direction - which way is this part of the front pointing?
473
ShiftLeft = ColumnNormals(i,2) > 0
474
IF(ShiftLeft) THEN
475
ShiftTo = HUGE(ShiftTo)
476
ELSE
477
ShiftTo = -HUGE(ShiftTo)
478
END IF
479
480
!Rotate points and find furthest left (or right)
481
DO j=1,ColumnNodes % NumberOfNodes
482
NodeHolder(1) = ColumnNodes % x(j)
483
NodeHolder(2) = ColumnNodes % y(j)
484
NodeHolder(3) = ColumnNodes % z(j)
485
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
486
487
IF(ShiftLeft) THEN
488
IF(NodeHolder(2) < ShiftTo) ShiftTo = NodeHolder(2)
489
ELSE
490
IF(NodeHolder(2) > ShiftTo) ShiftTo = NodeHolder(2)
491
END IF
492
END DO
493
494
!Now, for each node in column, compute the displacement (in rotated y coordinate)
495
DO j=1,ColumnNodes % NumberOfNodes
496
NodeHolder(1) = ColumnNodes % x(j)
497
NodeHolder(2) = ColumnNodes % y(j)
498
NodeHolder(3) = ColumnNodes % z(j)
499
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
500
501
ShiftDist = ShiftTo - NodeHolder(2)
502
503
Displace = 0.0_dp
504
Displace(2) = ShiftDist
505
506
Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace)
507
508
!Adjust the variable values to shift nodes in line.
509
Advance((Perm(NodeNumbers(j))-1)*DOFs + 1) = &
510
Advance((Perm(NodeNumbers(j))-1)*DOFs + 1) + Displace(1)
511
Advance((Perm(NodeNumbers(j))-1)*DOFs + 2) = &
512
Advance((Perm(NodeNumbers(j))-1)*DOFs + 2) + Displace(2)
513
514
IF(Debug) PRINT *,'node: ',NodeNumbers(j),' shifting: ',ShiftDist,' to ',ShiftTo,' point: ', &
515
ColumnNodes % x(j),ColumnNodes % y(j),ColumnNodes % z(j)
516
END DO
517
518
DEALLOCATE(NodeNumbers, &
519
ColumnNodes % x, &
520
ColumnNodes % y, &
521
ColumnNodes % z)
522
END DO
523
524
!-----------------------------------
525
! Limit longitudinal range everywhere
526
!-----------------------------------
527
! Two options for how to do this:
528
! Drag nodes back with melt, or effectively
529
! limit melt (keeping nodes forward)
530
! Opt for the latter, or else we're
531
! forcing melting to have an effect
532
!-----------------------------------
533
DO i=1,FrontLineCount
534
535
col = FrontColumnList(i)
536
hits = COUNT(FNColumns == col)
537
538
IF(hits == 0) CYCLE
539
540
IF((Rot_z_coords(i,2) - Rot_z_coords(i,1)) > LongRangeLimit) THEN
541
542
LimitZ = Rot_z_coords(i,2) - LongRangeLimit
543
Rot_z_coords(i,1) = LimitZ
544
545
DO j=1,Mesh % NumberOfNodes
546
IF(FNColumns(j) /= col) CYCLE
547
548
NodeHolder(1) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1)
549
NodeHolder(2) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2)
550
NodeHolder(3) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3)
551
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
552
553
IF(NodeHolder(3) >= LimitZ) CYCLE
554
555
Displace = 0.0_dp
556
Displace(3) = LimitZ - NodeHolder(3)
557
558
Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace)
559
560
!Adjust the variable values to shift nodes in line.
561
Advance((Perm(j)-1)*DOFs + 1) = &
562
Advance((Perm(j)-1)*DOFs + 1) + Displace(1)
563
Advance((Perm(j)-1)*DOFs + 2) = &
564
Advance((Perm(j)-1)*DOFs + 2) + Displace(2)
565
IF(Debug) PRINT *,ParEnv % MyPE,' Debug, limiting node range: col ',&
566
i,' node ',j,' limit: ',LimitZ,' displace: ',Displace
567
END DO
568
569
END IF
570
END DO
571
572
573
!-----------------------------------
574
! Now check projectability
575
!-----------------------------------
576
! If an unprojectable portion of the front is found,
577
! the inland nodes remain in place, while those further
578
! advanced shift sideways to maintain projectability
579
!
580
! Typical case is melt plume at end of recently calved
581
! straight edge.
582
!
583
! requires MPI comms
584
585
!Gather rotated y coord of all columns
586
DO i=1,FrontLineCount
587
#ifdef ELMER_BROKEN_MPI_IN_PLACE
588
buffer = Rot_y_coords(i,1)
589
CALL MPI_AllReduce(buffer, &
590
#else
591
CALL MPI_AllReduce(MPI_IN_PLACE, &
592
#endif
593
Rot_y_coords(i,1), 1, MPI_DOUBLE_PRECISION, MPI_MIN, &
594
ELMER_COMM_WORLD, ierr)
595
#ifdef ELMER_BROKEN_MPI_IN_PLACE
596
buffer = Rot_y_coords(i,2)
597
CALL MPI_AllReduce(buffer, &
598
#else
599
CALL MPI_AllReduce(MPI_IN_PLACE, &
600
#endif
601
Rot_y_coords(i,2), 1, MPI_DOUBLE_PRECISION, MPI_MAX, &
602
ELMER_COMM_WORLD, ierr)
603
604
#ifdef ELMER_BROKEN_MPI_IN_PLACE
605
buffer = Rot_z_coords(i,1)
606
CALL MPI_AllReduce(buffer, &
607
#else
608
CALL MPI_AllReduce(MPI_IN_PLACE, &
609
#endif
610
Rot_z_coords(i,1), 1, MPI_DOUBLE_PRECISION, MPI_MIN, &
611
ELMER_COMM_WORLD, ierr)
612
#ifdef ELMER_BROKEN_MPI_IN_PLACE
613
buffer = Rot_z_coords(i,2)
614
CALL MPI_AllReduce(buffer, &
615
#else
616
CALL MPI_AllReduce(MPI_IN_PLACE, &
617
#endif
618
Rot_z_coords(i,2), 1, MPI_DOUBLE_PRECISION, MPI_MAX, &
619
ELMER_COMM_WORLD,ierr)
620
621
IF(Boss .AND. Debug) PRINT *,'Debug, rot_y_coords: ',i,rot_y_coords(i,:)
622
IF(Boss .AND. Debug) PRINT *,'Debug, rot_z_coords: ',i,rot_z_coords(i,:)
623
END DO
624
625
ALLOCATE(UpdatedColumn(FrontLineCount), &
626
UpdatedDirection(FrontLineCount), &
627
Tangled(FrontLineCount),&
628
TangledGroup(FrontLineCount),&
629
TangledPivotIdx(FrontLineCount),&
630
TangledShiftTo(FrontLineCount),&
631
DontMove(FrontLineCount))
632
633
UpdatedColumn = .FALSE.
634
UpdatedDirection = 0
635
Tangled = .FALSE.
636
TangledGroup = 0
637
TangledPivotIdx = 0
638
TangledShiftTo = 0.0_dp
639
DontMove = .FALSE.
640
641
DontMove(1) = .TRUE.
642
DontMove(FrontLineCount) = .TRUE.
643
644
!TODO: Deal with DontMove and tangling properly...
645
! Ensure that comms is not necessary for DontMove
646
647
!Test for thin sliver at lateral margins - potential to get
648
!stuck like this, so impose an angle here
649
!We require that the 2nd node from the end not retreat beyond
650
!a 45 degree angle inland. PYTHAGORAS
651
!Shift the 2nd column in the lateral direction only,
652
!to the point where it makes a 45 degree angle w/
653
!the corner.
654
! *
655
! / |
656
! / |
657
! * <- *
658
659
DO i=1,2
660
661
IF(i==1) THEN
662
CornerIdx = 1
663
SecondIdx = 2
664
direction = 1.0_dp
665
ELSE
666
CornerIdx = FrontLineCount
667
SecondIdx = FrontLineCount-1
668
direction = -1.0_dp
669
END IF
670
671
!Conveniently, first time round we want the left most coord (Rot_y_coords(:,1))
672
!whereas second time we want the right (Rot_y_cords(:,2))
673
CornerDirection(1) = Rot_y_coords(SecondIdx,i) - Rot_y_coords(CornerIdx,1)
674
CornerDirection(2) = Rot_z_coords(SecondIdx,i) - Rot_z_coords(CornerIdx,1)
675
!Unit vector
676
CornerDirection = CornerDirection / (SUM(CornerDirection ** 2.0)**0.5)
677
678
IF(Debug) PRINT *,ParEnv % MyPE, 'CornerDirection ',i,': ',CornerDirection
679
680
IF( CornerDirection(2) < (-1.0_dp / (2.0_dp ** 0.5)) ) THEN
681
!Shift 2nd node and mark DontMove
682
683
ShiftToY = Rot_y_coords(CornerIdx,1) + &
684
direction * ((Rot_z_coords(CornerIdx,1) - Rot_z_coords(SecondIdx,1)))
685
686
Rot_y_coords(SecondIdx,1) = ShiftToY
687
Rot_y_coords(SecondIdx,2) = ShiftToY
688
689
DontMove(SecondIdx) = .TRUE.
690
IF(Debug) PRINT *,ParEnv % MyPE,' debug, side ',i,' of front is too inwards'
691
692
DO k=1,Mesh % NumberOfNodes
693
IF(FNColumns(k) /= FrontColumnList(SecondIdx)) CYCLE
694
695
NodeHolder(1) = Mesh % Nodes % x(k) + Advance((Perm(k)-1)*DOFs + 1)
696
NodeHolder(2) = Mesh % Nodes % y(k) + Advance((Perm(k)-1)*DOFs + 2)
697
NodeHolder(3) = Mesh % Nodes % z(k) + Advance((Perm(k)-1)*DOFs + 3)
698
699
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
700
701
Displace = 0.0_dp
702
Displace(2) = ShiftToY - NodeHolder(2)
703
704
Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace)
705
706
IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, shifting next to corner node ',k,&
707
NodeHolder,' by ',Displace
708
709
!Adjust the variable values to shift nodes in line.
710
Advance((Perm(k)-1)*DOFs + 1) = Advance((Perm(k)-1)*DOFs + 1) + Displace(1)
711
Advance((Perm(k)-1)*DOFs + 2) = Advance((Perm(k)-1)*DOFs + 2) + Displace(2)
712
END DO
713
714
END IF
715
END DO
716
717
!-----------------------------------------------
718
! Cycle the line, looking for unprojectable
719
! (but not tangled) regions.
720
! e.g. plume melting behind a vertical portion
721
!-----------------------------------------------
722
723
!In case shifting nodes affects another partition, we loop so long as
724
!at least one partition has MovedOne
725
MovedOne = .TRUE.
726
county = 0
727
DO WHILE(MovedOne)
728
county = county + 1
729
IF(county > 100) CALL Fatal(SolverName, "Infinite loop!")
730
IF(Debug) PRINT *,ParEnv % MyPE, 'Debug, iterating projectability ', county
731
732
MovedOne = .FALSE.
733
UpdatedColumn = .FALSE.
734
735
DO i=2,FrontLineCount
736
737
!If already detangled, skip
738
!IF(Tangled(i)) CYCLE
739
740
!epsShift here
741
IF((Rot_y_coords(i,1) - Rot_y_coords(i-1,2)) < 0.9*epsShift) THEN
742
743
IF(Debug) PRINT *, 'Debug diff ',i,i-1, &
744
(Rot_y_coords(i,1) - Rot_y_coords(i-1,2)), epsShift
745
746
IF(DontMove(i) .AND. DontMove(i-1)) THEN
747
CALL Warn(SolverName,&
748
"Both nodes are marked Dont Move, stopping shifting.")
749
EXIT
750
END IF
751
!Work out which to shift
752
!If one is marked DontMove (corner node, or 2nd inland and weird shape)
753
! then move the other
754
!Otherwise, shift whichever is further forward
755
IF(DontMove(i)) THEN
756
ShiftSecond = .FALSE.
757
DontMove(i-1) = .TRUE.
758
IF(Debug) PRINT *,ParEnv % MyPE,'Debug, do not move second: ',i
759
ELSE IF(DontMove(i-1)) THEN
760
ShiftSecond = .TRUE.
761
DontMove(i) = .TRUE.
762
IF(Debug) PRINT *,ParEnv % MyPE,'Debug, do not move first: ',i-1
763
ELSE
764
IF(SUM(Rot_z_coords(i,:)) > SUM(Rot_z_coords(i-1,:))) THEN
765
ShiftSecond = .TRUE.
766
ELSE
767
ShiftSecond = .FALSE.
768
END IF
769
END IF
770
771
IF(ShiftSecond) THEN
772
ShiftIdx = i
773
ShiftToIdx = i-1
774
ELSE
775
ShiftIdx = i-1
776
ShiftToIdx = i
777
END IF
778
779
!Calculate ShiftTo, depends on ShiftSecond
780
!Also update shifted Rot_y_coords
781
IF(ShiftSecond) THEN
782
!If this node has already been moved the other way, leave it alone
783
IF((UpdatedDirection(ShiftIdx) < 0) .AND. .NOT. DontMove(ShiftToIdx)) CYCLE
784
785
ShiftTo = Rot_y_coords(i-1,2) + epsShift
786
IF(Rot_y_coords(i,2) < ShiftTo) UpdatedDirection(ShiftIdx) = 1
787
788
Rot_y_coords(i,1) = MAX(Rot_y_coords(i,1), ShiftTo)
789
Rot_y_coords(i,2) = MAX(Rot_y_coords(i,2), ShiftTo)
790
ELSE
791
!If this node has already been moved the other way, leave it alone
792
IF((UpdatedDirection(ShiftIdx) > 0) .AND. .NOT. DontMove(ShiftToIdx)) CYCLE
793
794
ShiftTo = Rot_y_coords(i,1) - epsShift
795
IF(Rot_y_coords(i,1) > ShiftTo) UpdatedDirection(ShiftIdx) = -1
796
797
Rot_y_coords(i-1,1) = MIN(Rot_y_coords(i-1,1), ShiftTo)
798
Rot_y_coords(i-1,2) = MIN(Rot_y_coords(i-1,2), ShiftTo)
799
END IF
800
801
IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, updating col ',ShiftIdx,&
802
' rot_y_coords: ',Rot_y_coords(ShiftIdx,:)
803
804
UpdatedColumn(ShiftIdx) = .TRUE.
805
806
!Shift all the nodes in this column
807
DO j=1,Mesh % NumberOfNodes
808
IF(FNColumns(j) /= FrontColumnList(ShiftIdx)) CYCLE
809
810
NodeHolder(1) = Mesh % Nodes % x(j) + Advance((Perm(j)-1)*DOFs + 1)
811
NodeHolder(2) = Mesh % Nodes % y(j) + Advance((Perm(j)-1)*DOFs + 2)
812
NodeHolder(3) = Mesh % Nodes % z(j) + Advance((Perm(j)-1)*DOFs + 3)
813
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
814
815
Displace = 0.0_dp
816
Displace(2) = ShiftTo - NodeHolder(2)
817
818
!Check if node already projectable
819
IF(ShiftSecond) THEN
820
IF(Displace(2) < 0 ) CYCLE
821
ELSE
822
IF(Displace(2) > 0) CYCLE
823
END IF
824
825
Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace)
826
827
IF(Debug) PRINT *,ParEnv % MyPE, 'Debug, shifting node ',j,' col ',ShiftIdx,'xyz: ',&
828
Mesh % Nodes % x(j)+Advance((Perm(j)-1)*DOFs + 1),&
829
Mesh % Nodes % y(j)+Advance((Perm(j)-1)*DOFs + 2),&
830
Mesh % Nodes % z(j)+Advance((Perm(j)-1)*DOFs + 3),&
831
' by ',Displace,' to ensure projectability. 1'
832
833
834
!Adjust the variable values to shift nodes in line.
835
Advance((Perm(j)-1)*DOFs + 1) = Advance((Perm(j)-1)*DOFs + 1) + Displace(1)
836
Advance((Perm(j)-1)*DOFs + 2) = Advance((Perm(j)-1)*DOFs + 2) + Displace(2)
837
838
END DO
839
END IF
840
END DO
841
842
IF(ANY(UpdatedColumn)) MovedOne = .TRUE.
843
844
IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, MovedOne: ',MovedOne
845
IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, UpdatedColumn: ',UpdatedColumn
846
847
END DO
848
849
850
!-----------------------------------------------
851
! Check for pinnacles or rifts which can't be made
852
! projectable. Set the columns in a line and mark them
853
! for removal by Remesh.F90
854
!-----------------------------------------------
855
!TODO: At least 3 separate issues here:
856
!
857
! *This one should be fixed now, at the end we check for groups disappearing*
858
! 1 : If there's a tangled group, then another, superset tangled
859
! group, this causes "programming error, tangled group has zero nodes"
860
! potential solution here is to just remove this error message, because
861
! its not really a problem *I DON'T THINK*. However, if so, need to
862
! check for it, and shift TangledGroups down one, so Remesh behaves
863
!
864
! *This one should now be fixed, because we do all the unprojectable shifting first:*
865
! 2 : Here we iteratively: check tangled, then check unprojectable
866
! If correcting unprojectability causes further tangling, this
867
! isn't caught. Potential solutions:
868
! Improve parallel unprojectability checker (dirty fix, won't catch every poss case)
869
! Better: recheck previously tangled regions
870
!
871
! 3 : Long straight sides which also happen to tangle with the end of their headlands
872
! are not well handled. All the nodes along these sides are shifted out the way
873
! in the new mesh
874
875
876
NoTangledGroups = 0
877
DO i=1,FrontLineCount-2
878
IF(Tangled(i)) CYCLE
879
j = i+2
880
881
!If the column two columns away is less than 2*epsShift away, and there
882
!is a change of direction, problems...
883
IF((Rot_y_coords(j,1) - Rot_y_coords(i,2)) < 2*epsShift) THEN
884
885
IF(((Rot_z_coords(i,1) < Rot_z_coords(i+1,1)) .NEQV. &
886
(Rot_z_coords(i+1,1) < Rot_z_coords(j,1))) .OR. &
887
((Rot_z_coords(i,2) < Rot_z_coords(i+1,2)) .NEQV. &
888
(Rot_z_coords(i+1,2) < Rot_z_coords(j,2)))) THEN
889
890
!Either a pinnacle or a slit (i.e protrusion or rift)
891
Protrusion = SUM(Rot_z_coords(i+1,:)) > SUM(Rot_z_coords(i,:))
892
IF(Debug) PRINT *,'Debug, protrusion: ',Protrusion
893
894
NoTangledGroups = NoTangledGroups + 1
895
PivotIdx = i+1
896
897
DO k=2,PivotIdx
898
p1(1) = Rot_y_coords(k,2)
899
p1(2) = Rot_z_coords(k,2)
900
901
p2(1) = Rot_y_coords(k-1,2)
902
p2(2) = Rot_z_coords(k-1,2)
903
904
DO m=FrontLineCount-1,PivotIdx,-1
905
IF(k==m) CYCLE !first two will always intersect by definition, not what we want
906
q1(1) = Rot_y_coords(m,1)
907
q1(2) = Rot_z_coords(m,1)
908
909
q2(1) = Rot_y_coords(m+1,1)
910
q2(2) = Rot_z_coords(m+1,1)
911
912
CALL LineSegmentsIntersect ( p1, p2, q1, q2, intersect, intersect_flag )
913
914
IF(intersect_flag) EXIT
915
END DO
916
IF(intersect_flag) EXIT
917
END DO
918
919
IF(intersect_flag) THEN
920
921
!Found an intersection point (intersect)
922
PRINT *,'Debug, found tangle intersection ',intersect,' leaving last tangled nodes: ',k,m
923
924
Tangled(k:m) = .TRUE.
925
TangledPivotIdx(k:m) = PivotIdx
926
TangledShiftTo(k:m) = intersect(1)
927
928
IF(Protrusion) THEN
929
TangledGroup(k:m) = NoTangledGroups
930
ELSE
931
TangledGroup(k:m) = -NoTangledGroups
932
END IF
933
934
ELSE
935
PRINT *,'Debug, found no intersection, so nodes are not QUITE tangled: ',i,j
936
937
Tangled(i:j) = .TRUE.
938
TangledPivotIdx(i:j) = PivotIdx
939
TangledShiftTo(i:j) = (SUM(rot_y_coords(i,:)) + SUM(rot_y_coords(j,:))) / 4.0_dp
940
941
IF(Protrusion) THEN
942
TangledGroup(i:j) = NoTangledGroups
943
ELSE
944
TangledGroup(i:j) = -NoTangledGroups
945
END IF
946
947
END IF
948
END IF
949
END IF
950
END DO
951
952
!Check for a tangled group 'swallowing' another
953
county = 0
954
DO i=1,NoTangledGroups
955
IF(COUNT(TangledGroup == i) > 0) CYCLE
956
county = county + 1
957
!Shift group numbers down one
958
DO j=1,SIZE(TangledGroup)
959
IF(TangledGroup(j) > i) TangledGroup(j) = TangledGroup(j) - 1
960
END DO
961
END DO
962
NoTangledGroups = NoTangledGroups - county
963
964
!Strategy:
965
! Shift all nodes to near (offset) the y-coordinate
966
! of the tangle pivot (i+1, above)
967
DO i=1,NoTangledGroups
968
n = COUNT(TangledGroup == i)
969
IF(n==0) THEN
970
n = COUNT(TangledGroup == -i)
971
Protrusion = .FALSE.
972
ELSE
973
Protrusion = .TRUE.
974
END IF
975
IF(n==0) CALL Fatal(SolverName, "Programming error: tangled group has 0 nodes?")
976
977
!Get the pivot node index, ShiftToY, and tangled node range
978
FirstTangleIdx = 0
979
LastTangleIdx = 0
980
DO j=1,FrontLineCount
981
IF(TangledGroup(j) == i .OR. TangledGroup(j) == -i) THEN
982
IF(FirstTangleIdx == 0) FirstTangleIdx = j
983
LastTangleIdx = j
984
PivotIdx = TangledPivotIdx(j)
985
ShiftToY = TangledShiftTo(j)
986
!EXIT
987
END IF
988
END DO
989
990
IF(LastTangleIdx - FirstTangleIdx /= n-1) CALL Fatal(SolverName, &
991
"Programming error: wrong number of nodes in TangledGroup")
992
IF(Debug) PRINT *,'Debug, tangled pivot index, ShiftToY: ', PivotIdx, ShiftToY
993
994
LeftY = ShiftToY - (epsTangle * ((n-1) / 2.0_dp))
995
RightY = ShiftToY + (epsTangle * ((n-1) / 2.0_dp))
996
997
!Potentially 'squeezed' on either side by neighbour columns
998
SqueezeLeft = .FALSE.
999
SqueezeRight = .FALSE.
1000
1001
IF(LeftY < Rot_y_coords(FirstTangleIdx-1,2) + epsTangle) THEN
1002
SqueezeLeft = .TRUE.
1003
IF( ( (Rot_y_coords(LastTangleIdx+1,1) - epsTangle) - (epsTangle * (n-1)) ) < &
1004
(Rot_y_coords(FirstTangleIdx-1,2) + epsTangle)) THEN
1005
SqueezeRight = .TRUE.
1006
END IF
1007
END IF
1008
IF(RightY > (Rot_y_coords(LastTangleIdx+1,1) - epsTangle)) THEN
1009
SqueezeRight = .TRUE.
1010
IF( ( (Rot_y_coords(LastTangleIdx+1,1) - epsTangle) - (epsTangle * (n-1)) ) < &
1011
(Rot_y_coords(FirstTangleIdx-1,2) + epsTangle)) THEN
1012
SqueezeLeft = .TRUE.
1013
END IF
1014
END IF
1015
1016
IF(Debug) PRINT *,'Debug, LeftY: ',LeftY,' RightY: ',RightY,' SqueezeL: ',&
1017
SqueezeLeft,' SqueezeR: ',SqueezeRight,' prev: ',Rot_y_coords(FirstTangleIdx-1,2),&
1018
' next: ',Rot_y_coords(LastTangleIdx+1,1)
1019
1020
!If squeezed, adjust the new y coord of the tangled nodes
1021
IF(SqueezeLeft .AND. SqueezeRight) THEN
1022
thisEps = (Rot_y_coords(LastTangleIdx+1,1) - Rot_y_coords(FirstTangleIdx-1,2)) / (n+1)
1023
LeftY = Rot_y_coords(FirstTangleIdx-1,2) + thisEps
1024
RightY = Rot_y_coords(LastTangleIdx+1,1) - thisEps
1025
ShiftToY = (RightY + LeftY) / 2.0_dp !midpoint
1026
ELSE IF(SqueezeLeft) THEN
1027
Shift = (Rot_y_coords(FirstTangleIdx-1,2) + epsTangle) - LeftY
1028
LeftY = LeftY + Shift
1029
RightY = RightY + Shift
1030
ShiftToY = ShiftToY + Shift
1031
ELSE IF(SqueezeRight) THEN
1032
Shift = (Rot_y_coords(LastTangleIdx+1,1) - epsTangle) - RightY
1033
LeftY = LeftY + Shift
1034
RightY = RightY + Shift
1035
ShiftToY = ShiftToY + Shift
1036
END IF
1037
1038
!Where tangling occurs, we shift the tangled columns to be
1039
!1m apart in a series. Then Remesh gets rid of them
1040
DO j=FirstTangleIdx,LastTangleIdx
1041
IF(.NOT. (TangledGroup(j) == i .OR. TangledGroup(j) == -i)) &
1042
CALL Fatal(SolverName, "Programming error: node in specified idx range not tangled?")
1043
1044
thisY = LeftY + ((REAL(j - FirstTangleIdx)/(n-1)) * (RightY - LeftY))
1045
IF(Debug) PRINT *,'Debug, thisY: ',thisY, j
1046
1047
DO k=1,Mesh % NumberOfNodes
1048
IF(FNColumns(k) /= FrontColumnList(j)) CYCLE
1049
1050
NodeHolder(1) = Mesh % Nodes % x(k) + Advance((Perm(k)-1)*DOFs + 1)
1051
NodeHolder(2) = Mesh % Nodes % y(k) + Advance((Perm(k)-1)*DOFs + 2)
1052
NodeHolder(3) = Mesh % Nodes % z(k) + Advance((Perm(k)-1)*DOFs + 3)
1053
IF(Debug) PRINT *, ParEnv % MyPE, ' Debug, pre shift tangled node ',k,': ',NodeHolder
1054
1055
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
1056
1057
Displace = 0.0_dp
1058
Displace(2) = thisY - NodeHolder(2)
1059
1060
Displace = MATMUL(TRANSPOSE(RotationMatrix), Displace)
1061
1062
IF(Debug) PRINT *,ParEnv % MyPE, ' Debug, shifting node ',k, ' col ',j,&
1063
' by ',Displace,' to detangle.'
1064
1065
!Adjust the variable values to shift nodes in line.
1066
Advance((Perm(k)-1)*DOFs + 1) = Advance((Perm(k)-1)*DOFs + 1) + Displace(1)
1067
Advance((Perm(k)-1)*DOFs + 2) = Advance((Perm(k)-1)*DOFs + 2) + Displace(2)
1068
!Set this variable so that Remesh knows
1069
TangledVar % Values(TangledVar % Perm(k)) = 1.0_dp * ABS(TangledGroup(j))
1070
END DO
1071
END DO
1072
END DO
1073
1074
1075
!---------------------------------------
1076
!Done, just deallocations
1077
1078
FirstTime = .FALSE.
1079
1080
DEALLOCATE(FrontPerm, &
1081
TopPerm, &
1082
FrontNodeNums, &
1083
Rot_y_coords, &
1084
UpdatedColumn, &
1085
UpdatedDirection, &
1086
Tangled, &
1087
TangledGroup, &
1088
TangledPivotIdx, &
1089
TangledShiftTo, &
1090
FrontColumnList, &
1091
FrontLocalNodeNumbers)
1092
1093
END SUBROUTINE FrontAdvance3D
1094
1095