Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmerice/Solvers/CalvingGlacierAdvance3D.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: Eef van Dongen, Joe Todd
26
! * Email:
27
! * Web: http://elmerice.elmerfem.org
28
! *
29
! *
30
! *****************************************************************************
31
!
32
! A routine for getting frontal advance in 3D, given velocity and melt
33
! nodes on the intersection of Front and LateralMargin are also allowed to advance
34
! In order to assure the glacier still aligns with the valley walls,
35
! 'rails' are prescribed. The points on the rails need to be given in two
36
! ASCII files (x y), one for left and one for right.
37
! x and y values need to be sorted, but the direction is not of importance. (?)
38
! NOTE: if the prescribed timestep is too large and 'rails' are very nonsmooth
39
! this implementation may not obey mass conservation.
40
SUBROUTINE GlacierAdvance3D ( Model, Solver, dt, TransientSimulation )
41
42
USE CalvingGeometry
43
USE DefUtils
44
IMPLICIT NONE
45
46
!-----------------------------------------------
47
TYPE(Model_t) :: Model
48
TYPE(Solver_t), TARGET :: Solver
49
REAL(KIND=dp) :: dt
50
LOGICAL :: TransientSimulation
51
!-----------------------------------------------
52
TYPE(Mesh_t), POINTER :: Mesh
53
TYPE(Nodes_t), TARGET :: FrontNodes
54
TYPE(ValueList_t), POINTER :: Params, Material
55
TYPE(Variable_t), POINTER :: Var, VeloVar, MeltVar, NormalVar, TangledVar, &
56
DistVar
57
! TO DO clean all unused variables
58
INTEGER :: i, j,jmin, k, m, n, DOFs, TotalNodes,&
59
FaceNodeCount, DummyInt, hits, ierr, FrontLineCount, county,&
60
ShiftIdx, ShiftToIdx, PivotIdx, CornerIdx, &
61
SecondIdx, FirstTangleIdx, LastTangleIdx, Nl, Nr, Naux, ok, Nrail,&
62
NNodes, NBulk, NBdry, counter, LeftBCtag, RightBCtag, FrontBCtag,&
63
OnRails
64
INTEGER, POINTER :: Perm(:), FrontPerm(:)=>NULL(), TopPerm(:)=>NULL(), &
65
FrontNodeNums(:)=>NULL(),LeftPerm(:)=>NULL(), RightPerm(:)=>NULL(), &
66
NodeIndexes(:),InflowPerm(:)=>NULL()
67
INTEGER, ALLOCATABLE :: FrontLocalNodeNumbers(:), &
68
NodeNumbers(:), UpdatedDirection(:)
69
REAL(KIND=dp) :: NodeVelo(3), NodeMelt(3), NodeNormal(3), RailDir(2),&
70
MeltRate, Displace(3), y_coord(2), epsShift, LongRangeLimit, MaxDisplacement, &
71
EpsTangle,thisEps,Shift, thisY,xx,yy,TempDist,MinDist,xt,yt,t, &
72
a1(2), a2(2), b1(2), b2(2), b3(2), intersect(2), DistRailNode, RDisplace(3),&
73
buffer, VeloFactor, zb
74
REAL(KIND=dp), POINTER :: Advance(:)
75
REAL(KIND=dp), ALLOCATABLE :: Rot_y_coords(:,:), Rot_z_coords(:,:), &
76
xL(:),yL(:),xR(:),yR(:),xRail(:),yRail(:)
77
LOGICAL :: Found, Debug, Parallel, Boss, ShiftLeft, LeftToRight, MovedOne, ShiftSecond, &
78
Protrusion, SqueezeLeft, SqueezeRight, FirstTime=.TRUE., intersect_flag, FrontMelting, &
79
MovePastRailNode, HitsRails, Reverse, ThisBC, MoveBulk, MoveBase,&
80
UnFoundFatal
81
LOGICAL, ALLOCATABLE :: DangerZone(:), WorkLogical(:), &
82
DontMove(:), FrontToRight(:), FrontToLeft(:)
83
CHARACTER(LEN=MAX_NAME_LEN) :: SolverName, VeloVarName, MeltVarName, &
84
NormalVarName, FrontMaskName, TopMaskName, &
85
LeftMaskName, RightMaskName, LeftRailFName, RightRailFName,&
86
InflowMaskName
87
INTEGER,parameter :: io=20
88
SAVE :: FirstTime ! TO DO not actually using FirstTime here?
89
90
!-----------------------------------------------
91
! Initialisation
92
!-----------------------------------------------
93
94
Debug = .FALSE.
95
Parallel = (ParEnv % PEs > 1)
96
Boss = ParEnv % MyPE == 0
97
98
SolverName = "GlacierAdvance3D"
99
Params => Solver % Values
100
Mesh => Solver % Mesh
101
102
!The main solver var contains the magnitude of front advance
103
Var => Solver % Variable
104
Advance => Var % Values
105
Perm => Var % Perm
106
DOFs = Var % DOFs
107
IF(Var % DOFs /= 3) CALL Fatal(SolverName, "Variable should have 3 DOFs...")
108
109
!Get the flow solution
110
VeloVarName = ListGetString(Params, "Flow Solution Variable Name", Found)
111
IF(.NOT. Found) THEN
112
CALL Info(SolverName, "Flow Solution Variable Name not found, assuming 'Flow Solution'")
113
VeloVarName = "Flow Solution"
114
END IF
115
VeloVar => VariableGet(Mesh % Variables, VeloVarName, .TRUE., UnfoundFatal=.TRUE.)
116
117
LeftRailFName = ListGetString(Params, "Left Rail File Name", Found)
118
IF(.NOT. Found) THEN
119
CALL Info(SolverName, "Left Rail File Name not found, assuming './LeftRail.xy'")
120
LeftRailFName = "LeftRail.xy"
121
END IF
122
Nl = ListGetInteger(Params, "Left Rail Number Nodes", Found)
123
IF(.NOT.Found) THEN
124
WRITE(Message,'(A,A)') 'Left Rail Number Nodes not found'
125
CALL FATAL(SolverName, Message)
126
END IF
127
!TO DO only do these things if firsttime=true?
128
OPEN(unit = io, file = TRIM(LeftRailFName), status = 'old',iostat = ok)
129
print *, ok
130
IF (ok /= 0) THEN
131
WRITE(message,'(A,A)') 'Unable to open file ',TRIM(LeftRailFName)
132
CALL FATAL(Trim(SolverName),Trim(message))
133
END IF
134
ALLOCATE(xL(Nl), yL(Nl))
135
136
! read data
137
DO i = 1, Nl
138
READ(io,*,iostat = ok, end=200) xL(i), yL(i)
139
END DO
140
200 Naux = Nl - i
141
IF (Naux > 0) THEN
142
WRITE(message,'(I0,A,I0,A,A)') Naux,' out of ',Nl,' datasets in file ', TRIM(LeftRailFName)
143
CALL INFO(Trim(SolverName),Trim(message))
144
END IF
145
CLOSE(io)
146
RightRailFName = ListGetString(Params, "Right Rail File Name", Found)
147
IF(.NOT. Found) THEN
148
CALL Info(SolverName, "Right Rail File Name not found, assuming './RightRail.xy'")
149
RightRailFName = "RightRail.xy"
150
END IF
151
152
Nr = ListGetInteger(Params, "Right Rail Number Nodes", Found)
153
IF(.NOT.Found) THEN
154
WRITE(Message,'(A,A)') 'Right Rail Number Nodes not found'
155
CALL FATAL(SolverName, Message)
156
END IF
157
!TO DO only do these things if firsttime=true?
158
OPEN(unit = io, file = TRIM(RightRailFName), status = 'old',iostat = ok)
159
160
IF (ok /= 0) THEN
161
WRITE(message,'(A,A)') 'Unable to open file ',TRIM(RightRailFName)
162
CALL FATAL(Trim(SolverName),Trim(message))
163
END IF
164
ALLOCATE(xR(Nr), yR(Nr))
165
166
! TO DO would be nice if solver warns in case there is more data in file than number Nr/Nl tells
167
! read data
168
DO i = 1, Nr
169
READ(io,*,iostat = ok, end=100) xR(i), yR(i)
170
END DO
171
100 Naux = Nr - i
172
IF (Naux > 0) THEN
173
WRITE(message,'(I0,A,I0,A,A)') Naux,' out of ',Nl,' datasets in file ', TRIM(RightRailFName)
174
CALL INFO(Trim(SolverName),Trim(message))
175
END IF
176
CLOSE(io)
177
178
!Get melt rate
179
MeltVarName = ListGetString(Params, "Melt Variable Name", Found)
180
IF(.NOT. Found) THEN
181
CALL Info(SolverName, "Melt Variable Name not found, assuming no frontal melting")
182
FrontMelting = .FALSE.
183
ELSE
184
FrontMelting = .TRUE.
185
MeltVar => VariableGet(Mesh % Variables, MeltVarName, .TRUE., UnfoundFatal=.TRUE.)
186
END IF
187
188
!Get front normal vector
189
NormalVarName = ListGetString(Params, "Normal Vector Variable Name", UnfoundFatal=.TRUE.)
190
NormalVar => VariableGet(Mesh % Variables, NormalVarName, .TRUE., UnfoundFatal=.TRUE.)
191
192
MaxDisplacement = ListGetConstReal(Params, "Maximum Node Displacement", Found)
193
IF(.NOT.Found) THEN
194
CALL Info(SolverName, "'Maximum Node Displacement' not found, setting to 1.0E4.")
195
MaxDisplacement = 1.0E4_dp
196
END IF
197
198
VeloFactor = ListGetConstReal(Params, "Lateral Margin Velocity Factor", Found)
199
IF(.NOT.Found) THEN
200
CALL Info(SolverName, "'Lateral Margin Velocity Factor' not found, setting to 1.0.")
201
VeloFactor = 1.0_dp
202
END IF
203
204
buffer = ListGetConstReal(Params, "Rail Buffer", Found, DefValue=0.1_dp)
205
IF(.NOT. Found) CALL Info(SolverName, "No Rail Buffer set using default 0.1")
206
207
MoveBulk = ListGetLogical(Params,"MoveBulk", Found, DefValue=.FALSE.)
208
IF(.NOT. Found) CALL Info(SolverName, "Not moving bulk as default")
209
210
MoveBase = ListGetLogical(Params,"Account for bedrock", Found, DefValue=.FALSE.)
211
! still in testing
212
!IF(.NOT. Found) CALL Fatal(SolverName, "'Account for bedrock' not found")
213
214
!Get the front line
215
FrontMaskName = "Calving Front Mask"
216
TopMaskName = "Top Surface Mask"
217
218
CALL MakePermUsingMask( Model, Solver, Mesh, TopMaskName, &
219
.FALSE., TopPerm, dummyint)
220
221
CALL MakePermUsingMask( Model, Solver, Mesh, FrontMaskName, &
222
.FALSE., FrontPerm, FaceNodeCount)
223
224
LeftMaskName = "Left Sidewall Mask"
225
RightMaskName = "Right Sidewall Mask"
226
227
!Generate perms to quickly get nodes on each boundary
228
CALL MakePermUsingMask( Model, Solver, Mesh, LeftMaskName, &
229
.FALSE., LeftPerm, dummyint)
230
CALL MakePermUsingMask( Model, Solver, Mesh, RightMaskName, &
231
.FALSE., RightPerm, dummyint)
232
233
InflowMaskName = "Inflow Mask"
234
CALL MakePermUsingMask( Model, Solver, Mesh, InflowMaskName, &
235
.FALSE., InflowPerm, dummyint)
236
237
!--------------------------------------
238
! Action: Compute lagrangian displacement for all nodes
239
! This is the main function of the Solver.
240
! TO DO: check for 'tangled' regions, see CalvingFrontAdvance3D.F90
241
!--------------------------------------
242
243
NNodes = Mesh % NumberOfNodes
244
NBulk = Mesh % NumberOfBulkElements
245
NBdry = Mesh % NumberOfBoundaryElements
246
247
ALLOCATE(FrontToRight(NNodes), FrontToLeft(NNodes))
248
FrontToRight = .FALSE.; FrontToLeft = .FALSE.
249
250
Advance = 0.0_dp
251
IF(MoveBulk) THEN ! for a fully Lagrangian mesh
252
DO i=1, Mesh % NumberOfNodes
253
IF(InflowPerm(i) > 0) CYCLE
254
IF(FrontPerm(i) == 0 .AND. LeftPerm(i) == 0 .AND. RightPerm(i) == 0) THEN
255
NodeVelo(1) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 1)
256
NodeVelo(2) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 2)
257
NodeVelo(3) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 3)
258
259
Displace(1) = NodeVelo(1)
260
Displace(2) = NodeVelo(2)
261
Displace(3) = NodeVelo(3)
262
Displace = Displace * dt
263
264
Advance((Perm(i)-1)*DOFs + 1) = Displace(1)
265
Advance((Perm(i)-1)*DOFs + 2) = Displace(2)
266
Advance((Perm(i)-1)*DOFs + 3) = Displace(3)
267
END IF
268
END DO
269
END IF
270
271
DO i=1,Mesh % NumberOfNodes
272
IF(Perm(i) <= 0) CYCLE
273
IF(FrontPerm(i) == 0 .AND. LeftPerm(i) == 0 .AND. RightPerm(i) == 0) CYCLE
274
IF(InflowPerm(i) > 0) CYCLE
275
276
IF(FrontMelting .AND. (FrontPerm(i) >0 )) THEN
277
IF(MeltVar % Perm(i) <= 0) &
278
CALL Fatal(SolverName, "Permutation error on front node!")
279
280
281
!Scalar melt value from Plume solver
282
MeltRate = MeltVar % Values(MeltVar % Perm(i))
283
284
NodeNormal(1) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 1)
285
NodeNormal(2) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 2)
286
NodeNormal(3) = NormalVar % Values(((NormalVar % Perm(i)-1)*NormalVar % DOFs) + 3)
287
288
NodeMelt = NodeNormal * MeltRate
289
ELSE
290
NodeMelt = 0.0_dp
291
END IF
292
293
!Compute front normal component of velocity
294
NodeVelo(1) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 1)
295
NodeVelo(2) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 2)
296
NodeVelo(3) = VeloVar % Values(((VeloVar % Perm(i)-1)*VeloVar % DOFs) + 3)
297
298
IF(FrontPerm(i) > 0) THEN
299
IF(LeftPerm(i) > 0 .OR. RightPerm(i) > 0) THEN
300
NodeVelo = NodeVelo * VeloFactor
301
END IF
302
END IF
303
304
Displace = 0.0
305
IF ( FrontPerm(i) > 0 ) THEN
306
Displace(1) = NodeVelo(1) - NodeMelt(1)
307
Displace(2) = NodeVelo(2) - NodeMelt(2)
308
Displace(3) = NodeVelo(3) - NodeMelt(3)
309
Displace = Displace * dt
310
END IF
311
312
OnRails = 0
313
! if not lateral node need to check we don't cross rails if fjord narrowing
314
IF(LeftPerm(i) == 0 .AND. RightPerm(i) == 0) THEN
315
a1(1) = Solver % Mesh % Nodes % x(i)
316
a1(2) = Solver % Mesh % Nodes % y(i)
317
a2(1) = a1(1) + Displace(1)
318
a2(2) = a1(2) + Displace(2)
319
320
DO j=1, Nl-1
321
b1(1) = xL(j); b1(2) = yL(j)
322
b2(1) = xL(j+1); b2(2) = yL(j+1)
323
IF(j < NL - 1) THEN
324
b3(1) = xL(j+2); b3(2) = yL(j+2)
325
END IF
326
tempdist = PointLineSegmDist2D(b1, b2, a1)
327
IF(tempdist < buffer + AEPS) THEN
328
FrontToLeft(i) = .TRUE.
329
OnRails = 1 ! on rails so treat as edge
330
EXIT
331
END IF
332
333
CALL LineSegmentsIntersect(a1, a2, b1, b2, intersect, HitsRails)
334
335
IF(HitsRails) THEN
336
FrontToLeft(i) = .TRUE.
337
! check direction
338
Reverse = .FALSE.
339
IF (PointDist2D(intersect,b2) > PointDist2D(a1, b2)) Reverse = .TRUE.
340
341
IF(Reverse) THEN
342
b1(1) = xL(j+1); b1(2) = yL(j+1)
343
b2(1) = xL(j); b2(2) = yL(j)
344
IF(j > 1) THEN
345
b3(1) = xL(j-1); b3(2) = yL(j-1)
346
END IF
347
END IF
348
EXIT
349
END IF
350
END DO
351
352
IF(.NOT. HitsRails) THEN ! didn't hit left rail
353
DO j=1, Nr-1
354
b1(1) = xR(j); b1(2) = yR(j)
355
b2(1) = xR(j+1); b2(2) = yR(j+1)
356
IF(j < Nr - 1) THEN
357
b3(1) = xR(j+2); b3(2) = yR(j+2)
358
END IF
359
tempdist = PointLineSegmDist2D(b1, b2, a1)
360
IF(tempdist < buffer + AEPS) THEN
361
FrontToRight(i) = .TRUE.
362
OnRails = 2! on rails so treat as edge
363
EXIT
364
END IF
365
366
CALL LineSegmentsIntersect(a1, a2, b1, b2, intersect, HitsRails)
367
368
IF(HitsRails) THEN
369
FrontToRight(i) = .TRUE.
370
! check direction
371
Reverse = .FALSE.
372
IF (PointDist2D(intersect,b2) > PointDist2D(a1, b2)) Reverse = .TRUE.
373
374
IF(Reverse) THEN
375
b1(1) = xR(j+1); b1(2) = yR(j+1)
376
b2(1) = xR(j); b2(2) = yR(j)
377
IF(j > 1) THEN
378
b3(1) = xR(j-1); b3(2) = yR(j-1)
379
END IF
380
END IF
381
EXIT
382
END IF
383
END DO
384
END IF
385
386
IF(HitsRails) THEN ! hit a rail b1, b2, and b3 should be correct from above
387
! limit to rail and then move along
388
Displace(1:2) = intersect-a1
389
390
!remaining displacement
391
RDisplace = 0.0_dp
392
RDisplace(1) = (NodeVelo(1) - NodeMelt(1)) * dt - Displace(1)
393
RDisplace(2) = (NodeVelo(2) - NodeMelt(2)) * dt - Displace(2)
394
395
DistRailNode = PointDist2D(intersect, b2)
396
TempDist = ( RDisplace(1)**2 + RDisplace(2)**2 ) ** 0.5
397
398
!check if move past rail node
399
MovePastRailNode = .FALSE.
400
IF(TempDist > DistRailNode) MovePastRailNode=.TRUE.
401
402
!project along rail
403
IF(.NOT. MovePastRailNode) THEN
404
405
RailDir = b1 - b2
406
Displace(1:2) = Displace(1:2) + DOT_PRODUCT(RDisplace(1:2),RailDir) * &
407
RailDir / DOT_PRODUCT(RailDir,RailDir)
408
409
ELSE
410
411
IF((Reverse .AND. j == 1) .AND. (.NOT. Reverse .AND. j == Nr - 1)) &
412
CALL FATAL(SolverName, 'Moving past the end of the rails')
413
414
RailDir = b1 - b2
415
Displace(1:2) = Displace(1:2) + b2 - a1 ! get to new rail node
416
!TempDist is total distance it would have travelled only along its original segment
417
TempDist=DOT_PRODUCT(RDisplace(1:2),RailDir) * &
418
(RailDir(1)**2+RailDir(2)**2)**0.5 * dt / DOT_PRODUCT(RailDir,RailDir)
419
TempDist=ABS(TempDist) ! distance no sign
420
421
IF(TempDist < DistRailNode) THEN
422
CALL WARN(SolverName, 'Node outside rails and moving past rail node')
423
TempDist = DistRailNode
424
END IF
425
426
t=(TempDist - DistRailNode)/TempDist
427
428
! new rail direction
429
RailDir = b2 - b3
430
! add proportion left to travel along new direction
431
Displace(1:2) = Displace(1:2)+DOT_PRODUCT(RDisplace(1:2),RailDir) * &
432
RailDir * dt * t / DOT_PRODUCT(RailDir,RailDir)
433
END IF
434
END IF
435
END IF
436
437
! NOTE: Displace overwritten on corner of left-front and right-front
438
! melt not taken into account on those corner nodes
439
IF ((LeftPerm(i)>0) .OR. (RightPerm(i)>0) .OR. (OnRails > 0) ) THEN
440
! Strategy to project displace from x to x+v*dt along rail direction:
441
! - find closest rail node, then find cosest rail segment.
442
! - three cases to find which rail segment should be used:
443
! 1) x is rail node, then just find out which segment closest to x+dt*v
444
! 2) both x and x+dt*v are on one rail segment
445
! 3) x is on one segment and x+dt*v on another
446
! only do x,y direction; vertical update is handled by freesurf.
447
! NOTE mass is not strictly conserved but for small timesteps and
448
! a thin lateral boundary artificial mass change should be insignificant.
449
xx = Solver % Mesh % Nodes % x(i)
450
yy = Solver % Mesh % Nodes % y(i)
451
NodeVelo(1:2) = NodeVelo(1:2) - NodeMelt(1:2)
452
xt=xx+(NodeVelo(1))*dt
453
yt=yy+(NodeVelo(2))*dt
454
IF (LeftPerm(i)>0 .OR. OnRails == 1) THEN
455
Nrail= Nl
456
ALLOCATE(xRail(Nrail), yRail(Nrail))
457
xRail = xL
458
yRail = yL
459
ELSE
460
Nrail= Nr
461
ALLOCATE(xRail(Nrail), yRail(Nrail))
462
xRail = xR
463
yRail = yR ! TO DO use pointers instead?
464
END IF
465
MinDist=(xRail(1)-xRail(Nrail))**2.+(yRail(1)-yRail(Nrail))**2.
466
! MinDist is actually maximum distance, needed for finding closest rail node
467
DO j=1,Nrail ! Find closest point on rail
468
TempDist=(xRail(j)-xx)**2.+(yRail(j)-yy)**2.
469
IF(TempDist < MinDist) THEN
470
MinDist=TempDist
471
jmin=j
472
END IF
473
END DO
474
IF(jmin+1>Nrail) PRINT *, 'jmin=',jmin,'ERROR: advancing/retreating beyond rail!'
475
!NOTE, this assumes rails are starting at back and going towards front, should check k > 0 as well?
476
IF (MinDist < AEPS) THEN ! min distance very close to 0
477
! case 1) mesh node is a rail point
478
! this likely happens at t=0.
479
MovePastRailNode=.FALSE. !if both at a rail node and passing next rail node, rail resolution is smaller than displacement per timestep
480
! we assume that's never the case. TO DO include assert
481
! check whether x+v*dt is closest to segment jmin+1 or jmin-1
482
IF(PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
483
(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &
484
> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
485
(/xRail(jmin-1),yRail(jmin-1)/),(/xt,yt/))) THEN
486
k=jmin-1 ! x+v*dt is on jmin-1 -- jmin
487
ELSE
488
k=jmin+1
489
END IF
490
PRINT *, 'NOTE! mesh node on a rail node!'
491
ELSE ! x is not a rail node, check whether x is closest to jmin+1 or jmin-1
492
IF(jmin==1) THEN
493
IF(PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
494
(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &
495
> PointLineSegmDist2D((/xRail(jmin+1),yRail(jmin+1)/), &
496
(/xRail(jmin+2),yRail(jmin+2)/),(/xt,yt/))) THEN
497
! x+v*dt also closest to jmin--jmin-1
498
MovePastRailNode=.TRUE. ! case 2) x+dt*v and x are on same segment
499
k=jmin+1
500
ELSE
501
! case 3) advancing past rail segment
502
MovePastRailNode=.FALSE.
503
k=jmin+1 ! x is moving from jmin-1--jmin to jmin--jmin+1
504
END IF
505
ELSE
506
IF(PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
507
(/xRail(jmin+1),yRail(jmin+1)/),(/xx,yy/)) &
508
> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
509
(/xRail(jmin-1),yRail(jmin-1)/),(/xx,yy/))) THEN
510
! x closest to jmin-1 -- jmin segment
511
IF (PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
512
(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &
513
> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
514
(/xRail(jmin-1),yRail(jmin-1)/),(/xt,yt/))) THEN
515
! x+v*dt also closest to jmin--jmin-1
516
MovePastRailNode=.FALSE. ! case 2) x+dt*v and x are on same segment
517
k=jmin-1 ! x and x+v*dt are closest to jmin>jmin-1 segment
518
ELSE
519
! case 3) advancing past rail segment
520
MovePastRailNode=.TRUE.
521
k=jmin+1 ! x is moving from jmin-1--jmin to jmin--jmin+1
522
END IF
523
ELSE ! x closest to jmin -- jmin+1 segment, but closer to jmin than jmin+1
524
! assuming not moving past jmin+1 (see above assumption on time step and rail resolution)
525
IF (PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
526
(/xRail(jmin+1),yRail(jmin+1)/),(/xt,yt/)) &
527
> PointLineSegmDist2D((/xRail(jmin),yRail(jmin)/), &
528
(/xRail(jmin-1),yRail(jmin-1)/),(/xt,yt/))) THEN
529
! Case 3) x advancing past rail segment
530
MovePastRailNode=.TRUE.
531
k=jmin-1 ! x is moving from jmin+1>jmin to jmin>jmin-1
532
ELSE
533
! Case 2) x+v*dt and x are on same segment jmin>jmin+1
534
MovePastRailNode=.FALSE.
535
k=jmin+1
536
END IF
537
END IF
538
END IF
539
END IF
540
IF(MovePastRailNode) THEN
541
! check not moving past last node
542
IF((k > jmin .AND. jmin == Nrail) .OR. (k < jmin .AND. jmin == 1)) &
543
CALL FATAL(SolverName, 'Moving past the end of the rails')
544
! k is defined such that the node should after displacement lay on jmin -- k segment
545
! nodes first move along the current rail segment to the nearest rail node jmin.
546
! whatever magnitude of the horizontal part of v*dt is left
547
! will be the distance the node travels on the new segment.
548
RailDir=(/xRail(jmin),yRail(jmin)/)-(/xx,yy/) ! direction of current rail
549
Displace(1:2)=(/xRail(jmin),yRail(jmin)/)-(/xx,yy/) ! get to new rail node
550
!TempDist is total distance it would have travelled only along its original segment
551
TempDist=DOT_PRODUCT(NodeVelo(1:2),RailDir) * &
552
(RailDir(1)**2+RailDir(2)**2)**0.5 * dt / DOT_PRODUCT(RailDir,RailDir)
553
TempDist=ABS(TempDist) ! distance no sign
554
! t is the proportion left to travel along new segment
555
DistRailNode = ((xx-xRail(jmin))**2.+(yy-yRail(jmin))**2.)**0.5
556
IF(TempDist < DistRailNode) THEN
557
CALL WARN(SolverName, 'Node outside rails and moving past rail node')
558
TempDist = DistRailNode
559
END IF
560
561
t=(TempDist - DistRailNode)/TempDist
562
563
! new rail direction
564
RailDir=(/xRail(jmin),yRail(jmin)/)-(/xRail(k),yRail(k)/)
565
! add proportion left to travel along new direction
566
Displace(1:2) = Displace(1:2)+DOT_PRODUCT(NodeVelo(1:2),RailDir) * &
567
RailDir * dt * t / DOT_PRODUCT(RailDir,RailDir)
568
ELSE ! not moving past node, just project onto current rail
569
RailDir=(/xRail(jmin),yRail(jmin)/)-(/xRail(k),yRail(k)/)
570
Displace(1:2) = DOT_PRODUCT(NodeVelo(1:2),RailDir) * &
571
RailDir / DOT_PRODUCT(RailDir,RailDir)
572
Displace(1:2) = Displace(1:2) * dt
573
END IF
574
! TO DO write warning if distance point on margin to rail segment too large?
575
! TO DO also write warning if glacier advances out of range of rails?
576
! TO DO ASSERT that ||NewDisplace|| <= ||V||*dt
577
DEALLOCATE(xRail,yRail)
578
END IF
579
580
581
IF(MAXVAL(Displace) > MaxDisplacement) THEN
582
WRITE(Message,'(A,i0,A)') "Maximum allowable front displacement exceeded for node ",i,". Limiting..."
583
CALL Warn(SolverName, Message)
584
Displace = Displace * (MaxDisplacement/MAXVAL(Displace))
585
END IF
586
587
Advance((Perm(i)-1)*DOFs + 1) = Displace(1)
588
Advance((Perm(i)-1)*DOFs + 2) = Displace(2)
589
Advance((Perm(i)-1)*DOFs + 3) = Displace(3)
590
591
END DO
592
593
!do we need to check base base of new advance location?
594
IF(MoveBase) THEN
595
596
i = ListGetInteger( CurrentModel % Bodies(Mesh % Elements(1) % BodyId) % Values, &
597
'Material')
598
Material => CurrentModel % Materials(i) % Values !TODO, this is not generalised
599
600
DO i=1, Mesh % NumberOfNodes
601
IF(Perm(i) == 0) CYCLE
602
IF(FrontPerm(i) == 0) CYCLE
603
Mesh % Nodes % x(i) = Mesh % Nodes % x(i) + Advance((Perm(i)-1)*DOFs + 1)
604
Mesh % Nodes % y(i) = Mesh % Nodes % y(i) + Advance((Perm(i)-1)*DOFs + 2)
605
Mesh % Nodes % z(i) = Mesh % Nodes % z(i) + Advance((Perm(i)-1)*DOFs + 3)
606
zb = ListGetRealAtNode(Material, "Min Zs Bottom",i,UnfoundFatal=.TRUE.)
607
608
Mesh % Nodes % x(i) = Mesh % Nodes % x(i) - Advance((Perm(i)-1)*DOFs + 1)
609
Mesh % Nodes % y(i) = Mesh % Nodes % y(i) - Advance((Perm(i)-1)*DOFs + 2)
610
Mesh % Nodes % z(i) = Mesh % Nodes % z(i) - Advance((Perm(i)-1)*DOFs + 3)
611
612
IF(Mesh % Nodes % z(i) + Advance((Perm(i)-1)*DOFs + 3) < zb) THEN
613
Advance((Perm(i)-1)*DOFs + 3) = zb - Mesh % Nodes % z(i)
614
IF(Mesh % Nodes % z(i) < zb) THEN
615
Advance((Perm(i)-1)*DOFs + 3) = 0.0_dp
616
END IF
617
END IF
618
END DO
619
END IF
620
621
622
! find lateral boundary tags
623
DO i=1,Model % NumberOfBCs
624
ThisBC = ListGetLogical(Model % BCs(i) % Values,LeftMaskName,Found)
625
IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE
626
LeftBCtag = Model % BCs(i) % Tag
627
EXIT
628
END DO
629
DO i=1,Model % NumberOfBCs
630
ThisBC = ListGetLogical(Model % BCs(i) % Values,RightMaskName,Found)
631
IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE
632
RightBCtag = Model % BCs(i) % Tag
633
EXIT
634
END DO
635
DO i=1,Model % NumberOfBCs
636
ThisBC = ListGetLogical(Model % BCs(i) % Values,FrontMaskName,Found)
637
IF((.NOT. Found) .OR. (.NOT. ThisBC)) CYCLE
638
FrontBCtag = Model % BCs(i) % Tag
639
EXIT
640
END DO
641
642
!reassign any elements that now only contain nodes on lateral margins
643
DO i=NBulk+1, NBulk+NBdry
644
IF(Mesh % Elements(i) % BoundaryInfo % constraint /= FrontBCtag) CYCLE
645
NodeIndexes => Mesh % Elements(i) % NodeIndexes
646
n = Mesh % Elements(i) % TYPE % NumberOfNodes
647
counter = 0
648
DO j=1,n
649
IF(RightPerm(NodeIndexes(j)) > 0) CYCLE
650
IF(FrontToRight(NodeIndexes(j))) CYCLE
651
counter = counter + 1
652
END DO
653
654
IF(counter == 0) Mesh % Elements(i) % BoundaryInfo % constraint = RightBCtag
655
END DO
656
657
!reassign any elements that now only contain nodes on lateral margins
658
DO i=NBulk+1, NBulk+NBdry
659
IF(Mesh % Elements(i) % BoundaryInfo % constraint /= FrontBCtag) CYCLE
660
NodeIndexes => Mesh % Elements(i) % NodeIndexes
661
n = Mesh % Elements(i) % TYPE % NumberOfNodes
662
counter = 0
663
DO j=1,n
664
IF(LeftPerm(NodeIndexes(j)) > 0) CYCLE
665
IF(FrontToLeft(NodeIndexes(j))) CYCLE
666
counter = counter + 1
667
END DO
668
669
IF(counter == 0) Mesh % Elements(i) % BoundaryInfo % constraint = LeftBCtag
670
END DO
671
672
!---------------------------------------
673
!Done, just deallocations
674
675
FirstTime = .FALSE.
676
677
DEALLOCATE(FrontPerm, TopPerm, LeftPerm, RightPerm, InflowPerm)
678
679
END SUBROUTINE GlacierAdvance3D
680
681