Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/Calving3D_lset.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
!Subroutine for predicting calving in 3D
33
34
SUBROUTINE Find_Calving3D_LSet ( Model, Solver, dt, TransientSimulation )
35
36
USE CalvingGeometry
37
USE MainUtils
38
USE InterpVarToVar
39
USE MeshUtils
40
41
IMPLICIT NONE
42
43
!-----------------------------------------------
44
TYPE(Model_t) :: Model
45
TYPE(Solver_t), TARGET :: Solver
46
REAL(KIND=dp) :: dt
47
LOGICAL :: TransientSimulation
48
!-----------------------------------------------
49
TYPE(ValueList_t), POINTER :: Params, MeshParams => NULL()
50
TYPE(Variable_t), POINTER :: CalvingVar, DistVar, CrevVar, &
51
SignDistVar, HitCountVar, IsolineIDVar, MeshCrossVar
52
TYPE(Solver_t), POINTER :: PCSolver => NULL(), &
53
VTUOutputSolver => NULL(), IsoSolver => NULL()
54
TYPE(Mesh_t), POINTER :: Mesh, PlaneMesh, IsoMesh, WorkMesh, WorkMesh2
55
TYPE(Element_t), POINTER :: Element, WorkElements(:),IceElement
56
TYPE(Nodes_t), TARGET :: FaceNodesT
57
INTEGER :: i,j,jmin,k,n,dim, dummyint, NoNodes, ierr, PEs, &
58
FaceNodeCount, DOFs, PathCount, LeftConstraint, RightConstraint, &
59
FrontConstraint, NoCrevNodes, NoPaths, IMBdryCount, &
60
node, nodecounter, CurrentNodePosition, StartNode, &
61
directions, Counter, ClosestCrev, NumEdgeNodes, UnFoundLoops, EdgeLength,&
62
status(MPI_STATUS_SIZE), NUnfoundConstraint
63
INTEGER, POINTER :: CalvingPerm(:), TopPerm(:)=>NULL(), BotPerm(:)=>NULL(), &
64
LeftPerm(:)=>NULL(), RightPerm(:)=>NULL(), FrontPerm(:)=>NULL(), InflowPerm(:)=>NULL(),&
65
FrontNodeNums(:), FaceNodeNums(:)=>NULL(), DistPerm(:), WorkPerm(:), &
66
SignDistPerm(:), NodeIndexes(:),IceNodeIndexes(:),&
67
EdgeMap(:,:)
68
INTEGER, ALLOCATABLE :: CrevEnd(:),CrevStart(:),IMBdryConstraint(:),IMBdryENums(:),&
69
PolyStart(:), PolyEnd(:), EdgeLine(:,:), EdgeCount(:), Nodes(:), StartNodes(:,:),&
70
WorkInt(:), WorkInt2D(:,:), PartCount(:), ElemsToAdd(:), PartElemsToAdd(:), &
71
EdgeLineNodes(:), NodePositions(:), FrontToLateralConstraint(:), UnfoundConstraints(:)
72
#ifdef ELMER_BROKEN_MPI_IN_PLACE
73
INTEGER, ALLOCATABLE :: buffer2(:)
74
#endif
75
REAL(KIND=dp) :: FrontOrientation(3), &
76
RotationMatrix(3,3), UnRotationMatrix(3,3), NodeHolder(3), MaxMeshDist,&
77
y_coord(2), TempDist,MinDist, xl,xr,yl, yr, xx,yy,&
78
angle,angle0,a1(2),a2(2),b1(2),b2(2),a2a1(2),isect(2),front_extent(4), &
79
buffer, gridmesh_dx, FrontLeft(2), FrontRight(2), ElemEdge(2,5), &
80
CalvingLimit, CrevPenetration, PrevValue, PartMinDist, &
81
Calv_delta_t, Calv_dmax, Calv_k, RandomNumber, x, maxprob, Mu, Prob, calv_f, &
82
rt0, rt
83
84
REAL(KIND=dp), POINTER :: DistValues(:), SignDistValues(:), WorkReal(:), &
85
CalvingValues(:)
86
REAL(KIND=dp), ALLOCATABLE :: CrevX(:),CrevY(:),IMBdryNodes(:,:), Polygon(:,:), PathPoly(:,:), &
87
EdgeX(:), EdgeY(:), EdgePoly(:,:), CrevOrient(:,:)
88
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName, DistVarname, &
89
FrontMaskName,TopMaskName,BotMaskName,LeftMaskName,RightMaskName,InflowMaskName, &
90
PC_EqName, Iso_EqName, VTUSolverName, EqName, FileName
91
LOGICAL :: Found, Parallel, Boss, Debug, FirstTime = .TRUE., CalvingOccurs=.FALSE., &
92
SaveParallelActive, LeftToRight, inside, Complete, SaveToFile, &
93
LatCalvMargins, FullThickness, UnfoundConstraint, RandomCalving, FileCreated
94
LOGICAL, ALLOCATABLE :: RemoveNode(:), IMNOnFront(:), IMOnMargin(:), &
95
IMNOnLeft(:), IMNOnRight(:), IMElmONFront(:), IMElmOnLeft(:), IMElmOnRight(:), FoundNode(:), &
96
IMElemOnMargin(:), DeleteMe(:), IsCalvingNode(:), PlaneEdgeElem(:), EdgeNode(:), UsedElem(:), &
97
CrevLR(:), DeleteNode(:), DeleteElement(:)
98
99
TYPE(CrevassePath_t), POINTER :: CrevassePaths, CurrentPath
100
101
SAVE :: FirstTime, SolverName, Params, Parallel, Boss, dim, Debug, &
102
DistVarName, PC_EqName, Iso_EqName, LeftConstraint, &
103
RightConstraint, FrontConstraint,TopMaskName, BotMaskName, &
104
LeftMaskName, RightMaskName, FrontMaskName, InflowMaskName, FileCreated
105
106
!---------------Get Variables and Parameters for Solution-----------
107
108
rt0 = RealTime()
109
110
IF(FirstTime) THEN
111
SolverName = "Find_Calving3D"
112
Params => Solver % Values
113
Parallel = (ParEnv % PEs > 1)
114
Boss = (ParEnv % MyPE == 0) .OR. (.NOT. Parallel)
115
Debug = .TRUE.
116
117
TopMaskName = "Top Surface Mask"
118
BotMaskName = "Bottom Surface Mask"
119
LeftMaskName = "Left Sidewall Mask"
120
RightMaskName = "Right Sidewall Mask"
121
FrontMaskName = "Calving Front Mask"
122
InflowMaskName = "Inflow Mask"
123
124
dim = CoordinateSystemDimension()
125
IF(dim /= 3) CALL Fatal(SolverName, "Solver only works in 3D!")
126
127
DistVarName = ListGetString(Params,"Distance Variable Name", Found)
128
IF(.NOT. Found) DistVarName = "Distance"
129
130
PC_EqName = ListGetString(Params,"Project Calving Equation Name",Found, UnfoundFatal=.TRUE.)
131
Iso_EqName = ListGetString(Params,"Isosurface Equation Name",Found, UnfoundFatal=.TRUE.)
132
133
!Get the boundary constraint of the left, right & front boundaries
134
LeftConstraint = 0; RightConstraint = 0; FrontConstraint = 0
135
DO i=1,Model % NumberOfBCs
136
IF(ListCheckPresent(Model % BCs(i) % Values,FrontMaskName)) &
137
FrontConstraint = Model % BCs(i) % Tag
138
IF(ListCheckPresent(Model % BCs(i) % Values,LeftMaskName)) &
139
LeftConstraint = Model % BCs(i) % Tag
140
IF(ListCheckPresent(Model % BCs(i) % Values,RightMaskName)) &
141
RightConstraint = Model % BCs(i) % Tag
142
END DO
143
IF(Debug) PRINT *,'Front, Left, Right constraints: ',FrontConstraint,LeftConstraint,RightConstraint
144
END IF !FirstTime
145
146
RandomCalving = ListGetLogical(Params,"Random Calving")
147
IF(RandomCalving) THEN
148
IF(Boss) THEN
149
150
Calv_k = ListGetConstReal(Params, "Calving k",Found)
151
IF(.NOT. Found) CALL FATAL(SolverName, "Random calving specified but no 'Calving k' value")
152
Calv_delta_t = ListGetConstReal(Params, "Calving delta t",Found)
153
IF(.NOT. Found) CALL FATAL(SolverName, "Random calving specified but no 'Calving delta t' value")
154
Calv_dmax = ListGetConstReal(Params, "Calving dmax",Found)
155
IF(.NOT. Found) CALL FATAL(SolverName, "Random calving specified but no 'Calving dmax' value")
156
Calv_f = ListGetConstReal(Params, "Calving f",Found)
157
IF(.NOT. Found) CALL FATAL(SolverName, "Random calving specified but no 'Calving f' value")
158
159
SaveToFile = ListGetLogical(Params,"Save Probability to File")
160
161
! calculate dcrev from calving probability
162
!x = (dcrev - dmin) / (1 - dmin)
163
!x[dcrev < dmin] = 0
164
!mu = (x**k) / ( (x**k) + (1-x)**k )
165
!prob = 1 - np.exp(-mu * delta_t)
166
167
maxprob = 1.0_dp - EXP(-1.0_dp * Calv_delta_t * Calv_f)
168
169
! one random number per timestep
170
CALL Random_Seed()
171
CALL Random_Number(RandomNumber)
172
173
IF(RandomNumber >= maxprob + AEPS) THEN
174
CALL INFO(SolverName, 'shortening random number')
175
Prob = maxprob
176
ELSE
177
Prob = RandomNumber
178
END IF
179
180
Mu = -LOG(1.0_dp-Prob)/(Calv_delta_t*calv_f)
181
182
CrevPenetration = Calv_dmax - (LOG(1/mu) / Calv_k)
183
184
IF(SaveToFile) THEN
185
Filename = ListGetString(Params,"Probability File Name", Found)
186
IF(.NOT. Found) THEN
187
CALL WARN(SolverName, 'Output file name not given so using Probability.txt')
188
Filename = "Probability.txt"
189
END IF
190
191
! write to file
192
IF(FileCreated) THEN
193
OPEN( 47, FILE=filename, STATUS='UNKNOWN', ACCESS='APPEND')
194
ELSE
195
OPEN( 47, FILE=filename, STATUS='UNKNOWN')
196
WRITE(47, '(A)') "Calving Probability Output File"
197
WRITE(47, '(A)') "TimeStep, Time, RandomNumber, Probability, Mu, DCrev"
198
END IF
199
200
WRITE(47, *) GetTimestep(), GetTime(), RandomNumber, Prob, Mu, CrevPenetration
201
CLOSE(47)
202
FileCreated = .TRUE.
203
END IF
204
ELSE
205
CrevPenetration = 0.0_dp
206
END IF
207
208
CALL MPI_ALLREDUCE(MPI_IN_PLACE, CrevPenetration, 1, MPI_DOUBLE_PRECISION, MPI_MAX, ELMER_COMM_WORLD, ierr)
209
210
PRINT*, 'CrevPenetration: ', CrevPenetration
211
212
WRITE (Message,'(A,F1.2,A)') 'Calving occuring using crevasse penetration:', CrevPenetration, &
213
'due to probability.'
214
CALL INFO(SolverName, Message)
215
ELSE
216
CrevPenetration = ListGetConstReal(Params, "Crevasse Penetration",Found, DefValue = 1.0_dp)
217
IF(.NOT. Found) CALL Info(SolverName, "No Crevasse Penetration specified so assuming full thickness")
218
PRINT*, 'CrevPenetration: ', CrevPenetration
219
IF(CrevPenetration > 1 .OR. CrevPenetration < 0) CALL FATAL(SolverName, "Crevasse Penetraion must be between 0-1")
220
END IF
221
222
CalvingOccurs = .FALSE.
223
224
Mesh => Model % Mesh
225
226
! addition of the lateral boundaries when calculating constrictions for crevasses
227
! on the lateral boundaries
228
LatCalvMargins = ListGetLogical(Params,"Lateral Calving Margins", DefValue=.TRUE.)
229
230
MaxMeshDist = ListGetConstReal(Params, "Calving Search Distance",Found, UnfoundFatal=.TRUE.)
231
232
CrevPenetration = ListGetConstReal(Params, "Crevasse Penetration",Found, DefValue = 1.0_dp)
233
IF(.NOT. Found) CALL Info(SolverName, "No Crevasse Penetration specified so assuming full thickness")
234
FullThickness = CrevPenetration == 1.0_dp
235
PRINT*, 'CrevPenetration: ', CrevPenetration
236
IF(CrevPenetration > 1 .OR. CrevPenetration < 0) CALL FATAL(SolverName, "Crevasse Penetraion must be between 0-1")
237
238
DistVar => VariableGet(Model % Variables, DistVarName, .TRUE., UnfoundFatal=.TRUE.)
239
DistValues => DistVar % Values
240
DistPerm => DistVar % Perm
241
242
!This solver's variable - holds the levelset value for
243
! CalvingRemeshMMG - negative where calving occurs
244
CalvingVar => Solver % Variable
245
IF(.NOT.ASSOCIATED(CalvingVar)) &
246
CALL Fatal(SolverName, "Find_Calving3D_Lset has no variable!")
247
IF(CalvingVar % DOFs /= 1) &
248
CALL Fatal(SolverName,"Solver variable has more than one DOF")
249
250
CalvingValues => CalvingVar % Values
251
CalvingPerm => CalvingVar % Perm
252
DOFs = CalvingVar % DOFs
253
254
NoNodes = Mesh % NumberOfNodes
255
ALLOCATE( TopPerm(NoNodes), BotPerm(NoNodes), LeftPerm(NoNodes),&
256
RightPerm(NoNodes), FrontPerm(NoNodes), InflowPerm(NoNodes))
257
258
!Generate perms to quickly get nodes on each boundary
259
CALL MakePermUsingMask( Model, Solver, Mesh, TopMaskName, &
260
.FALSE., TopPerm, dummyint)
261
CALL MakePermUsingMask( Model, Solver, Mesh, BotMaskName, &
262
.FALSE., BotPerm, dummyint)
263
CALL MakePermUsingMask( Model, Solver, Mesh, LeftMaskName, &
264
.FALSE., LeftPerm, dummyint)
265
CALL MakePermUsingMask( Model, Solver, Mesh, RightMaskName, &
266
.FALSE., RightPerm, dummyint)
267
CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, &
268
.FALSE., FrontPerm, FaceNodeCount)
269
CALL MakePermUsingMask( Model, Solver, Mesh, InflowMaskName, &
270
.FALSE., InflowPerm, dummyint)
271
272
!Get the orientation of the calving front, compute rotation matrix
273
FrontOrientation = GetFrontOrientation(Model)
274
RotationMatrix = ComputeRotationMatrix(FrontOrientation)
275
UnRotationMatrix = TRANSPOSE(RotationMatrix)
276
277
278
DO i=1, Mesh % NumberOfNodes
279
IF(InflowPerm(i) > 0) THEN
280
IF(ABS(DistValues(DistPerm(i)) * FrontOrientation(2)) <= MaxMeshDist) &
281
CALL FATAL(SolverName, "Reduce Calving Search Distance as parts of the inflow &
282
boundary have a lower distance.")
283
END IF
284
END DO
285
286
rt = RealTime() - rt0
287
IF(ParEnv % MyPE == 0) &
288
PRINT *, 'Time taken for variable loading, making perms etc: ', rt
289
rt0 = RealTime()
290
291
!-----------------------------------------------------------
292
! Action!
293
!-----------------------------------------------------------
294
295
!-----------------------------------------------------------
296
!
297
! The CIndex "calving criterion":
298
! At its core, the Nye criterion says, in 2D, crevasses exist
299
! if sigma_xx > 0.
300
! Water filled extension: sigma_xx + water_pressure > 0
301
!
302
! 3D extension: If any ( planar principal stress + water_pressure) > 0, crevasse exists
303
!-----------------------------------------------------------
304
305
!TODO here - rotate the main mesh, or determine the rotated extent
306
! to pass for Grid Min X, etc
307
! Use MaxMeshDist...
308
309
gridmesh_dx = ListGetConstReal(Params, "PlaneMesh Grid Size",Found, DefValue=20.0_dp)
310
IF(.NOT. Found) CALL WARN(SolverName, "No PlaneMesh Grid Size set in sif so setting to 20")
311
buffer = gridmesh_dx * 4
312
313
front_extent = GetFrontExtent(Mesh, RotationMatrix, DistVar, MaxMeshDist, buffer)
314
315
CALL ListAddConstReal(MeshParams,"Grid Mesh Min X",front_extent(1))
316
CALL ListAddConstReal(MeshParams,"Grid Mesh Max X",front_extent(2))
317
CALL ListAddConstReal(MeshParams,"Grid Mesh Min Y",front_extent(3))
318
CALL ListAddConstReal(MeshParams,"Grid Mesh Max Y",front_extent(4))
319
CALL ListAddConstReal(MeshParams,"Grid Mesh dx",gridmesh_dx)
320
321
322
PRINT *,ParEnv % MyPE,' front extent: ',front_extent
323
324
PlaneMesh => CreateRectangularMesh(MeshParams)
325
326
CALL SetMeshMaxDOFs(PlaneMesh)
327
328
PlaneMesh % Nodes % z = PlaneMesh % Nodes % y
329
PlaneMesh % Nodes % y = PlaneMesh % Nodes % x
330
PlaneMesh % Nodes % x = 0.0
331
CALL RotateMesh(PlaneMesh, UnrotationMatrix)
332
333
PlaneMesh % Name = "calving_plane"
334
PlaneMesh % OutputActive = .TRUE.
335
PlaneMesh % Changed = .TRUE.
336
337
! CALL WriteMeshToDisk2(Model, PlaneMesh, ".")
338
339
rt = RealTime() - rt0
340
IF(ParEnv % MyPE == 0) &
341
PRINT *, 'Time taken to create rectangular mesh: ', rt
342
rt0 = RealTime()
343
344
IF(Parallel) CALL MPI_BARRIER(ELMER_COMM_WORLD, ierr)
345
346
WorkMesh => Mesh % Next
347
Mesh % Next => PlaneMesh
348
349
CALL CopyIntrinsicVars(Mesh, PlaneMesh)
350
351
!----------------------------------------------------
352
! Project Calving Solver to get % fractured
353
!----------------------------------------------------
354
355
! Locate ProjectCalving Solver
356
DO i=1,Model % NumberOfSolvers
357
IF(GetString(Model % Solvers(i) % Values, 'Equation') == PC_EqName) THEN
358
PCSolver => Model % Solvers(i)
359
EXIT
360
END IF
361
END DO
362
IF(.NOT. ASSOCIATED(PCSolver)) &
363
CALL Fatal("Calving Remesh","Couldn't find Project Calving Solver")
364
PCSolver % Mesh => PlaneMesh
365
PCSolver % dt = dt
366
PCSolver % NumberOfActiveElements = 0 !forces recomputation of matrix, is this necessary?
367
368
n = PlaneMesh % NumberOfNodes
369
ALLOCATE(WorkPerm(n), WorkReal(n))
370
WorkReal = 0.0_dp
371
WorkPerm = [(i,i=1,n)]
372
373
IF(ASSOCIATED(PCSolver % Matrix)) CALL FreeMatrix(PCSolver % Matrix) !shouldn't be required...
374
PCSolver % Matrix => CreateMatrix(Model, PCSolver, PlaneMesh, &
375
WorkPerm, 1, MATRIX_CRS, .TRUE.)
376
377
!NOTE: ave_cindex is a misnomer. It actually contains the proprtion (0-1) of intact ice...
378
CALL VariableAdd(PlaneMesh % Variables, PlaneMesh, PCSolver, "ave_cindex", &
379
1, WorkReal, WorkPerm)
380
NULLIFY(WorkReal)
381
382
!Surf cindex (surface crevasses reaching waterline)
383
ALLOCATE(WorkReal(n))
384
WorkReal = 0.0_dp
385
CALL VariableAdd(PlaneMesh % Variables, PlaneMesh, PCSolver, "surf_cindex", &
386
1, WorkReal, WorkPerm)
387
NULLIFY(WorkReal)
388
389
!Basal cindex (surface and basal crevasses meeting)
390
ALLOCATE(WorkReal(n))
391
WorkReal = 0.0_dp
392
CALL VariableAdd(PlaneMesh % Variables, PlaneMesh, PCSolver, "basal_cindex", &
393
1, WorkReal, WorkPerm)
394
NULLIFY(WorkReal)
395
396
!Helper var for determining edges in isoline
397
ALLOCATE(WorkReal(n))
398
WorkReal = 0.0_dp
399
CALL VariableAdd(PlaneMesh % Variables, PlaneMesh, PCSolver, "isoline id", &
400
1, WorkReal, WorkPerm)
401
NULLIFY(WorkReal)
402
403
!Variable to hold the number of hits in ProjectCalving
404
ALLOCATE(WorkReal(n))
405
WorkReal = 0.0_dp
406
CALL VariableAdd(PlaneMesh % Variables, PlaneMesh, PCSolver, "hitcount", &
407
1, WorkReal, WorkPerm)
408
NULLIFY(WorkReal)
409
410
!Variable for edge of Solver % Mesh for polygon creation for levelset sign
411
ALLOCATE(WorkReal(n))
412
WorkReal = 0.0_dp
413
CALL VariableAdd(PlaneMesh % Variables, PlaneMesh, PCSolver, "meshcrossover", &
414
1, WorkReal, WorkPerm)
415
NULLIFY(WorkReal, WorkPerm)
416
417
!Solver variable - crevasse penetration in range 0-1
418
CrevVar => VariableGet(PlaneMesh % Variables, "ave_cindex", .TRUE.)
419
PCSolver % Variable => CrevVar
420
PCSolver % Matrix % Perm => CrevVar % Perm
421
422
!----------------------------------------------------
423
! Run Project Calving solver
424
!----------------------------------------------------
425
SaveParallelActive = ParEnv % Active(ParEnv % MyPE+1)
426
CALL ParallelActive(.TRUE.)
427
428
Model % Solver => PCSolver
429
CALL SingleSolver( Model, PCSolver, PCSolver % dt, .FALSE. )
430
IF(Parallel) CALL MPI_BARRIER(ELMER_COMM_WORLD, ierr)
431
432
rt = RealTime() - rt0
433
IF(ParEnv % MyPE == 0) &
434
PRINT *, 'Time taken up to project cindex into plane: ', rt
435
rt0 = RealTime()
436
437
PlaneMesh % OutputActive = .TRUE.
438
439
Model % Solver => Solver
440
Mesh % Next => WorkMesh !Probably null...
441
442
!--------------------------------------------------------------
443
! Isosurface solver to find cindex 0 contour
444
!--------------------------------------------------------------
445
446
IF(Boss) THEN
447
448
HitCountVar => VariableGet(PlaneMesh % Variables, "hitcount", .TRUE.,UnfoundFatal=.TRUE.)
449
IsolineIdVar => VariableGet(PlaneMesh % Variables, "isoline id", .TRUE.,UnfoundFatal=.TRUE.)
450
MeshCrossVar => VariableGet(PlaneMesh % Variables, "meshcrossover", .TRUE.,UnfoundFatal=.TRUE.)
451
452
! meshcrossover - 2 = glacier hit, 1 = edge, first node outside glacier domain, 0=outside glacier domain
453
MeshCrossVar % Values = 2.0
454
!Set PlaneMesh exterior nodes to ave_cindex = 1 (no calving)
455
! and IsolineID = 1 (exterior)
456
DO i=1,PlaneMesh % NumberOfNodes
457
IF(HitCountVar % Values(HitCountVar % Perm(i)) <= 0.0_dp) THEN
458
CrevVar % Values(CrevVar % Perm(i)) = 1.0
459
IsolineIDVar % Values(IsolineIDVar % Perm(i)) = 1.0
460
MeshCrossVar % Values(MeshCrossVar % Perm(i)) = 0.0
461
END IF
462
END DO
463
464
!PlaneMesh nodes in elements which cross the 3D domain boundary
465
!get ave_cindex = 0 (to enable CrevassePaths/isolines to reach the edge)
466
!Also mark elements which cross the edge of the 3D domain (TODO - not used!)
467
ALLOCATE(PlaneEdgeElem(PlaneMesh % NumberOfBulkElements), EdgeNode(PlaneMesh % NumberOfNodes))
468
PlaneEdgeElem = .FALSE.
469
EdgeNode = .FALSE.
470
471
DO i=1, PlaneMesh % NumberOfBulkElements
472
NodeIndexes => PlaneMesh % Elements(i) % NodeIndexes
473
n = PlaneMesh % Elements(i) % TYPE % NumberOfNodes
474
475
!Some but not all element nodes have hitcount == 0
476
IF((.NOT. ALL(HitCountVar % Values(HitCountVar % Perm(NodeIndexes(1:n))) <= 0.0_dp)) .AND. &
477
ANY(HitCountVar % Values(HitCountVar % Perm(NodeIndexes(1:n))) <= 0.0_dp)) THEN
478
479
PlaneEdgeElem(i) = .TRUE.
480
481
!Mark nodes just outside the edge to CrevVar = 0.0
482
DO j=1,n
483
IF(HitCountVar % Values(HitCountVar % Perm(NodeIndexes(j))) <= 0.0_dp) THEN
484
CrevVar % Values(CrevVar % Perm(NodeIndexes(j))) = 0.0
485
MeshCrossVar % Values(MeshCrossVar % Perm(NodeIndexes(j))) = 1.0
486
EdgeNode(NodeIndexes(j)) = .TRUE.
487
END IF
488
END DO
489
490
END IF
491
END DO
492
PRINT *,'Debug - PlaneEdgeElem: ',COUNT(PlaneEdgeElem), 'EdgeNode: ', COUNT(EdgeNode)
493
494
! get planmesh edgenodes in a line- nodes just outside the solver%mesh domain-
495
! for calving lset sign. These nodes used to make calving polygon
496
!! Elem 404 Structure
497
! 4____1
498
! | |
499
! |____|
500
! 3 2
501
! following code assumes this structure in order to find edge nodes in order
502
! create edgeline so we can stitch this with crevasses
503
504
ALLOCATE(UsedElem(PlaneMesh % NumberOfBulkElements), StartNodes(2, 5), NodePositions(3))
505
UsedElem=.FALSE.
506
StartNodes=0
507
DO startnode=1, PlaneMesh % NumberOfNodes
508
IF(.NOT. EdgeNode(startnode)) CYCLE
509
!StartNode = !random start point
510
directions=0
511
512
! find how many starting directions
513
DO i=1, PlaneMesh % NumberOfBulkElements
514
IF(.NOT. PlaneEdgeElem(i)) CYCLE
515
NodeIndexes => PlaneMesh % Elements(i) % NodeIndexes
516
n = PlaneMesh % Elements(i) % TYPE % NumberOfNodes
517
IF(.NOT. ANY(NodeIndexes(1:n)==startnode)) CYCLE
518
NodePositions=0
519
nodecounter=0
520
DO j=1,n
521
IF(.NOT. EdgeNode(NodeIndexes(j))) CYCLE ! not a edge node
522
IF(NodeIndexes(j) == startnode) THEN
523
CurrentNodePosition = j
524
CYCLE ! this node
525
END IF
526
nodecounter=nodecounter+1
527
NodePositions(nodecounter)=j
528
END DO
529
530
! assign nodes found so we can create edgeline in two directions
531
IF(nodecounter == 0) THEN
532
CYCLE !only contains startnode
533
ELSE IF(nodecounter == 1) THEN
534
directions=directions+1
535
StartNodes(directions, 1) = NodeIndexes(NodePositions(1))
536
ELSE IF(nodecounter == 2) THEN
537
IF(NodePositions(2)-NodePositions(1) == 2) THEN
538
directions=directions+2
539
StartNodes(1, 1)=NodeIndexes(NodePositions(1))
540
StartNodes(2, 1)=NodeIndexes(NodePositions(2))
541
ELSE
542
directions=directions+1
543
IF(ABS(NodePositions(1)-CurrentNodePosition) /= 2) THEN ! closest node
544
StartNodes(directions, 1)=NodeIndexes(NodePositions(1))
545
StartNodes(directions, 2)=NodeIndexes(NodePositions(2))
546
ELSE
547
StartNodes(directions, 1)=NodeIndexes(NodePositions(2))
548
StartNodes(directions, 2)=NodeIndexes(NodePositions(1))
549
END IF
550
END IF
551
END IF
552
UsedElem(i)=.TRUE.
553
END DO
554
555
NumEdgeNodes = COUNT(EdgeNode)
556
! add startnodes to edgeline
557
ALLOCATE(Edgeline(directions, NumEdgeNodes), nodes(directions), &
558
EdgeCount(directions), FoundNode(directions))
559
EdgeCount = 0
560
EdgeLine = 0
561
DO i=1, directions
562
EdgeCount(i) = COUNT(StartNodes(i,:) /= 0)
563
IF(i==1) THEN ! for initial startnode
564
EdgeCount(i) = EdgeCount(i) + 1
565
EdgeLine(i, 1) = startnode
566
EdgeLine(i, 2:EdgeCount(i)) = PACK(StartNodes(i,:), StartNodes(i,:) /= 0)
567
ELSE
568
EdgeLine(i, 1:EdgeCount(i)) = PACK(StartNodes(i,:), StartNodes(i,:) /= 0)
569
END IF
570
571
nodes(i) = EdgeLine(i, EdgeCount(i))
572
END DO
573
574
! loop through starting with startnodes to find remaining edgenodes
575
! in order
576
UnFoundLoops = 0
577
Complete = .FALSE.
578
DO WHILE(.NOT. Complete)
579
FoundNode=.FALSE.
580
DO i=1, PlaneMesh % NumberOfBulkElements
581
IF(.NOT. PlaneEdgeElem(i)) CYCLE
582
IF(UsedElem(i)) CYCLE ! already used elem
583
NodeIndexes => PlaneMesh % Elements(i) % NodeIndexes
584
n = PlaneMesh % Elements(i) % TYPE % NumberOfNodes
585
DO j=1, directions
586
node = Nodes(j)
587
IF(.NOT. ANY(NodeIndexes(1:n)==node)) CYCLE
588
nodecounter=0
589
NodePositions=0
590
DO k=1,n
591
IF(.NOT. EdgeNode(NodeIndexes(k))) CYCLE ! not a edge node
592
IF(NodeIndexes(k) == node) THEN
593
CurrentNodePosition = k
594
CYCLE ! this node
595
END IF
596
nodecounter=nodecounter+1
597
NodePositions(nodecounter) = k
598
END DO
599
IF(nodecounter == 1) THEN
600
IF(ABS(CurrentNodePosition - NodePositions(1)) == 2) CYCLE ! nodes not connected
601
IF(ANY(EdgeLine(j, :) == NodeIndexes(NodePositions(1)))) THEN
602
! increase capactiy by one
603
ALLOCATE(WorkInt2D(directions, NumEdgeNodes))
604
WorkInt2D = EdgeLine
605
DEALLOCATE(EdgeLine)
606
NumEdgeNodes=NumEdgeNodes+1
607
ALLOCATE(EdgeLine(directions, NumEdgeNodes))
608
EdgeLine=0
609
EdgeLine(:,1:NumEdgeNodes-1) = WorkInt2D
610
DEALLOCATE(WorkInt2D)
611
END IF
612
EdgeCount(j) = EdgeCount(j) + 1
613
EdgeLine(j, EdgeCount(j)) = NodeIndexes(NodePositions(1))
614
ELSE IF(nodecounter == 2) THEN
615
counter=0
616
DO k=1, nodecounter
617
IF(ANY(EdgeLine(j, :) == NodeIndexes(NodePositions(k)))) THEN
618
! increase capactiy by one
619
ALLOCATE(WorkInt2D(directions, NumEdgeNodes))
620
WorkInt2D = EdgeLine
621
DEALLOCATE(EdgeLine)
622
NumEdgeNodes=NumEdgeNodes+1
623
ALLOCATE(EdgeLine(directions, NumEdgeNodes))
624
EdgeLine=0
625
EdgeLine(:,1:NumEdgeNodes-1) = WorkInt2D
626
DEALLOCATE(WorkInt2D)
627
END IF
628
IF(ABS(CurrentNodePosition - NodePositions(k)) /= 2) THEN ! first node
629
EdgeLine(j, EdgeCount(j) + 1 + Counter) = NodeIndexes(NodePositions(k))
630
ELSE ! second node
631
EdgeLine(j, EdgeCount(j) + 1 + Counter) = NodeIndexes(NodePositions(k))
632
END IF
633
counter=counter+1
634
END DO
635
EdgeCount(j) = EdgeCount(j) + Counter
636
ELSE IF(nodecounter == 3) THEN
637
CALL FATAL('PlaneMesh', '4 edge nodes in one element!')
638
END IF
639
Nodes(j)=Edgeline(j, EdgeCount(j))
640
IF(nodecounter>0) THEN
641
UsedElem(i)=.TRUE.
642
FoundNode(j)=.TRUE.
643
END IF
644
END DO
645
END DO
646
IF(.NOT. ANY(FoundNode)) THEN
647
DO i=1, directions
648
IF(FoundNode(i)) CYCLE
649
Nodes(i)=Edgeline(i, EdgeCount(i)-1)
650
END DO
651
UnFoundLoops=UnFoundLoops+1
652
ELSE
653
UnFoundLoops=0
654
END IF
655
IF(UnFoundLoops == 2) THEN
656
! if can't find all edge nodes
657
! check if unfound node lies in poly of edgeline
658
ALLOCATE(EdgePoly(2, SUM(EdgeCount)+1))
659
nodecounter=0
660
IF(directions > 1) THEN
661
DO i=EdgeCount(2),1, -1 ! backwards iteration
662
nodecounter=nodecounter+1
663
EdgePoly(1,nodecounter) = PlaneMesh % Nodes % x(EdgeLine(2, i))
664
EdgePoly(2,nodecounter) = PlaneMesh % Nodes % y(EdgeLine(2, i))
665
END DO
666
END IF
667
DO i=1, EdgeCount(1)
668
nodecounter=nodecounter+1
669
EdgePoly(1,nodecounter) = PlaneMesh % Nodes % x(EdgeLine(1, i))
670
EdgePoly(2,nodecounter) = PlaneMesh % Nodes % y(EdgeLine(1, i))
671
END DO
672
EdgePoly(1, SUM(EdgeCount)+1) = EdgePoly(1,1)
673
EdgePoly(2, SUM(EdgeCount)+1) = EdgePoly(2,1)
674
675
counter=0
676
DO i=1, PlaneMesh % NumberOfNodes
677
inside=.FALSE.
678
IF(.NOT. EdgeNode(i)) CYCLE
679
IF(ANY(EdgeLine == i)) CYCLE
680
xx = PlaneMesh % Nodes % x(i)
681
yy = PlaneMesh % Nodes % y(i)
682
inside = PointInPolygon2D(EdgePoly, (/xx, yy/))
683
IF(inside) counter=counter+1
684
END DO
685
IF(NumEdgeNodes == SUM(EdgeCount) + counter) Complete = .TRUE.
686
DEALLOCATE(EdgePoly)
687
END IF
688
IF(NumEdgeNodes == SUM(EdgeCount)) Complete = .TRUE.
689
IF(UnFoundLoops == 10) CALL FATAL('Calving_lset', 'Cannot find all edge nodes')
690
END DO
691
EXIT ! initial loop only to get random start point
692
END DO
693
DEALLOCATE(UsedElem, NodePositions)
694
695
EdgeLength = SUM(EdgeCount)
696
! translate edge nodes into x and y and join both strings
697
ALLOCATE(EdgeX(EdgeLength), EdgeY(EdgeLength), EdgeLineNodes(EdgeLength))
698
nodecounter=0
699
IF(directions > 1) THEN
700
DO i=EdgeCount(2),1, -1 ! backwards iteration
701
nodecounter=nodecounter+1
702
EdgeX(nodecounter) = PlaneMesh % Nodes % x(EdgeLine(2, i))
703
EdgeY(nodecounter) = PlaneMesh % Nodes % y(EdgeLine(2, i))
704
EdgeLineNodes(nodecounter) = EdgeLine(2,i)
705
END DO
706
END IF
707
DO i=1, EdgeCount(1)
708
nodecounter=nodecounter+1
709
EdgeX(nodecounter) = PlaneMesh % Nodes % x(EdgeLine(1, i))
710
EdgeY(nodecounter) = PlaneMesh % Nodes % y(EdgeLine(1, i))
711
EdgeLineNodes(nodecounter) = EdgeLine(1,i)
712
END DO
713
714
! see if all mesh nodes lie with edgeline if not adjust
715
ALLOCATE(EdgePoly(2, EdgeLength+1))
716
EdgePoly(1,1:EdgeLength) = EdgeX
717
EdgePoly(1,EdgeLength+1) = EdgeX(1)
718
EdgePoly(2,1:EdgeLength) = EdgeY
719
EdgePoly(2,EdgeLength+1) = EdgeY(1)
720
! end of finding planmesh edge
721
END IF ! BOSS
722
723
CALL MPI_BARRIER(ELMER_COMM_WORLD, ierr)
724
CALL MPI_BCAST(EdgeLength, 1, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
725
IF(.NOT. Boss) ALLOCATE(EdgePoly(2,EdgeLength+1))
726
CALL MPI_BCAST(EdgePoly, (EdgeLength+1)*2, MPI_DOUBLE_PRECISION, 0, ELMER_COMM_WORLD, ierr)
727
728
! check all nodes lie within edgeline
729
ALLOCATE(ElemsToAdd(Mesh % NumberOfNodes))
730
counter=0; ElemsToAdd = 0
731
DO i=1, Mesh % NumberOfNodes
732
IF(DistValues(DistPerm(i)) > MaxMeshDist/2) CYCLE
733
inside = PointInPolygon2D(EdgePoly, (/Mesh % Nodes % x(i), Mesh % Nodes % y(i)/))
734
IF(.NOT. inside) THEN
735
DO j=1, PlaneMesh % NumberOfBulkElements
736
NodeIndexes => PlaneMesh % Elements(j) % NodeIndexes
737
DO k=1,4
738
ElemEdge(1,k) = PlaneMesh % Nodes % x(NodeIndexes(k))
739
ElemEdge(2,k) = PlaneMesh % Nodes % y(NodeIndexes(k))
740
END DO
741
ElemEdge(1,5) = PlaneMesh % Nodes % x(NodeIndexes(1))
742
ElemEdge(2,5) = PlaneMesh % Nodes % y(NodeIndexes(1))
743
inside = PointInPolygon2D(ElemEdge, (/Mesh % Nodes % x(i), Mesh % Nodes % y(i)/))
744
IF(inside) THEN
745
IF(ANY(ElemsToAdd == j)) CYCLE
746
counter=counter+1
747
ElemsToAdd(counter) = j
748
END IF
749
END DO
750
END IF
751
END DO
752
753
ALLOCATE(PartCount(ParEnv % PEs))
754
PartCount=0
755
CALL MPI_GATHER(counter, 1, MPI_INTEGER, PartCount, 1, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
756
757
IF(.NOT. Boss .AND. Counter > 0) THEN
758
CALL MPI_BSEND(ElemsToAdd, counter, MPI_INTEGER, 0, &
759
8000, ELMER_COMM_WORLD, ierr)
760
END IF
761
IF(Boss.AND. SUM(PartCount) > 0) THEN
762
ALLOCATE(PartElemsToAdd(SUM(PartCount)))
763
IF(counter > 0) PartElemsToAdd(1:Counter) = ElemsToAdd(1:counter)
764
DO i=2, ParEnv % PEs ! boss is zero
765
IF(PartCount(i) == 0) CYCLE
766
PRINT*, i-1, counter, PartCount(i)
767
CALL MPI_RECV(PartElemsToAdd(counter+1:counter+PartCount(i)), PartCount(i), &
768
MPI_INTEGER, i-1, 8000, ELMER_COMM_WORLD, status, ierr)
769
counter=counter+PartCount(i)
770
END DO
771
772
END IF
773
774
IF(Boss .AND. SUM(PartCount) > 0) THEN
775
!remove duplicates
776
ALLOCATE(WorkInt(SUM(PartCount)), RemoveNode(SUM(PartCount)))
777
WorkInt = PartElemsToAdd
778
RemoveNode = .FALSE.
779
DO i=1,SUM(PartCount)
780
IF(RemoveNode(i)) CYCLE
781
DO j=1,SUM(PartCount)
782
IF(i==j) CYCLE
783
IF(WorkInt(i) == WorkInt(j)) RemoveNode(j) = .TRUE.
784
END DO
785
END DO
786
DEALLOCATE(PartElemsToAdd)
787
PartElemsToAdd = PACK(WorkInt, .NOT. RemoveNode)
788
DEALLOCATE(WorkInt, RemoveNode)
789
790
!if nodes lie outwith edgeline expand edgeline
791
ALLOCATE(UsedElem(SIZE(PartElemsToAdd)), NodePositions(4))
792
UsedElem=.FALSE.
793
DO WHILE(.NOT. ALL(UsedElem))
794
DO i=1, SIZE(PartElemsToAdd)
795
IF(UsedElem(i)) CYCLE
796
NodeIndexes => PlaneMesh % Elements(PartElemsToAdd(i)) % NodeIndexes
797
counter=0
798
DO j=1,4
799
IF(ANY(EdgeLineNodes == NodeIndexes(j))) counter=counter+1
800
END DO
801
IF(counter == 1) THEN
802
! add three missing nodes in order
803
DO j=1,EdgeLength
804
IF(ANY(NodeIndexes == EdgeLineNodes(j))) THEN ! found first node
805
DO k=1,4
806
IF(NodeIndexes(k) == EdgeLineNodes(j)) NodePositions(1) = k
807
END DO
808
ALLOCATE(WorkInt(EdgeLength+4))
809
WorkInt(1:j) = EdgeLineNodes(1:j)
810
DO k=1,4 ! 4 as need to add original node back in at end
811
n = NodePositions(1) + k
812
IF(n > 4) n = n - 4
813
WorkInt(j+k) = NodeIndexes(n)
814
END DO
815
WorkInt(j+5:EdgeLength+4) = EdgeLineNodes(j+1:EdgeLength)
816
DEALLOCATE(EdgeLineNodes)
817
EdgeLength = EdgeLength + 4
818
ALLOCATE(EdgeLineNodes(EdgeLength))
819
EdgeLineNodes = WorkInt
820
DEALLOCATE(WorkInt)
821
EXIT
822
END IF
823
END DO
824
ELSE IF(Counter == 2) THEN
825
! add two missing nodes in order
826
DO j=1,EdgeLength
827
IF(ANY(NodeIndexes == EdgeLineNodes(j))) THEN ! found first node
828
DO k=1,4
829
IF(NodeIndexes(k) == EdgeLineNodes(j)) NodePositions(1) = k
830
IF(NodeIndexes(k) == EdgeLineNodes(j+1)) NodePositions(2) = k
831
END DO
832
IF(NodePositions(1) == NodePositions(2)) CYCLE
833
IF(ABS(NodePositions(1) - NodePositions(2)) == 2) &
834
CALL FATAL('Calving3D_lset', 'Error building edgeline')
835
! add in other nodes
836
ALLOCATE(WorkInt(EdgeLength+2))
837
WorkInt(1:j) = EdgeLineNodes(1:j)
838
! first node is opposite NodePostiions(1)
839
DO k=1,4
840
IF(ANY(NodePositions(1:2) == k)) CYCLE
841
IF(ABS(k-NodePositions(1)) /= 2) WorkInt(j+1) = NodeIndexes(k)
842
IF(ABS(k-NodePositions(2)) /= 2) WorkInt(j+2) = NodeIndexes(k)
843
END DO
844
WorkInt(j+3:EdgeLength+2) = EdgeLineNodes(j+1:EdgeLength)
845
DEALLOCATE(EdgeLineNodes)
846
EdgeLength = EdgeLength + 2
847
ALLOCATE(EdgeLineNodes(EdgeLength))
848
EdgeLineNodes = WorkInt
849
DEALLOCATE(WorkInt)
850
EXIT
851
END IF
852
END DO
853
ELSE IF(counter == 3) THEN !swap middle node for unsed node
854
DO j=1,EdgeLength
855
IF(ANY(NodeIndexes == EdgeLineNodes(j))) THEN ! found first node
856
IF(ANY(EdgeLineNodes(j+1:j+2) == EdgeLineNodes(j))) CYCLE ! loops back on itself
857
IF(.NOT. ANY(NodeIndexes == EdgeLineNodes(j+1))) CYCLE ! moves out of element
858
IF(.NOT. ANY(NodeIndexes == EdgeLineNodes(j+2))) CYCLE ! moves out of element
859
DO k=1,4
860
IF(NodeIndexes(k) == EdgeLineNodes(j)) NodePositions(1) = k
861
IF(NodeIndexes(k) == EdgeLineNodes(j+1)) NodePositions(2) = k
862
IF(ANY(EdgeLineNodes(j:j+2) == NodeIndexes(k))) CYCLE
863
NodePositions(4) = k
864
END DO
865
! swap node 2 with 4
866
EdgeLineNodes(j+1) = NodeIndexes(NodePositions(4))
867
EXIT
868
END IF
869
END DO
870
ELSE IF(counter == 4) THEN ! remove two middle nodes
871
DO j=1,EdgeLength
872
IF(ANY(NodeIndexes == EdgeLineNodes(j))) THEN ! found first node
873
IF(ANY(EdgeLineNodes(j+1:j+3) == EdgeLineNodes(j))) CYCLE ! loops back on itself
874
IF(ANY(EdgeLineNodes(j+2:j+3) == EdgeLineNodes(j+1))) CYCLE ! loops back on itself
875
IF(EdgeLineNodes(j+2) == EdgeLineNodes(j+3)) CYCLE ! loops back on itself
876
IF(.NOT. ANY(NodeIndexes == EdgeLineNodes(j+1))) CYCLE ! moves out of element
877
IF(.NOT. ANY(NodeIndexes == EdgeLineNodes(j+2))) CYCLE ! moves out of element
878
IF(.NOT. ANY(NodeIndexes == EdgeLineNodes(j+3))) CYCLE ! moves out of element
879
DO k=1,4
880
IF(NodeIndexes(k) == EdgeLineNodes(j)) NodePositions(1) = k
881
IF(NodeIndexes(k) == EdgeLineNodes(j+3)) NodePositions(4) = k
882
END DO
883
IF(ABS(NodePositions(1) - NodePositions(4)) == 2) &
884
CALL FATAL('Calving3D_lset', 'Error building edgeine')
885
ALLOCATE(WorkInt(EdgeLength-2))
886
WorkInt(1:j) = EdgeLineNodes(1:j)
887
WorkInt(j+1:) = EdgeLineNodes(j+3:)
888
DEALLOCATE(EdgeLineNodes)
889
EdgeLength = EdgeLength - 2
890
ALLOCATE(EdgeLineNodes(EdgeLength))
891
EdgeLineNodes = WorkInt
892
DEALLOCATE(WorkInt)
893
EXIT
894
END IF
895
END DO
896
END IF
897
UsedElem(i)=.TRUE.
898
IF(counter == 0) CALL WARN(SolverName, 'Element to be added not connected')
899
END DO
900
END DO
901
! update edge line
902
DEALLOCATE(EdgeX, EdgeY)
903
ALLOCATE(EdgeX(EdgeLength), EdgeY(EdgeLength))
904
DO i=1, EdgeLength
905
EdgeX(i) = PlaneMesh % Nodes % x(EdgeLineNodes(i))
906
EdgeY(i) = PlaneMesh % Nodes % y(EdgeLineNodes(i))
907
END DO
908
END IF
909
910
IF(Debug .AND. Boss) THEN
911
PRINT*, 'EdgeLine ----'
912
DO i=1, EdgeLength
913
PRINT*, EdgeX(i), ',', EdgeY(i), ','
914
END DO
915
END IF
916
917
IF(Boss) THEN
918
919
IF(.NOT. FullThickness) THEN
920
! save original ave_cindex
921
n = PlaneMesh % NumberOfNodes
922
ALLOCATE(WorkPerm(n), WorkReal(n))
923
WorkReal = CrevVar % Values(CrevVar % Perm)
924
WorkPerm = [(i,i=1,n)]
925
CALL VariableAdd(PlaneMesh % Variables, PlaneMesh, PCSolver, "ave_cindex_fullthickness", &
926
1, WorkReal, WorkPerm)
927
NULLIFY(WorkReal, WorkPerm)
928
929
CalvingLimit = 1.0_dp - CrevPenetration
930
931
!alter ave_cindix so relflect %crevasses indicated in sif
932
! 0 full
933
DO i=1, n
934
IF(CrevVar % Values(CrevVar % Perm(i)) <= CalvingLimit) THEN
935
CrevVar % Values(CrevVar % Perm(i)) = 0.0_dp
936
ELSE
937
PrevValue = CrevVar % Values(CrevVar % Perm(i))
938
CrevVar % Values(CrevVar % Perm(i)) = PrevValue - CalvingLimit
939
END IF
940
END DO
941
END IF
942
943
944
945
! Locate Isosurface Solver
946
DO i=1,Model % NumberOfSolvers
947
IF(GetString(Model % Solvers(i) % Values, 'Equation') == Iso_EqName) THEN
948
IsoSolver => Model % Solvers(i)
949
EXIT
950
END IF
951
END DO
952
IF(.NOT. ASSOCIATED(IsoSolver)) &
953
CALL Fatal("Calving Remesh","Couldn't find Isosurface Solver")
954
955
IsoSolver % Mesh => PlaneMesh
956
IsoSolver % dt = dt
957
IsoSolver % NumberOfActiveElements = 0 !forces recomputation of matrix, is this necessary?
958
959
PEs = ParEnv % PEs
960
ParEnv % PEs = 1
961
962
Model % Solver => IsoSolver
963
CALL SingleSolver( Model, IsoSolver, IsoSolver % dt, .FALSE. )
964
965
Model % Solver => Solver
966
ParEnv % PEs = PEs
967
968
!Immediately following call to Isosurface solver, the resulting
969
!isoline mesh is the last in the list. We want to remove it from the
970
!Model % Mesh linked list and attach it to PlaneMesh
971
WorkMesh => Model % Mesh
972
DO WHILE(ASSOCIATED(WorkMesh % Next))
973
WorkMesh2 => WorkMesh
974
WorkMesh => WorkMesh % Next
975
END DO
976
IsoMesh => WorkMesh
977
WorkMesh2 % Next => NULL() !break the list
978
PlaneMesh % Next => IsoMesh !add to planemesh
979
980
ALLOCATE(DeleteNode(PlaneMesh % NumberOfNodes), DeleteElement(PlaneMesh % NumberOfBulkElements))
981
DeleteNode = .FALSE.; DeleteElement = .FALSE.
982
!remove unwanted elements
983
DO i=1, PlaneMesh % NumberOfNodes
984
IF(CrevVar % Values(CrevVar % Perm(i)) /= CrevPenetration) CYCLE !all nodes outside should equal 1
985
inside = PointInPolygon2D(EdgePoly, (/PlaneMesh % Nodes % x(i), PlaneMesh % Nodes % y(i)/))
986
IF(inside) CYCLE
987
DeleteNode(i) = .TRUE.
988
END DO
989
990
DO i=1, PlaneMesh % NumberOfBulkElements
991
IF(ANY(DeleteNode(PlaneMesh % Elements(i) % NodeIndexes))) &
992
DeleteElement(i) = .TRUE.
993
END DO
994
995
CALL CutPlaneMesh(PlaneMesh, DeleteNode, DeleteElement)
996
997
!-------------------------------------------------
998
!
999
! Compare rotated isomesh to current calving front
1000
! position to see if and where calving occurs
1001
!
1002
!-------------------------------------------------
1003
1004
!-------------------------------------------------
1005
! Need to map boundary info from the main
1006
! 3D mesh to the IsoMesh. We ask Isosurface Solver
1007
! to interpolate the 'Isoline ID' var, which is
1008
! 1 where the PlaneMesh didn't hit the 3D mesh, and
1009
! 0 elsewhere. This does not allow us to distinguish
1010
! between frontal and lateral Isomesh elements/nodes
1011
! but it identifies candidate boundary elements in
1012
! Isomesh.
1013
!-------------------------------------------------
1014
1015
ALLOCATE(IMNOnFront(IsoMesh % NumberOfNodes), &
1016
IMNOnLeft(IsoMesh % NumberOfNodes),&
1017
IMNOnRight(IsoMesh % NumberOfNodes),&
1018
IMOnMargin(IsoMesh % NumberOfNodes))
1019
IMNOnFront=.FALSE.; IMOnMargin=.FALSE.
1020
IMNOnLeft=.FALSE.; IMNOnRight=.FALSE.
1021
1022
IsolineIdVar => VariableGet(IsoMesh % Variables, "isoline id", .TRUE.,UnfoundFatal=.TRUE.)
1023
DO i=1, IsoMesh % NumberOfNodes
1024
ImOnMargin(i) = IsolineIDVar % Values(IsolineIDVar % Perm(i)) > 0.0_dp
1025
END DO
1026
1027
!Count the elements which cross through the ice domain boundary
1028
!and fill IMBdryNodes to send to other partitions
1029
ALLOCATE(IMElemOnMargin(IsoMesh % NumberOfBulkElements))
1030
IMElemOnMargin = .FALSE.
1031
1032
DO k=1,2 !2 passes, count then fill
1033
IMBdryCount = 0
1034
DO i=1, IsoMesh % NumberOfBulkElements
1035
NodeIndexes => Isomesh % Elements(i) % NodeIndexes
1036
IF(IMOnMargin(NodeIndexes(1)) .EQV. IMOnMargin(NodeIndexes(2))) CYCLE
1037
IMElemOnMargin(i) = .TRUE.
1038
IMBdryCount = IMBdryCount + 1
1039
1040
IF(k==2) THEN
1041
IMBdryNodes(IMBdryCount,1) = Isomesh % Nodes % x(NodeIndexes(1))
1042
IMBdryNodes(IMBdryCount,2) = Isomesh % Nodes % y(NodeIndexes(1))
1043
IMBdryNodes(IMBdryCount,3) = Isomesh % Nodes % x(NodeIndexes(2))
1044
IMBdryNodes(IMBdryCount,4) = Isomesh % Nodes % y(NodeIndexes(2))
1045
IMBdryENums(IMBdryCount) = i
1046
END IF
1047
END DO
1048
IF(k==1) ALLOCATE(IMBdryNodes(IMBdryCount,4),IMBdryENums(IMBdryCount))
1049
END DO
1050
1051
END IF
1052
1053
IF(Parallel) CALL MPI_BARRIER(ELMER_COMM_WORLD, ierr)
1054
! check front boundary is connected returns FrontToLateralConstraint which
1055
! reassigns unconnected elems to nearest lateral margin in IMBdryConstraints
1056
CALL CheckFrontBoundary(Model, FrontConstraint, RightConstraint, LeftConstraint, FrontToLateralConstraint)
1057
1058
!Pass isoline boundary elements to all partitions to get info
1059
!about which boundary they cross
1060
1061
CALL MPI_BCAST(IMBdryCount,1,MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1062
IF(.NOT. Boss) ALLOCATE(IMBdryNodes(IMBdryCount,4))
1063
1064
CALL MPI_BCAST(IMBdryNodes,IMBdryCount*4, MPI_DOUBLE_PRECISION,&
1065
0, ELMER_COMM_WORLD, ierr)
1066
1067
ALLOCATE(IMBdryConstraint(IMBdryCount))
1068
IMBdryConstraint = 0
1069
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1070
ALLOCATE(buffer2(IMBdryCount))
1071
#endif
1072
1073
!Now cycle elements: for those with a node either side
1074
!of domain boundary, cycle 3d mesh boundary elements
1075
!looking for a 2D intersection. This identifies the
1076
!physical boundary for the isomesh node.
1077
DO i=1, IMBdryCount
1078
1079
a1(1) = IMBdryNodes(i,1)
1080
a1(2) = IMBdryNodes(i,2)
1081
a2(1) = IMBdryNodes(i,3)
1082
a2(2) = IMBdryNodes(i,4)
1083
1084
!Slightly extend the length of the element to account for floating point
1085
!precision issues:
1086
a2a1 = (a2 - a1) * 0.1
1087
a1 = a1 - a2a1
1088
a2 = a2 + a2a1
1089
1090
DO j=Mesh % NumberOfBulkElements + 1, Mesh % NumberOfBulkElements + &
1091
Mesh % NumberOfBoundaryElements
1092
1093
IceElement => Mesh % Elements(j)
1094
IF(IceElement % BoundaryInfo % Constraint /= FrontConstraint .AND. &
1095
IceElement % BoundaryInfo % Constraint /= LeftConstraint .AND. &
1096
IceElement % BoundaryInfo % Constraint /= RightConstraint) CYCLE
1097
1098
IceNodeIndexes => IceElement % NodeIndexes
1099
1100
EdgeMap => GetEdgeMap(IceElement % TYPE % ElementCode / 100)
1101
1102
!set K = element number of edges
1103
! cycle K, setting edge to b1 b2, checking
1104
n = SIZE(EdgeMap,1)
1105
DO k=1,n
1106
b1(1) = Mesh % Nodes % x(IceNodeIndexes(EdgeMap(k,1)))
1107
b1(2) = Mesh % Nodes % y(IceNodeIndexes(EdgeMap(k,1)))
1108
b2(1) = Mesh % Nodes % x(IceNodeIndexes(EdgeMap(k,2)))
1109
b2(2) = Mesh % Nodes % y(IceNodeIndexes(EdgeMap(k,2)))
1110
1111
CALL LineSegmentsIntersect ( a1, a2, b1, b2, isect, Found)
1112
1113
IF(Found) THEN
1114
!set the element BC id here!
1115
CALL Assert(ASSOCIATED(IceElement % BoundaryInfo), SolverName,&
1116
"Boundary element has no % boundaryinfo!")
1117
IMBdryConstraint(i) = IceElement % BoundaryInfo % Constraint
1118
IF(Debug) PRINT *,ParEnv % MyPE,' isomesh element ',i,' hit ',j,'constraint: ', &
1119
IceElement % BoundaryInfo % Constraint,' xy: ',a1
1120
EXIT
1121
END IF
1122
END DO
1123
! when lateral margin advances it doesn't follow the z axis so we want to determine
1124
! the further point the lateral margins have advanced
1125
IF(Found .AND. FrontToLateralConstraint(j) /= 0) &
1126
IMBdryConstraint(i) = FrontToLateralConstraint(j)
1127
IF(Found .AND. IMBdryConstraint(i) /= FrontConstraint) EXIT
1128
END DO
1129
END DO
1130
1131
!Send info back to boss
1132
IF(Boss) THEN
1133
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1134
buffer2 = IMBdryConstraint
1135
CALL MPI_Reduce(buffer2, &
1136
#else
1137
CALL MPI_Reduce(MPI_IN_PLACE, &
1138
#endif
1139
IMBdryConstraint, IMBdryCount, MPI_INTEGER, &
1140
MPI_MAX, 0, ELMER_COMM_WORLD, ierr)
1141
ELSE
1142
CALL MPI_Reduce(IMBdryConstraint, IMBdryConstraint, IMBdryCount, MPI_INTEGER, &
1143
MPI_MAX, 0, ELMER_COMM_WORLD, ierr)
1144
END IF
1145
1146
CALL GetFrontCorners(Model, Solver, FrontLeft, FrontRight)
1147
1148
IF(Boss) THEN
1149
1150
UnfoundConstraint = .FALSE.
1151
IF(ANY(IMBdryConstraint == 0)) THEN
1152
PRINT *,'Debug constraints: ', IMBdryConstraint
1153
CALL WARN(SolverName,"Failed to identify boundary constraint for all isomesh edge elements")
1154
UnfoundConstraints = PACK((/ (i,i=1,IMBdryCount) /),IMBdryConstraint == 0)
1155
UnfoundConstraint = .TRUE.
1156
END IF
1157
END IF
1158
1159
CALL MPI_BCAST(UnfoundConstraint, 1, MPI_LOGICAL, 0, ELMER_COMM_WORLD, ierr)
1160
1161
IF(UnfoundConstraint) THEN
1162
CALL INFO(SolverName, "Unfound boundary constraints so searching for nearest boundary element")
1163
1164
IF(Boss) NUnfoundConstraint = SIZE(UnfoundConstraints)
1165
CALL MPI_BCAST(NUnfoundConstraint, 1, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1166
IF(.NOT. Boss) ALLOCATE(UnfoundConstraints(NUnfoundConstraint))
1167
CALL MPI_BCAST(UnfoundConstraints, NUnfoundConstraint, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1168
1169
DO node=1, NUnfoundConstraint
1170
1171
MinDist = HUGE(1.0_dp)
1172
i = UnfoundConstraints(node)
1173
1174
a1(1) = IMBdryNodes(i,1)
1175
a1(2) = IMBdryNodes(i,2)
1176
a2(1) = IMBdryNodes(i,3)
1177
a2(2) = IMBdryNodes(i,4)
1178
1179
!Slightly extend the length of the element to account for floating point
1180
!precision issues:
1181
a2a1 = (a2 - a1) * 0.1
1182
a1 = a1 - a2a1
1183
a2 = a2 + a2a1
1184
1185
DO j=Mesh % NumberOfBulkElements + 1, Mesh % NumberOfBulkElements + &
1186
Mesh % NumberOfBoundaryElements
1187
1188
IceElement => Mesh % Elements(j)
1189
IF(IceElement % BoundaryInfo % Constraint /= FrontConstraint .AND. &
1190
IceElement % BoundaryInfo % Constraint /= LeftConstraint .AND. &
1191
IceElement % BoundaryInfo % Constraint /= RightConstraint) CYCLE
1192
1193
IceNodeIndexes => IceElement % NodeIndexes
1194
1195
n = IceElement % TYPE % NumberOfNodes
1196
1197
DO k=1,n
1198
b1(1) = Mesh % Nodes % x(IceNodeIndexes(k))
1199
b1(2) = Mesh % Nodes % y(IceNodeIndexes(k))
1200
1201
tempdist = PointLineSegmDist2D ( a1, a2, b1)
1202
1203
IF(TempDist < MinDist) THEN
1204
MinDist = TempDist
1205
jmin = j
1206
END IF
1207
END DO
1208
END DO
1209
1210
CALL MPI_AllReduce(MinDist, PartMinDist, 1, MPI_DOUBLE_PRECISION, &
1211
MPI_MIN, ELMER_COMM_WORLD, ierr)
1212
1213
IF(MinDist == PartMinDist) THEN
1214
IMBdryConstraint(i) = Mesh % Elements(jmin) % BoundaryInfo % Constraint
1215
PRINT*, ParEnv % MyPE, 'Assigning constraint', IMBdryConstraint(i), &
1216
'based off mindist:', PartMinDist
1217
END IF
1218
END DO
1219
1220
IF(Boss) THEN
1221
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1222
buffer2 = IMBdryConstraint
1223
CALL MPI_Reduce(buffer2, &
1224
#else
1225
CALL MPI_Reduce(MPI_IN_PLACE, &
1226
#endif
1227
IMBdryConstraint, IMBdryCount, MPI_INTEGER, &
1228
MPI_MAX, 0, ELMER_COMM_WORLD, ierr)
1229
ELSE
1230
CALL MPI_Reduce(IMBdryConstraint, IMBdryConstraint, IMBdryCount, MPI_INTEGER, &
1231
MPI_MAX, 0, ELMER_COMM_WORLD, ierr)
1232
END IF
1233
END IF
1234
1235
1236
IF(Boss) THEN
1237
!-----------------------------------------------------------------
1238
! Cycle elements, deleting any which lie wholly on a margin
1239
!-----------------------------------------------------------------
1240
1241
ALLOCATE(DeleteMe( IsoMesh % NumberOfBulkElements ))
1242
DeleteMe = .FALSE.
1243
DO i=1, IsoMesh % NumberOfBulkElements
1244
Element => IsoMesh % Elements(i)
1245
N = Element % TYPE % NumberOfNodes
1246
IF(ALL(IMOnMargin(Element % NodeIndexes(1:N)))) THEN
1247
!delete the element, we don't need it
1248
DeleteMe(i) = .TRUE.
1249
END IF
1250
END DO
1251
1252
PRINT *, 'debug, ', COUNT(DeleteMe), ' elements marked for deletion from IsoMesh.'
1253
1254
ALLOCATE(WorkElements(COUNT(.NOT. DeleteMe)))
1255
WorkElements = PACK(IsoMesh % Elements, (.NOT. DeleteMe))
1256
1257
IF(Debug) THEN
1258
DO i=1, SIZE(WorkElements)
1259
PRINT *, 'Workelements', i, ' nodeindexes: ', &
1260
WorkElements(i) % NodeIndexes
1261
END DO
1262
END IF
1263
1264
DO i=1, IsoMesh % NumberOfBulkElements
1265
IF(DeleteMe(i)) CALL DeallocateElement(IsoMesh % Elements(i))
1266
END DO
1267
1268
DEALLOCATE(DeleteMe)
1269
IF(ASSOCIATED(IsoMesh % Elements)) DEALLOCATE(IsoMesh % Elements)
1270
IsoMesh % Elements => WorkElements
1271
IsoMesh % NumberOfBulkElements = SIZE(WorkElements)
1272
NULLIFY(WorkElements)
1273
1274
Counter=0
1275
DO i=1,IsoMesh % NumberOfBulkElements
1276
NodeIndexes => Isomesh % Elements(i) % NodeIndexes
1277
IF(IMOnMargin(NodeIndexes(1)) .EQV. IMOnMargin(NodeIndexes(2))) CYCLE
1278
counter = counter + 1
1279
IMBdryENums(Counter) = i
1280
END DO
1281
IF(counter /= IMBdryCount) THEN
1282
IMBdryCount = Counter
1283
ALLOCATE(WorkInt(IMBdryCount))
1284
WorkInt = IMBdryENums(1:IMBdryCount)
1285
DEALLOCATE(IMBdryENums)
1286
ALLOCATE(IMBdryENums(IMBdryCount))
1287
IMBdryENums = WorkInt
1288
DEALLOCATE(WorkInt)
1289
END IF
1290
1291
ALLOCATE(IMElmOnFront(IsoMesh % NumberOfBulkElements), &
1292
IMElmOnLeft(IsoMesh % NumberOfBulkElements),&
1293
IMElmOnRight(IsoMesh % NumberOfBulkElements))
1294
IMElmOnFront=.FALSE.; IMElmOnLeft=.FALSE.; IMElmOnRight=.FALSE.
1295
1296
! remember IMOnMargin - nodes, IMBdryConstrain - Elems
1297
DO i=1,IMBdryCount
1298
k = IMBdryENums(i)
1299
PRINT*, i, k, IMBdryConstraint(i)
1300
IF(k==0) CALL FATAL(SolverName, 'IMBdryConstraint = zero')
1301
IF(IMBdryConstraint(i) == FrontConstraint) IMElmOnFront(k) = .TRUE.
1302
IF(IMBdryConstraint(i) == LeftConstraint) IMElmOnLeft(k) = .TRUE.
1303
IF(IMBdryConstraint(i) == RightConstraint) IMElmOnRight(k) = .TRUE.
1304
NodeIndexes => Isomesh % Elements(k) % NodeIndexes
1305
DO j=1,2
1306
IF(.NOT. IMOnMargin(NodeIndexes(j))) CYCLE
1307
IF(IMBdryConstraint(i) == FrontConstraint) IMNOnFront(NodeIndexes(j)) = .TRUE.
1308
IF(IMBdryConstraint(i) == LeftConstraint) IMNOnLeft(NodeIndexes(j)) = .TRUE.
1309
IF(IMBdryConstraint(i) == RightConstraint) IMNOnRight(NodeIndexes(j)) = .TRUE.
1310
END DO
1311
END DO
1312
1313
IF(Debug) THEN
1314
PRINT *, 'debug, count IMNOnFront: ', COUNT(IMNOnFront), 'IMElmOnFront', COUNT(IMElmOnFront)
1315
PRINT *, 'debug, count IMNOnLeft: ', COUNT(IMNOnLeft), 'IMElmOnLeft', COUNT(IMElmOnLeft)
1316
PRINT *, 'debug, count IMNOnRight: ', COUNT(IMNOnRight), 'IMElmOnRight', COUNT(IMElmOnRight)
1317
PRINT *, 'debug, count IMOnMargin: ', COUNT(IMOnMargin)
1318
PRINT *, 'debug, isomesh bulkelements,', IsoMesh % NumberOfBulkElements
1319
PRINT *, 'debug, isomesh boundaryelements,', IsoMesh % NumberOfBoundaryElements
1320
PRINT *, 'debug, size isomesh elements: ', SIZE(IsoMesh % Elements)
1321
END IF
1322
1323
!Find chains which make contact with front twice
1324
!===============================================
1325
! NOTES:
1326
! Because intersections lie exactly on nodes, IsoSurface
1327
! creates several nodes per real node, and several 202 elems.
1328
! This probably isn't a problem, but we'll see...
1329
! Also, we have deleted unnecessary elements, but their nodes
1330
! remain, but this also isn't a problem as InterpVarToVar
1331
! cycles elements, not nodes.
1332
CALL FindCrevassePaths(IsoMesh, IMOnMargin, CrevassePaths, PathCount)
1333
CALL CheckCrevasseNodes(IsoMesh, CrevassePaths, IMNOnLeft, IMNOnRight)
1334
!CALL ValidateCrevassePaths(IsoMesh, CrevassePaths, FrontOrientation, PathCount,&
1335
! IMOnLeft, IMOnRight, .FALSE.)
1336
IF(Debug) THEN
1337
PRINT*, 'Debug: Crevs PreChecks'
1338
counter=0
1339
CurrentPath => CrevassePaths
1340
DO WHILE(ASSOCIATED(CurrentPath))
1341
counter=counter+1
1342
PRINT*, counter, ',',counter+CurrentPath % NumberOfNodes-1, ','
1343
counter=counter+CurrentPath % NumberOfNodes-1
1344
CurrentPath => CurrentPath % Next
1345
END DO
1346
CurrentPath => CrevassePaths
1347
DO WHILE(ASSOCIATED(CurrentPath))
1348
DO i=1, CurrentPath % NumberOfNodes
1349
PRINT*, IsoMesh % Nodes % x(CurrentPath % NodeNumbers(i)),',',&
1350
IsoMesh % Nodes % y(CurrentPath % NodeNumbers(i)), ','
1351
END DO
1352
CurrentPath => CurrentPath % Next
1353
END DO
1354
END IF
1355
1356
! do not remove crevs inside each other as the bigger crev may be severely constricted
1357
CALL RemoveInvalidCrevs(IsoMesh, CrevassePaths, EdgeX, EdgeY, .FALSE., .FALSE., &
1358
IMNOnleft, IMNOnRight, IMNOnFront, gridmesh_dx)
1359
CALL ValidateNPCrevassePaths(IsoMesh, CrevassePaths, IMNOnLeft, IMNOnRight, &
1360
FrontLeft, FrontRight, EdgeX, EdgeY, LatCalvMargins, gridmesh_dx)
1361
! this call to remove crevs within other crevs
1362
CALL RemoveInvalidCrevs(IsoMesh, CrevassePaths, EdgeX, EdgeY, .TRUE., .TRUE., GridSize=gridmesh_dx)
1363
1364
IF(Debug) THEN
1365
PRINT*, 'Debug: Crevs PostChecks'
1366
counter=0
1367
CurrentPath => CrevassePaths
1368
DO WHILE(ASSOCIATED(CurrentPath))
1369
counter=counter+1
1370
PRINT*, counter, ',',counter+CurrentPath % NumberOfNodes-1, ','
1371
counter=counter+CurrentPath % NumberOfNodes-1
1372
CurrentPath => CurrentPath % Next
1373
END DO
1374
CurrentPath => CrevassePaths
1375
DO WHILE(ASSOCIATED(CurrentPath))
1376
DO i=1, CurrentPath % NumberOfNodes
1377
PRINT*, IsoMesh % Nodes % x(CurrentPath % NodeNumbers(i)),',',&
1378
IsoMesh % Nodes % y(CurrentPath % NodeNumbers(i)), ','
1379
END DO
1380
CurrentPath => CurrentPath % Next
1381
END DO
1382
END IF
1383
1384
IF(Debug) THEN
1385
PRINT *,'Crevasse Path Count: ', PathCount
1386
CurrentPath => CrevassePaths
1387
DO WHILE(ASSOCIATED(CurrentPath))
1388
PRINT *, 'New Crevasse Path:'
1389
PRINT *, 'Current path elems:', CurrentPath % ElementNumbers
1390
PRINT *, 'Current path nodes:', CurrentPath % NodeNumbers
1391
DO i=1, CurrentPath % NumberOfNodes
1392
PRINT *,'path ID', CurrentPath % ID, 'path node: ',i,&
1393
' x: ',IsoMesh % Nodes % x(CurrentPath % NodeNumbers(i)),&
1394
' y: ',IsoMesh % Nodes % y(CurrentPath % NodeNumbers(i))
1395
END DO
1396
PRINT *, ''
1397
CurrentPath => CurrentPath % Next
1398
END DO
1399
END IF
1400
1401
ALLOCATE(DeleteMe(IsoMesh % NumberOfBulkElements))
1402
DeleteMe = .FALSE.
1403
1404
DO i=1, IsoMesh % NumberOfBulkElements
1405
IF(ElementPathID(CrevassePaths, i) == 0) DeleteMe(i) = .TRUE.
1406
END DO
1407
1408
IF(Debug) THEN
1409
WRITE (Message,'(A,i0,A)') "Deleting ",COUNT(DeleteMe)," elements which &
1410
&don't lie on valid crevasse paths."
1411
CALL Info(SolverName, Message)
1412
END IF
1413
1414
ALLOCATE(WorkElements(COUNT(.NOT. DeleteMe)))
1415
WorkElements = PACK(IsoMesh % Elements, (.NOT. DeleteMe))
1416
1417
DO i=1, IsoMesh % NumberOfBulkElements
1418
IF(DeleteMe(i)) CALL DeallocateElement(IsoMesh % Elements(i))
1419
END DO
1420
1421
DEALLOCATE(DeleteMe)
1422
DEALLOCATE(IsoMesh % Elements)
1423
IsoMesh % Elements => WorkElements
1424
IsoMesh % NumberOfBulkElements = SIZE(WorkElements)
1425
NULLIFY(WorkElements)
1426
1427
!InterpVarToVar only looks at boundary elements. In reality, the
1428
!two are equivalent here because all are 202 elements.
1429
IsoMesh % NumberOfBoundaryElements = IsoMesh % NumberOfBulkElements
1430
IsoMesh % NumberOfBulkElements = 0
1431
IsoMesh % MaxElementNodes = 2
1432
ELSE
1433
!not boss, allocate dummy IsoMesh
1434
!all front partitions will ask root for interp
1435
IsoMesh => AllocateMesh()
1436
ALLOCATE(IsoMesh % Nodes % x(0),&
1437
IsoMesh % Nodes % y(0),&
1438
IsoMesh % Nodes % z(0))
1439
END IF !Boss
1440
1441
1442
! calculate signed distance here
1443
ALLOCATE(WorkReal(NoNodes))
1444
WorkReal = 0.0_dp
1445
CALL VariableAdd(Mesh % Variables, Mesh, Solver, &
1446
"SignedDistance", 1, WorkReal, CalvingPerm) ! TO DO check this is correct perm
1447
NULLIFY(WorkReal)
1448
SignDistVar => VariableGet(Mesh % Variables, "SignedDistance", .TRUE.)
1449
SignDistValues => SignDistVar % Values
1450
SignDistPerm => SignDistVar % Perm
1451
CurrentPath => CrevassePaths
1452
1453
IF(Debug) THEN
1454
PRINT *, ' IsoMesh % NumberOfNodes', IsoMesh % NumberOfNodes
1455
PRINT *, 'IsoMesh % NumberOfBoundaryElements', IsoMesh % NumberOfBoundaryElements
1456
PRINT *, 'PathCount', PathCount
1457
END IF
1458
1459
! boss contains isomesh and crevpaths
1460
IF (Boss) THEN
1461
IF(IsoMesh % NumberOfNodes > 0 ) THEN ! check if there is any valid paths
1462
CurrentPath => CrevassePaths
1463
NoCrevNodes=0 ! Number of Crevasse nodes
1464
NoPaths=0
1465
1466
DO WHILE(ASSOCIATED(CurrentPath))
1467
NoPaths=NoPaths+1
1468
NoCrevNodes=NoCrevNodes+CurrentPath % NumberOfNodes
1469
CurrentPath => CurrentPath % Next
1470
END DO
1471
1472
IF(NoPaths > 0) THEN
1473
1474
ALLOCATE(CrevX(NoCrevNodes),CrevY(NoCrevNodes),&
1475
CrevEnd(NoPaths),CrevStart(NoPaths),CrevOrient(NoPaths,2),&
1476
CrevLR(NoPaths))
1477
1478
j=0
1479
CurrentPath => CrevassePaths
1480
DO WHILE(ASSOCIATED(CurrentPath))
1481
j=j+1
1482
CrevOrient(j,:) = CurrentPath % Orientation
1483
CrevLR(j) = CurrentPath % LeftToRight
1484
CurrentPath => CurrentPath % Next
1485
END DO
1486
1487
CurrentPath => CrevassePaths
1488
j=1;k=1
1489
n=CurrentPath % ID ! first ID may not be 1..
1490
CrevStart(1)=1
1491
DO WHILE(ASSOCIATED(CurrentPath))
1492
DO i=1,CurrentPath % NumberOfNodes
1493
CrevX(j)=IsoMesh % Nodes % x(CurrentPath % NodeNumbers(i))
1494
CrevY(j)=IsoMesh % Nodes % y(CurrentPath % NodeNumbers(i))
1495
IF(n < CurrentPath % ID .AND. CurrentPath % ID>0) THEN ! non valid paths set to 0?
1496
CrevEnd(k)=j-1
1497
IF(k < NoPaths) CrevStart(k+1)=j
1498
n=CurrentPath % ID
1499
k=k+1
1500
END IF
1501
j=j+1
1502
END DO
1503
CurrentPath => CurrentPath % Next
1504
END DO
1505
IF(j/=NoCrevNodes+1) PRINT *, 'programming error'
1506
CrevEnd(NoPaths)=NoCrevNodes
1507
IF (Debug) THEN
1508
PRINT *, 'number of crevasse nodes', NoCrevNodes
1509
PRINT *, 'crevasse start numbers', CrevStart
1510
PRINT *, 'crevasse end numbers',CrevEnd
1511
END IF
1512
END IF
1513
END IF
1514
1515
NodeHolder(3)=0.0_dp
1516
DO i=1,NoPaths
1517
NodeHolder(1) = CrevX(CrevStart(i))
1518
NodeHolder(2) = CrevY(CrevStart(i))
1519
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
1520
y_coord(1) = NodeHolder(2)
1521
NodeHolder(1) = CrevX(CrevEnd(i))
1522
NodeHolder(2) = CrevY(CrevEnd(i))
1523
! NodeHolder(3) = FrontNodes % z(FrontLineCount)
1524
!TODO - Ask Eef about this ---^
1525
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
1526
y_coord(2) = NodeHolder(2)
1527
LeftToRight = y_coord(2) > y_coord(1) ! TODO check if this doesn't break for special cases
1528
IF(LeftToRight) THEN
1529
CrevX(CrevStart(i):CrevEnd(i))=CrevX(CrevEnd(i):CrevStart(i):-1)
1530
CrevY(CrevStart(i):CrevEnd(i))=CrevY(CrevEnd(i):CrevStart(i):-1)
1531
END IF
1532
END DO
1533
IF (Debug) Print *, CrevX
1534
END IF
1535
1536
1537
CALL MPI_BCAST(NoCrevNodes,1,MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1538
CALL MPI_BCAST(NoPaths,1,MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1539
IF (.NOT. Boss) ALLOCATE(CrevX(NoCrevNodes),CrevY(NoCrevNodes),&
1540
CrevEnd(NoPaths),CrevStart(NoPaths), CrevOrient(NoPaths,2),&
1541
CrevLR(NoPaths))! (because already created on boss)
1542
CALL MPI_BCAST(CrevX,NoCrevNodes,MPI_DOUBLE_PRECISION, 0, ELMER_COMM_WORLD, ierr)
1543
CALL MPI_BCAST(CrevY,NoCrevNodes,MPI_DOUBLE_PRECISION, 0, ELMER_COMM_WORLD, ierr)
1544
CALL MPI_BCAST(CrevEnd,NoPaths,MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1545
CALL MPI_BCAST(CrevStart,NoPaths,MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1546
CALL MPI_BCAST(CrevOrient,NoPaths*2,MPI_DOUBLE_PRECISION, 0, ELMER_COMM_WORLD, ierr)
1547
CALL MPI_BCAST(CrevLR,NoPaths,MPI_LOGICAL, 0, ELMER_COMM_WORLD, ierr)
1548
1549
! if there are no crevasses no need to calculate signed distance
1550
IF(NoCrevNodes == 0) THEN
1551
CalvingOccurs = .FALSE.
1552
1553
CALL SParIterAllReduceOR(CalvingOccurs)
1554
CALL ListAddLogical( Model % Simulation, 'CalvingOccurs', CalvingOccurs )
1555
1556
!EqName = ListGetString( Params, "Remesh Equation Name", Found, UnfoundFatal = .TRUE.)
1557
!DO j=1,Model % NumberOfSolvers
1558
! IF(ListGetString(Model % Solvers(j) % Values, "Equation") == EqName) THEN
1559
! Found = .TRUE.
1560
!Turn off (or on) the solver
1561
!If CalvingOccurs, (switch) off = .true.
1562
! CALL SwitchSolverExec(Model % Solvers(j), .NOT. CalvingOccurs)
1563
! IF(.NOT. CalvingOccurs) CALL ResetMeshUpdate(Model, Model % Solvers(j))
1564
1565
! if remeshing if skipped need to ensure calving solvers are not paused
1566
! IF(.NOT. CalvingOccurs) CALL PauseCalvingSolvers(Model, Model % Solvers(j) % Values, .FALSE.)
1567
1568
! EXIT
1569
! END IF
1570
!END DO
1571
CalvingValues(CalvingPerm) = DistValues(DistPerm) + 1
1572
CALL WARN(SolverName, 'No crevasses so not calculating signed distance')
1573
!RETURN
1574
ELSE
1575
!above IF(Parallel) but that's assumed implicitly
1576
!make sure that code works for empty isomesh as well!!
1577
1578
! get calving polygons
1579
IF(Boss) THEN
1580
CALL GetCalvingPolygons(IsoMesh, CrevassePaths, EdgeX, EdgeY, Polygon, PolyStart, PolyEnd, gridmesh_dx)
1581
IF(Debug) THEN
1582
PRINT*, 'Calving Polygons ----'
1583
DO i=1, SIZE(PolyStart)
1584
PRINT*, PolyStart(i), ',', PolyEnd(i), ','
1585
END DO
1586
DO i=1, SIZE(Polygon(1,:))
1587
PRINT*, Polygon(1,i), ',', Polygon(2,i), ','
1588
END DO
1589
END IF
1590
! release crevasse paths
1591
IF(ASSOCIATED(CrevassePaths)) CALL ReleaseCrevassePaths(CrevassePaths)
1592
END IF
1593
1594
! send bdrynode info to all procs
1595
CALL MPI_BARRIER(ELMER_COMM_WORLD, ierr)
1596
IF(Boss) counter=SIZE(Polygon(1,:))
1597
CALL MPI_BCAST(counter, 1, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1598
IF(.NOT. Boss) ALLOCATE(Polygon(2, counter), PolyStart(NoPaths), &
1599
PolyEnd(NoPaths))
1600
CALL MPI_BCAST(Polygon, Counter*2, MPI_DOUBLE_PRECISION, 0, ELMER_COMM_WORLD, ierr)
1601
CALL MPI_BCAST(PolyEnd, NoPaths, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1602
CALL MPI_BCAST(PolyStart, NoPaths, MPI_INTEGER, 0, ELMER_COMM_WORLD, ierr)
1603
1604
CALL CheckLateralCalving(Mesh, Params, FrontPerm, CrevX,CrevY,CrevStart,CrevEnd, CrevOrient,&
1605
CrevLR, Polygon, PolyStart, PolyEnd)
1606
NoPaths = SIZE(CrevStart)
1607
1608
ALLOCATE(IsCalvingNode(Mesh % NumberOfNodes))
1609
IsCalvingNode=.FALSE.
1610
1611
IF (NoPaths > 0 ) THEN
1612
DO i=1,Solver % Mesh % NumberOfNodes
1613
IF (Debug) PRINT *, ParEnv % MyPE, 'For node i', i,' out of ',Solver % Mesh % NumberOfNodes
1614
xx = Solver % Mesh % Nodes % x(i)
1615
yy = Solver % Mesh % Nodes % y(i)
1616
MinDist = HUGE(1.0_dp)
1617
1618
inside=.FALSE.
1619
ClosestCrev=0
1620
DO j=1, NoPaths
1621
ALLOCATE(PathPoly(2, PolyEnd(j)-PolyStart(j)+1))
1622
PathPoly = Polygon(:, PolyStart(j):PolyEnd(j))
1623
inside = PointInPolygon2D(PathPoly, (/xx, yy/))
1624
DEALLOCATE(PathPoly)
1625
IF(inside) THEN
1626
ClosestCrev = j
1627
EXIT
1628
END IF
1629
END DO
1630
1631
! TO DO; brute force here, checking all crevasse segments, better to find closest crev first
1632
DO j=1, NoPaths
1633
IF(inside .AND. j/=ClosestCrev) CYCLE
1634
DO k=CrevStart(j), CrevEnd(j)-1
1635
xl=CrevX(k);yl=CrevY(k)
1636
xr=CrevX(k+1);yr=CrevY(k+1)
1637
TempDist=PointLineSegmDist2D( (/xl,yl/),(/xr,yr/), (/xx,yy/))
1638
IF(TempDist <= (ABS(MinDist)+AEPS) ) THEN ! as in ComputeDistanceWithDirection
1639
! updated so no longer based off an angle. This caused problems when the front was
1640
! no longer projectable. Instead the node is marked to calve if it is inside the calving polygon.
1641
! PointInPolygon2D based of the winding number algorithm
1642
IF(j==ClosestCrev) THEN ! inside calved area
1643
IsCalvingNode(i) = .TRUE.
1644
MinDist = -TempDist
1645
ELSE
1646
MinDist = TempDist
1647
END IF
1648
jmin=k ! TO DO rm jmin? not necessary anymore
1649
END IF
1650
END DO
1651
END DO
1652
SignDistValues(SignDistPerm(i)) = MinDist
1653
IF(Debug) PRINT *, ParEnv % MyPE, i, 'Shortest distance to closest segment in crevassepath ',MinDist
1654
IF(Debug) PRINT *, ParEnv % MyPE, i, 'jmin is ',jmin
1655
END DO
1656
ELSE
1657
SignDistValues = 0.0_dp
1658
END IF
1659
1660
Debug = .FALSE.
1661
CalvingValues(CalvingPerm) = SignDistValues(SignDistPerm)
1662
IF(MINVAL(SignDistValues) < - AEPS) CalvingOccurs = .TRUE.
1663
1664
1665
! TO DO check in each partition whether calving sizes are sufficient and whether calving occurs by
1666
! IF( integrate negative part of signdistance < -MinCalvingSize) CalvingOccurs = .TRUE.
1667
! IsCalvingNode = (SignDistValues < 0 ) if they have same perm, but not actually used?
1668
! then parallel reduce with MPI_LOR on 'CalvingOccurs'
1669
! NOTE; what happens if calving event is divided over 2 partitions with insignificant in each
1670
! but significant in total? should something be done to avoid that they're filtered out?
1671
!Pass CalvingOccurs to all processes, add to simulation
1672
CALL SParIterAllReduceOR(CalvingOccurs)
1673
CALL ListAddLogical( Model % Simulation, 'CalvingOccurs', CalvingOccurs )
1674
1675
IF(CalvingOccurs) THEN
1676
CALL Info( SolverName, 'Calving Event',Level=1)
1677
ELSE
1678
!If only insignificant calving events occur, reset everything
1679
!CalvingValues = 0.0_dp
1680
IsCalvingNode = .FALSE.
1681
END IF
1682
1683
!if calving doesn't occur then no need to run remeshing solver
1684
!EqName = ListGetString( Params, "Remesh Equation Name", Found, UnfoundFatal = .TRUE.)
1685
!DO j=1,Model % NumberOfSolvers
1686
! IF(ListGetString(Model % Solvers(j) % Values, "Equation") == EqName) THEN
1687
! Found = .TRUE.
1688
!Turn off (or on) the solver
1689
!If CalvingOccurs, (switch) off = .true.
1690
! CALL SwitchSolverExec(Model % Solvers(j), .NOT. CalvingOccurs)
1691
! IF(.NOT. CalvingOccurs) CALL ResetMeshUpdate(Model, Model % Solvers(j))
1692
1693
! if remeshing if skipped need to ensure calving solvers are not paused
1694
! IF(.NOT. CalvingOccurs) CALL PauseCalvingSolvers(Model, Model % Solvers(j) % Values, .FALSE.)
1695
1696
! EXIT
1697
! END IF
1698
!END DO
1699
1700
!IF(.NOT. Found) THEN
1701
! WRITE (Message,'(A,A,A)') "Failed to find Equation Name: ",EqName,&
1702
! " to switch off after calving."
1703
! CALL Fatal(SolverName,Message)
1704
!END IF
1705
END IF
1706
1707
! because isomesh has no bulk?
1708
IsoMesh % NumberOfBulkElements = IsoMesh % NumberOfBoundaryElements
1709
IsoMesh % NumberOfBoundaryElements = 0
1710
1711
1712
!=========================================================
1713
! DONE, just plane VTU and deallocations left
1714
!=========================================================
1715
1716
!-----------------------------------------------------------
1717
! Call ResultOutputSolver in faux-serial to output calving
1718
! plane for debugging
1719
!-----------------------------------------------------------
1720
IF(Boss) THEN
1721
VTUSolverName = "calvingresultoutput"
1722
DO i=1,Model % NumberOfSolvers
1723
IF(GetString(Model % Solvers(i) % Values, 'Equation') == VTUSolverName) THEN
1724
VTUOutputSolver => Model % Solvers(i)
1725
EXIT
1726
END IF
1727
END DO
1728
IF(.NOT. ASSOCIATED(VTUOutputSolver)) &
1729
CALL Fatal("Calving Remesh","Couldn't find VTUSolver")
1730
1731
PEs = ParEnv % PEs
1732
ParEnv % PEs = 1
1733
1734
WorkMesh => Model % Mesh
1735
WorkMesh2 => Model % Meshes
1736
1737
Model % Mesh => PlaneMesh
1738
Model % Meshes => PlaneMesh
1739
VTUOutputSolver % Mesh => PlaneMesh
1740
PlaneMesh % Next => IsoMesh
1741
1742
VTUOutputSolver % dt = dt
1743
VTUOutputSolver % NumberOfActiveElements = 0
1744
Model % Solver => VTUOutputSolver
1745
1746
CALL SingleSolver( Model, VTUOutputSolver, VTUOutputSolver % dt, TransientSimulation )
1747
1748
Model % Solver => Solver
1749
Model % Mesh => WorkMesh
1750
Model % Meshes => WorkMesh2
1751
PlaneMesh % Next => NULL()
1752
VTUOutputSolver % Mesh => WorkMesh
1753
1754
ParEnv % PEs = PEs
1755
1756
END IF
1757
1758
rt = RealTime() - rt0
1759
IF(ParEnv % MyPE == 0) &
1760
PRINT *, 'Time taken up to finish up: ', rt
1761
rt0 = RealTime()
1762
1763
!-----------------------------------------------------------
1764
! Tidy up and deallocate
1765
!-----------------------------------------------------------
1766
1767
FirstTime = .FALSE.
1768
1769
PCSolver % Variable => NULL()
1770
PCSolver % Matrix % Perm => NULL()
1771
CALL FreeMatrix(PCSolver % Matrix)
1772
CALL ReleaseMesh(PlaneMesh)
1773
! isomesh doesn't seem to released as part of planemesh
1774
CALL ReleaseMesh(IsoMesh)
1775
1776
DEALLOCATE(TopPerm, BotPerm, LeftPerm, RightPerm, FrontPerm, InflowPerm)
1777
1778
IF(Parallel) CALL MPI_BARRIER(ELMER_COMM_WORLD, ierr)
1779
1780
CONTAINS
1781
1782
!Returns extent: min_x, max_x, min_y, max_y of front in rotated coord system
1783
FUNCTION GetFrontExtent(Mesh, RotationMatrix, DistVar, SearchDist, Buffer) RESULT(Extent)
1784
TYPE(Mesh_t), POINTER :: Mesh
1785
TYPE(Variable_t), POINTER :: DistVar
1786
REAL(KIND=dp) :: SearchDist, RotationMatrix(3,3), Extent(4), Buffer
1787
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1788
REAL(KIND=dp) :: buffer2
1789
#endif
1790
!------------------------------
1791
REAL(KIND=dp) :: NodeHolder(3)
1792
INTEGER :: i,ierr
1793
1794
!Get the min,max x and y in rotated coords:
1795
extent(1) = HUGE(extent(1))
1796
extent(2) = -HUGE(extent(1))
1797
extent(3) = HUGE(extent(1))
1798
extent(4) = -HUGE(extent(1))
1799
1800
DO i=1,Mesh % NumberOfNodes
1801
1802
IF(DistVar % Values(DistVar % Perm(i)) > SearchDist) CYCLE
1803
1804
NodeHolder(1) = Mesh % Nodes % x(i)
1805
NodeHolder(2) = Mesh % Nodes % y(i)
1806
NodeHolder(3) = Mesh % Nodes % z(i)
1807
NodeHolder = MATMUL(RotationMatrix, NodeHolder)
1808
1809
extent(1) = MIN(extent(1), NodeHolder(2))
1810
extent(2) = MAX(extent(2), NodeHolder(2))
1811
extent(3) = MIN(extent(3), NodeHolder(3))
1812
extent(4) = MAX(extent(4), NodeHolder(3))
1813
1814
END DO
1815
1816
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1817
buffer2 = extent(1)
1818
CALL MPI_AllReduce(buffer2, &
1819
#else
1820
CALL MPI_AllReduce(MPI_IN_PLACE, &
1821
#endif
1822
extent(1), 1, MPI_DOUBLE_PRECISION, MPI_MIN, ELMER_COMM_WORLD, ierr)
1823
1824
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1825
buffer2 = extent(2)
1826
CALL MPI_AllReduce(buffer2, &
1827
#else
1828
CALL MPI_AllReduce(MPI_IN_PLACE, &
1829
#endif
1830
extent(2), 1, MPI_DOUBLE_PRECISION, MPI_MAX, ELMER_COMM_WORLD, ierr)
1831
1832
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1833
buffer2 = extent(3)
1834
CALL MPI_AllReduce(buffer2, &
1835
#else
1836
CALL MPI_AllReduce(MPI_IN_PLACE, &
1837
#endif
1838
extent(3), 1, MPI_DOUBLE_PRECISION, MPI_MIN, ELMER_COMM_WORLD, ierr)
1839
1840
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1841
buffer2 = extent(4)
1842
CALL MPI_AllReduce(buffer2, &
1843
#else
1844
CALL MPI_AllReduce(MPI_IN_PLACE, &
1845
#endif
1846
extent(4), 1, MPI_DOUBLE_PRECISION, MPI_MAX, ELMER_COMM_WORLD, ierr)
1847
1848
extent(1) = extent(1) - buffer
1849
extent(2) = extent(2) + buffer
1850
extent(3) = extent(3) - buffer
1851
extent(4) = extent(4) + buffer
1852
END FUNCTION GetFrontExtent
1853
1854
!subroutine to check if lateral calving would be evacuated or would jam on fjord walls
1855
SUBROUTINE CheckLateralCalving(Mesh, SolverParams, FrontPerm, CrevX,CrevY,CrevStart,CrevEnd, CrevOrient,&
1856
CrevLR, Polygon, PolyStart, PolyEnd)
1857
1858
IMPLICIT NONE
1859
1860
TYPE(Mesh_t), POINTER :: Mesh
1861
TYPE(Valuelist_t), POINTER :: SolverParams
1862
INTEGER, POINTER :: FrontPerm(:)
1863
REAL(KIND=dp),ALLOCATABLE :: CrevX(:),CrevY(:),CrevOrient(:,:),Polygon(:,:)
1864
INTEGER, ALLOCATABLE :: CrevStart(:),CrevEnd(:),PolyStart(:),PolyEnd(:)
1865
LOGICAL, ALLOCATABLE :: CrevLR(:)
1866
!--------------------------------------------------------------------------------------
1867
TYPE(Solver_t), POINTER :: AdvSolver
1868
TYPE(Valuelist_t), POINTER :: AdvParams
1869
TYPE(Variable_t), POINTER :: SignDistVar
1870
INTEGER, POINTER :: SignDistPerm(:)
1871
REAL(KIND=dp), POINTER :: SignDistValues(:)
1872
INTEGER :: i,j,NoPaths,ClosestCrev,Naux,Nl,Nr,ok,RemovePoints
1873
REAL(KIND=dp) :: xx,yy,MinDist,a1(2),a2(2),b1(2),b2(2),Orientation(2),intersect(2), crevdist,&
1874
TempDist, SecDist
1875
INTEGER, ALLOCATABLE :: NodeClosestCrev(:), WorkInt(:)
1876
REAL(KIND=dp), ALLOCATABLE :: PathPoly(:,:),xL(:),yL(:),xR(:),yR(:),WorkReal(:),WorkReal2(:,:)
1877
LOGICAL :: inside,does_intersect,FoundIntersect
1878
LOGICAL, ALLOCATABLE :: RemoveCrev(:), WorkLogical(:)
1879
#ifdef ELMER_BROKEN_MPI_IN_PLACE
1880
LOGICAL, ALLOCATABLE :: buffer(:)
1881
#endif
1882
CHARACTER(MAX_NAME_LEN) :: FuncName="CheckLateralCalving", Adv_EqName, LeftRailFName, RightRailFName
1883
INTEGER, PARAMETER :: io=20
1884
1885
SignDistVar => VariableGet(Mesh % Variables, "SignedDistance", .TRUE.)
1886
SignDistValues => SignDistVar % Values
1887
SignDistPerm => SignDistVar % Perm
1888
1889
NoPaths = SIZE(CrevStart)
1890
1891
ALLOCATE(NodeClosestCrev(Mesh % NumberOfNodes))
1892
1893
DO i=1, Mesh % NumberOfNodes
1894
1895
IF(FrontPerm(i) == 0) CYCLE
1896
1897
xx = Solver % Mesh % Nodes % x(i)
1898
yy = Solver % Mesh % Nodes % y(i)
1899
MinDist = HUGE(1.0_dp)
1900
1901
inside=.FALSE.
1902
ClosestCrev=0
1903
DO j=1, NoPaths
1904
ALLOCATE(PathPoly(2, PolyEnd(j)-PolyStart(j)+1))
1905
PathPoly = Polygon(:, PolyStart(j):PolyEnd(j))
1906
inside = PointInPolygon2D(PathPoly, (/xx, yy/))
1907
DEALLOCATE(PathPoly)
1908
IF(inside) THEN
1909
ClosestCrev = j
1910
NodeClosestCrev(i) = j
1911
EXIT
1912
END IF
1913
END DO
1914
1915
! TO DO; brute force here, checking all crevasse segments, better to find closest crev first
1916
DO j=1, NoPaths
1917
IF(inside .AND. j/=ClosestCrev) CYCLE
1918
DO k=CrevStart(j), CrevEnd(j)-1
1919
a1(1)=CrevX(k);a1(2)=CrevY(k)
1920
a2(1)=CrevX(k+1);a2(2)=CrevY(k+1)
1921
TempDist=PointLineSegmDist2D( a1,a2, (/xx,yy/))
1922
IF(TempDist <= (ABS(MinDist)+AEPS) ) THEN ! as in ComputeDistanceWithDirection
1923
! updated so no longer based off an angle. This caused problems when the front was
1924
! no longer projectable. Instead the node is marked to calve if it is inside the calving polygon.
1925
! PointInPolygon2D based of the winding number algorithm
1926
IF(j==ClosestCrev) THEN ! inside calved area
1927
MinDist = -TempDist
1928
ELSE
1929
MinDist = TempDist
1930
END IF
1931
jmin=k ! TO DO rm jmin? not necessary anymore
1932
END IF
1933
END DO
1934
END DO
1935
1936
!hold in dist values temporarily
1937
SignDistValues(SignDistPerm(i)) = MinDist
1938
END DO
1939
1940
Adv_EqName = ListGetString(SolverParams,"Front Advance Solver", UnfoundFatal=.TRUE.)
1941
! Locate CalvingAdvance Solver
1942
DO i=1,Model % NumberOfSolvers
1943
IF(GetString(Model % Solvers(i) % Values, 'Equation') == Adv_EqName) THEN
1944
AdvSolver => Model % Solvers(i)
1945
EXIT
1946
END IF
1947
END DO
1948
AdvParams => AdvSolver % Values
1949
1950
LeftRailFName = ListGetString(AdvParams, "Left Rail File Name", Found)
1951
IF(.NOT. Found) THEN
1952
CALL Info(FuncName, "Left Rail File Name not found, assuming './LeftRail.xy'")
1953
LeftRailFName = "LeftRail.xy"
1954
END IF
1955
Nl = ListGetInteger(AdvParams, "Left Rail Number Nodes", Found)
1956
IF(.NOT.Found) THEN
1957
WRITE(Message,'(A,A)') 'Left Rail Number Nodes not found'
1958
CALL FATAL(FuncName, Message)
1959
END IF
1960
!TO DO only do these things if firsttime=true?
1961
OPEN(unit = io, file = TRIM(LeftRailFName), status = 'old',iostat = ok)
1962
IF (ok /= 0) THEN
1963
WRITE(message,'(A,A)') 'Unable to open file ',TRIM(LeftRailFName)
1964
CALL FATAL(Trim(FuncName),Trim(message))
1965
END IF
1966
ALLOCATE(xL(Nl), yL(Nl))
1967
1968
! read data
1969
DO i = 1, Nl
1970
READ(io,*,iostat = ok, end=200) xL(i), yL(i)
1971
END DO
1972
200 Naux = Nl - i
1973
IF (Naux > 0) THEN
1974
WRITE(Message,'(I0,A,I0,A,A)') Naux,' out of ',Nl,' datasets in file ', TRIM(LeftRailFName)
1975
CALL INFO(Trim(FuncName),Trim(message))
1976
END IF
1977
CLOSE(io)
1978
RightRailFName = ListGetString(AdvParams, "Right Rail File Name", Found)
1979
IF(.NOT. Found) THEN
1980
CALL Info(FuncName, "Right Rail File Name not found, assuming './RightRail.xy'")
1981
RightRailFName = "RightRail.xy"
1982
END IF
1983
1984
Nr = ListGetInteger(AdvParams, "Right Rail Number Nodes", Found)
1985
IF(.NOT.Found) THEN
1986
WRITE(Message,'(A,A)') 'Right Rail Number Nodes not found'
1987
CALL FATAL(FuncName, Message)
1988
END IF
1989
!TO DO only do these things if firsttime=true?
1990
OPEN(unit = io, file = TRIM(RightRailFName), status = 'old',iostat = ok)
1991
1992
IF (ok /= 0) THEN
1993
WRITE(Message,'(A,A)') 'Unable to open file ',TRIM(RightRailFName)
1994
CALL FATAL(Trim(FuncName),Trim(message))
1995
END IF
1996
ALLOCATE(xR(Nr), yR(Nr))
1997
1998
! read data
1999
DO i = 1, Nr
2000
READ(io,*,iostat = ok, end=100) xR(i), yR(i)
2001
END DO
2002
100 Naux = Nr - i
2003
IF (Naux > 0) THEN
2004
WRITE(message,'(I0,A,I0,A,A)') Naux,' out of ',Nl,' datasets in file ', TRIM(RightRailFName)
2005
CALL INFO(Trim(FuncName),Trim(message))
2006
END IF
2007
CLOSE(io)
2008
2009
ALLOCATE(RemoveCrev(NoPaths))
2010
#ifdef ELMER_BROKEN_MPI_IN_PLACE
2011
ALLOCATE(buffer(NoPaths))
2012
#endif
2013
RemoveCrev = .FALSE.
2014
DO i=1, Mesh % NumberOfNodes
2015
2016
IF(FrontPerm(i) == 0) CYCLE
2017
IF(SignDistValues(SignDistPerm(i)) >= 0) CYCLE
2018
IF(RemoveCrev(NodeClosestCrev(i))) CYCLE
2019
2020
b1(1) = Solver % Mesh % Nodes % x(i)
2021
b1(2) = Solver % Mesh % Nodes % y(i)
2022
MinDist = HUGE(1.0_dp)
2023
2024
Orientation = CrevOrient(NodeClosestCrev(i),:)
2025
2026
IF(CrevLR(NodeClosestCrev(i))) THEN
2027
b2 = b1 - 10*Orientation
2028
ELSE
2029
b2 = b1 + 10*Orientation
2030
END IF
2031
2032
FoundIntersect = .FALSE.
2033
DO j=1, Nl-1
2034
a1 = (/xL(j), yL(j)/)
2035
a2 = (/xL(j+1), yL(j+1)/)
2036
IF(PointInPolygon2D(Polygon(:, PolyStart(NodeClosestCrev(i)):PolyEnd(NodeClosestCrev(i))),a1)) THEN
2037
DO k=CrevStart(NodeClosestCrev(i)), CrevEnd(NodeClosestCrev(i))-1
2038
CALL LineSegmentsIntersect (a1, a2, (/CrevX(k), CrevY(k)/), (/CrevX(k+1), CrevY(k+1)/),&
2039
intersect, does_intersect )
2040
IF(does_intersect) a1 = intersect
2041
END DO
2042
END IF
2043
IF(PointInPolygon2D(Polygon(:, PolyStart(NodeClosestCrev(i)):PolyEnd(NodeClosestCrev(i))),a2)) THEN
2044
DO k=CrevStart(NodeClosestCrev(i)), CrevEnd(NodeClosestCrev(i))-1
2045
CALL LineSegmentsIntersect (a1, a2, (/CrevX(k), CrevY(k)/), (/CrevX(k+1), CrevY(k+1)/),&
2046
intersect, does_intersect )
2047
IF(does_intersect) a2 = intersect
2048
END DO
2049
END IF
2050
IF(a1(1)==a2(1) .AND. a1(2)==a2(2)) CYCLE
2051
CALL LineSegmLineIntersect (a1, a2, b1, b2, intersect, does_intersect )
2052
2053
IF(.NOT. does_intersect) CYCLE
2054
tempdist = PointDist2D(b1,intersect)
2055
secdist = PointDist2D(b2, intersect)
2056
IF(secdist > tempdist) CYCLE
2057
IF(tempdist < mindist) THEN
2058
mindist = tempdist
2059
FoundIntersect = .TRUE.
2060
END IF
2061
END DO
2062
2063
IF(.NOT. FoundIntersect) THEN
2064
DO j=1, Nr-1
2065
a1 = (/xR(j), yR(j)/)
2066
a2 = (/xR(j+1), yR(j+1)/)
2067
IF(PointInPolygon2D(Polygon(:, PolyStart(NodeClosestCrev(i)):PolyEnd(NodeClosestCrev(i))),a1)) THEN
2068
DO k=CrevStart(NodeClosestCrev(i)), CrevEnd(NodeClosestCrev(i))-1
2069
CALL LineSegmentsIntersect (a1, a2, (/CrevX(k), CrevY(k)/), (/CrevX(k+1), CrevY(k+1)/),&
2070
intersect, does_intersect )
2071
IF(does_intersect) a1 = intersect
2072
END DO
2073
END IF
2074
IF(PointInPolygon2D(Polygon(:, PolyStart(NodeClosestCrev(i)):PolyEnd(NodeClosestCrev(i))),a2)) THEN
2075
DO k=CrevStart(NodeClosestCrev(i)), CrevEnd(NodeClosestCrev(i))-1
2076
CALL LineSegmentsIntersect (a1, a2, (/CrevX(k), CrevY(k)/), (/CrevX(k+1), CrevY(k+1)/),&
2077
intersect, does_intersect )
2078
IF(does_intersect) a2 = intersect
2079
END DO
2080
END IF
2081
IF(a1(1)==a2(1) .AND. a1(2)==a2(2)) CYCLE
2082
CALL LineSegmLineIntersect (a1, a2, b1, b2, intersect, does_intersect )
2083
IF(.NOT. does_intersect) CYCLE
2084
tempdist = PointDist2D(b1,intersect)
2085
secdist = PointDist2D(b2, intersect)
2086
IF(secdist > tempdist) CYCLE
2087
IF(tempdist < mindist) THEN
2088
mindist = tempdist
2089
FoundIntersect = .TRUE.
2090
END IF
2091
END DO
2092
END IF
2093
2094
crevdist = 0.0_dp
2095
IF(FoundIntersect) THEN
2096
FoundIntersect = .FALSE.
2097
crevdist = HUGE(1.0_dp)
2098
DO j=CrevStart(NodeClosestCrev(i)), CrevEnd(NodeClosestCrev(i))-1
2099
a1 = (/CrevX(j), CrevY(j)/)
2100
a2 = (/CrevX(j+1), CrevY(j+1)/)
2101
CALL LineSegmLineIntersect (a1, a2, b1, b2, intersect, does_intersect )
2102
IF(.NOT. does_intersect) CYCLE
2103
tempdist = PointDist2D(b1,intersect)
2104
IF(tempdist < crevdist) THEN
2105
crevdist = tempdist
2106
END IF
2107
FoundIntersect = .TRUE.
2108
END DO
2109
END IF
2110
2111
IF(MinDist < crevdist .AND. FoundIntersect) THEN
2112
CALL WARN(FuncName, 'Removing lateral calving event as it would jam on lateral margins')
2113
RemoveCrev(NodeClosestCrev(i)) = .TRUE.
2114
END IF
2115
END DO
2116
2117
#ifdef ELMER_BROKEN_MPI_IN_PLACE
2118
buffer = RemoveCrev
2119
CALL MPI_ALLREDUCE(buffer, &
2120
#else
2121
CALL MPI_ALLREDUCE(MPI_IN_PLACE, &
2122
#endif
2123
RemoveCrev, NoPaths, MPI_LOGICAL, MPI_LOR, ELMER_COMM_WORLD, ierr)
2124
2125
DO WHILE(ANY(RemoveCrev))
2126
DO i=1, NoPaths
2127
IF(.NOT. RemoveCrev(i)) CYCLE
2128
!CrevX,CrevY,CrevStart,CrevEnd, CrevOrient,&
2129
!Polygon, PolyStart, PolyEnd)
2130
2131
!change crevasse allocations
2132
RemovePoints = CrevEnd(i) - CrevStart(i) + 1
2133
ALLOCATE(WorkReal(CrevEnd(NoPaths) - RemovePoints))
2134
! alter crevx
2135
IF(i > 1) THEN
2136
WorkReal(1:CrevEnd(i-1)) = CrevX(1:CrevEnd(i-1))
2137
IF(i < NoPaths) WorkReal(CrevEnd(i-1)+1:) = CrevX(CrevStart(i+1):)
2138
ELSE IF (i < NoPaths) THEN
2139
WorkReal(1:) = CrevX(CrevStart(i+1):)
2140
END IF
2141
DEALLOCATE(CrevX)
2142
ALLOCATE(CrevX((CrevEnd(NoPaths) - RemovePoints)))
2143
CrevX = WorkReal
2144
! alter crevy
2145
IF(i > 1) THEN
2146
WorkReal(1:CrevEnd(i-1)) = CrevY(1:CrevEnd(i-1))
2147
IF(i < NoPaths) WorkReal(CrevEnd(i-1)+1:) = CrevY(CrevStart(i+1):)
2148
ELSE IF (i < NoPaths) THEN
2149
WorkReal(1:) = CrevY(CrevStart(i+1):)
2150
END IF
2151
DEALLOCATE(CrevY)
2152
ALLOCATE(CrevY((CrevEnd(NoPaths) - RemovePoints)))
2153
CrevY = WorkReal
2154
DEALLOCATE(WorkReal)
2155
2156
ALLOCATE(WorkInt(NoPaths-1))
2157
!alter crevstart
2158
IF(i > 1) THEN
2159
WorkInt(1:i-1) = CrevStart(1:i-1)
2160
IF(i < NoPaths) WorkInt(i:) = CrevStart(i+1:) - RemovePoints
2161
ELSE IF (i < NoPaths) THEN
2162
WorkInt = CrevStart(i+1:) - RemovePoints
2163
END IF
2164
DEALLOCATE(CrevStart)
2165
ALLOCATE(CrevStart(NoPaths-1))
2166
CrevStart = WorkInt
2167
!alter crevend
2168
IF(i > 1) THEN
2169
WorkInt(1:i-1) = CrevEnd(1:i-1)
2170
IF(i < NoPaths) WorkInt(i:) = CrevEnd(i+1:) - RemovePoints
2171
ELSE IF (i < NoPaths) THEN
2172
WorkInt = CrevEnd(i+1:) - RemovePoints
2173
END IF
2174
DEALLOCATE(CrevEnd)
2175
ALLOCATE(CrevEnd(NoPaths-1))
2176
CrevEnd = WorkInt
2177
2178
!now polygons
2179
RemovePoints = PolyEnd(i) - PolyStart(i) + 1
2180
ALLOCATE(WorkReal2(2, PolyEnd(NoPaths) - RemovePoints))
2181
IF(i > 1) THEN
2182
WorkReal2(:,1:PolyEnd(i-1)) = Polygon(:,1:PolyEnd(i-1))
2183
IF(i < NoPaths) WorkReal2(:,PolyEnd(i-1)+1:) = Polygon(:,PolyStart(i+1):)
2184
ELSE IF (i < NoPaths) THEN
2185
WorkReal2(:,1:) = Polygon(:,PolyStart(i+1):)
2186
END IF
2187
DEALLOCATE(Polygon)
2188
ALLOCATE(Polygon(2,PolyEnd(NoPaths) - RemovePoints))
2189
Polygon = WorkReal2
2190
DEALLOCATE(WorkReal2)
2191
2192
!alter polystart
2193
IF(i > 1) THEN
2194
WorkInt(1:i-1) = PolyStart(1:i-1)
2195
IF(i < NoPaths) WorkInt(i:) = PolyStart(i+1:) - RemovePoints
2196
ELSE IF (i < NoPaths) THEN
2197
WorkInt = PolyStart(i+1:) - RemovePoints
2198
END IF
2199
DEALLOCATE(PolyStart)
2200
ALLOCATE(PolyStart(NoPaths-1))
2201
PolyStart = WorkInt
2202
!alter polyend
2203
IF(i > 1) THEN
2204
WorkInt(1:i-1) = PolyEnd(1:i-1)
2205
IF(i < NoPaths) WorkInt(i:) = PolyEnd(i+1:) - RemovePoints
2206
ELSE IF (i < NoPaths) THEN
2207
WorkInt = PolyEnd(i+1:) - RemovePoints
2208
END IF
2209
DEALLOCATE(PolyEnd)
2210
ALLOCATE(PolyEnd(NoPaths-1))
2211
PolyEnd = WorkInt
2212
DEALLOCATE(WorkInt)
2213
2214
!finally remove crev marker
2215
ALLOCATE(WorkLogical(NoPaths-1))
2216
IF(i > 1) THEN
2217
WorkLogical(1:i-1) = RemoveCrev(1:i-1)
2218
IF(i < NoPaths) WorkLogical(i:) = RemoveCrev(i+1:)
2219
ELSE IF (i < NoPaths) THEN
2220
WorkLogical = RemoveCrev(i+1:)
2221
END IF
2222
DEALLOCATE(RemoveCrev)
2223
ALLOCATE(RemoveCrev(NoPaths-1))
2224
RemoveCrev = WorkLogical
2225
DEALLOCATE(WorkLogical)
2226
2227
EXIT
2228
END DO
2229
2230
NoPaths = SIZE(RemoveCrev)
2231
END DO
2232
2233
END SUBROUTINE CheckLateralCalving
2234
2235
!Cleanly removes elements & nodes from a mesh based on mask
2236
!Any element containing a removed node (RmNode) will be deleted
2237
!May optionally specify which elements to remove
2238
!If only RmElem is provided, no nodes are removed
2239
!(should this be changed? i.e. detect orphaned nodes?)
2240
SUBROUTINE CutPlaneMesh(Mesh, RmNode, RmElem)
2241
2242
IMPLICIT NONE
2243
2244
TYPE(Mesh_t), POINTER :: Mesh
2245
LOGICAL, OPTIONAL :: RmNode(:)
2246
LOGICAL, OPTIONAL, TARGET :: RmElem(:)
2247
!--------------------------------
2248
TYPE(Element_t), POINTER :: Element, Work_Elements(:)
2249
TYPE(Variable_t), POINTER :: Variables, Var
2250
TYPE(Nodes_t), POINTER :: Nodes
2251
TYPE(NeighbourList_t), POINTER :: work_neighlist(:)
2252
REAL(KIND=dp), ALLOCATABLE :: work_xyz(:,:)
2253
REAL(KIND=dp), POINTER CONTIG :: work_x(:),work_y(:), work_z(:)
2254
REAL(KIND=dp), POINTER :: WorkReal(:)=>NULL(), ptr(:)
2255
INTEGER :: i,j,counter,NNodes,NBulk, NBdry,NewNNodes, NewNElems, NewNBulk,&
2256
NewNbdry, ElNNodes
2257
INTEGER, ALLOCATABLE :: Nodeno_map(:),EIdx_map(:)
2258
INTEGER, POINTER :: NodeIndexes(:), work_pInt(:),WorkPerm(:)=>NULL()
2259
LOGICAL, POINTER :: RmElement(:),work_logical(:)
2260
CHARACTER(*), PARAMETER :: FuncName="CutMesh"
2261
CHARACTER(LEN=MAX_NAME_LEN) :: VarName
2262
NNodes = Mesh % NumberOfNodes
2263
NBulk = Mesh % NumberOfBulkElements
2264
NBdry = Mesh % NumberOfBoundaryElements
2265
Variables => Mesh % Variables
2266
2267
IF(.NOT. (PRESENT(RmElem) .OR. PRESENT(RmNode))) &
2268
CALL Fatal(FuncName,"Need to provide at least one of RmElem, RmNode!")
2269
2270
IF(PRESENT(RmElem)) THEN
2271
RmElement => RmElem
2272
ELSE
2273
!Mark elements containing deleted nodes for deletion
2274
ALLOCATE(RmElement(NBulk + Nbdry))
2275
RmElement = .FALSE.
2276
DO i=1,NBulk + NBdry
2277
Element => Mesh % Elements(i)
2278
NodeIndexes => Element % NodeIndexes
2279
ElNNodes = Element % TYPE % NumberOfNodes
2280
IF(ANY(RmNode(NodeIndexes(1:ElNNodes)))) RmElement(i) = .TRUE.
2281
!Get rid of orphans
2282
IF(i > NBulk) THEN
2283
IF(ASSOCIATED(Element % BoundaryInfo)) THEN
2284
!If the main body element is removed, remove this BC elem
2285
IF(ASSOCIATED(Element % BoundaryInfo % Left)) THEN
2286
j = Element % BoundaryInfo % Left % ElementIndex
2287
IF(RmElement(j)) RmElement(i) = .TRUE.
2288
END IF
2289
!Point % Right => NULL() if % Right element is removed
2290
IF(ASSOCIATED(Element % BoundaryInfo % Right)) THEN
2291
j = Element % BoundaryInfo % Right % ElementIndex
2292
IF(RmElement(j)) Element % BoundaryInfo % Right => NULL()
2293
END IF
2294
END IF
2295
END IF
2296
END DO
2297
END IF
2298
2299
IF(PRESENT(RmNode)) THEN
2300
!Removing nodes implies shifting element nodeindexes
2301
!Map pre -> post deletion node nums
2302
ALLOCATE(Nodeno_map(NNodes))
2303
Nodeno_map = 0
2304
counter = 0
2305
DO i=1,NNodes
2306
IF(RmNode(i)) CYCLE
2307
counter = counter + 1
2308
Nodeno_map(i) = counter
2309
END DO
2310
2311
!Update the element nodeindexes
2312
DO i=1,NBulk+NBdry
2313
Element => Mesh % Elements(i)
2314
IF(RmElement(i)) CYCLE
2315
DO j=1,Element % TYPE % NumberOfNodes
2316
Element % NodeIndexes(j) = Nodeno_map(Element % NodeIndexes(j))
2317
IF(Element % NodeIndexes(j) == 0) CALL Fatal(FuncName, &
2318
"Programming error: mapped nodeno = 0")
2319
END DO
2320
END DO
2321
2322
!Clear out deleted nodes
2323
Nodes => Mesh % Nodes
2324
NewNNodes = COUNT(.NOT. RmNode)
2325
2326
ALLOCATE(work_x(NewNNodes),&
2327
work_y(NewNNodes),&
2328
work_z(NewNNodes))
2329
2330
counter = 0
2331
DO i=1,NNodes
2332
IF(RmNode(i)) CYCLE
2333
counter = counter + 1
2334
work_x(counter) = Nodes % x(i)
2335
work_y(counter) = Nodes % y(i)
2336
work_z(counter) = Nodes % z(i)
2337
END DO
2338
2339
DEALLOCATE(Nodes % x, Nodes % y, Nodes % z)
2340
Nodes % x => work_x
2341
Nodes % y => work_y
2342
Nodes % z => work_z
2343
2344
Nodes % NumberOfNodes = NewNNodes
2345
Mesh % NumberOfNodes = NewNNodes
2346
2347
!update perms
2348
Var => Variables
2349
DO WHILE(ASSOCIATED(Var))
2350
IF(SIZE(Var % Values) == Var % DOFs) THEN
2351
Var => Var % Next
2352
CYCLE
2353
ELSE IF(LEN(Var % Name) > 10) THEN
2354
IF(Var % Name(1:10)=='coordinate') THEN
2355
Var => Var % Next
2356
CYCLE
2357
END IF
2358
END IF
2359
2360
ALLOCATE(WorkPerm(NewNNodes))
2361
WorkPerm = [(i,i=1,NewNNodes)]
2362
IF(.NOT. ASSOCIATED(WorkReal)) ALLOCATE(WorkReal(NewNNodes))
2363
2364
VarName = Var % Name
2365
2366
counter = 0
2367
DO i=1,NNodes
2368
IF(RmNode(i)) CYCLE
2369
counter = counter + 1
2370
WorkReal(counter) = Var % Values(Var % Perm(i))
2371
END DO
2372
2373
ptr => Var % Values(i::Var % DOFs)
2374
2375
!DEALLOCATE(Var % Perm)
2376
IF ( ASSOCIATED( Var % Values ) ) &
2377
DEALLOCATE( Var % Values )
2378
2379
Var % Perm => WorkPerm
2380
Var % Values => WorkReal
2381
NULLIFY(WorkPerm, WorkReal)
2382
Var => Var % Next
2383
END DO
2384
2385
!Clear out ParallelInfo
2386
IF(ASSOCIATED(Mesh % ParallelInfo % GlobalDOFs)) THEN
2387
ALLOCATE(work_pInt(NewNNodes))
2388
counter = 0
2389
DO i=1,NNodes
2390
IF(RmNode(i)) CYCLE
2391
counter = counter + 1
2392
work_pInt(counter) = Mesh % ParallelInfo % GlobalDOFs(i)
2393
END DO
2394
DEALLOCATE(Mesh % ParallelInfo % GlobalDOFs)
2395
Mesh % ParallelInfo % GlobalDOFs => work_pInt
2396
work_pInt => NULL()
2397
END IF
2398
2399
!Get rid of NeighbourList
2400
IF(ASSOCIATED(Mesh % ParallelInfo % NeighbourList)) THEN
2401
ALLOCATE(work_neighlist(NewNNodes))
2402
DO i=1,NNodes
2403
IF(.NOT. RmNode(i)) CYCLE
2404
IF(ASSOCIATED( Mesh % ParallelInfo % NeighbourList(i) % Neighbours ) ) &
2405
DEALLOCATE( Mesh % ParallelInfo % NeighbourList(i) % Neighbours )
2406
END DO
2407
2408
counter = 0
2409
DO i=1,NNodes
2410
IF(RmNode(i)) CYCLE
2411
counter = counter + 1
2412
work_neighlist(counter) % Neighbours => Mesh % ParallelInfo % NeighbourList(i) % Neighbours
2413
END DO
2414
DEALLOCATE(Mesh % ParallelInfo % NeighbourList)
2415
Mesh % ParallelInfo % NeighbourList => work_neighlist
2416
work_neighlist => NULL()
2417
END IF
2418
2419
!Get rid of ParallelInfo % NodeInterface
2420
IF(ASSOCIATED(Mesh % ParallelInfo % GInterface)) THEN
2421
ALLOCATE(work_logical(NewNNodes))
2422
counter = 0
2423
DO i=1,NNodes
2424
IF(RmNode(i)) CYCLE
2425
counter = counter + 1
2426
work_logical(counter) = Mesh % ParallelInfo % GInterface(i)
2427
END DO
2428
DEALLOCATE(Mesh % ParallelInfo % GInterface)
2429
Mesh % ParallelInfo % GInterface => work_logical
2430
work_logical => NULL()
2431
END IF
2432
END IF
2433
2434
!TODO - Mesh % Edges - see ReleaseMeshEdgeTables
2435
IF ( ASSOCIATED( Mesh % Edges ) ) THEN
2436
CALL Fatal(FuncName,"Clearing out Mesh % Edges not yet implemented.")
2437
END IF
2438
2439
!TODO - Mesh % Faces - see ReleaseMeshFaceTables
2440
IF ( ASSOCIATED( Mesh % Faces ) ) THEN
2441
CALL Fatal(FuncName,"Clearing out Mesh % Faces not yet implemented.")
2442
END IF
2443
2444
!TODO - Mesh % ViewFactors - see ReleaseMeshFactorTables
2445
IF (ASSOCIATED(Mesh % ViewFactors) ) THEN
2446
CALL Fatal(FuncName,"Clearing out Mesh % ViewFactors not yet implemented.")
2447
END IF
2448
2449
!TODO - Mesh % Projector - see FreeMatrix in ReleaseMesh
2450
IF (ASSOCIATED(Mesh % Projector) ) THEN
2451
CALL Fatal(FuncName,"Clearing out Mesh % Projector not yet implemented.")
2452
END IF
2453
2454
!TODO - Mesh % RootQuadrant - see FreeQuadrantTree
2455
IF( ASSOCIATED( Mesh % RootQuadrant ) ) THEN
2456
CALL Fatal(FuncName,"Clearing out Mesh % RootQuadrant not yet implemented.")
2457
END IF
2458
2459
NewNElems = COUNT(.NOT. RmElement)
2460
2461
2462
!Clear out deleted elements structures - taken from ReleaseMesh
2463
DO i=1,NBulk+NBdry
2464
IF(.NOT. RmElement(i)) CYCLE
2465
2466
! Boundaryinfo structure for boundary elements
2467
! ---------------------------------------------
2468
IF ( Mesh % Elements(i) % Copy ) CYCLE
2469
2470
IF ( i > NBulk ) THEN
2471
IF ( ASSOCIATED( Mesh % Elements(i) % BoundaryInfo ) ) THEN
2472
DEALLOCATE( Mesh % Elements(i) % BoundaryInfo )
2473
END IF
2474
END IF
2475
2476
IF ( ASSOCIATED( Mesh % Elements(i) % NodeIndexes ) ) &
2477
DEALLOCATE( Mesh % Elements(i) % NodeIndexes )
2478
Mesh % Elements(i) % NodeIndexes => NULL()
2479
2480
IF ( ASSOCIATED( Mesh % Elements(i) % EdgeIndexes ) ) &
2481
DEALLOCATE( Mesh % Elements(i) % EdgeIndexes )
2482
Mesh % Elements(i) % EdgeIndexes => NULL()
2483
2484
IF ( ASSOCIATED( Mesh % Elements(i) % FaceIndexes ) ) &
2485
DEALLOCATE( Mesh % Elements(i) % FaceIndexes )
2486
Mesh % Elements(i) % FaceIndexes => NULL()
2487
2488
IF ( ASSOCIATED( Mesh % Elements(i) % DGIndexes ) ) &
2489
DEALLOCATE( Mesh % Elements(i) % DGIndexes )
2490
Mesh % Elements(i) % DGIndexes => NULL()
2491
2492
IF ( ASSOCIATED( Mesh % Elements(i) % BubbleIndexes ) ) &
2493
DEALLOCATE( Mesh % Elements(i) % BubbleIndexes )
2494
Mesh % Elements(i) % BubbleIndexes => NULL()
2495
2496
! This creates problems later on!!!
2497
!IF ( ASSOCIATED( Mesh % Elements(i) % PDefs ) ) &
2498
! DEALLOCATE( Mesh % Elements(i) % PDefs )
2499
2500
Mesh % Elements(i) % PDefs => NULL()
2501
END DO
2502
2503
!Construct a map of old element indexes => new element indexes
2504
ALLOCATE(EIdx_map(NBdry+NBulk))
2505
EIdx_map = 0
2506
counter = 0
2507
DO i=1,NBulk+NBdry
2508
IF(RmElement(i)) CYCLE
2509
counter = counter + 1
2510
IF(Mesh % Elements(i) % ElementIndex /= i) CALL Warn(FuncName,&
2511
"Assumption Elements(i) % ElementIndex == i not valid! Expect memory corruption...")
2512
EIdx_map(Mesh % Elements(i) % ElementIndex) = counter
2513
END DO
2514
2515
!Repoint elements
2516
ALLOCATE(work_elements(NewNElems))
2517
counter = 0
2518
DO i=1,Nbulk+NBdry
2519
IF(RmElement(i)) CYCLE
2520
counter = counter + 1
2521
2522
Element => Mesh % Elements(i)
2523
work_elements(counter) = Element
2524
2525
!Repoint BoundaryInfo % Left, % Right
2526
IF(i > NBdry) THEN
2527
IF(ASSOCIATED(Element % BoundaryInfo)) THEN
2528
IF(ASSOCIATED(Element % BoundaryInfo % Left)) THEN
2529
j = Element % BoundaryInfo % Left % ElementIndex
2530
work_elements(counter) % BoundaryInfo % Left => work_elements(EIdx_map(j))
2531
END IF
2532
IF(ASSOCIATED(Element % BoundaryInfo % Right)) THEN
2533
j = Element % BoundaryInfo % Right % ElementIndex
2534
work_elements(counter) % BoundaryInfo % Right => work_elements(EIdx_map(j))
2535
END IF
2536
END IF
2537
END IF
2538
END DO
2539
2540
!Update ElementIndexes
2541
DO i=1,NewNElems
2542
work_elements(i) % ElementIndex = i
2543
END DO
2544
2545
DEALLOCATE(Mesh % Elements)
2546
Mesh % Elements => work_elements
2547
work_elements => NULL()
2548
2549
Mesh % NumberOfBulkElements = COUNT(.NOT. RmElement(1:nbulk))
2550
Mesh % NumberOfBoundaryElements = COUNT(.NOT. RmElement(nbulk+1:nbulk+nbdry))
2551
2552
IF(.NOT. PRESENT(RmElem)) DEALLOCATE(RmElement)
2553
2554
END SUBROUTINE CutPlaneMesh
2555
2556
END SUBROUTINE Find_Calving3D_LSet
2557
2558